diff options
427 files changed, 17457 insertions, 10691 deletions
diff --git a/Android.bp b/Android.bp index 4ef6c5e82a5d..9d05ffd3de8c 100644 --- a/Android.bp +++ b/Android.bp @@ -25,721 +25,125 @@ // // READ ME: ######################################################## -java_defaults { - name: "framework-defaults", - installable: true, - +filegroup { + name: "framework-defaults-java-srcs", srcs: [ - // From build/make/core/pathmap.mk FRAMEWORK_BASE_SUBDIRS + // java sources under this directory "core/java/**/*.java", + "drm/java/**/*.java", "graphics/java/**/*.java", + "keystore/java/**/*.java", "location/java/**/*.java", "lowpan/java/**/*.java", "media/java/**/*.java", "media/mca/effect/java/**/*.java", "media/mca/filterfw/java/**/*.java", "media/mca/filterpacks/java/**/*.java", - "drm/java/**/*.java", "opengl/java/**/*.java", + "rs/java/**/*.java", "sax/java/**/*.java", "telecomm/java/**/*.java", "telephony/java/**/*.java", "wifi/java/**/*.java", - "keystore/java/**/*.java", - "rs/java/**/*.java", - - ":framework-javastream-protos", - - "core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl", - "core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl", - "core/java/android/accounts/IAccountManager.aidl", - "core/java/android/accounts/IAccountManagerResponse.aidl", - "core/java/android/accounts/IAccountAuthenticator.aidl", - "core/java/android/accounts/IAccountAuthenticatorResponse.aidl", - "core/java/android/app/IActivityController.aidl", - "core/java/android/app/IActivityManager.aidl", - "core/java/android/app/IActivityPendingResult.aidl", - "core/java/android/app/IActivityTaskManager.aidl", - "core/java/android/app/IAlarmCompleteListener.aidl", - "core/java/android/app/IAlarmListener.aidl", - "core/java/android/app/IAlarmManager.aidl", - "core/java/android/app/IAppTask.aidl", - "core/java/android/app/IApplicationThread.aidl", - "core/java/android/app/IAssistDataReceiver.aidl", - "core/java/android/app/ITaskStackListener.aidl", - "core/java/android/app/IBackupAgent.aidl", - "core/java/android/app/IEphemeralResolver.aidl", - "core/java/android/app/IInstantAppResolver.aidl", - "core/java/android/app/IInstrumentationWatcher.aidl", - "core/java/android/app/INotificationManager.aidl", - "core/java/android/app/IProcessObserver.aidl", - "core/java/android/app/IRequestFinishCallback.aidl", - "core/java/android/app/ISearchManager.aidl", - "core/java/android/app/ISearchManagerCallback.aidl", - "core/java/android/app/IServiceConnection.aidl", - "core/java/android/app/IStopUserCallback.aidl", - "core/java/android/app/job/IJobCallback.aidl", - "core/java/android/app/job/IJobScheduler.aidl", - "core/java/android/app/job/IJobService.aidl", - "core/java/android/app/ITransientNotification.aidl", - "core/java/android/app/IUidObserver.aidl", - "core/java/android/app/IUiAutomationConnection.aidl", - "core/java/android/app/IUiModeManager.aidl", - "core/java/android/app/IUriGrantsManager.aidl", - "core/java/android/app/IUserSwitchObserver.aidl", - "core/java/android/app/IWallpaperManager.aidl", - "core/java/android/app/IWallpaperManagerCallback.aidl", - "core/java/android/app/admin/IDeviceAdminService.aidl", - "core/java/android/app/admin/IDevicePolicyManager.aidl", - "core/java/android/app/admin/StartInstallingUpdateCallback.aidl", - "core/java/android/app/trust/IStrongAuthTracker.aidl", - "core/java/android/app/trust/ITrustManager.aidl", - "core/java/android/app/trust/ITrustListener.aidl", - "core/java/android/app/backup/IBackupCallback.aidl", - "core/java/android/app/backup/IBackupManager.aidl", - "core/java/android/app/backup/IBackupObserver.aidl", - "core/java/android/app/backup/IBackupManagerMonitor.aidl", - "core/java/android/app/backup/IFullBackupRestoreObserver.aidl", - "core/java/android/app/backup/IRestoreObserver.aidl", - "core/java/android/app/backup/IRestoreSession.aidl", - "core/java/android/app/backup/ISelectBackupTransportCallback.aidl", - "core/java/android/app/contentsuggestions/IClassificationsCallback.aidl", - "core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl", - "core/java/android/app/contentsuggestions/ISelectionsCallback.aidl", - "core/java/android/app/prediction/IPredictionCallback.aidl", - "core/java/android/app/prediction/IPredictionManager.aidl", - "core/java/android/app/role/IOnRoleHoldersChangedListener.aidl", - "core/java/android/app/role/IRoleController.aidl", - "core/java/android/app/role/IRoleManager.aidl", - "core/java/android/app/slice/ISliceManager.aidl", - "core/java/android/app/slice/ISliceListener.aidl", - "core/java/android/app/timedetector/ITimeDetectorService.aidl", - "core/java/android/app/timezone/ICallback.aidl", - "core/java/android/app/timezone/IRulesManager.aidl", - "core/java/android/app/usage/ICacheQuotaService.aidl", - "core/java/android/app/usage/IStorageStatsManager.aidl", - "core/java/android/app/usage/IUsageStatsManager.aidl", - ":libbluetooth-binder-aidl", - "core/java/android/content/IClipboard.aidl", - "core/java/android/content/IContentService.aidl", - "core/java/android/content/IIntentReceiver.aidl", - "core/java/android/content/IIntentSender.aidl", - "core/java/android/content/IOnPrimaryClipChangedListener.aidl", - "core/java/android/content/IRestrictionsManager.aidl", - "core/java/android/content/ISyncAdapter.aidl", - "core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl", - "core/java/android/content/ISyncContext.aidl", - "core/java/android/content/ISyncServiceAdapter.aidl", - "core/java/android/content/ISyncStatusObserver.aidl", - "core/java/android/content/om/IOverlayManager.aidl", - "core/java/android/content/pm/ICrossProfileApps.aidl", - "core/java/android/content/pm/IDexModuleRegisterCallback.aidl", - "core/java/android/content/pm/ILauncherApps.aidl", - "core/java/android/content/pm/IOnAppsChangedListener.aidl", - "core/java/android/content/pm/IOtaDexopt.aidl", - "core/java/android/content/pm/IPackageDataObserver.aidl", - "core/java/android/content/pm/IPackageDeleteObserver.aidl", - "core/java/android/content/pm/IPackageDeleteObserver2.aidl", - "core/java/android/content/pm/IPackageInstallObserver2.aidl", - "core/java/android/content/pm/IPackageInstaller.aidl", - "core/java/android/content/pm/IPackageInstallerCallback.aidl", - "core/java/android/content/pm/IPackageInstallerSession.aidl", - "core/java/android/content/pm/IPackageManager.aidl", - ":libbinder_aidl", - "core/java/android/content/pm/IPackageMoveObserver.aidl", - "core/java/android/content/pm/IPackageStatsObserver.aidl", - "core/java/android/content/pm/IPinItemRequest.aidl", - "core/java/android/content/pm/IShortcutService.aidl", - "core/java/android/content/pm/dex/IArtManager.aidl", - "core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl", - "core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl", - "core/java/android/content/rollback/IRollbackManager.aidl", - "core/java/android/database/IContentObserver.aidl", - "core/java/android/debug/IAdbManager.aidl", - "core/java/android/debug/IAdbTransport.aidl", - ":libcamera_client_aidl", - ":libcamera_client_framework_aidl", - "core/java/android/hardware/IConsumerIrService.aidl", - "core/java/android/hardware/ISerialManager.aidl", - "core/java/android/hardware/biometrics/IBiometricConfirmDeviceCredentialCallback.aidl", - "core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl", - "core/java/android/hardware/biometrics/IBiometricService.aidl", - "core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl", - "core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl", - "core/java/android/hardware/biometrics/IBiometricServiceLockoutResetCallback.aidl", - "core/java/android/hardware/display/IColorDisplayManager.aidl", - "core/java/android/hardware/display/IDisplayManager.aidl", - "core/java/android/hardware/display/IDisplayManagerCallback.aidl", - "core/java/android/hardware/display/IVirtualDisplayCallback.aidl", - "core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl", - "core/java/android/hardware/face/IFaceService.aidl", - "core/java/android/hardware/face/IFaceServiceReceiver.aidl", - "core/java/android/hardware/fingerprint/IFingerprintService.aidl", - "core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl", - "core/java/android/hardware/hdmi/IHdmiControlCallback.aidl", - "core/java/android/hardware/hdmi/IHdmiControlService.aidl", - "core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl", - "core/java/android/hardware/hdmi/IHdmiHotplugEventListener.aidl", - "core/java/android/hardware/hdmi/IHdmiInputChangeListener.aidl", - "core/java/android/hardware/hdmi/IHdmiMhlVendorCommandListener.aidl", - "core/java/android/hardware/hdmi/IHdmiRecordListener.aidl", - "core/java/android/hardware/hdmi/IHdmiSystemAudioModeChangeListener.aidl", - "core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl", - "core/java/android/hardware/input/IInputManager.aidl", - "core/java/android/hardware/input/IInputDevicesChangedListener.aidl", - "core/java/android/hardware/input/ITabletModeChangedListener.aidl", - "core/java/android/hardware/iris/IIrisService.aidl", - "core/java/android/hardware/location/IActivityRecognitionHardware.aidl", - "core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl", - "core/java/android/hardware/location/IActivityRecognitionHardwareSink.aidl", - "core/java/android/hardware/location/IActivityRecognitionHardwareWatcher.aidl", - "core/java/android/hardware/location/IGeofenceHardware.aidl", - "core/java/android/hardware/location/IGeofenceHardwareCallback.aidl", - "core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl", - "core/java/android/hardware/location/IContextHubCallback.aidl", - "core/java/android/hardware/location/IContextHubClient.aidl", - "core/java/android/hardware/location/IContextHubClientCallback.aidl", - "core/java/android/hardware/location/IContextHubService.aidl", - "core/java/android/hardware/location/IContextHubTransactionCallback.aidl", - "core/java/android/hardware/radio/IAnnouncementListener.aidl", - "core/java/android/hardware/radio/ICloseHandle.aidl", - "core/java/android/hardware/radio/IRadioService.aidl", - "core/java/android/hardware/radio/ITuner.aidl", - "core/java/android/hardware/radio/ITunerCallback.aidl", - "core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl", - "core/java/android/hardware/usb/IUsbManager.aidl", - "core/java/android/hardware/usb/IUsbSerialReader.aidl", - "core/java/android/net/ICaptivePortal.aidl", - "core/java/android/net/IConnectivityManager.aidl", - "core/java/android/hardware/ISensorPrivacyListener.aidl", - "core/java/android/hardware/ISensorPrivacyManager.aidl", - "core/java/android/net/IIpConnectivityMetrics.aidl", - "core/java/android/net/IEthernetManager.aidl", - "core/java/android/net/IEthernetServiceListener.aidl", - "core/java/android/net/INetdEventCallback.aidl", - "core/java/android/net/IIpSecService.aidl", - "core/java/android/net/INetworkManagementEventObserver.aidl", - "core/java/android/net/INetworkPolicyListener.aidl", - "core/java/android/net/INetworkPolicyManager.aidl", - "core/java/android/net/INetworkRecommendationProvider.aidl", - "core/java/android/net/INetworkScoreCache.aidl", - "core/java/android/net/INetworkScoreService.aidl", - "core/java/android/net/INetworkStatsService.aidl", - "core/java/android/net/INetworkStatsSession.aidl", - "core/java/android/net/ISocketKeepaliveCallback.aidl", - "core/java/android/net/ITestNetworkManager.aidl", - "core/java/android/net/ITetheringEventCallback.aidl", - "core/java/android/net/ITetheringStatsProvider.aidl", - "core/java/android/net/nsd/INsdManager.aidl", - "core/java/android/nfc/IAppCallback.aidl", - "core/java/android/nfc/INfcAdapter.aidl", - "core/java/android/nfc/INfcAdapterExtras.aidl", - "core/java/android/nfc/INfcTag.aidl", - "core/java/android/nfc/INfcCardEmulation.aidl", - "core/java/android/nfc/INfcFCardEmulation.aidl", - "core/java/android/nfc/INfcUnlockHandler.aidl", - "core/java/android/nfc/INfcDta.aidl", - "core/java/android/nfc/ITagRemovedCallback.aidl", - "core/java/android/se/omapi/ISecureElementService.aidl", - "core/java/android/se/omapi/ISecureElementListener.aidl", - "core/java/android/se/omapi/ISecureElementChannel.aidl", - "core/java/android/se/omapi/ISecureElementReader.aidl", - "core/java/android/se/omapi/ISecureElementSession.aidl", - "core/java/android/os/IBatteryPropertiesRegistrar.aidl", - "core/java/android/os/ICancellationSignal.aidl", - "core/java/android/os/IDeviceIdentifiersPolicyService.aidl", - "core/java/android/os/IDeviceIdleController.aidl", - "core/java/android/os/IHardwarePropertiesManager.aidl", - ":libincident_aidl", - "core/java/android/os/IMaintenanceActivityListener.aidl", - "core/java/android/os/IMessenger.aidl", - "core/java/android/os/INetworkActivityListener.aidl", - "core/java/android/os/INetworkManagementService.aidl", - "core/java/android/os/IPermissionController.aidl", - "core/java/android/os/IProcessInfoService.aidl", - "core/java/android/os/IProgressListener.aidl", - "core/java/android/os/IPowerManager.aidl", - "core/java/android/os/IRecoverySystem.aidl", - "core/java/android/os/IRecoverySystemProgressListener.aidl", - "core/java/android/os/IRemoteCallback.aidl", - "core/java/android/os/ISchedulingPolicyService.aidl", - ":statsd_aidl", - "core/java/android/os/ISystemUpdateManager.aidl", - "core/java/android/os/IThermalEventListener.aidl", - "core/java/android/os/IThermalStatusListener.aidl", - "core/java/android/os/IThermalService.aidl", - "core/java/android/os/IUpdateLock.aidl", - "core/java/android/os/IUserManager.aidl", - ":libvibrator_aidl", - "core/java/android/os/IVibratorService.aidl", - "core/java/android/os/image/IDynamicSystemService.aidl", - "core/java/android/os/storage/IStorageManager.aidl", - "core/java/android/os/storage/IStorageEventListener.aidl", - "core/java/android/os/storage/IStorageShutdownObserver.aidl", - "core/java/android/os/storage/IObbActionListener.aidl", - "core/java/android/permission/IOnPermissionsChangeListener.aidl", - "core/java/android/permission/IPermissionController.aidl", - "core/java/android/permission/IPermissionManager.aidl", - ":keystore_aidl", - "core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl", - "core/java/android/service/appprediction/IPredictionService.aidl", - "core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl", - "core/java/android/service/autofill/augmented/IFillCallback.aidl", - "core/java/android/service/autofill/IAutoFillService.aidl", - "core/java/android/service/autofill/IAutofillFieldClassificationService.aidl", - "core/java/android/service/autofill/IFillCallback.aidl", - "core/java/android/service/autofill/ISaveCallback.aidl", - "core/java/android/service/carrier/ICarrierService.aidl", - "core/java/android/service/carrier/ICarrierMessagingCallback.aidl", - "core/java/android/service/carrier/ICarrierMessagingService.aidl", - "core/java/android/service/carrier/ICarrierMessagingClientService.aidl", - "core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl", - "core/java/android/service/euicc/IDeleteSubscriptionCallback.aidl", - "core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl", - "core/java/android/service/euicc/IEraseSubscriptionsCallback.aidl", - "core/java/android/service/euicc/IEuiccService.aidl", - "core/java/android/service/euicc/IGetDefaultDownloadableSubscriptionListCallback.aidl", - "core/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl", - "core/java/android/service/euicc/IGetEidCallback.aidl", - "core/java/android/service/euicc/IGetEuiccInfoCallback.aidl", - "core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl", - "core/java/android/service/euicc/IGetOtaStatusCallback.aidl", - "core/java/android/service/euicc/IOtaStatusChangedCallback.aidl", - "core/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl", - "core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl", - "core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl", - ":gatekeeper_aidl", - "core/java/android/service/contentcapture/IContentCaptureService.aidl", - "core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl", - "core/java/android/service/notification/INotificationListener.aidl", - "core/java/android/service/notification/IStatusBarNotificationHolder.aidl", - "core/java/android/service/notification/IConditionListener.aidl", - "core/java/android/service/notification/IConditionProvider.aidl", - "core/java/android/service/settings/suggestions/ISuggestionService.aidl", - "core/java/android/service/sms/IFinancialSmsService.aidl", - "core/java/android/service/vr/IPersistentVrStateCallbacks.aidl", - "core/java/android/service/vr/IVrListener.aidl", - "core/java/android/service/vr/IVrManager.aidl", - "core/java/android/service/vr/IVrStateCallbacks.aidl", - "core/java/android/service/watchdog/IExplicitHealthCheckService.aidl", - "core/java/android/service/watchdog/PackageConfig.aidl", - "core/java/android/print/ILayoutResultCallback.aidl", - "core/java/android/print/IPrinterDiscoveryObserver.aidl", - "core/java/android/print/IPrintDocumentAdapter.aidl", - "core/java/android/print/IPrintDocumentAdapterObserver.aidl", - "core/java/android/print/IPrintJobStateChangeListener.aidl", - "core/java/android/print/IPrintServicesChangeListener.aidl", - "core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl", - "core/java/android/print/IPrintManager.aidl", - "core/java/android/print/IPrintSpooler.aidl", - "core/java/android/print/IPrintSpoolerCallbacks.aidl", - "core/java/android/print/IPrintSpoolerClient.aidl", - "core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl", - "core/java/android/printservice/recommendation/IRecommendationService.aidl", - "core/java/android/print/IWriteResultCallback.aidl", - "core/java/android/printservice/IPrintService.aidl", - "core/java/android/printservice/IPrintServiceClient.aidl", - "core/java/android/companion/ICompanionDeviceManager.aidl", - "core/java/android/companion/ICompanionDeviceDiscoveryService.aidl", - "core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl", - "core/java/android/companion/IFindDeviceCallback.aidl", - "core/java/android/service/dreams/IDreamManager.aidl", - "core/java/android/service/dreams/IDreamService.aidl", - "core/java/android/service/oemlock/IOemLockService.aidl", - "core/java/android/service/persistentdata/IPersistentDataBlockService.aidl", - "core/java/android/service/trust/ITrustAgentService.aidl", - "core/java/android/service/trust/ITrustAgentServiceCallback.aidl", - "core/java/android/service/voice/IVoiceInteractionService.aidl", - "core/java/android/service/voice/IVoiceInteractionSession.aidl", - "core/java/android/service/voice/IVoiceInteractionSessionService.aidl", - "core/java/android/service/wallpaper/IWallpaperConnection.aidl", - "core/java/android/service/wallpaper/IWallpaperEngine.aidl", - "core/java/android/service/wallpaper/IWallpaperService.aidl", - "core/java/android/service/chooser/IChooserTargetService.aidl", - "core/java/android/service/chooser/IChooserTargetResult.aidl", - "core/java/android/service/resolver/IResolverRankerService.aidl", - "core/java/android/service/resolver/IResolverRankerResult.aidl", - "core/java/android/service/textclassifier/ITextClassifierCallback.aidl", - "core/java/android/service/textclassifier/ITextClassifierService.aidl", - "core/java/android/service/attention/IAttentionService.aidl", - "core/java/android/service/attention/IAttentionCallback.aidl", - "core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl", - "core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl", - "core/java/android/view/accessibility/IAccessibilityManager.aidl", - "core/java/android/view/accessibility/IAccessibilityManagerClient.aidl", - "core/java/android/view/autofill/IAutoFillManager.aidl", - "core/java/android/view/autofill/IAutoFillManagerClient.aidl", - "core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl", - "core/java/android/view/autofill/IAutofillWindowPresenter.aidl", - "core/java/android/view/contentcapture/IContentCaptureDirectManager.aidl", - "core/java/android/view/contentcapture/IContentCaptureManager.aidl", - "core/java/android/view/IApplicationToken.aidl", - "core/java/android/view/IAppTransitionAnimationSpecsFuture.aidl", - "core/java/android/view/IDockedStackListener.aidl", - "core/java/android/view/IDisplayFoldListener.aidl", - "core/java/android/view/IGraphicsStats.aidl", - "core/java/android/view/IGraphicsStatsCallback.aidl", - "core/java/android/view/IInputMonitorHost.aidl", - "core/java/android/view/IInputFilter.aidl", - "core/java/android/view/IInputFilterHost.aidl", - "core/java/android/view/IOnKeyguardExitResult.aidl", - "core/java/android/view/IPinnedStackController.aidl", - "core/java/android/view/IPinnedStackListener.aidl", - "core/java/android/view/IRemoteAnimationRunner.aidl", - "core/java/android/view/IRecentsAnimationController.aidl", - "core/java/android/view/IRecentsAnimationRunner.aidl", - "core/java/android/view/IRemoteAnimationFinishedCallback.aidl", - "core/java/android/view/IRotationWatcher.aidl", - "core/java/android/view/ISystemGestureExclusionListener.aidl", - "core/java/android/view/IWallpaperVisibilityListener.aidl", - "core/java/android/view/IWindow.aidl", - "core/java/android/view/IWindowFocusObserver.aidl", - "core/java/android/view/IWindowId.aidl", - "core/java/android/view/IWindowManager.aidl", - "core/java/android/view/IWindowSession.aidl", - "core/java/android/view/IWindowSessionCallback.aidl", - "core/java/android/webkit/IWebViewUpdateService.aidl", - "core/java/android/speech/IRecognitionListener.aidl", - "core/java/android/speech/IRecognitionService.aidl", - "core/java/android/speech/tts/ITextToSpeechCallback.aidl", - "core/java/android/speech/tts/ITextToSpeechService.aidl", - "core/java/com/android/internal/app/IAppOpsActiveCallback.aidl", - "core/java/com/android/internal/app/IAppOpsCallback.aidl", - "core/java/com/android/internal/app/IAppOpsNotedCallback.aidl", - "core/java/com/android/internal/app/IAppOpsService.aidl", - "core/java/com/android/internal/app/IBatteryStats.aidl", - "core/java/com/android/internal/app/ISoundTriggerService.aidl", - "core/java/com/android/internal/app/IVoiceActionCheckCallback.aidl", - "core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl", - "core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl", - "core/java/com/android/internal/app/IVoiceInteractionSessionShowCallback.aidl", - "core/java/com/android/internal/app/IVoiceInteractor.aidl", - "core/java/com/android/internal/app/IVoiceInteractorCallback.aidl", - "core/java/com/android/internal/app/IVoiceInteractorRequest.aidl", - "core/java/com/android/internal/app/IMediaContainerService.aidl", - "core/java/com/android/internal/app/procstats/IProcessStats.aidl", - "core/java/com/android/internal/appwidget/IAppWidgetService.aidl", - "core/java/com/android/internal/appwidget/IAppWidgetHost.aidl", - "core/java/com/android/internal/backup/IBackupTransport.aidl", - "core/java/com/android/internal/backup/IObbBackupService.aidl", - "core/java/com/android/internal/infra/IAndroidFuture.aidl", - "core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl", - "core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl", - "core/java/com/android/internal/inputmethod/IMultiClientInputMethod.aidl", - "core/java/com/android/internal/inputmethod/IMultiClientInputMethodPrivilegedOperations.aidl", - "core/java/com/android/internal/inputmethod/IMultiClientInputMethodSession.aidl", - "core/java/com/android/internal/net/INetworkWatchlistManager.aidl", - "core/java/com/android/internal/policy/IKeyguardDrawnCallback.aidl", - "core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl", - "core/java/com/android/internal/policy/IKeyguardExitCallback.aidl", - "core/java/com/android/internal/policy/IKeyguardService.aidl", - "core/java/com/android/internal/policy/IKeyguardStateCallback.aidl", - "core/java/com/android/internal/policy/IShortcutService.aidl", - "core/java/com/android/internal/os/IDropBoxManagerService.aidl", - "core/java/com/android/internal/os/IParcelFileDescriptorFactory.aidl", - "core/java/com/android/internal/os/IResultReceiver.aidl", - "core/java/com/android/internal/os/IShellCallback.aidl", - "core/java/com/android/internal/statusbar/IStatusBar.aidl", - "core/java/com/android/internal/statusbar/IStatusBarService.aidl", - "core/java/com/android/internal/statusbar/RegisterStatusBarResult.aidl", - "core/java/com/android/internal/textservice/ISpellCheckerService.aidl", - "core/java/com/android/internal/textservice/ISpellCheckerServiceCallback.aidl", - "core/java/com/android/internal/textservice/ISpellCheckerSession.aidl", - "core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl", - "core/java/com/android/internal/textservice/ITextServicesManager.aidl", - "core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl", - "core/java/com/android/internal/view/IDragAndDropPermissions.aidl", - "core/java/com/android/internal/view/IInputContext.aidl", - "core/java/com/android/internal/view/IInputContextCallback.aidl", - "core/java/com/android/internal/view/IInputMethod.aidl", - "core/java/com/android/internal/view/IInputMethodClient.aidl", - "core/java/com/android/internal/view/IInputMethodManager.aidl", - "core/java/com/android/internal/view/IInputMethodSession.aidl", - "core/java/com/android/internal/view/IInputSessionCallback.aidl", - "core/java/com/android/internal/widget/ICheckCredentialProgressCallback.aidl", - "core/java/com/android/internal/widget/ILockSettings.aidl", - "core/java/com/android/internal/widget/IRemoteViewsFactory.aidl", - "keystore/java/android/security/IKeyChainAliasCallback.aidl", - "keystore/java/android/security/IKeyChainService.aidl", - "location/java/android/location/IBatchedLocationCallback.aidl", - "location/java/android/location/ICountryDetector.aidl", - "location/java/android/location/ICountryListener.aidl", - "location/java/android/location/IGeocodeProvider.aidl", - "location/java/android/location/IGeofenceProvider.aidl", - "location/java/android/location/IGnssStatusListener.aidl", - "location/java/android/location/IGnssMeasurementsListener.aidl", - "location/java/android/location/IGnssNavigationMessageListener.aidl", - "location/java/android/location/ILocationListener.aidl", - "location/java/android/location/ILocationManager.aidl", - "location/java/android/location/IFusedGeofenceHardware.aidl", - "location/java/android/location/IGpsGeofenceHardware.aidl", - "location/java/android/location/INetInitiatedListener.aidl", - "location/java/com/android/internal/location/ILocationProvider.aidl", - "location/java/com/android/internal/location/ILocationProviderManager.aidl", - "media/java/android/media/IAudioFocusDispatcher.aidl", - "media/java/android/media/IAudioRoutesObserver.aidl", - "media/java/android/media/IAudioService.aidl", - "media/java/android/media/IAudioServerStateDispatcher.aidl", - "media/java/android/media/IMediaHTTPConnection.aidl", - "media/java/android/media/IMediaHTTPService.aidl", - "media/java/android/media/IMediaResourceMonitor.aidl", - "media/java/android/media/IMediaRoute2Provider.aidl", - "media/java/android/media/IMediaRoute2ProviderClient.aidl", - "media/java/android/media/IMediaRouter2Client.aidl", - "media/java/android/media/IMediaRouter2Manager.aidl", - "media/java/android/media/IMediaRouterClient.aidl", - "media/java/android/media/IMediaRouterService.aidl", - "media/java/android/media/IMediaScannerListener.aidl", - "media/java/android/media/IMediaScannerService.aidl", - "media/java/android/media/IPlaybackConfigDispatcher.aidl", - ":libaudioclient_aidl", - "media/java/android/media/IRecordingConfigDispatcher.aidl", - "media/java/android/media/IRemoteDisplayCallback.aidl", - "media/java/android/media/IRemoteDisplayProvider.aidl", - "media/java/android/media/IRemoteVolumeController.aidl", - "media/java/android/media/IRemoteVolumeObserver.aidl", - "media/java/android/media/IRingtonePlayer.aidl", - "media/java/android/media/IVolumeController.aidl", - "media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl", - "media/java/android/media/midi/IBluetoothMidiService.aidl", - "media/java/android/media/midi/IMidiDeviceListener.aidl", - "media/java/android/media/midi/IMidiDeviceOpenCallback.aidl", - "media/java/android/media/midi/IMidiDeviceServer.aidl", - "media/java/android/media/midi/IMidiManager.aidl", - "media/java/android/media/projection/IMediaProjection.aidl", - "media/java/android/media/projection/IMediaProjectionCallback.aidl", - "media/java/android/media/projection/IMediaProjectionManager.aidl", - "media/java/android/media/projection/IMediaProjectionWatcherCallback.aidl", - "media/java/android/media/session/IActiveSessionsListener.aidl", - "media/java/android/media/session/ICallback.aidl", - "media/java/android/media/session/IOnMediaKeyListener.aidl", - "media/java/android/media/session/IOnVolumeKeyLongPressListener.aidl", - "media/java/android/media/session/ISession.aidl", - "media/java/android/media/session/ISession2TokensListener.aidl", - "media/java/android/media/session/ISessionCallback.aidl", - "media/java/android/media/session/ISessionController.aidl", - "media/java/android/media/session/ISessionControllerCallback.aidl", - "media/java/android/media/session/ISessionManager.aidl", - "media/java/android/media/soundtrigger/ISoundTriggerDetectionService.aidl", - "media/java/android/media/soundtrigger/ISoundTriggerDetectionServiceClient.aidl", - "media/java/android/media/tv/ITvInputClient.aidl", - "media/java/android/media/tv/ITvInputHardware.aidl", - "media/java/android/media/tv/ITvInputHardwareCallback.aidl", - "media/java/android/media/tv/ITvInputManager.aidl", - "media/java/android/media/tv/ITvInputManagerCallback.aidl", - "media/java/android/media/tv/ITvInputService.aidl", - "media/java/android/media/tv/ITvInputServiceCallback.aidl", - "media/java/android/media/tv/ITvInputSession.aidl", - "media/java/android/media/tv/ITvInputSessionCallback.aidl", - "media/java/android/media/tv/ITvRemoteProvider.aidl", - "media/java/android/media/tv/ITvRemoteServiceInput.aidl", - "media/java/android/service/media/IMediaBrowserService.aidl", - "media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl", - "telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl", - "telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl", - "telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl", - "telecomm/java/com/android/internal/telecom/ICallScreeningService.aidl", - "telecomm/java/com/android/internal/telecom/IVideoCallback.aidl", - "telecomm/java/com/android/internal/telecom/IVideoProvider.aidl", - "telecomm/java/com/android/internal/telecom/IConnectionService.aidl", - "telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl", - "telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl", - "telecomm/java/com/android/internal/telecom/IInCallService.aidl", - "telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionCallback.aidl", - "telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionService.aidl", - "telecomm/java/com/android/internal/telecom/ITelecomService.aidl", - "telecomm/java/com/android/internal/telecom/RemoteServiceCallback.aidl", - "telephony/java/android/telephony/data/IDataService.aidl", - "telephony/java/android/telephony/data/IDataServiceCallback.aidl", - "telephony/java/android/telephony/data/IQualifiedNetworksService.aidl", - "telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl", - "telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl", - "telephony/java/android/telephony/ims/aidl/IImsCapabilityCallback.aidl", - "telephony/java/android/telephony/ims/aidl/IImsConfig.aidl", - "telephony/java/android/telephony/ims/aidl/IImsConfigCallback.aidl", - "telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl", - "telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl", - "telephony/java/android/telephony/ims/aidl/IImsRegistration.aidl", - "telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl", - "telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl", - "telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl", - "telephony/java/android/telephony/ims/aidl/IImsServiceControllerListener.aidl", - "telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl", - "telephony/java/android/telephony/ims/aidl/IRcsMessage.aidl", - "telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl", - "telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl", - "telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl", - "telephony/java/android/telephony/mbms/IDownloadStatusListener.aidl", - "telephony/java/android/telephony/mbms/IDownloadProgressListener.aidl", - "telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl", - "telephony/java/android/telephony/mbms/IGroupCallCallback.aidl", - "telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl", - "telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl", - "telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl", - "telephony/java/android/telephony/ICellInfoCallback.aidl", - "telephony/java/android/telephony/IFinancialSmsCallback.aidl", - "telephony/java/android/telephony/INetworkService.aidl", - "telephony/java/android/telephony/INetworkServiceCallback.aidl", - "telephony/java/com/android/ims/internal/IImsCallSession.aidl", - "telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl", - "telephony/java/com/android/ims/internal/IImsConfig.aidl", - "telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl", - "telephony/java/com/android/ims/internal/IImsEcbm.aidl", - "telephony/java/com/android/ims/internal/IImsEcbmListener.aidl", - "telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl", - "telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl", - "telephony/java/com/android/ims/internal/IImsMMTelFeature.aidl", - "telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl", - "telephony/java/com/android/ims/internal/IImsRcsFeature.aidl", - "telephony/java/com/android/ims/internal/IImsService.aidl", - "telephony/java/com/android/ims/internal/IImsServiceController.aidl", - "telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl", - "telephony/java/com/android/ims/internal/IImsStreamMediaSession.aidl", - "telephony/java/com/android/ims/internal/IImsUt.aidl", - "telephony/java/com/android/ims/internal/IImsUtListener.aidl", - "telephony/java/com/android/ims/internal/IImsVideoCallCallback.aidl", - "telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl", - "telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl", - "telephony/java/com/android/ims/internal/uce/uceservice/IUceListener.aidl", - "telephony/java/com/android/ims/internal/uce/options/IOptionsService.aidl", - "telephony/java/com/android/ims/internal/uce/options/IOptionsListener.aidl", - "telephony/java/com/android/ims/internal/uce/presence/IPresenceService.aidl", - "telephony/java/com/android/ims/internal/uce/presence/IPresenceListener.aidl", - "telephony/java/com/android/ims/ImsConfigListener.aidl", - "telephony/java/com/android/internal/telephony/IApnSourceService.aidl", - "telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl", - "telephony/java/com/android/internal/telephony/IIntegerConsumer.aidl", - "telephony/java/com/android/internal/telephony/IMms.aidl", - "telephony/java/com/android/internal/telephony/INumberVerificationCallback.aidl", - "telephony/java/com/android/internal/telephony/IOnSubscriptionsChangedListener.aidl", - "telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl", - "telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl", - "telephony/java/com/android/internal/telephony/ISetOpportunisticDataCallback.aidl", - "telephony/java/com/android/internal/telephony/ISms.aidl", - "telephony/java/com/android/internal/telephony/ISub.aidl", - "telephony/java/com/android/internal/telephony/IOns.aidl", - "telephony/java/com/android/internal/telephony/ITelephony.aidl", - "telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl", - "telephony/java/com/android/internal/telephony/IUpdateAvailableNetworksCallback.aidl", - "telephony/java/com/android/internal/telephony/IWapPushManager.aidl", - "telephony/java/com/android/internal/telephony/euicc/IAuthenticateServerCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/ICancelSessionCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/IDeleteProfileCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/IDisableProfileCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl", - "telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl", - "telephony/java/com/android/internal/telephony/euicc/IGetAllProfilesCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/IGetDefaultSmdpAddressCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/IGetEuiccChallengeCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/IGetEuiccInfo1Callback.aidl", - "telephony/java/com/android/internal/telephony/euicc/IGetEuiccInfo2Callback.aidl", - "telephony/java/com/android/internal/telephony/euicc/IGetProfileCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/IGetRulesAuthTableCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/IGetSmdsAddressCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/IListNotificationsCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/ILoadBoundProfilePackageCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/IPrepareDownloadCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/IRemoveNotificationFromListCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/IResetMemoryCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/IRetrieveNotificationCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/IRetrieveNotificationListCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/ISetDefaultSmdpAddressCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/ISetNicknameCallback.aidl", - "telephony/java/com/android/internal/telephony/euicc/ISwitchToProfileCallback.aidl", - "wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl", - "wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl", - "wifi/java/android/net/wifi/ISoftApCallback.aidl", - "wifi/java/android/net/wifi/ITrafficStateCallback.aidl", - "wifi/java/android/net/wifi/IWifiManager.aidl", - "wifi/java/android/net/wifi/IOnWifiUsabilityStatsListener.aidl", - "wifi/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl", - "wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl", - "wifi/java/android/net/wifi/aware/IWifiAwareMacAddressProvider.aidl", - "wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl", - "wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl", - "wifi/java/android/net/wifi/rtt/IRttCallback.aidl", - "wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl", - "wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl", - "wifi/java/android/net/wifi/IDppCallback.aidl", - "wifi/java/android/net/wifi/IWifiScanner.aidl", - "packages/services/PacProcessor/com/android/net/IProxyService.aidl", - "packages/services/Proxy/com/android/net/IProxyCallback.aidl", - "packages/services/Proxy/com/android/net/IProxyPortListener.aidl", - "core/java/android/service/quicksettings/IQSService.aidl", - "core/java/android/service/quicksettings/IQSTileService.aidl", - - ":libupdate_engine_aidl", - - ":storaged_aidl", - ":vold_aidl", - ":gsiservice_aidl", - ":installd_aidl", - ":dumpstate_aidl", - ":incidentcompanion_aidl", - - "lowpan/java/android/net/lowpan/ILowpanEnergyScanCallback.aidl", - "lowpan/java/android/net/lowpan/ILowpanNetScanCallback.aidl", - "lowpan/java/android/net/lowpan/ILowpanInterfaceListener.aidl", - "lowpan/java/android/net/lowpan/ILowpanInterface.aidl", - "lowpan/java/android/net/lowpan/ILowpanManagerListener.aidl", - "lowpan/java/android/net/lowpan/ILowpanManager.aidl", - - "core/java/android/app/admin/SecurityLogTags.logtags", - "core/java/android/content/EventLogTags.logtags", - "core/java/android/speech/tts/EventLogTags.logtags", - "core/java/android/net/EventLogTags.logtags", - "core/java/android/os/EventLogTags.logtags", - "core/java/android/webkit/EventLogTags.logtags", - "core/java/com/android/internal/app/EventLogTags.logtags", - "core/java/com/android/internal/logging/EventLogTags.logtags", - "core/java/com/android/server/DropboxLogTags.logtags", - "core/java/org/chromium/arc/EventLogTags.logtags", - - ":apex-properties", - ":platform-properties", - - ":framework-statslog-gen", ], +} + +// TODO(b/70046217): make these as filegroups where the base directory for aidl files +// is given as 'path'. Eliminate the need for aidl_local_include_dirs. +framework_srcs = [ + // aidl under this directory + // b/70046217#comment15 These MUST come after all java srcs. + // TODO(b/70046217) remove the above requirement + "core/java/**/*.aidl", + "graphics/java/**/*.aidl", + "keystore/java/**/*.aidl", + "location/java/**/*.aidl", + "lowpan/java/**/*.aidl", + "media/java/**/*.aidl", + "packages/services/PacProcessor/**/*.aidl", + "packages/services/Proxy/**/*.aidl", + "telecomm/java/**/*.aidl", + "telephony/java/**/*.aidl", + "wifi/java/**/*.aidl", + + // aidl from external directories + ":dumpstate_aidl", + ":gatekeeper_aidl", + ":gsiservice_aidl", + ":incidentcompanion_aidl", + ":installd_aidl", + ":keystore_aidl", + ":libaudioclient_aidl", + ":libbinder_aidl", + ":libbluetooth-binder-aidl", + ":libcamera_client_aidl", + ":libcamera_client_framework_aidl", + ":libupdate_engine_aidl", + ":storaged_aidl", + ":vold_aidl", + + // etc. + "core/java/**/*.logtags", + ":framework-javastream-protos", + ":framework-statslog-gen", +] + +framework_aidl_local_include_dirs = [ + "core/java", + "drm/java", + "graphics/java", + "keystore/java", + "location/java", + "lowpan/java", + "media/java", + "media/apex/java", + "media/mca/effect/java", + "media/mca/filterfw/java", + "media/mca/filterpacks/java", + "opengl/java", + "rs/java", + "sax/java", + "telecomm/java", + "telephony/java", + "wifi/java", +] + +framework_aidl_external_include_dirs = [ + "frameworks/av/camera/aidl", + "frameworks/av/media/libaudioclient/aidl", + "frameworks/native/aidl/binder", + "frameworks/native/aidl/gui", + "frameworks/native/cmds/dumpstate/binder", + "frameworks/native/libs/incidentcompanion/binder", + "system/bt/binder", + "system/core/gatekeeperd/binder", + "system/core/storaged/binder", + "system/gsid/aidl", + "system/security/keystore/binder", + "system/update_engine/binder_bindings", + "system/vold/binder", +] + +java_defaults { + name: "framework-aidl-export-defaults", aidl: { - export_include_dirs: [ - // From build/make/core/pathmap.mk FRAMEWORK_BASE_SUBDIRS - "core/java", - "graphics/java", - "location/java", - "lowpan/java", - "media/java", - "media/apex/java", - "media/mca/effect/java", - "media/mca/filterfw/java", - "media/mca/filterpacks/java", - "drm/java", - "opengl/java", - "sax/java", - "telecomm/java", - "telephony/java", - "wifi/java", - "keystore/java", - "rs/java", - ], - - include_dirs: [ - "system/update_engine/binder_bindings", - "frameworks/native/aidl/binder", - "frameworks/native/cmds/dumpstate/binder", - "frameworks/native/libs/incidentcompanion/binder", - "frameworks/av/camera/aidl", - "frameworks/av/media/libaudioclient/aidl", - "frameworks/native/aidl/gui", - "frameworks/native/libs/incidentcompanion/binder", - "system/core/gatekeeperd/binder", - "system/core/storaged/binder", - "system/vold/binder", - "system/gsid/aidl", - "system/bt/binder", - "system/security/keystore/binder", - ], + export_include_dirs: framework_aidl_local_include_dirs, + }, +} + +java_defaults { + name: "framework-defaults", + defaults: ["framework-aidl-export-defaults"], + installable: true, + + srcs: [ + ":framework-defaults-java-srcs", + ] + framework_srcs, + aidl: { + local_include_dirs: framework_aidl_local_include_dirs, + include_dirs: framework_aidl_external_include_dirs, generate_get_transaction_name: true, }, @@ -786,6 +190,9 @@ java_defaults { "android.hardware.vibrator-V1.3-java", "android.hardware.wifi-V1.0-java-constants", "devicepolicyprotosnano", + + "com.android.sysprop.apex", + "PlatformProperties", ], required: [ @@ -838,13 +245,24 @@ filegroup { } java_library { - name: "framework", + name: "framework-minus-apex", defaults: ["framework-defaults"], javac_shard_size: 150, +} + +java_library { + name: "framework", + defaults: ["framework-aidl-export-defaults"], + installable: true, + static_libs: [ + "framework-minus-apex", + "jobscheduler-framework", + ], required: [ "framework-platform-compat-config", "libcore-platform-compat-config", ], + sdk_version: "core_platform", } java_library { @@ -1371,8 +789,9 @@ stubs_defaults { ":updatable-media-srcs-without-aidls", "test-mock/src/**/*.java", "test-runner/src/**/*.java", + ":jobscheduler-framework-source", ], - srcs_lib: "framework", + srcs_lib: "framework-minus-apex", srcs_lib_whitelist_dirs: frameworks_base_subdirs, srcs_lib_whitelist_pkgs: packages_to_document, libs: framework_docs_only_libs, @@ -1428,8 +847,9 @@ stubs_defaults { ":opt-net-voip-srcs", ":core_public_api_files", ":updatable-media-srcs-without-aidls", + ":jobscheduler-framework-source", ], - srcs_lib: "framework", + srcs_lib: "framework-minus-apex", srcs_lib_whitelist_dirs: frameworks_base_subdirs, srcs_lib_whitelist_pkgs: packages_to_document, local_sourcepaths: frameworks_base_subdirs, @@ -1752,10 +1172,10 @@ droidstubs { name: "hiddenapi-mappings", defaults: ["metalava-api-stubs-default"], srcs: [ - ":openjdk_java_files", + ":framework-defaults-java-srcs", ":non_openjdk_java_files", + ":openjdk_java_files", ":opt-telephony-common-srcs", - "core/java/**/*.java", ], arg_files: [ "core/res/AndroidManifest.xml", @@ -1810,6 +1230,7 @@ droidstubs { last_released: { api_file: ":last-released-public-api", removed_api_file: "api/removed.txt", + baseline_file: ":public-api-incompatibilities-with-last-released", }, }, jdiff_enabled: true, @@ -1835,6 +1256,7 @@ droidstubs { last_released: { api_file: ":last-released-system-api", removed_api_file: "api/system-removed.txt", + baseline_file: ":system-api-incompatibilities-with-last-released" }, }, jdiff_enabled: true, @@ -1889,7 +1311,9 @@ filegroup { // annotations to private apis aidl_mapping { name: "framework-aidl-mappings", - srcs: [":framework-defaults"], + srcs: framework_srcs, + local_include_dirs: framework_aidl_local_include_dirs, + include_dirs: framework_aidl_external_include_dirs, output: "framework-aidl-mappings.txt", } diff --git a/apex/jobscheduler/OWNERS b/apex/jobscheduler/OWNERS new file mode 100644 index 000000000000..d004eed2a0db --- /dev/null +++ b/apex/jobscheduler/OWNERS @@ -0,0 +1,6 @@ +yamasani@google.com +omakoto@google.com +ctate@android.com +ctate@google.com +kwekua@google.com +suprabh@google.com
\ No newline at end of file diff --git a/apex/jobscheduler/README_js-mainline.md b/apex/jobscheduler/README_js-mainline.md index b5fea5e0a4df..c1ad666e3e05 100644 --- a/apex/jobscheduler/README_js-mainline.md +++ b/apex/jobscheduler/README_js-mainline.md @@ -6,46 +6,33 @@ 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.) +## Current structure -## 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. +- JS service side classes are put in `jobscheduler-service.jar`. +It's *not* included in services.jar, and instead it's put in the system server classpath, +which currently looks like the following: +`SYSTEMSERVERCLASSPATH=/system/framework/services.jar:/system/framework/jobscheduler-service.jar:/system/framework/ethernet-service.jar:/system/framework/wifi-service.jar:/system/framework/com.android.location.provider.jar` + + (Note `jobscheduler-service.jar` will be put at the end in http://ag/9128109) + + `SYSTEMSERVERCLASSPATH` is generated from `PRODUCT_SYSTEM_SERVER_JARS`. + +- JS framework side classes are put in `jobscheduler-framework.jar`, +and the rest of the framework code is put in `framework-minus-apex.jar`, +as of http://ag/9145619. + + However these jar files are *not* put on the device. We still generate + `framework.jar` merging the two jar files, and this jar file is what's + put on the device and loaded by Zygote. + + +This is *not* the final design. From a gerrit comment on http://ag/9145619: + +> This CL is just the first step, and the current state isn't not really the final form. For now we just want to have two separate jars, which makes it easier for us to analyze dependencies between them, and I wanted to minimize the change to the rest of the system. So, for example, zygote will still only have "framework.jar" in its classpath, instead of the two jars for now. +> But yes, eventually, we won't even be able to have the monolithic "framework.jar" file because of mainline, so we need to figure out how to build the system without creating it. At that point zygote will have the two separate jar files in its classpath. +> When we reach that point, we should revisit the naming of it, and yes, maybe the simple "framework.jar" is a good option. +> But again, for now, I want to make this change as transparent as possible to the rest of the world. diff --git a/apex/jobscheduler/framework/Android.bp b/apex/jobscheduler/framework/Android.bp new file mode 100644 index 000000000000..bdb5248afcee --- /dev/null +++ b/apex/jobscheduler/framework/Android.bp @@ -0,0 +1,29 @@ +filegroup { + name: "jobscheduler-framework-source", + srcs: [ + "java/**/*.java", + "java/android/app/job/IJobCallback.aidl", + "java/android/app/job/IJobScheduler.aidl", + "java/android/app/job/IJobService.aidl", + ], + path: "java", +} + +java_library { + name: "jobscheduler-framework", + installable: true, + sdk_version: "core_platform", + + srcs: [ + ":jobscheduler-framework-source", + ], + + aidl: { + export_include_dirs: [ + "java", + ], + }, + libs: [ + "framework-minus-apex", + ], +} diff --git a/core/java/android/app/JobSchedulerImpl.java b/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java index 924a70809747..f59e7a4ae6ec 100644 --- a/core/java/android/app/JobSchedulerImpl.java +++ b/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java @@ -14,7 +14,6 @@ * limitations under the License. */ -// in android.app so ContextImpl has package access package android.app; import android.app.job.IJobScheduler; @@ -27,10 +26,12 @@ 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 + * + * Note android.app.job is the better package to put this class, but we can't move it there + * because that'd break robolectric. Grr. + * * @hide */ public class JobSchedulerImpl extends JobScheduler { diff --git a/core/java/android/app/job/IJobCallback.aidl b/apex/jobscheduler/framework/java/android/app/job/IJobCallback.aidl index d281da037fde..d281da037fde 100644 --- a/core/java/android/app/job/IJobCallback.aidl +++ b/apex/jobscheduler/framework/java/android/app/job/IJobCallback.aidl diff --git a/core/java/android/app/job/IJobScheduler.aidl b/apex/jobscheduler/framework/java/android/app/job/IJobScheduler.aidl index 3006f50e54fc..3006f50e54fc 100644 --- a/core/java/android/app/job/IJobScheduler.aidl +++ b/apex/jobscheduler/framework/java/android/app/job/IJobScheduler.aidl diff --git a/core/java/android/app/job/IJobService.aidl b/apex/jobscheduler/framework/java/android/app/job/IJobService.aidl index 22ad252b9639..22ad252b9639 100644 --- a/core/java/android/app/job/IJobService.aidl +++ b/apex/jobscheduler/framework/java/android/app/job/IJobService.aidl diff --git a/core/java/android/app/job/JobInfo.aidl b/apex/jobscheduler/framework/java/android/app/job/JobInfo.aidl index 7b198a8ab14d..7b198a8ab14d 100644 --- a/core/java/android/app/job/JobInfo.aidl +++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.aidl diff --git a/core/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java index 8b3b3a28f2bc..8b3b3a28f2bc 100644 --- a/core/java/android/app/job/JobInfo.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java diff --git a/core/java/android/app/job/JobParameters.aidl b/apex/jobscheduler/framework/java/android/app/job/JobParameters.aidl index e7551b9ab9f2..e7551b9ab9f2 100644 --- a/core/java/android/app/job/JobParameters.aidl +++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.aidl diff --git a/core/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java index ecc859d8320c..150cdbc3cacf 100644 --- a/core/java/android/app/job/JobParameters.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java @@ -52,6 +52,11 @@ public class JobParameters implements Parcelable { /** * All the stop reason codes. This should be regarded as an immutable array at runtime. + * + * Note the order of these values will affect "dumpsys batterystats", and we do not want to + * change the order of existing fields, so adding new fields is okay but do not remove or + * change existing fields. When deprecating a field, just replace that with "-1" in this array. + * * @hide */ public static final int[] JOB_STOP_REASON_CODES = { diff --git a/core/java/android/app/job/JobScheduler.java b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java index 08b1c2b9f548..08b1c2b9f548 100644 --- a/core/java/android/app/job/JobScheduler.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java diff --git a/core/java/android/app/job/JobSchedulerFrameworkInitializer.java b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java index c90b8728bf4a..c90b8728bf4a 100644 --- a/core/java/android/app/job/JobSchedulerFrameworkInitializer.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java diff --git a/core/java/android/app/job/JobService.java b/apex/jobscheduler/framework/java/android/app/job/JobService.java index 61afadab9b0c..61afadab9b0c 100644 --- a/core/java/android/app/job/JobService.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobService.java diff --git a/core/java/android/app/job/JobServiceEngine.java b/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java index ab94da843635..ab94da843635 100644 --- a/core/java/android/app/job/JobServiceEngine.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java diff --git a/core/java/android/app/job/JobSnapshot.aidl b/apex/jobscheduler/framework/java/android/app/job/JobSnapshot.aidl index d40f4e39ea2e..d40f4e39ea2e 100644 --- a/core/java/android/app/job/JobSnapshot.aidl +++ b/apex/jobscheduler/framework/java/android/app/job/JobSnapshot.aidl diff --git a/core/java/android/app/job/JobSnapshot.java b/apex/jobscheduler/framework/java/android/app/job/JobSnapshot.java index 2c58908a6064..2c58908a6064 100644 --- a/core/java/android/app/job/JobSnapshot.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobSnapshot.java diff --git a/core/java/android/app/job/JobWorkItem.aidl b/apex/jobscheduler/framework/java/android/app/job/JobWorkItem.aidl index e8fe47d07865..e8fe47d07865 100644 --- a/core/java/android/app/job/JobWorkItem.aidl +++ b/apex/jobscheduler/framework/java/android/app/job/JobWorkItem.aidl diff --git a/core/java/android/app/job/JobWorkItem.java b/apex/jobscheduler/framework/java/android/app/job/JobWorkItem.java index c6631fa76494..c6631fa76494 100644 --- a/core/java/android/app/job/JobWorkItem.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobWorkItem.java diff --git a/core/java/com/android/server/job/JobSchedulerInternal.java b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java index eefb9fafd286..eefb9fafd286 100644 --- a/core/java/com/android/server/job/JobSchedulerInternal.java +++ b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java diff --git a/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java b/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java index 005b1892f6a6..b7e8cf6e3fc8 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java +++ b/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java @@ -16,7 +16,6 @@ package com.android.server.job; -import android.app.IActivityManager; import android.app.UriGrantsManager; import android.content.ClipData; import android.content.ContentProvider; @@ -40,7 +39,7 @@ public final class GrantedUriPermissions { private final IBinder mPermissionOwner; private final ArrayList<Uri> mUris = new ArrayList<>(); - private GrantedUriPermissions(IActivityManager am, int grantFlags, int uid, String tag) + private GrantedUriPermissions(int grantFlags, int uid, String tag) throws RemoteException { mGrantFlags = grantFlags; mSourceUserId = UserHandle.getUserId(uid); @@ -49,7 +48,7 @@ public final class GrantedUriPermissions { .getService(UriGrantsManagerInternal.class).newUriPermissionOwner("job: " + tag); } - public void revoke(IActivityManager am) { + public void revoke() { for (int i = mUris.size()-1; i >= 0; i--) { LocalServices.getService(UriGrantsManagerInternal.class).revokeUriPermissionFromOwner( mPermissionOwner, mUris.get(i), mGrantFlags, mSourceUserId); @@ -62,7 +61,7 @@ public final class GrantedUriPermissions { |Intent.FLAG_GRANT_READ_URI_PERMISSION)) != 0; } - public static GrantedUriPermissions createFromIntent(IActivityManager am, Intent intent, + public static GrantedUriPermissions createFromIntent(Intent intent, int sourceUid, String targetPackage, int targetUserId, String tag) { int grantFlags = intent.getFlags(); if (!checkGrantFlags(grantFlags)) { @@ -73,44 +72,44 @@ public final class GrantedUriPermissions { Uri data = intent.getData(); if (data != null) { - perms = grantUri(am, data, sourceUid, targetPackage, targetUserId, grantFlags, tag, + perms = grantUri(data, sourceUid, targetPackage, targetUserId, grantFlags, tag, perms); } ClipData clip = intent.getClipData(); if (clip != null) { - perms = grantClip(am, clip, sourceUid, targetPackage, targetUserId, grantFlags, tag, + perms = grantClip(clip, sourceUid, targetPackage, targetUserId, grantFlags, tag, perms); } return perms; } - public static GrantedUriPermissions createFromClip(IActivityManager am, ClipData clip, + public static GrantedUriPermissions createFromClip(ClipData clip, int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag) { if (!checkGrantFlags(grantFlags)) { return null; } GrantedUriPermissions perms = null; if (clip != null) { - perms = grantClip(am, clip, sourceUid, targetPackage, targetUserId, grantFlags, + perms = grantClip(clip, sourceUid, targetPackage, targetUserId, grantFlags, tag, perms); } return perms; } - private static GrantedUriPermissions grantClip(IActivityManager am, ClipData clip, + private static GrantedUriPermissions grantClip(ClipData clip, int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag, GrantedUriPermissions curPerms) { final int N = clip.getItemCount(); for (int i = 0; i < N; i++) { - curPerms = grantItem(am, clip.getItemAt(i), sourceUid, targetPackage, targetUserId, + curPerms = grantItem(clip.getItemAt(i), sourceUid, targetPackage, targetUserId, grantFlags, tag, curPerms); } return curPerms; } - private static GrantedUriPermissions grantUri(IActivityManager am, Uri uri, + private static GrantedUriPermissions grantUri(Uri uri, int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag, GrantedUriPermissions curPerms) { try { @@ -118,7 +117,7 @@ public final class GrantedUriPermissions { UserHandle.getUserId(sourceUid)); uri = ContentProvider.getUriWithoutUserId(uri); if (curPerms == null) { - curPerms = new GrantedUriPermissions(am, grantFlags, sourceUid, tag); + curPerms = new GrantedUriPermissions(grantFlags, sourceUid, tag); } UriGrantsManager.getService().grantUriPermissionFromOwner(curPerms.mPermissionOwner, sourceUid, targetPackage, uri, grantFlags, sourceUserId, targetUserId); @@ -129,16 +128,16 @@ public final class GrantedUriPermissions { return curPerms; } - private static GrantedUriPermissions grantItem(IActivityManager am, ClipData.Item item, + private static GrantedUriPermissions grantItem(ClipData.Item item, int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag, GrantedUriPermissions curPerms) { if (item.getUri() != null) { - curPerms = grantUri(am, item.getUri(), sourceUid, targetPackage, targetUserId, + curPerms = grantUri(item.getUri(), sourceUid, targetPackage, targetUserId, grantFlags, tag, curPerms); } Intent intent = item.getIntent(); if (intent != null && intent.getData() != null) { - curPerms = grantUri(am, intent.getData(), sourceUid, targetPackage, targetUserId, + curPerms = grantUri(intent.getData(), sourceUid, targetPackage, targetUserId, grantFlags, tag, curPerms); } return curPerms; diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index 5ba563c20b57..a633350996cd 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -89,7 +89,7 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.AppStateTracker; -import com.android.server.DeviceIdleController; +import com.android.server.DeviceIdleInternal; import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob; @@ -207,7 +207,7 @@ public class JobSchedulerService extends com.android.server.SystemService PackageManagerInternal mLocalPM; ActivityManagerInternal mActivityManagerInternal; IBatteryStats mBatteryStats; - DeviceIdleController.LocalService mLocalDeviceIdleController; + DeviceIdleInternal mLocalDeviceIdleController; AppStateTracker mAppStateTracker; final UsageStatsManagerInternal mUsageStats; @@ -963,7 +963,7 @@ public class JobSchedulerService extends com.android.server.SystemService // changing. We can just directly enqueue this work in to the job. if (toCancel.getJob().equals(job)) { - toCancel.enqueueWorkLocked(ActivityManager.getService(), work); + toCancel.enqueueWorkLocked(work); // If any of work item is enqueued when the source is in the foreground, // exempt the entire job. @@ -992,11 +992,11 @@ public class JobSchedulerService extends com.android.server.SystemService } // This may throw a SecurityException. - jobStatus.prepareLocked(ActivityManager.getService()); + jobStatus.prepareLocked(); if (work != null) { // If work has been supplied, enqueue it into the new job. - jobStatus.enqueueWorkLocked(ActivityManager.getService(), work); + jobStatus.enqueueWorkLocked(work); } if (toCancel != null) { @@ -1144,7 +1144,7 @@ public class JobSchedulerService extends com.android.server.SystemService */ private void cancelJobImplLocked(JobStatus cancelled, JobStatus incomingJob, String reason) { if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString()); - cancelled.unprepareLocked(ActivityManager.getService()); + cancelled.unprepareLocked(); stopTrackingJobLocked(cancelled, incomingJob, true /* writeBack */); // Remove from pending queue. if (mPendingJobs.remove(cancelled)) { @@ -1399,8 +1399,8 @@ public class JobSchedulerService extends com.android.server.SystemService mReadyToRock = true; mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( BatteryStats.SERVICE_NAME)); - mLocalDeviceIdleController - = LocalServices.getService(DeviceIdleController.LocalService.class); + mLocalDeviceIdleController = + LocalServices.getService(DeviceIdleInternal.class); // Create the "runners". for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) { mActiveServices.add( @@ -1449,7 +1449,7 @@ public class JobSchedulerService extends com.android.server.SystemService private boolean stopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean removeFromPersisted) { // Deal with any remaining work items in the old job. - jobStatus.stopTrackingJobLocked(ActivityManager.getService(), incomingJob); + jobStatus.stopTrackingJobLocked(incomingJob); // Remove from store as well as controllers. final boolean removed = mJobs.remove(jobStatus, removeFromPersisted); @@ -1705,7 +1705,7 @@ public class JobSchedulerService extends com.android.server.SystemService if (rescheduledJob != null) { try { - rescheduledJob.prepareLocked(ActivityManager.getService()); + rescheduledJob.prepareLocked(); } catch (SecurityException e) { Slog.w(TAG, "Unable to regrant job permissions for " + rescheduledJob); } @@ -1713,13 +1713,13 @@ public class JobSchedulerService extends com.android.server.SystemService } else if (jobStatus.getJob().isPeriodic()) { JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus); try { - rescheduledPeriodic.prepareLocked(ActivityManager.getService()); + rescheduledPeriodic.prepareLocked(); } catch (SecurityException e) { Slog.w(TAG, "Unable to regrant job permissions for " + rescheduledPeriodic); } startTrackingJobLocked(rescheduledPeriodic, jobStatus); } - jobStatus.unprepareLocked(ActivityManager.getService()); + jobStatus.unprepareLocked(); reportActiveLocked(); mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget(); } diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java index 4d9f1331e6ff..782e6463d845 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -18,7 +18,6 @@ package com.android.server.job; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; -import android.app.ActivityManager; import android.app.job.IJobCallback; import android.app.job.IJobService; import android.app.job.JobInfo; @@ -389,7 +388,7 @@ public final class JobServiceContext implements ServiceConnection { try { synchronized (mLock) { assertCallerLocked(cb); - return mRunningJob.completeWorkLocked(ActivityManager.getService(), workId); + return mRunningJob.completeWorkLocked(workId); } } finally { Binder.restoreCallingIdentity(ident); diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java index 4321fc716b4d..c2bdb6caffd3 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java @@ -20,8 +20,6 @@ import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import static com.android.server.job.JobSchedulerService.sSystemClock; import android.annotation.Nullable; -import android.app.ActivityManager; -import android.app.IActivityManager; import android.app.job.JobInfo; import android.content.ComponentName; import android.content.Context; @@ -180,7 +178,6 @@ public final class JobStore { public void getRtcCorrectedJobsLocked(final ArrayList<JobStatus> toAdd, final ArrayList<JobStatus> toRemove) { final long elapsedNow = sElapsedRealtimeClock.millis(); - final IActivityManager am = ActivityManager.getService(); // Find the jobs that need to be fixed up, collecting them for post-iteration // replacement with their new versions @@ -192,7 +189,7 @@ public final class JobStore { JobStatus newJob = new JobStatus(job, elapsedRuntimes.first, elapsedRuntimes.second, 0, job.getLastSuccessfulRunTime(), job.getLastFailedRunTime()); - newJob.prepareLocked(am); + newJob.prepareLocked(); toAdd.add(newJob); toRemove.add(job); } @@ -667,10 +664,9 @@ public final class JobStore { jobs = readJobMapImpl(fis, rtcGood); if (jobs != null) { long now = sElapsedRealtimeClock.millis(); - IActivityManager am = ActivityManager.getService(); for (int i=0; i<jobs.size(); i++) { JobStatus js = jobs.get(i); - js.prepareLocked(am); + js.prepareLocked(); js.enqueueTime = now; this.jobSet.add(js); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java index 0b6797139eac..01f5fa62f889 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java @@ -34,7 +34,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; -import com.android.server.DeviceIdleController; +import com.android.server.DeviceIdleInternal; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; import com.android.server.job.StateControllerProto; @@ -66,7 +66,7 @@ public final class DeviceIdleJobsController extends StateController { private final DeviceIdleUpdateFunctor mDeviceIdleUpdateFunctor; private final DeviceIdleJobsDelayHandler mHandler; private final PowerManager mPowerManager; - private final DeviceIdleController.LocalService mLocalDeviceIdleController; + private final DeviceIdleInternal mLocalDeviceIdleController; /** * True when in device idle mode, so we don't want to schedule any jobs. @@ -123,7 +123,7 @@ public final class DeviceIdleJobsController extends StateController { // Register for device idle mode changes mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mLocalDeviceIdleController = - LocalServices.getService(DeviceIdleController.LocalService.class); + LocalServices.getService(DeviceIdleInternal.class); mDeviceIdleWhitelistAppIds = mLocalDeviceIdleController.getPowerSaveWhitelistUserAppIds(); mPowerSaveTempWhitelistAppIds = mLocalDeviceIdleController.getPowerSaveTempWhitelistAppIds(); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java index 1133f7b851a4..adb43141b9c1 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java @@ -20,7 +20,6 @@ import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import android.app.AppGlobals; -import android.app.IActivityManager; import android.app.job.JobInfo; import android.app.job.JobWorkItem; import android.content.ClipData; @@ -528,7 +527,7 @@ public final class JobStatus { /*innerFlags=*/ 0); } - public void enqueueWorkLocked(IActivityManager am, JobWorkItem work) { + public void enqueueWorkLocked(JobWorkItem work) { if (pendingWork == null) { pendingWork = new ArrayList<>(); } @@ -536,7 +535,7 @@ public final class JobStatus { nextPendingWorkId++; if (work.getIntent() != null && GrantedUriPermissions.checkGrantFlags(work.getIntent().getFlags())) { - work.setGrants(GrantedUriPermissions.createFromIntent(am, work.getIntent(), sourceUid, + work.setGrants(GrantedUriPermissions.createFromIntent(work.getIntent(), sourceUid, sourcePackageName, sourceUserId, toShortString())); } pendingWork.add(work); @@ -567,20 +566,20 @@ public final class JobStatus { return executingWork != null && executingWork.size() > 0; } - private static void ungrantWorkItem(IActivityManager am, JobWorkItem work) { + private static void ungrantWorkItem(JobWorkItem work) { if (work.getGrants() != null) { - ((GrantedUriPermissions)work.getGrants()).revoke(am); + ((GrantedUriPermissions)work.getGrants()).revoke(); } } - public boolean completeWorkLocked(IActivityManager am, int workId) { + public boolean completeWorkLocked(int workId) { if (executingWork != null) { final int N = executingWork.size(); for (int i = 0; i < N; i++) { JobWorkItem work = executingWork.get(i); if (work.getWorkId() == workId) { executingWork.remove(i); - ungrantWorkItem(am, work); + ungrantWorkItem(work); return true; } } @@ -588,16 +587,16 @@ public final class JobStatus { return false; } - private static void ungrantWorkList(IActivityManager am, ArrayList<JobWorkItem> list) { + private static void ungrantWorkList(ArrayList<JobWorkItem> list) { if (list != null) { final int N = list.size(); for (int i = 0; i < N; i++) { - ungrantWorkItem(am, list.get(i)); + ungrantWorkItem(list.get(i)); } } } - public void stopTrackingJobLocked(IActivityManager am, JobStatus incomingJob) { + public void stopTrackingJobLocked(JobStatus incomingJob) { if (incomingJob != null) { // We are replacing with a new job -- transfer the work! We do any executing // work first, since that was originally at the front of the pending work. @@ -615,15 +614,15 @@ public final class JobStatus { incomingJob.updateEstimatedNetworkBytesLocked(); } else { // We are completely stopping the job... need to clean up work. - ungrantWorkList(am, pendingWork); + ungrantWorkList(pendingWork); pendingWork = null; - ungrantWorkList(am, executingWork); + ungrantWorkList(executingWork); executingWork = null; } updateEstimatedNetworkBytesLocked(); } - public void prepareLocked(IActivityManager am) { + public void prepareLocked() { if (prepared) { Slog.wtf(TAG, "Already prepared: " + this); return; @@ -634,12 +633,12 @@ public final class JobStatus { } final ClipData clip = job.getClipData(); if (clip != null) { - uriPerms = GrantedUriPermissions.createFromClip(am, clip, sourceUid, sourcePackageName, + uriPerms = GrantedUriPermissions.createFromClip(clip, sourceUid, sourcePackageName, sourceUserId, job.getClipGrantFlags(), toShortString()); } } - public void unprepareLocked(IActivityManager am) { + public void unprepareLocked() { if (!prepared) { Slog.wtf(TAG, "Hasn't been prepared: " + this); if (DEBUG_PREPARE && unpreparedPoint != null) { @@ -652,7 +651,7 @@ public final class JobStatus { unpreparedPoint = new Throwable().fillInStackTrace(); } if (uriPerms != null) { - uriPerms.revoke(am); + uriPerms.revoke(); uriPerms = null; } } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java index 4c11947212f9..1bb9e967c025 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java @@ -18,13 +18,20 @@ package com.android.server.job.controllers; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AlarmManager; import android.app.AlarmManager.OnAlarmListener; +import android.content.ContentResolver; import android.content.Context; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; import android.os.Process; import android.os.UserHandle; import android.os.WorkSource; +import android.provider.Settings; +import android.util.KeyValueListParser; import android.util.Log; import android.util.Slog; import android.util.TimeUtils; @@ -32,6 +39,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; +import com.android.server.job.ConstantsProto; import com.android.server.job.JobSchedulerService; import com.android.server.job.StateControllerProto; @@ -55,6 +63,9 @@ public final class TimeController extends StateController { /** Delay alarm tag for logging purposes */ private final String DELAY_TAG = "*job.delay*"; + private final Handler mHandler; + private final TcConstants mTcConstants; + private long mNextJobExpiredElapsedMillis; private long mNextDelayExpiredElapsedMillis; @@ -70,6 +81,14 @@ public final class TimeController extends StateController { mNextJobExpiredElapsedMillis = Long.MAX_VALUE; mNextDelayExpiredElapsedMillis = Long.MAX_VALUE; mChainedAttributionEnabled = mService.isChainedAttributionEnabled(); + + mHandler = new Handler(mContext.getMainLooper()); + mTcConstants = new TcConstants(mHandler); + } + + @Override + public void onSystemServicesReady() { + mTcConstants.start(mContext.getContentResolver()); } /** @@ -294,8 +313,7 @@ public final class TimeController extends StateController { } else { if (!wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_TIMING_DELAY)) { if (DEBUG) { - Slog.i(TAG, - "Skipping " + job + " because delay won't make it ready."); + Slog.i(TAG, "Skipping " + job + " because delay won't make it ready."); } continue; } @@ -354,7 +372,8 @@ public final class TimeController extends StateController { /** * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a job's * delay will expire. - * This alarm <b>will</b> wake up the phone. + * This alarm <b>will not</b> wake up the phone if + * {@link TcConstants#USE_NON_WAKEUP_ALARM_FOR_DELAY} is true. */ private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) { alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis); @@ -362,8 +381,11 @@ public final class TimeController extends StateController { return; } mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis; - updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener, - mNextDelayExpiredElapsedMillis, ws); + final int alarmType = + mTcConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY + ? AlarmManager.ELAPSED_REALTIME : AlarmManager.ELAPSED_REALTIME_WAKEUP; + updateAlarmWithListenerLocked(DELAY_TAG, alarmType, + mNextDelayExpiredListener, mNextDelayExpiredElapsedMillis, ws); } /** @@ -377,16 +399,16 @@ public final class TimeController extends StateController { return; } mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis; - updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener, - mNextJobExpiredElapsedMillis, ws); + updateAlarmWithListenerLocked(DEADLINE_TAG, AlarmManager.ELAPSED_REALTIME_WAKEUP, + mDeadlineExpiredListener, mNextJobExpiredElapsedMillis, ws); } private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) { return Math.max(proposedAlarmTimeElapsedMillis, sElapsedRealtimeClock.millis()); } - private void updateAlarmWithListenerLocked(String tag, OnAlarmListener listener, - long alarmTimeElapsed, WorkSource ws) { + private void updateAlarmWithListenerLocked(String tag, @AlarmManager.AlarmType int alarmType, + OnAlarmListener listener, long alarmTimeElapsed, WorkSource ws) { ensureAlarmServiceLocked(); if (alarmTimeElapsed == Long.MAX_VALUE) { mAlarmService.cancel(listener); @@ -394,7 +416,7 @@ public final class TimeController extends StateController { if (DEBUG) { Slog.d(TAG, "Setting " + tag + " for: " + alarmTimeElapsed); } - mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTimeElapsed, + mAlarmService.set(alarmType, alarmTimeElapsed, AlarmManager.WINDOW_HEURISTIC, 0, tag, listener, null, ws); } } @@ -422,9 +444,77 @@ public final class TimeController extends StateController { }; @VisibleForTesting - void recheckAlarmsLocked() { - checkExpiredDeadlinesAndResetAlarm(); - checkExpiredDelaysAndResetAlarm(); + class TcConstants extends ContentObserver { + private ContentResolver mResolver; + private final KeyValueListParser mParser = new KeyValueListParser(','); + + private static final String KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY = + "use_non_wakeup_delay_alarm"; + + private static final boolean DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY = true; + + /** + * Whether or not TimeController should skip setting wakeup alarms for jobs that aren't + * ready now. + */ + public boolean USE_NON_WAKEUP_ALARM_FOR_DELAY = DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY; + + /** + * Creates a content observer. + * + * @param handler The handler to run {@link #onChange} on, or null if none. + */ + TcConstants(Handler handler) { + super(handler); + } + + private void start(ContentResolver resolver) { + mResolver = resolver; + mResolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS), false, this); + onChange(true, null); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + final String constants = Settings.Global.getString( + mResolver, Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS); + + try { + mParser.setString(constants); + } catch (Exception e) { + // Failed to parse the settings string, log this and move on with defaults. + Slog.e(TAG, "Bad jobscheduler time controller settings", e); + } + + USE_NON_WAKEUP_ALARM_FOR_DELAY = mParser.getBoolean( + KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY, DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY); + // Intentionally not calling checkExpiredDelaysAndResetAlarm() here. There's no need to + // iterate through the entire list again for this constant change. The next delay alarm + // that is set will make use of the new constant value. + } + + private void dump(IndentingPrintWriter pw) { + pw.println(); + pw.println("TimeController:"); + pw.increaseIndent(); + pw.printPair(KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY, + USE_NON_WAKEUP_ALARM_FOR_DELAY).println(); + pw.decreaseIndent(); + } + + private void dump(ProtoOutputStream proto) { + final long tcToken = proto.start(ConstantsProto.TIME_CONTROLLER); + proto.write(ConstantsProto.TimeController.USE_NON_WAKEUP_ALARM_FOR_DELAY, + USE_NON_WAKEUP_ALARM_FOR_DELAY); + proto.end(tcToken); + } + } + + @VisibleForTesting + @NonNull + TcConstants getTcConstants() { + return mTcConstants; } @Override @@ -501,4 +591,14 @@ public final class TimeController extends StateController { proto.end(mToken); proto.end(token); } + + @Override + public void dumpConstants(IndentingPrintWriter pw) { + mTcConstants.dump(pw); + } + + @Override + public void dumpConstants(ProtoOutputStream proto) { + mTcConstants.dump(proto); + } } diff --git a/api/current.txt b/api/current.txt index 3bb2d5ab02f6..a0d272189000 100644 --- a/api/current.txt +++ b/api/current.txt @@ -2826,6 +2826,7 @@ package android.accessibilityservice { method public final boolean dispatchGesture(@NonNull android.accessibilityservice.GestureDescription, @Nullable android.accessibilityservice.AccessibilityService.GestureResultCallback, @Nullable android.os.Handler); method public android.view.accessibility.AccessibilityNodeInfo findFocus(int); method @NonNull public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController(); + method @NonNull public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController(int); method @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) @NonNull public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController(); method @NonNull public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController(); method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow(); @@ -6726,6 +6727,7 @@ package android.app.admin { method @Nullable public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(@Nullable android.content.ComponentName, @NonNull android.content.ComponentName); method @NonNull public android.os.Bundle getUserRestrictions(@NonNull android.content.ComponentName); method @Nullable public String getWifiMacAddress(@NonNull android.content.ComponentName); + method public boolean grantKeyPairToApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String); method public boolean hasCaCertInstalled(@Nullable android.content.ComponentName, byte[]); method public boolean hasGrantedPolicy(@NonNull android.content.ComponentName, int); method public boolean installCaCert(@Nullable android.content.ComponentName, byte[]); @@ -6772,6 +6774,7 @@ package android.app.admin { method @Nullable public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(@Nullable android.content.ComponentName, long); method @Nullable public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(@NonNull android.content.ComponentName); method @Nullable public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(@NonNull android.content.ComponentName); + method public boolean revokeKeyPairFromApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String); method public void setAccountManagementDisabled(@NonNull android.content.ComponentName, String, boolean); method public void setAffiliationIds(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>); method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean) throws android.content.pm.PackageManager.NameNotFoundException; @@ -6795,7 +6798,6 @@ package android.app.admin { method @WorkerThread public int setGlobalPrivateDnsModeSpecifiedHost(@NonNull android.content.ComponentName, @NonNull String); method public void setGlobalSetting(@NonNull android.content.ComponentName, String, String); method public void setKeepUninstalledPackages(@Nullable android.content.ComponentName, @NonNull java.util.List<java.lang.String>); - method public boolean setKeyGrantForApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String, boolean); method public boolean setKeyPairCertificate(@Nullable android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.security.cert.Certificate>, boolean); method public boolean setKeyguardDisabled(@NonNull android.content.ComponentName, boolean); method public void setKeyguardDisabledFeatures(@NonNull android.content.ComponentName, int); @@ -18417,8 +18419,12 @@ package android.icu.lang { field public static final int EARLY_DYNASTIC_CUNEIFORM_ID = 257; // 0x101 field public static final android.icu.lang.UCharacter.UnicodeBlock EGYPTIAN_HIEROGLYPHS; field public static final int EGYPTIAN_HIEROGLYPHS_ID = 194; // 0xc2 + field public static final android.icu.lang.UCharacter.UnicodeBlock EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS; + field public static final int EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS_ID = 292; // 0x124 field public static final android.icu.lang.UCharacter.UnicodeBlock ELBASAN; field public static final int ELBASAN_ID = 226; // 0xe2 + field public static final android.icu.lang.UCharacter.UnicodeBlock ELYMAIC; + field public static final int ELYMAIC_ID = 293; // 0x125 field public static final android.icu.lang.UCharacter.UnicodeBlock EMOTICONS; field public static final int EMOTICONS_ID = 206; // 0xce field public static final android.icu.lang.UCharacter.UnicodeBlock ENCLOSED_ALPHANUMERICS; @@ -18645,6 +18651,8 @@ package android.icu.lang { field public static final int MYANMAR_ID = 28; // 0x1c field public static final android.icu.lang.UCharacter.UnicodeBlock NABATAEAN; field public static final int NABATAEAN_ID = 239; // 0xef + field public static final android.icu.lang.UCharacter.UnicodeBlock NANDINAGARI; + field public static final int NANDINAGARI_ID = 294; // 0x126 field public static final android.icu.lang.UCharacter.UnicodeBlock NEWA; field public static final int NEWA_ID = 270; // 0x10e field public static final android.icu.lang.UCharacter.UnicodeBlock NEW_TAI_LUE; @@ -18656,6 +18664,8 @@ package android.icu.lang { field public static final int NUMBER_FORMS_ID = 45; // 0x2d field public static final android.icu.lang.UCharacter.UnicodeBlock NUSHU; field public static final int NUSHU_ID = 277; // 0x115 + field public static final android.icu.lang.UCharacter.UnicodeBlock NYIAKENG_PUACHUE_HMONG; + field public static final int NYIAKENG_PUACHUE_HMONG_ID = 295; // 0x127 field public static final android.icu.lang.UCharacter.UnicodeBlock OGHAM; field public static final int OGHAM_ID = 34; // 0x22 field public static final android.icu.lang.UCharacter.UnicodeBlock OLD_HUNGARIAN; @@ -18686,6 +18696,8 @@ package android.icu.lang { field public static final int OSAGE_ID = 271; // 0x10f field public static final android.icu.lang.UCharacter.UnicodeBlock OSMANYA; field public static final int OSMANYA_ID = 122; // 0x7a + field public static final android.icu.lang.UCharacter.UnicodeBlock OTTOMAN_SIYAQ_NUMBERS; + field public static final int OTTOMAN_SIYAQ_NUMBERS_ID = 296; // 0x128 field public static final android.icu.lang.UCharacter.UnicodeBlock PAHAWH_HMONG; field public static final int PAHAWH_HMONG_ID = 243; // 0xf3 field public static final android.icu.lang.UCharacter.UnicodeBlock PALMYRENE; @@ -18734,6 +18746,8 @@ package android.icu.lang { field public static final int SINHALA_ID = 24; // 0x18 field public static final android.icu.lang.UCharacter.UnicodeBlock SMALL_FORM_VARIANTS; field public static final int SMALL_FORM_VARIANTS_ID = 84; // 0x54 + field public static final android.icu.lang.UCharacter.UnicodeBlock SMALL_KANA_EXTENSION; + field public static final int SMALL_KANA_EXTENSION_ID = 297; // 0x129 field public static final android.icu.lang.UCharacter.UnicodeBlock SOGDIAN; field public static final int SOGDIAN_ID = 291; // 0x123 field public static final android.icu.lang.UCharacter.UnicodeBlock SORA_SOMPENG; @@ -18770,6 +18784,8 @@ package android.icu.lang { field public static final int SUTTON_SIGNWRITING_ID = 262; // 0x106 field public static final android.icu.lang.UCharacter.UnicodeBlock SYLOTI_NAGRI; field public static final int SYLOTI_NAGRI_ID = 143; // 0x8f + field public static final android.icu.lang.UCharacter.UnicodeBlock SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A; + field public static final int SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A_ID = 298; // 0x12a field public static final android.icu.lang.UCharacter.UnicodeBlock SYRIAC; field public static final int SYRIAC_ID = 13; // 0xd field public static final android.icu.lang.UCharacter.UnicodeBlock SYRIAC_SUPPLEMENT; @@ -18792,6 +18808,8 @@ package android.icu.lang { field public static final int TAKRI_ID = 220; // 0xdc field public static final android.icu.lang.UCharacter.UnicodeBlock TAMIL; field public static final int TAMIL_ID = 20; // 0x14 + field public static final android.icu.lang.UCharacter.UnicodeBlock TAMIL_SUPPLEMENT; + field public static final int TAMIL_SUPPLEMENT_ID = 299; // 0x12b field public static final android.icu.lang.UCharacter.UnicodeBlock TANGUT; field public static final android.icu.lang.UCharacter.UnicodeBlock TANGUT_COMPONENTS; field public static final int TANGUT_COMPONENTS_ID = 273; // 0x111 @@ -18826,6 +18844,8 @@ package android.icu.lang { field public static final int VEDIC_EXTENSIONS_ID = 175; // 0xaf field public static final android.icu.lang.UCharacter.UnicodeBlock VERTICAL_FORMS; field public static final int VERTICAL_FORMS_ID = 145; // 0x91 + field public static final android.icu.lang.UCharacter.UnicodeBlock WANCHO; + field public static final int WANCHO_ID = 300; // 0x12c field public static final android.icu.lang.UCharacter.UnicodeBlock WARANG_CITI; field public static final int WARANG_CITI_ID = 252; // 0xfc field public static final android.icu.lang.UCharacter.UnicodeBlock YIJING_HEXAGRAM_SYMBOLS; @@ -19138,6 +19158,7 @@ package android.icu.lang { field public static final int EASTERN_SYRIAC = 97; // 0x61 field public static final int EGYPTIAN_HIEROGLYPHS = 71; // 0x47 field public static final int ELBASAN = 136; // 0x88 + field public static final int ELYMAIC = 185; // 0xb9 field public static final int ESTRANGELO_SYRIAC = 95; // 0x5f field public static final int ETHIOPIC = 11; // 0xb field public static final int GEORGIAN = 12; // 0xc @@ -19217,10 +19238,12 @@ package android.icu.lang { field public static final int MYANMAR = 28; // 0x1c field public static final int NABATAEAN = 143; // 0x8f field public static final int NAKHI_GEBA = 132; // 0x84 + field public static final int NANDINAGARI = 187; // 0xbb field public static final int NEWA = 170; // 0xaa field public static final int NEW_TAI_LUE = 59; // 0x3b field public static final int NKO = 87; // 0x57 field public static final int NUSHU = 150; // 0x96 + field public static final int NYIAKENG_PUACHUE_HMONG = 186; // 0xba field public static final int OGHAM = 29; // 0x1d field public static final int OLD_CHURCH_SLAVONIC_CYRILLIC = 68; // 0x44 field public static final int OLD_HUNGARIAN = 76; // 0x4c @@ -19284,6 +19307,7 @@ package android.icu.lang { field public static final int UNWRITTEN_LANGUAGES = 102; // 0x66 field public static final int VAI = 99; // 0x63 field public static final int VISIBLE_SPEECH = 100; // 0x64 + field public static final int WANCHO = 188; // 0xbc field public static final int WARANG_CITI = 146; // 0x92 field public static final int WESTERN_SYRIAC = 96; // 0x60 field public static final int WOLEAI = 155; // 0x9b @@ -20072,6 +20096,7 @@ package android.icu.text { method public String getDateTimeFormat(); method public String getDecimal(); method public static android.icu.text.DateTimePatternGenerator getEmptyInstance(); + method public String getFieldDisplayName(int, android.icu.text.DateTimePatternGenerator.DisplayWidth); method public static android.icu.text.DateTimePatternGenerator getInstance(); method public static android.icu.text.DateTimePatternGenerator getInstance(android.icu.util.ULocale); method public static android.icu.text.DateTimePatternGenerator getInstance(java.util.Locale); @@ -20105,6 +20130,12 @@ package android.icu.text { field public static final int ZONE = 15; // 0xf } + public enum DateTimePatternGenerator.DisplayWidth { + enum_constant public static final android.icu.text.DateTimePatternGenerator.DisplayWidth ABBREVIATED; + enum_constant public static final android.icu.text.DateTimePatternGenerator.DisplayWidth NARROW; + enum_constant public static final android.icu.text.DateTimePatternGenerator.DisplayWidth WIDE; + } + public static final class DateTimePatternGenerator.PatternInfo { ctor public DateTimePatternGenerator.PatternInfo(); field public static final int BASE_CONFLICT = 1; // 0x1 @@ -21659,6 +21690,7 @@ package android.icu.util { method public static boolean isAvailable(String, java.util.Date, java.util.Date); method public java.util.Currency toJavaCurrency(); field public static final int LONG_NAME = 1; // 0x1 + field public static final int NARROW_SYMBOL_NAME = 3; // 0x3 field public static final int PLURAL_LONG_NAME = 2; // 0x2 field public static final int SYMBOL_NAME = 0; // 0x0 } @@ -21861,6 +21893,7 @@ package android.icu.util { ctor public JapaneseCalendar(int, int, int, int, int, int); field public static final int HEISEI; field public static final int MEIJI; + field public static final int REIWA; field public static final int SHOWA; field public static final int TAISHO; } @@ -22336,6 +22369,8 @@ package android.icu.util { field public static final android.icu.util.VersionInfo UCOL_RUNTIME_VERSION; field public static final android.icu.util.VersionInfo UNICODE_10_0; field public static final android.icu.util.VersionInfo UNICODE_11_0; + field public static final android.icu.util.VersionInfo UNICODE_12_0; + field public static final android.icu.util.VersionInfo UNICODE_12_1; field public static final android.icu.util.VersionInfo UNICODE_1_0; field public static final android.icu.util.VersionInfo UNICODE_1_0_1; field public static final android.icu.util.VersionInfo UNICODE_1_1_0; diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc index 469c9646a4aa..9f4f314a4324 100644 --- a/cmds/bootanimation/bootanim.rc +++ b/cmds/bootanimation/bootanim.rc @@ -4,4 +4,5 @@ service bootanim /system/bin/bootanimation group graphics audio disabled oneshot + ioprio rt 0 writepid /dev/stune/top-app/tasks diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp index 3bb99298debf..d4d587108a54 100644 --- a/cmds/idmap2/Android.bp +++ b/cmds/idmap2/Android.bp @@ -18,6 +18,7 @@ cc_defaults { tidy_checks: [ "modernize-*", "-modernize-avoid-c-arrays", + "-modernize-use-trailing-return-type", "android-*", "misc-*", "readability-*", diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp index f4a306e41e32..f55acee029dc 100644 --- a/cmds/idmap2/tests/FileUtilsTests.cpp +++ b/cmds/idmap2/tests/FileUtilsTests.cpp @@ -15,6 +15,7 @@ */ #include <dirent.h> +#include <fcntl.h> #include <set> #include <string> @@ -69,7 +70,7 @@ TEST(FileUtilsTests, FindFilesFindApkFilesRecursive) { TEST(FileUtilsTests, ReadFile) { int pipefd[2]; - ASSERT_EQ(pipe(pipefd), 0); + ASSERT_EQ(pipe2(pipefd, O_CLOEXEC), 0); ASSERT_EQ(write(pipefd[1], "foobar", 6), 6); close(pipefd[1]); diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 35c4cebdcf6c..96522f7f8ea1 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -57,6 +57,7 @@ import "frameworks/base/core/proto/android/telephony/enums.proto"; import "frameworks/base/core/proto/android/view/enums.proto"; import "frameworks/base/core/proto/android/wifi/enums.proto"; import "frameworks/base/core/proto/android/stats/textclassifier/textclassifier_enums.proto"; +import "frameworks/base/core/proto/android/stats/otaupdate/updateengine_enums.proto"; /** * The master atom class. This message defines all of the available @@ -330,6 +331,8 @@ message Atom { 222 [(log_from_module) = "textclassifier"]; ExclusionRectStateChanged exclusion_rect_state_changed = 223; BackGesture back_gesture_reported_reported = 224; + UpdateEngineUpdateAttemptReported update_engine_update_attempt_reported = 225; + UpdateEngineSuccessfulUpdateReported update_engine_successful_update_reported = 226; } // Pulled events will start at field 10000. @@ -6872,6 +6875,9 @@ message TextSelectionEvent { // Relative word (exclusive) index of the end of the smart selection. optional int32 relative_suggested_word_end_index = 10; + + // Name of source package. + optional string package_name = 11; } /** @@ -6909,6 +6915,9 @@ message TextLinkifyEvent { // Time spent on generating links in ms. optional int64 latency_millis = 10; + + // Name of source package. + optional string package_name = 11; } /** @@ -6940,6 +6949,9 @@ message ConversationActionsEvent { // The score of the first entity type. optional float score = 8; + + // Name of source package. + optional string package_name = 9; } /** @@ -6968,4 +6980,74 @@ message LanguageDetectionEvent { // Position of this action. optional int32 action_index = 7; + + // Name of source package. + optional string package_name = 8; +} + +/** + * Information about an OTA update attempt by update_engine. + * Logged from platform/system/update_engine/metrics_reporter_android.cc + */ +message UpdateEngineUpdateAttemptReported { + // The number of attempts for the update engine to apply a given payload. + optional int32 attempt_number = 1; + + optional android.stats.otaupdate.PayloadType payload_type = 2; + + // The total time in minutes for the update engine to apply a given payload. + // The time is calculated by calling clock_gettime() / CLOCK_BOOTTIME; and + // it's increased when the system is sleeping. + optional int32 duration_boottime_in_minutes = 3; + + // The total time in minutes for the update engine to apply a given payload. + // The time is calculated by calling clock_gettime() / CLOCK_MONOTONIC_RAW; + // and it's not increased when the system is sleeping. + optional int32 duration_monotonic_in_minutes = 4; + + // The size of the payload in MiBs. + optional int32 payload_size_mib = 5; + + // The attempt result reported by the update engine for an OTA update. + optional android.stats.otaupdate.AttemptResult attempt_result = 6; + + // The error code reported by the update engine after an OTA update attempt + // on A/B devices. + optional android.stats.otaupdate.ErrorCode error_code = 7; + + // The build fingerprint of the source system. The value is read from a + // system property when the device takes the update. e.g. + // Android/aosp_sailfish/sailfish:10/QP1A.190425.004/5507117:userdebug/test-keys + optional string source_fingerprint = 8; +} + +/** + * Information about all the attempts the device make before finishing the + * successful update. + * Logged from platform/system/update_engine/metrics_reporter_android.cc + */ +message UpdateEngineSuccessfulUpdateReported { + // The number of attempts for the update engine to apply the payload for a + // successful update. + optional int32 attempt_count = 1; + + optional android.stats.otaupdate.PayloadType payload_type = 2; + + optional int32 payload_size_mib = 3; + + // The total number of bytes downloaded by update_engine since the last + // successful update. + optional int32 total_bytes_downloaded_mib = 4; + + // The ratio in percentage of the over-downloaded bytes compared to the + // total bytes needed to successfully install the update. e.g. 200 if we + // download 200MiB in total for a 100MiB package. + optional int32 download_overhead_percentage = 5; + + // The total time in minutes for the update engine to apply the payload for a + // successful update. + optional int32 total_duration_minutes = 6; + + // The number of reboot of the device during a successful update. + optional int32 reboot_count = 7; } diff --git a/config/boot-profile.txt b/config/boot-profile.txt index 57e06c23b7ec..e0e9164b3f90 100644 --- a/config/boot-profile.txt +++ b/config/boot-profile.txt @@ -1,642 +1,1221 @@ -Lcom/android/internal/os/RuntimeInit$MethodAndArgsCaller;->run()V -Lcom/android/internal/os/ZygoteInit;->main([Ljava/lang/String;)V -Lcom/android/internal/util/ConcurrentUtils$1$1;->run()V -Lcom/android/server/SystemConfig;->getInstance()Lcom/android/server/SystemConfig; -Lcom/android/server/SystemConfig;-><init>()V -Lcom/android/server/SystemConfig;->readPermissions(Ljava/io/File;I)V -Lcom/android/server/SystemConfig;->readPermissionsFromXml(Ljava/io/File;I)V -Lcom/android/internal/os/ProcessCpuTracker;->update()V -Lcom/android/internal/os/ProcessCpuTracker;->init()V -Lcom/android/internal/os/ProcessCpuTracker;->collectStats(Ljava/lang/String;IZ[ILjava/util/ArrayList;)[I -Landroid/content/pm/PackageParser$SigningDetails$Builder;->build()Landroid/content/pm/PackageParser$SigningDetails; -Landroid/content/pm/PackageParser$SigningDetails;-><init>(Landroid/content/pm/PackageParser$SigningDetails;)V -Landroid/content/pm/PackageParser$SigningDetails;-><init>([Landroid/content/pm/Signature;I)V -Landroid/content/pm/PackageParser$SigningDetails;-><init>([Landroid/content/pm/Signature;ILandroid/util/ArraySet;[Landroid/content/pm/Signature;)V -Landroid/content/pm/PackageParser$SigningDetails;-><init>([Landroid/content/pm/Signature;I[Landroid/content/pm/Signature;)V +Landroid/os/Trace;->isTagEnabled(J)Z +Lcom/android/internal/os/ZygoteInit;->preloadClasses()V +Landroid/os/Trace;->traceBegin(JLjava/lang/String;)V +Landroid/os/Trace;->traceEnd(J)V +Landroid/graphics/FontListParser;->readFamily(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)Landroid/text/FontConfig$Family; +Landroid/graphics/FontListParser;->readFont(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)Landroid/text/FontConfig$Font; +Landroid/graphics/FontListParser;->readFamilies(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)Landroid/text/FontConfig; +Landroid/text/FontConfig$Font;-><init>(Ljava/lang/String;I[Landroid/graphics/fonts/FontVariationAxis;IZLjava/lang/String;)V +Landroid/util/ContainerHelpers;->binarySearch([III)I +Landroid/graphics/fonts/SystemFonts;->pushFamilyToFallback(Landroid/text/FontConfig$Family;Landroid/util/ArrayMap;Ljava/util/Map;Ljava/util/ArrayList;)V +Landroid/util/ArrayMap;->indexOf(Ljava/lang/Object;I)I +Lcom/android/internal/util/Preconditions;->checkArgument(ZLjava/lang/Object;)V +Lcom/android/internal/util/Preconditions;->checkNotNull(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +Landroid/graphics/fonts/Font;->getStyle()Landroid/graphics/fonts/FontStyle; Landroid/util/ArrayMap;->get(Ljava/lang/Object;)Ljava/lang/Object; Landroid/util/ArrayMap;->indexOfKey(Ljava/lang/Object;)I -Landroid/content/pm/Signature;->getPublicKey()Ljava/security/PublicKey; -Landroid/util/ArrayMap;->indexOf(Ljava/lang/Object;I)I -Landroid/util/ArrayMap;->indexOfNull()I -Landroid/util/ArrayMap;->indexOfValue(Ljava/lang/Object;)I -Lcom/android/internal/os/ProcessCpuTracker;->getName(Lcom/android/internal/os/ProcessCpuTracker$Stats;Ljava/lang/String;)V -Lcom/android/internal/os/ProcStatsUtil;->readTerminatedProcFile(Ljava/lang/String;B)Ljava/lang/String; -Lcom/android/internal/os/BatteryStatsImpl;->writeAsyncLocked()V -Lcom/android/internal/os/BatteryStatsImpl;->writeStatsLocked(Z)V -Lcom/android/internal/os/BatteryStatsImpl;->writeSummaryToParcel(Landroid/os/Parcel;Z)V -Landroid/util/SparseArray;->get(I)Ljava/lang/Object; -Landroid/util/SparseArray;->get(ILjava/lang/Object;)Ljava/lang/Object; -Lcom/android/internal/os/BatteryStatsImpl;->readLocked()V -Lcom/android/internal/os/BatteryStatsImpl;->readSummaryFromParcel(Landroid/os/Parcel;)V +Landroid/util/ArrayMap;->size()I +Landroid/util/ArrayMap;->keyAt(I)Ljava/lang/Object; +Landroid/util/ArrayMap;->valueAt(I)Ljava/lang/Object; Landroid/util/ArrayMap;->binarySearchHashes([III)I -Landroid/util/ContainerHelpers;->binarySearch([III)I -Lcom/android/internal/os/BatteryStatsImpl;->updateCpuTimeLocked(ZZ)V -Lcom/android/internal/os/KernelCpuUidTimeReader;->readDelta(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V -Landroid/util/ArrayMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; -Landroid/util/ArrayMap;->putAll(Landroid/util/ArrayMap;)V -Landroid/util/ArrayMap;->putAll(Ljava/util/Map;)V -Landroid/util/SparseArray;-><init>()V -Landroid/util/SparseArray;-><init>(I)V -Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V -Lcom/android/server/SystemConfig;->readPrivAppPermissions(Lorg/xmlpull/v1/XmlPullParser;Landroid/util/ArrayMap;Landroid/util/ArrayMap;)V -Landroid/content/pm/Signature;-><init>(Ljava/lang/String;)V -Landroid/content/pm/Signature;-><init>([B)V -Landroid/content/pm/Signature;-><init>([Ljava/security/cert/Certificate;)V -Lcom/android/internal/os/ProcessCpuTracker$Stats;-><init>(IIZ)V -Lcom/android/internal/os/KernelCpuProcStringReader;->asLongs(Ljava/nio/CharBuffer;[J)I -Lcom/android/internal/util/XmlUtils;->nextElement(Lorg/xmlpull/v1/XmlPullParser;)V -Lcom/android/internal/util/XmlUtils;->nextElementWithin(Lorg/xmlpull/v1/XmlPullParser;I)Z -Lcom/android/internal/util/ArrayUtils;->newUnpaddedObjectArray(I)[Ljava/lang/Object; -Landroid/util/SparseArray;->put(ILjava/lang/Object;)V -Lcom/android/internal/os/BatteryStatsImpl;->updateKernelWakelocksLocked()V -Landroid/util/ArraySet;->add(Ljava/lang/Object;)Z -Landroid/util/ArraySet;->addAll(Landroid/util/ArraySet;)V -Landroid/util/ArraySet;->addAll(Ljava/util/Collection;)Z -Lcom/android/internal/os/KernelWakelockReader;->readKernelWakelockStats(Lcom/android/internal/os/KernelWakelockStats;)Lcom/android/internal/os/KernelWakelockStats; +Landroid/text/FontConfig$Family;->getName()Ljava/lang/String; +Landroid/graphics/fonts/SystemFonts;->createFontFamily(Ljava/lang/String;Ljava/util/List;Ljava/lang/String;ILjava/util/Map;Ljava/util/ArrayList;)Landroid/graphics/fonts/FontFamily; +Landroid/graphics/fonts/FontFamily$Builder;->build(Ljava/lang/String;IZ)Landroid/graphics/fonts/FontFamily; +Landroid/graphics/fonts/Font$Builder;->build()Landroid/graphics/fonts/Font; +Landroid/text/FontConfig$Font;->getFontName()Ljava/lang/String; +Landroid/graphics/fonts/Font$Builder;-><init>(Ljava/nio/ByteBuffer;Ljava/io/File;Ljava/lang/String;)V +Landroid/graphics/fonts/Font$Builder;-><init>(Ljava/nio/ByteBuffer;)V +Landroid/text/FontConfig$Font;->getWeight()I +Landroid/graphics/fonts/Font$Builder;->setWeight(I)Landroid/graphics/fonts/Font$Builder; +Lcom/android/internal/util/Preconditions;->checkArgument(Z)V +Landroid/text/FontConfig$Font;->isItalic()Z +Landroid/graphics/fonts/Font$Builder;->setSlant(I)Landroid/graphics/fonts/Font$Builder; +Landroid/text/FontConfig$Font;->getTtcIndex()I +Landroid/graphics/fonts/Font$Builder;->setTtcIndex(I)Landroid/graphics/fonts/Font$Builder; +Landroid/text/FontConfig$Font;->getAxes()[Landroid/graphics/fonts/FontVariationAxis; +Landroid/graphics/fonts/Font$Builder;->setFontVariationSettings([Landroid/graphics/fonts/FontVariationAxis;)Landroid/graphics/fonts/Font$Builder; +Landroid/graphics/fonts/FontStyle;-><init>(II)V +Landroid/graphics/fonts/Font;-><init>(JLjava/nio/ByteBuffer;Ljava/io/File;Landroid/graphics/fonts/FontStyle;I[Landroid/graphics/fonts/FontVariationAxis;Ljava/lang/String;Landroid/graphics/fonts/Font$1;)V +Landroid/graphics/fonts/Font;-><init>(JLjava/nio/ByteBuffer;Ljava/io/File;Landroid/graphics/fonts/FontStyle;I[Landroid/graphics/fonts/FontVariationAxis;Ljava/lang/String;)V +Landroid/graphics/fonts/FontFamily$Builder;->makeStyleIdentifier(Landroid/graphics/fonts/Font;)I +Landroid/graphics/fonts/FontStyle;->getWeight()I +Landroid/graphics/fonts/FontStyle;->getSlant()I +Landroid/graphics/fonts/Font;->getNativePtr()J +Landroid/graphics/fonts/SystemFonts;->buildSystemFallback(Ljava/lang/String;Ljava/lang/String;Landroid/graphics/fonts/FontCustomizationParser$Result;Landroid/util/ArrayMap;Ljava/util/ArrayList;)[Landroid/text/FontConfig$Alias; +Landroid/graphics/fonts/SystemFonts;->$closeResource(Ljava/lang/Throwable;Ljava/lang/AutoCloseable;)V +Landroid/graphics/fonts/SystemFonts;->mmap(Ljava/lang/String;)Ljava/nio/ByteBuffer; +Landroid/graphics/Typeface;->createFromFamilies([Landroid/graphics/fonts/FontFamily;)Landroid/graphics/Typeface; +Landroid/graphics/fonts/FontFamily;->getNativePtr()J +Landroid/content/pm/ActivityInfo;->activityInfoConfigNativeToJava(I)I +Landroid/content/res/TypedArray;->getChangingConfigurations()I +Landroid/content/res/TypedArray;->extractThemeAttrs([I)[I +Landroid/util/ContainerHelpers;->binarySearch([JIJ)I +Landroid/util/Pools$SimplePool;->isInPool(Ljava/lang/Object;)Z +Landroid/content/res/ResourcesImpl;->getAssets()Landroid/content/res/AssetManager; +Landroid/content/res/XmlBlock$Parser;->next()I +Landroid/content/res/XmlBlock$Parser;->getDepth()I +Landroid/content/res/StringBlock;->get(I)Ljava/lang/CharSequence; +Landroid/content/res/Resources;->getDisplayMetrics()Landroid/util/DisplayMetrics; +Landroid/content/res/ResourcesImpl;->getDisplayMetrics()Landroid/util/DisplayMetrics; +Landroid/content/res/TypedArray;->length()I +Landroid/content/res/AssetManager;->ensureValidLocked()V +Landroid/content/res/TypedArray;->getFloat(IF)F +Landroid/content/res/ResourcesImpl;->loadXmlResourceParser(Ljava/lang/String;IILjava/lang/String;)Landroid/content/res/XmlResourceParser; +Landroid/content/res/XmlBlock$Parser;->getName()Ljava/lang/String; +Landroid/content/res/Resources;->getAssets()Landroid/content/res/AssetManager; +Landroid/content/res/TypedArray;->obtain(Landroid/content/res/Resources;I)Landroid/content/res/TypedArray; +Landroid/util/Pools$SynchronizedPool;->acquire()Ljava/lang/Object; +Landroid/util/Pools$SimplePool;->acquire()Ljava/lang/Object; +Landroid/content/res/TypedArray;->resize(I)V +Landroid/content/res/Resources;->obtainAttributes(Landroid/util/AttributeSet;[I)Landroid/content/res/TypedArray; +Landroid/content/res/AssetManager;->retrieveAttributes(Landroid/content/res/XmlBlock$Parser;[I[I[I)Z +Landroid/content/res/TypedArray;->recycle()V +Landroid/util/Pools$SynchronizedPool;->release(Ljava/lang/Object;)Z +Landroid/util/Pools$SimplePool;->release(Ljava/lang/Object;)Z +Landroid/graphics/drawable/Drawable;->obtainAttributes(Landroid/content/res/Resources;Landroid/content/res/Resources$Theme;Landroid/util/AttributeSet;[I)Landroid/content/res/TypedArray; +Landroid/graphics/drawable/VectorDrawable$VGroup;->setTree(Lcom/android/internal/util/VirtualRefBasePtr;)V +Landroid/graphics/drawable/VectorDrawable$VGroup;->getNativeSize()I +Landroid/graphics/Rect;-><init>()V +Landroid/graphics/drawable/VectorDrawable$VObject;->setTree(Lcom/android/internal/util/VirtualRefBasePtr;)V Lcom/android/internal/util/GrowingArrayUtils;->insert([IIII)[I -Lcom/android/internal/util/GrowingArrayUtils;->insert([JIIJ)[J Lcom/android/internal/util/GrowingArrayUtils;->insert([Ljava/lang/Object;IILjava/lang/Object;)[Ljava/lang/Object; -Lcom/android/internal/util/GrowingArrayUtils;->insert([ZIIZ)[Z -HPLcom/android/internal/app/procstats/ProcessStats;-><init>(Landroid/os/Parcel;)V -Lcom/android/internal/app/procstats/ProcessStats;-><init>(Z)V -Lcom/android/internal/os/BatteryStatsImpl$Uid;-><init>(Lcom/android/internal/os/BatteryStatsImpl;I)V -Lcom/android/internal/os/KernelWakelockReader;->parseProcWakelocks([BIZLcom/android/internal/os/KernelWakelockStats;)Lcom/android/internal/os/KernelWakelockStats; -Landroid/content/pm/PackageParser;->getCachedResult(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package; -Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package; -Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;IZ)Landroid/content/pm/PackageParser$Package; -Landroid/content/pm/PackageParser;->parsePackageItemInfo(Landroid/content/pm/PackageParser$Package;Landroid/content/pm/PackageItemInfo;[Ljava/lang/String;Ljava/lang/String;Landroid/content/res/TypedArray;ZIIIIII)Z -Landroid/content/pm/PackageParser;->parsePackageList(Ljava/lang/String;)Ljava/util/Set; -Landroid/content/pm/PackageParser;->parsePackageLite(Ljava/io/File;I)Landroid/content/pm/PackageParser$PackageLite; -Landroid/content/pm/PackageParser;->parsePackageSplitNames(Lorg/xmlpull/v1/XmlPullParser;Landroid/util/AttributeSet;)Landroid/util/Pair; -Lcom/android/internal/os/BatteryStatsImpl$DualTimer;->writeSummaryFromParcelLocked(Landroid/os/Parcel;J)V -Landroid/content/pm/Signature;->parseHexDigit(I)I -Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->writeSummaryFromParcelLocked(Landroid/os/Parcel;J)V -Lcom/android/internal/os/BatteryStatsImpl$Uid;->readWakeSummaryFromParcelLocked(Ljava/lang/String;Landroid/os/Parcel;)V -Landroid/util/ArraySet;->iterator()Ljava/util/Iterator; -Landroid/content/pm/PackageParser;->fromCacheEntryStatic([B)Landroid/content/pm/PackageParser$Package; -Landroid/content/pm/PackageParser;->fromCacheEntry([B)Landroid/content/pm/PackageParser$Package; -Lcom/android/internal/os/BatteryStatsImpl$Timer;->writeSummaryFromParcelLocked(Landroid/os/Parcel;J)V -Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidUserSysTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V -Landroid/os/FileUtils;->bytesToFile(Ljava/lang/String;[B)V -Landroid/os/StrictMode;->allowThreadDiskReads()Landroid/os/StrictMode$ThreadPolicy; -Landroid/os/StrictMode;->allowThreadDiskReadsMask()I -Landroid/content/pm/PackageParser$Package;-><init>(Landroid/os/Parcel;)V -Landroid/content/pm/PackageParser$Package;-><init>(Ljava/lang/String;)V -Lcom/android/server/SystemConfig;->addFeature(Ljava/lang/String;I)V -Landroid/os/StrictMode;->setThreadPolicy(Landroid/os/StrictMode$ThreadPolicy;)V -Landroid/os/StrictMode;->setThreadPolicyMask(I)V -Landroid/content/pm/FallbackCategoryProvider;->loadFallbacks()V -Landroid/os/Parcel$ReadWriteHelper;->writeString(Landroid/os/Parcel;Ljava/lang/String;)V -Landroid/os/Parcel;->writeString(Ljava/lang/String;)V -Landroid/os/Parcel;->writeStringArray([Ljava/lang/String;)V -Landroid/os/Parcel;->writeStringList(Ljava/util/List;)V -Lcom/android/internal/os/BatteryStatsImpl$Timer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;ILcom/android/internal/os/BatteryStatsImpl$TimeBase;)V -Lcom/android/internal/os/BatteryStatsImpl$Timer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;ILcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V -Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->add(Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V -Landroid/os/Parcel;->writeInt(I)V -Landroid/os/Parcel;->writeIntArray([I)V -Landroid/os/Parcel;->writeInterfaceToken(Ljava/lang/String;)V -Landroid/content/pm/PackageParser;->parsePublicKey(Ljava/lang/String;)Ljava/security/PublicKey; -Lcom/android/internal/os/KernelCpuProcStringReader$ProcFileIterator;->nextLine()Ljava/nio/CharBuffer; -Landroid/util/Xml;->newPullParser()Lorg/xmlpull/v1/XmlPullParser; -Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->readFreqs(Lcom/android/internal/os/PowerProfile;)[J -Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->readFreqs(Ljava/lang/String;)[J -Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V -Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V -Landroid/os/HandlerThread;->run()V -Landroid/os/Looper;->loop()V -Landroid/util/SparseArray;->size()I +Landroid/graphics/drawable/Drawable;->resolveDensity(Landroid/content/res/Resources;I)I +Landroid/graphics/drawable/VectorDrawable$VObject;-><init>()V +Landroid/util/ArrayMap;->freeArrays([I[Ljava/lang/Object;I)V +Landroid/content/res/TypedArray;->extractThemeAttrs()[I +Landroid/content/res/TypedArray;->getDimensionPixelSize(II)I +Landroid/graphics/drawable/Drawable$ConstantState;-><init>()V +Landroid/content/res/TypedArray;->getValueAt(ILandroid/util/TypedValue;)Z +Landroid/content/res/ColorStateList;->inflate(Landroid/content/res/Resources;Lorg/xmlpull/v1/XmlPullParser;Landroid/util/AttributeSet;Landroid/content/res/Resources$Theme;)V +Landroid/content/res/XmlBlock$Parser;->getAttributeNameResource(I)I +Landroid/content/res/XmlBlock;->access$1200(JI)I +Landroid/util/LongSparseArray;->put(JLjava/lang/Object;)V +Lcom/android/internal/util/GrowingArrayUtils;->append([Ljava/lang/Object;ILjava/lang/Object;)[Ljava/lang/Object; +Landroid/content/res/XmlBlock;->decOpenCountLocked()V +Landroid/content/res/XmlBlock$Parser;->close()V +Landroid/content/res/XmlBlock;->close()V Landroid/util/ArrayMap;-><init>()V -Landroid/util/ArrayMap;-><init>(I)V Landroid/util/ArrayMap;-><init>(IZ)V -Landroid/util/ArrayMap;-><init>(Landroid/util/ArrayMap;)V -Landroid/os/Parcel;->writeLong(J)V -Landroid/os/Parcel;->writeLongArray([J)V -Landroid/os/Parcel;->readParcelable(Ljava/lang/ClassLoader;)Landroid/os/Parcelable; -Landroid/os/Parcel;->readParcelableArray(Ljava/lang/ClassLoader;Ljava/lang/Class;)[Landroid/os/Parcelable; -Landroid/os/Parcel;->readParcelableCreator(Ljava/lang/ClassLoader;)Landroid/os/Parcelable$Creator; -Landroid/os/Parcel;->readParcelableList(Ljava/util/List;Ljava/lang/ClassLoader;)Ljava/util/List; -Lcom/android/internal/os/BatteryStatsImpl$DualTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V -Landroid/os/SystemProperties;->getBoolean(Ljava/lang/String;Z)Z -Landroid/content/pm/IntentFilterVerificationInfo;-><init>(Lorg/xmlpull/v1/XmlPullParser;)V -Landroid/util/ArrayMap;->allocArrays(I)V +Landroid/util/ArrayMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +Lcom/android/internal/util/XmlUtils;->nextElementWithin(Lorg/xmlpull/v1/XmlPullParser;I)Z +Landroid/util/ArraySet;->indexOf(Ljava/lang/Object;I)I +Landroid/util/ArraySet;->add(Ljava/lang/Object;)Z +Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z +Lcom/android/server/SystemConfig;->readPrivAppPermissions(Lorg/xmlpull/v1/XmlPullParser;Landroid/util/ArrayMap;Landroid/util/ArrayMap;)V +Lcom/android/internal/util/XmlUtils;->nextElement(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/SystemConfig;->readPermissionsFromXml(Ljava/io/File;I)V +Lcom/android/server/SystemConfig;->addFeature(Ljava/lang/String;I)V +Lcom/android/internal/util/XmlUtils;->skipCurrentTag(Lorg/xmlpull/v1/XmlPullParser;)V Landroid/os/Parcel;->readInt()I -Landroid/os/Parcel;->readIntArray([I)V -Landroid/content/pm/IntentFilterVerificationInfo;->readFromXml(Lorg/xmlpull/v1/XmlPullParser;)V -Lcom/android/internal/util/ArrayUtils;->appendInt([II)[I -Lcom/android/internal/util/ArrayUtils;->appendInt([IIZ)[I -Landroid/util/TimingsTraceLog;->traceEnd()V +Landroid/os/Parcel;->readLong()J +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->add(Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V +Lcom/android/internal/os/BatteryStatsImpl$Timer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;ILcom/android/internal/os/BatteryStatsImpl$TimeBase;)V +Landroid/os/BatteryStats$Timer;-><init>()V Lcom/android/internal/os/BatteryStatsImpl$Timer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V -Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl;->readSummaryFromParcel(Landroid/os/Parcel;)V +Landroid/os/Parcel;->access$000(Landroid/os/Parcel;)J Landroid/os/Parcel;->readString()Ljava/lang/String; -Landroid/os/Parcel;->readStringArray()[Ljava/lang/String; -Landroid/os/Parcel;->readStringList(Ljava/util/List;)V -Lcom/android/internal/os/BatteryStatsImpl$OverflowArrayMap;->add(Ljava/lang/String;Ljava/lang/Object;)V -Lcom/android/internal/os/BatteryStatsImpl;->getKernelWakelockTimerLocked(Ljava/lang/String;)Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer; -Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V -Lcom/android/internal/os/BatteryStatsImpl$DualTimer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V -Landroid/os/storage/StorageManager;->hasAdoptable()Z Landroid/os/Parcel$ReadWriteHelper;->readString(Landroid/os/Parcel;)Ljava/lang/String; -Landroid/os/Handler;->dispatchMessage(Landroid/os/Message;)V -Lcom/android/internal/os/BatteryStatsImpl$5;->run()V -Lcom/android/internal/os/BatteryStatsImpl;->commitPendingDataToDisk(Landroid/os/Parcel;Lcom/android/internal/os/AtomicFile;)V +Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->isRunning()Z +Lcom/android/internal/os/BatteryStatsImpl;->getKernelWakelockTimerLocked(Ljava/lang/String;)Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer; +Landroid/util/ArraySet;->freeArrays([I[Ljava/lang/Object;I)V +Landroid/util/ArraySet;->allocArrays(I)V +Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V -Landroid/util/ArraySet;->indexOf(Ljava/lang/Object;)I -Landroid/util/ArraySet;->indexOf(Ljava/lang/Object;I)I -Landroid/util/ArraySet;->indexOfNull()I -Landroid/os/Parcel;->readLong()J -Landroid/os/Parcel;->readLongArray([J)V -Lcom/android/internal/util/XmlUtils;->skipCurrentTag(Lorg/xmlpull/v1/XmlPullParser;)V -Lcom/android/internal/os/BatteryStatsImpl$Uid;->getServiceStatsLocked(Ljava/lang/String;Ljava/lang/String;)Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg$Serv; -Landroid/os/StrictMode;->setBlockGuardPolicy(I)V -Landroid/util/TimingsTraceLog;->logDuration(Ljava/lang/String;J)V -Landroid/util/Base64;->decode(Ljava/lang/String;I)[B -Landroid/util/Base64;->decode([BI)[B -Landroid/util/Base64;->decode([BIII)[B -Landroid/util/ArrayMap;->valueAt(I)Ljava/lang/Object; -Lcom/android/internal/os/BatteryStatsImpl$Uid;->getWakelockTimerLocked(Lcom/android/internal/os/BatteryStatsImpl$Uid$Wakelock;I)Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer; -Landroid/util/ArraySet;-><init>()V -Landroid/util/ArraySet;-><init>(I)V -Landroid/util/ArraySet;-><init>(Landroid/util/ArraySet;)V -Landroid/util/ArraySet;-><init>(Ljava/util/Collection;)V -Lcom/android/internal/os/KernelCpuProcStringReader;->open(Z)Lcom/android/internal/os/KernelCpuProcStringReader$ProcFileIterator; -Landroid/content/pm/ApplicationInfo;-><init>()V -Landroid/content/pm/ApplicationInfo;-><init>(Landroid/content/pm/ApplicationInfo;)V -Landroid/content/pm/ApplicationInfo;-><init>(Landroid/os/Parcel;)V -Landroid/util/ArraySet;->remove(Ljava/lang/Object;)Z -Landroid/util/ArraySet;->removeAll(Ljava/util/Collection;)Z -Landroid/util/ArraySet;->removeAt(I)Ljava/lang/Object; -Landroid/util/ArraySet;->removeAll(Landroid/util/ArraySet;)Z -Landroid/content/pm/ApplicationInfo$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/ApplicationInfo; -Landroid/content/pm/ApplicationInfo$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; -Landroid/os/ServiceManagerProxy;->addService(Ljava/lang/String;Landroid/os/IBinder;ZI)V -Lcom/android/internal/os/PowerProfile;-><init>(Landroid/content/Context;)V -Lcom/android/internal/os/PowerProfile;-><init>(Landroid/content/Context;Z)V -Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V -Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;)V -Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;ZI)V -Lcom/android/internal/os/PowerProfile;->readPowerValuesFromXml(Landroid/content/Context;Z)V -Lcom/android/server/SystemConfig;->readPermission(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)V -Landroid/content/res/ResourcesImpl;-><init>(Landroid/content/res/AssetManager;Landroid/util/DisplayMetrics;Landroid/content/res/Configuration;Landroid/view/DisplayAdjustments;)V -Landroid/os/ServiceManager;->getService(Ljava/lang/String;)Landroid/os/IBinder; -Landroid/os/ServiceManager;->getServiceOrThrow(Ljava/lang/String;)Landroid/os/IBinder; -Landroid/util/Base64$Decoder;->process([BIIZ)Z -Lcom/android/internal/util/XmlUtils;->readLongAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)J -Lcom/android/internal/util/XmlUtils;->readLongAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;J)J +Lcom/android/internal/os/BatteryStatsImpl;->detachIfNotNull(Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V +Lcom/android/internal/os/BatteryStatsImpl;->detachIfNotNull([Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V +Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V +Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V +Landroid/os/BatteryStats$LongCounter;-><init>()V +Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V +Landroid/util/ArrayMap;->allocArrays(I)V +Lcom/android/internal/os/BatteryStatsImpl$DualTimer;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Lcom/android/internal/os/BatteryStatsImpl$Uid;ILjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V +Lcom/android/internal/os/BatteryStatsImpl$DualTimer;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V +Landroid/util/SparseArray;->put(ILjava/lang/Object;)V +Lcom/android/internal/os/BatteryStatsImpl$OverflowArrayMap;-><init>(Lcom/android/internal/os/BatteryStatsImpl;I)V +Lcom/android/internal/os/BatteryStatsImpl$OverflowArrayMap;->add(Ljava/lang/String;Ljava/lang/Object;)V Lcom/android/internal/os/BatteryStatsImpl$Uid;->getPackageStatsLocked(Ljava/lang/String;)Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg; -Lcom/android/internal/app/procstats/ProcessStats;->resetCommon()V -HPLcom/android/internal/app/procstats/ProcessStats;->resetSafely()V -Landroid/content/res/ResourcesImpl;->updateConfiguration(Landroid/content/res/Configuration;Landroid/util/DisplayMetrics;Landroid/content/res/CompatibilityInfo;)V -Landroid/content/res/Resources;-><init>()V -Landroid/content/res/Resources;-><init>(Landroid/content/res/AssetManager;Landroid/util/DisplayMetrics;Landroid/content/res/Configuration;)V -Landroid/content/res/Resources;-><init>(Ljava/lang/ClassLoader;)V -Landroid/os/ServiceManager;->rawGetService(Ljava/lang/String;)Landroid/os/IBinder; -Landroid/util/LongSparseArray;->put(JLjava/lang/Object;)V -Landroid/util/ArrayMap;->freeArrays([I[Ljava/lang/Object;I)V -Landroid/util/ArrayMap;->keyAt(I)Ljava/lang/Object; -Landroid/content/pm/PackageParser$Activity$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/PackageParser$Activity; -Landroid/content/pm/PackageParser$Activity$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; -Landroid/content/pm/PackageParser$Activity;-><init>(Landroid/content/pm/PackageParser$ParseComponentArgs;Landroid/content/pm/ActivityInfo;)V -Landroid/content/pm/PackageParser$Activity;-><init>(Landroid/os/Parcel;)V -Landroid/content/res/AssetManager;->setConfiguration(IILjava/lang/String;IIIIIIIIIIIIIII)V +Lcom/android/internal/util/ArrayUtils;->newUnpaddedObjectArray(I)[Ljava/lang/Object; +Landroid/util/SparseArray;-><init>(I)V +Landroid/util/SparseArray;-><init>()V +Lcom/android/internal/os/BatteryStatsImpl$Uid;->readWakeSummaryFromParcelLocked(Ljava/lang/String;Landroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl$Uid$Wakelock;-><init>(Lcom/android/internal/os/BatteryStatsImpl;Lcom/android/internal/os/BatteryStatsImpl$Uid;)V +Landroid/os/BatteryStats$Uid$Wakelock;-><init>()V +Lcom/android/internal/os/BatteryStatsImpl$Uid;->getWakelockTimerLocked(Lcom/android/internal/os/BatteryStatsImpl$Uid$Wakelock;I)Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer; Lcom/android/internal/os/BatteryStatsImpl$Counter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V -Lcom/android/internal/os/BatteryStatsImpl$Counter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V -Landroid/util/ArraySet;->allocArrays(I)V -Landroid/os/storage/StorageManager;->isFileEncryptedNativeOnly()Z -Lcom/android/internal/os/BatteryStatsImpl$Counter;->writeSummaryFromParcelLocked(Landroid/os/Parcel;)V -Lcom/android/internal/os/BatteryStatsImpl;->updateRailStatsLocked()V -Landroid/os/ServiceManagerProxy;->getService(Ljava/lang/String;)Landroid/os/IBinder; -Landroid/util/SparseIntArray;-><init>()V -Landroid/util/SparseIntArray;-><init>(I)V -Lcom/android/internal/util/XmlUtils;->readIntAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)I -Lcom/android/internal/util/XmlUtils;->readIntAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;I)I -Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)V -Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;-><init>(Lcom/android/internal/os/BatteryStatsImpl$TimeBase;Landroid/os/Parcel;)V -Lcom/android/internal/os/BatteryStatsImpl;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Landroid/os/Parcel;)V -Lcom/android/internal/os/BatteryStatsImpl;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Ljava/io/File;Landroid/os/Handler;Lcom/android/internal/os/BatteryStatsImpl$PlatformIdleStateCallback;Lcom/android/internal/os/BatteryStatsImpl$RailEnergyDataCallback;Lcom/android/internal/os/BatteryStatsImpl$UserInfoProvider;)V -Lcom/android/internal/os/BatteryStatsImpl;-><init>(Ljava/io/File;Landroid/os/Handler;Lcom/android/internal/os/BatteryStatsImpl$PlatformIdleStateCallback;Lcom/android/internal/os/BatteryStatsImpl$RailEnergyDataCallback;Lcom/android/internal/os/BatteryStatsImpl$UserInfoProvider;)V -Lcom/android/internal/os/BatteryStatsImpl$Uid;->readJobSummaryFromParcelLocked(Ljava/lang/String;Landroid/os/Parcel;)V -Lcom/android/internal/app/procstats/ProcessStats;->updateFragmentation()V -Landroid/os/Parcel;->readTypedObject(Landroid/os/Parcelable$Creator;)Ljava/lang/Object; -Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->getTotalDurationMsLocked(J)J -Landroid/os/Parcel;->createTypedArray(Landroid/os/Parcelable$Creator;)[Ljava/lang/Object; -Landroid/os/Parcel;->createTypedArrayList(Landroid/os/Parcelable$Creator;)Ljava/util/ArrayList; -Landroid/os/Parcel;->createTypedArrayMap(Landroid/os/Parcelable$Creator;)Landroid/util/ArrayMap; -Landroid/content/pm/PackageParserCacheHelper$ReadHelper;->readString(Landroid/os/Parcel;)Ljava/lang/String; -Lcom/android/server/LocalServices;->addService(Ljava/lang/Class;Ljava/lang/Object;)V -Landroid/util/Slog;->d(Ljava/lang/String;Ljava/lang/String;)I -Landroid/util/TimingsTraceLog;->traceBegin(Ljava/lang/String;)V -Landroid/content/res/AssetManager;-><init>()V -Landroid/content/res/AssetManager;->getResourceValue(IILandroid/util/TypedValue;Z)Z -Landroid/util/LongSparseLongArray;->put(JJ)V +Landroid/os/BatteryStats$Counter;-><init>()V +Lcom/android/internal/os/BatteryStatsImpl$Counter;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;-><init>(Z)V +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->init(JJ)V +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->getUptime(J)J +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->getRealtime(J)J +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->readSummaryFromParcel(Landroid/os/Parcel;)V Lcom/android/internal/os/BatteryStatsImpl$SystemClocks;->uptimeMillis()J -Landroid/content/res/AssetManager;->setApkAssets([Landroid/content/res/ApkAssets;Z)V +Lcom/android/internal/os/BatteryStatsImpl$SystemClocks;->elapsedRealtime()J Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->readSummaryFromParcelLocked(Landroid/os/Parcel;Lcom/android/internal/os/BatteryStatsImpl$TimeBase;)Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray; -Lcom/android/internal/util/XmlUtils;->readBooleanAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)Z -Lcom/android/internal/util/XmlUtils;->readBooleanAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Z)Z -Landroid/os/StrictMode$ThreadPolicy;-><init>(ILandroid/os/StrictMode$OnThreadViolationListener;Ljava/util/concurrent/Executor;)V -Lcom/android/internal/os/KernelCpuSpeedReader;->readDelta()[J -Lcom/android/internal/os/AtomicFile;->startWrite()Ljava/io/FileOutputStream; -Landroid/app/ContextImpl;->createSystemUiContext(Landroid/app/ContextImpl;I)Landroid/app/ContextImpl; -Landroid/app/ActivityThread;->getSystemUiContext()Landroid/app/ContextImpl; -Landroid/os/Parcel;->recycle()V -Landroid/util/Slog;->i(Ljava/lang/String;Ljava/lang/String;)I -Landroid/os/Binder;-><init>()V -Landroid/os/Binder;-><init>(Ljava/lang/String;)V -Landroid/content/Context;->getSystemService(Ljava/lang/Class;)Ljava/lang/Object; +Lcom/android/internal/os/BatteryStatsImpl$Uid;->getServiceStatsLocked(Ljava/lang/String;Ljava/lang/String;)Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg$Serv; +Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg;->newServiceStatsLocked()Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg$Serv; +Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg$Serv;-><init>(Lcom/android/internal/os/BatteryStatsImpl;)V +Landroid/os/BatteryStats$Uid$Pkg$Serv;-><init>()V +Lcom/android/internal/app/procstats/ProcessStats;->splitAndParseNumbers(Ljava/lang/String;)[I +Lcom/android/internal/os/KernelCpuProcStringReader;->isNumber(C)Z +Lcom/android/internal/os/KernelCpuProcStringReader;->access$000(Lcom/android/internal/os/KernelCpuProcStringReader;)[C +Lcom/android/internal/os/KernelCpuProcStringReader$ProcFileIterator;->nextLine()Ljava/nio/CharBuffer; +Lcom/android/internal/os/KernelCpuProcStringReader;->asLongs(Ljava/nio/CharBuffer;[J)I +Landroid/util/SparseArray;->get(I)Ljava/lang/Object; +Landroid/util/SparseArray;->get(ILjava/lang/Object;)Ljava/lang/Object; +Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->copyToCurTimes()V +Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V +Lcom/android/internal/os/KernelWakelockReader;->readKernelWakelockStats(Lcom/android/internal/os/KernelWakelockStats;)Lcom/android/internal/os/KernelWakelockStats; +Lcom/android/internal/util/GrowingArrayUtils;->insert([JIIJ)[J +Lcom/android/internal/util/XmlUtils;->readIntAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;I)I +Lcom/android/internal/util/XmlUtils;->readLongAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;J)J +Landroid/os/Parcel;->dataPosition()I +Landroid/util/LongSparseLongArray;->put(JJ)V Lcom/android/internal/util/ArrayUtils;->newUnpaddedLongArray(I)[J -Landroid/content/res/ResourcesImpl;->getValue(ILandroid/util/TypedValue;Z)V -Landroid/content/res/ResourcesImpl;->getValueForDensity(IILandroid/util/TypedValue;Z)V +Lcom/android/internal/os/KernelWakelockReader;->parseProcWakelocks([BIZLcom/android/internal/os/KernelWakelockStats;)Lcom/android/internal/os/KernelWakelockStats; +Landroid/util/SparseArray;->valueAt(I)Ljava/lang/Object; Landroid/util/LongSparseLongArray;-><init>()V Landroid/util/LongSparseLongArray;-><init>(I)V -Landroid/os/BatteryStats$Timer;-><init>()V -Lcom/android/internal/os/BatteryStatsImpl$Uid;->createAggregatedPartialWakelockTimerLocked()Lcom/android/internal/os/BatteryStatsImpl$DualTimer; -Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->access$2300(Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;Landroid/os/Parcel;)V -Lcom/android/internal/os/BatteryStatsImpl$Uid;->readJobCompletionsFromParcelLocked(Landroid/os/Parcel;)V -Landroid/util/MapCollections$KeySet;->iterator()Ljava/util/Iterator; -Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z -Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->writeSummaryToParcel(Landroid/os/Parcel;JJ)V +Landroid/app/AppOpsManager;->makeKey(II)J +Landroid/app/AppOpsManager;->opToDefaultMode(I)I +Lcom/android/internal/util/XmlUtils;->readLongAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)J +Landroid/app/AppOpsManager;->extractFlagsFromKey(J)I +Landroid/app/AppOpsManager;->extractUidStateFromKey(J)I +Lcom/android/internal/util/XmlUtils;->readStringAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)Ljava/lang/String; +Lcom/android/internal/os/KernelWakelockStats$Entry;-><init>(IJI)V +Lcom/android/internal/os/KernelWakelockReader;->removeOldStats(Lcom/android/internal/os/KernelWakelockStats;)Lcom/android/internal/os/KernelWakelockStats; +Lcom/android/internal/os/BatteryStatsImpl;->updateKernelWakelocksLocked()V +Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->update(JI)V +Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->setUpdateVersion(I)V +Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->getUpdateVersion()I +Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->endSample()V +Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->computeRunTimeLocked(J)J +Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->computeCurrentCountLocked()I +Landroid/os/Parcel;->writeInt(I)V +Landroid/os/Parcel;->writeLong(J)V +Lcom/android/internal/os/BatteryStatsImpl$Timer;->writeSummaryFromParcelLocked(Landroid/os/Parcel;J)V +Lcom/android/internal/os/BatteryStatsImpl;->writeSummaryToParcel(Landroid/os/Parcel;Z)V +Landroid/os/Parcel;->writeString(Ljava/lang/String;)V +Landroid/os/Parcel$ReadWriteHelper;->writeString(Landroid/os/Parcel;Ljava/lang/String;)V +Landroid/os/StrictMode;->setThreadPolicyMask(I)V +Landroid/os/StrictMode;->setBlockGuardPolicy(I)V +Lcom/android/internal/os/ProcStatsUtil;->readTerminatedProcFile(Ljava/lang/String;B)Ljava/lang/String; +Landroid/os/StrictMode$ThreadPolicy;-><init>(ILandroid/os/StrictMode$OnThreadViolationListener;Ljava/util/concurrent/Executor;Landroid/os/StrictMode$1;)V +Landroid/os/StrictMode$ThreadPolicy;-><init>(ILandroid/os/StrictMode$OnThreadViolationListener;Ljava/util/concurrent/Executor;)V +Landroid/os/StrictMode;->setThreadPolicy(Landroid/os/StrictMode$ThreadPolicy;)V +Landroid/os/StrictMode;->allowThreadDiskReadsMask()I +Landroid/os/StrictMode;->getThreadPolicyMask()I +Landroid/os/StrictMode;->allowThreadDiskReads()Landroid/os/StrictMode$ThreadPolicy; +Lcom/android/internal/os/ProcessCpuTracker;->collectStats(Ljava/lang/String;IZ[ILjava/util/ArrayList;)[I +Lcom/android/internal/os/ProcessCpuTracker$Stats;-><init>(IIZ)V +Lcom/android/internal/os/ProcessCpuTracker$Stats;->getUid(Ljava/lang/String;)I +Lcom/android/internal/os/ProcessCpuTracker;->getName(Lcom/android/internal/os/ProcessCpuTracker$Stats;Ljava/lang/String;)V +Lcom/android/internal/os/ProcessCpuTracker;->onMeasureProcessName(Ljava/lang/String;)I Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;->computeRunTimeLocked(J)J -Landroid/bluetooth/BluetoothAdapter;->getDefaultAdapter()Landroid/bluetooth/BluetoothAdapter; -Landroid/content/pm/PackageParserCacheHelper$ReadHelper;->startAndInstall()V -Landroid/content/pm/PackageItemInfo;-><init>(Landroid/content/pm/PackageItemInfo;)V -Landroid/content/pm/PackageItemInfo;-><init>(Landroid/os/Parcel;)V -Landroid/content/pm/ActivityInfo;-><init>()V -Landroid/content/pm/ActivityInfo;-><init>(Landroid/content/pm/ActivityInfo;)V -Landroid/content/pm/ActivityInfo;-><init>(Landroid/os/Parcel;)V -Landroid/content/pm/ActivityInfo$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/ActivityInfo; -Landroid/content/pm/ActivityInfo$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; -Landroid/os/BinderProxy;->transact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z -Landroid/os/HandlerThread;->getLooper()Landroid/os/Looper; -Landroid/os/FileUtils;->$closeResource(Ljava/lang/Throwable;Ljava/lang/AutoCloseable;)V -Landroid/os/SystemProperties;->digestOf([Ljava/lang/String;)Ljava/lang/String; -Lcom/android/internal/util/ArrayUtils;->isEmpty(Ljava/util/Collection;)Z -Lcom/android/internal/util/ArrayUtils;->isEmpty([Ljava/lang/Object;)Z -Landroid/util/AtomicFile;-><init>(Ljava/io/File;)V -Landroid/util/AtomicFile;-><init>(Ljava/io/File;Ljava/lang/String;)V -Landroid/util/LongSparseArray;-><init>()V -Landroid/util/LongSparseArray;-><init>(I)V -Landroid/content/res/Resources;->obtainTypedArray(I)Landroid/content/res/TypedArray; -Landroid/util/AtomicFile;->openRead()Ljava/io/FileInputStream; -Lcom/android/internal/os/BatteryStatsImpl$TimeBase;-><init>(Z)V -Lcom/android/internal/os/BatteryStatsImpl$Counter;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V -Lcom/android/internal/os/BatteryStatsImpl$Uid;->makeProcessState(ILandroid/os/Parcel;)V -Lcom/android/internal/os/BatteryStatsImpl$Uid$3;->instantiateObject()Lcom/android/internal/os/BatteryStatsImpl$DualTimer; -Lcom/android/internal/os/BatteryStatsImpl$Uid$3;->instantiateObject()Ljava/lang/Object; -Landroid/content/pm/PackageUserState;-><init>()V -Landroid/app/ActivityManager;->isLowRamDeviceStatic()Z -Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidActiveTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V -Lcom/android/internal/os/BatteryStatsImpl;->updateRpmStatsLocked()V -Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;->writeSummaryFromParcelLocked(Landroid/os/Parcel;)V -Lcom/android/internal/os/KernelMemoryBandwidthStats;->updateStats()V -Landroid/content/pm/PackageParser;->isCacheUpToDate(Ljava/io/File;Ljava/io/File;)Z -Landroid/os/StrictMode;->initThreadDefaults(Landroid/content/pm/ApplicationInfo;)V -Landroid/app/ResourcesManager;->getOrCreateResources(Landroid/os/IBinder;Landroid/content/res/ResourcesKey;Ljava/lang/ClassLoader;)Landroid/content/res/Resources; -Landroid/app/ResourcesManager;->getOrCreateResourcesForActivityLocked(Landroid/os/IBinder;Ljava/lang/ClassLoader;Landroid/content/res/ResourcesImpl;Landroid/content/res/CompatibilityInfo;)Landroid/content/res/Resources; -Landroid/app/ResourcesManager;->getOrCreateResourcesLocked(Ljava/lang/ClassLoader;Landroid/content/res/ResourcesImpl;Landroid/content/res/CompatibilityInfo;)Landroid/content/res/Resources; -Landroid/app/ResourcesManager;->getResources(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ILandroid/content/res/Configuration;Landroid/content/res/CompatibilityInfo;Ljava/lang/ClassLoader;)Landroid/content/res/Resources; -Landroid/app/ContextImpl;->createResources(Landroid/os/IBinder;Landroid/app/LoadedApk;Ljava/lang/String;ILandroid/content/res/Configuration;Landroid/content/res/CompatibilityInfo;[Ljava/lang/String;)Landroid/content/res/Resources; -Landroid/app/ContextImpl;->createResources(Landroid/os/IBinder;Landroid/app/LoadedApk;Ljava/lang/String;ILandroid/content/res/Configuration;Landroid/content/res/CompatibilityInfo;)Landroid/content/res/Resources; -Landroid/app/ContextImpl;->getSystemService(Ljava/lang/String;)Ljava/lang/Object; -Landroid/app/ContextImpl;->getSystemServiceName(Ljava/lang/Class;)Ljava/lang/String; -Landroid/app/SystemServiceRegistry$CachedServiceFetcher;->getService(Landroid/app/ContextImpl;)Ljava/lang/Object; -Landroid/util/TimingsTraceLog;->assertSameThread()V -Landroid/os/HandlerThread;-><init>(Ljava/lang/String;)V -Landroid/os/HandlerThread;-><init>(Ljava/lang/String;I)V -Lcom/android/internal/util/ArrayUtils;->newUnpaddedIntArray(I)[I -Landroid/content/res/Configuration;-><init>()V -Landroid/content/res/Configuration;-><init>(Landroid/content/res/Configuration;)V -Landroid/view/SurfaceControl;->getInternalDisplayToken()Landroid/os/IBinder; -Landroid/view/SurfaceControl;->getPhysicalDisplayToken(J)Landroid/os/IBinder; -Landroid/content/res/Resources;->getInteger(I)I -Landroid/os/Handler;->sendMessageAtTime(Landroid/os/Message;J)Z -Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->init(JJ)V -Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->readSummaryFromParcel(Landroid/os/Parcel;)V -Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg;-><init>(Lcom/android/internal/os/BatteryStatsImpl;)V -Landroid/util/ArraySet;->freeArrays([I[Ljava/lang/Object;I)V -Landroid/util/ArrayMap;->entrySet()Ljava/util/Set; -Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidClusterTimeReader;->readDeltaImpl(Lcom/android/internal/os/KernelCpuUidTimeReader$Callback;)V -Landroid/telephony/TelephonyManager;->getITelephony()Lcom/android/internal/telephony/ITelephony; -Landroid/telephony/TelephonyManager;->requestModemActivityInfo(Landroid/os/ResultReceiver;)V +Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;->computeCurrentCountLocked()I +Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->writeSummaryFromParcelLocked(Landroid/os/Parcel;J)V Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->getMaxDurationMsLocked(J)J -Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->endSample()V -Lcom/android/internal/os/BatteryStatsImpl;->updateKernelMemoryBandwidthLocked()V -Landroid/content/pm/ComponentInfo;-><init>()V -Landroid/content/pm/ComponentInfo;-><init>(Landroid/content/pm/ComponentInfo;)V -Landroid/content/pm/ComponentInfo;-><init>(Landroid/os/Parcel;)V -Landroid/view/SurfaceControl;->getDisplayConfigs(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo; -Lcom/android/internal/os/AtomicFile;->finishWrite(Ljava/io/FileOutputStream;)V -Landroid/app/ResourcesManager;->createResourcesImpl(Landroid/content/res/ResourcesKey;)Landroid/content/res/ResourcesImpl; -Landroid/app/ContextImpl;->updateDisplay(I)V -Landroid/hardware/display/DisplayManagerGlobal;->getInstance()Landroid/hardware/display/DisplayManagerGlobal; -Landroid/app/ResourcesManager;->getAdjustedDisplay(ILandroid/content/res/Resources;)Landroid/view/Display; -Landroid/app/ResourcesManager;->getAdjustedDisplay(ILandroid/view/DisplayAdjustments;)Landroid/view/Display; -Landroid/os/Parcel;->readStrongBinder()Landroid/os/IBinder; -Landroid/app/ContextImpl;->setTheme(I)V -Landroid/content/IntentFilter;->readFromXml(Lorg/xmlpull/v1/XmlPullParser;)V -Landroid/text/TextUtils;->getLayoutDirectionFromLocale(Ljava/util/Locale;)I -Landroid/os/Handler;-><init>()V -Landroid/os/Handler;-><init>(Landroid/os/Handler$Callback;)V -Landroid/os/Handler;-><init>(Landroid/os/Handler$Callback;Z)V -Landroid/os/Handler;-><init>(Landroid/os/Looper;)V -Landroid/os/Handler;-><init>(Landroid/os/Looper;Landroid/os/Handler$Callback;)V -Landroid/os/Handler;-><init>(Landroid/os/Looper;Landroid/os/Handler$Callback;Z)V -Landroid/os/Handler;-><init>(Z)V -Landroid/os/Binder;->queryLocalInterface(Ljava/lang/String;)Landroid/os/IInterface; -Landroid/content/pm/PackageParser;->isApkFile(Ljava/io/File;)Z -Landroid/util/SparseIntArray;->put(II)V -Landroid/content/pm/ApplicationInfo;->initForUser(I)V -Landroid/os/BinderProxy;->getInstance(JJ)Landroid/os/BinderProxy; +Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->getTotalDurationMsLocked(J)J +Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->getCurrentDurationMsLocked(J)J +Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;->writeSummaryFromParcelLocked(Landroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl$DualTimer;->writeSummaryFromParcelLocked(Landroid/os/Parcel;J)V +Lcom/android/internal/os/BatteryStatsImpl$OverflowArrayMap;->getMap()Landroid/util/ArrayMap; +Lcom/android/internal/os/BatteryStatsImpl$Uid;->access$2400(Lcom/android/internal/os/BatteryStatsImpl$Uid;)Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter; +Lcom/android/internal/os/BatteryStatsImpl$Uid;->access$2500(Lcom/android/internal/os/BatteryStatsImpl$Uid;)Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter; +Lcom/android/internal/os/BatteryStatsImpl$Counter;->writeSummaryFromParcelLocked(Landroid/os/Parcel;)V +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->writeSummaryToParcel(Landroid/os/Parcel;JJ)V +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->computeUptime(JI)J +Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->computeRealtime(JI)J +Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->writeSummaryToParcelLocked(Landroid/os/Parcel;Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;)V +Lcom/android/internal/os/BatteryStatsImpl$Uid$Pkg$Serv;->getStartTimeToNowLocked(J)J +Landroid/util/MapCollections$ArrayIterator;->hasNext()Z +Landroid/util/SparseArray;->size()I +Landroid/content/pm/Signature;->parseHexDigit(I)I +Landroid/content/pm/Signature;-><init>(Ljava/lang/String;)V +Landroid/content/pm/FallbackCategoryProvider;->loadFallbacks()V +Landroid/content/pm/PermissionInfo;->fixProtectionLevel(I)I +Lcom/android/internal/util/ArrayUtils;->isEmpty([I)Z +Lcom/android/internal/util/ArrayUtils;->appendInt([IIZ)[I +Landroid/util/ArraySet;-><init>(IZ)V +Landroid/content/pm/IntentFilterVerificationInfo;->readFromXml(Lorg/xmlpull/v1/XmlPullParser;)V Landroid/content/pm/IntentFilterVerificationInfo;->getStringFromXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; -Landroid/app/SystemServiceRegistry$35;->createService(Landroid/app/ContextImpl;)Landroid/os/PowerManager; -Landroid/app/SystemServiceRegistry$35;->createService(Landroid/app/ContextImpl;)Ljava/lang/Object; -Landroid/util/ArrayMap;->containsKey(Ljava/lang/Object;)Z -Landroid/app/WindowConfiguration;->setToDefaults()V -Lcom/android/internal/util/MemInfoReader;->readMemInfo()V +Landroid/content/pm/PackageParser;->toSigningKeys([Landroid/content/pm/Signature;)Landroid/util/ArraySet; +Landroid/util/ArraySet;-><init>(I)V +Landroid/util/Base64$Decoder;->process([BIIZ)Z Landroid/util/LongSparseArray;->get(J)Ljava/lang/Object; Landroid/util/LongSparseArray;->get(JLjava/lang/Object;)Ljava/lang/Object; -Landroid/util/Spline;->createSpline([F[F)Landroid/util/Spline; -Landroid/os/PowerManager;->getDefaultScreenBrightnessSetting()I -Landroid/view/Display;-><init>(Landroid/hardware/display/DisplayManagerGlobal;ILandroid/view/DisplayInfo;Landroid/content/res/Resources;)V -Landroid/view/Display;-><init>(Landroid/hardware/display/DisplayManagerGlobal;ILandroid/view/DisplayInfo;Landroid/view/DisplayAdjustments;)V -Landroid/view/Display;-><init>(Landroid/hardware/display/DisplayManagerGlobal;ILandroid/view/DisplayInfo;Landroid/view/DisplayAdjustments;Landroid/content/res/Resources;)V -Landroid/net/Uri;->withAppendedPath(Landroid/net/Uri;Ljava/lang/String;)Landroid/net/Uri; -Landroid/content/res/TypedArray;->obtain(Landroid/content/res/Resources;I)Landroid/content/res/TypedArray; -Landroid/provider/Settings$System;->getUriFor(Ljava/lang/String;)Landroid/net/Uri; +Landroid/util/ArraySet;-><init>()V +Lcom/android/internal/util/XmlUtils;->readBooleanAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Z)Z +Landroid/util/ArrayMap$1;->colGetEntry(II)Ljava/lang/Object; Landroid/util/MapCollections$ArrayIterator;->next()Ljava/lang/Object; -Landroid/view/DisplayAdjustments;-><init>()V -Landroid/view/DisplayAdjustments;-><init>(Landroid/content/res/Configuration;)V -Landroid/view/DisplayAdjustments;-><init>(Landroid/view/DisplayAdjustments;)V -Landroid/hardware/display/DisplayManager;->getOrCreateDisplayLocked(IZ)Landroid/view/Display; -Landroid/content/res/Resources;->getIntArray(I)[I -Landroid/content/res/StringBlock;->get(I)Ljava/lang/CharSequence; -Landroid/content/res/XmlBlock$Parser;->getText()Ljava/lang/String; -Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounter;->readSummaryFromParcelLocked(Landroid/os/Parcel;)V -Lcom/android/internal/os/BatteryStatsImpl$Uid$Wakelock;-><init>(Lcom/android/internal/os/BatteryStatsImpl;Lcom/android/internal/os/BatteryStatsImpl$Uid;)V -Lcom/android/internal/os/BatteryStatsImpl$Uid;->readSyncSummaryFromParcelLocked(Ljava/lang/String;Landroid/os/Parcel;)V -Landroid/hardware/display/DisplayManagerGlobal;->getDisplayInfo(I)Landroid/view/DisplayInfo; -Landroid/os/FileUtils;->readTextFile(Ljava/io/File;ILjava/lang/String;)Ljava/lang/String; -Lcom/android/internal/app/procstats/ProcessStats;->buildTimePeriodStartClockStr()V -Landroid/text/format/DateFormat;->format(Ljava/lang/CharSequence;J)Ljava/lang/CharSequence; -Landroid/text/format/DateFormat;->format(Ljava/lang/CharSequence;Ljava/util/Calendar;)Ljava/lang/CharSequence; -Landroid/text/format/DateFormat;->format(Ljava/lang/CharSequence;Ljava/util/Date;)Ljava/lang/CharSequence; -Landroid/telephony/TelephonyManager;->from(Landroid/content/Context;)Landroid/telephony/TelephonyManager; -Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->getRealtime(J)J -Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->writeSummaryToParcelLocked(Landroid/os/Parcel;Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;)V -Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;->access$2600(Lcom/android/internal/os/BatteryStatsImpl$LongSamplingCounterArray;Landroid/os/Parcel;)V -Landroid/os/Parcel;->unmarshall([BII)V +Landroid/content/pm/PackageParserCacheHelper$ReadHelper;->readString(Landroid/os/Parcel;)Ljava/lang/String; +Landroid/util/ArraySet;->indexOf(Ljava/lang/Object;)I +Landroid/util/MapCollections$MapIterator;->hasNext()Z +Landroid/os/Parcel;->readStringList(Ljava/util/List;)V +Landroid/content/pm/Signature;->equals(Ljava/lang/Object;)Z +Lcom/android/internal/util/ArrayUtils;->indexOf([Ljava/lang/Object;Ljava/lang/Object;)I +Landroid/os/Parcel;->readParcelableList(Ljava/util/List;Ljava/lang/ClassLoader;)Ljava/util/List; +Landroid/os/Parcel;->readStringArray()[Ljava/lang/String; +Landroid/content/pm/PackageParser$SigningDetails;->hasCertificateInternal(Landroid/content/pm/Signature;I)Z +Landroid/content/pm/PackageParser$SigningDetails;->hasPastSigningCertificates()Z +Landroid/util/MapCollections$MapIterator;->getValue()Ljava/lang/Object; Landroid/content/pm/PackageParser$Package;->fixupOwner(Ljava/util/List;)V -Landroid/content/res/Resources;->getBoolean(I)Z -Landroid/content/res/AssetManager;->getResourceText(I)Ljava/lang/CharSequence; -Landroid/content/res/AssetManager;->getResourceTextArray(I)[Ljava/lang/CharSequence; -Landroid/content/res/Resources;->getText(I)Ljava/lang/CharSequence; -HPLandroid/content/res/Resources;->getText(ILjava/lang/CharSequence;)Ljava/lang/CharSequence; -Landroid/content/res/Resources;->getTextArray(I)[Ljava/lang/CharSequence; -Landroid/os/MessageQueue;->next()Landroid/os/Message; -Landroid/os/Parcel;->marshall()[B -Lcom/android/internal/logging/EventLogTags;->writeCommitSysConfigFile(Ljava/lang/String;J)V -Landroid/os/ThreadLocalWorkSource;->restore(J)V -Landroid/os/Looper;->prepare()V -Landroid/os/Looper;->prepareMainLooper()V -Lcom/android/internal/app/procstats/ProcessStats;->splitAndParseNumbers(Ljava/lang/String;)[I -Landroid/os/Trace;->traceEnd(J)V -Landroid/os/Parcel;->readExceptionCode()I -Landroid/os/Parcel;->readException()V -Landroid/os/Parcel;->readException(ILjava/lang/String;)V -Lcom/android/internal/util/StatLogger;->logDurationStat(IJ)J -Landroid/content/res/ResourcesImpl$ThemeImpl;->applyStyle(IZ)V -Landroid/content/res/Resources$Theme;->applyStyle(IZ)V -Landroid/content/res/AssetManager;->applyStyleToTheme(JIZ)V -Landroid/os/Trace;->isTagEnabled(J)Z -Lcom/android/internal/util/ArrayUtils;->containsAll([Ljava/lang/Object;[Ljava/lang/Object;)Z -Landroid/os/Trace;->traceBegin(JLjava/lang/String;)V -Landroid/hardware/display/DisplayManager;-><init>(Landroid/content/Context;)V -Landroid/os/Bundle;-><init>()V -Landroid/os/Bundle;-><init>(I)V -Landroid/os/Bundle;-><init>(Landroid/os/Bundle;)V -Landroid/os/Bundle;-><init>(Landroid/os/PersistableBundle;)V -Landroid/content/pm/PackageBackwardCompatibility;->updatePackage(Landroid/content/pm/PackageParser$Package;)V -Landroid/content/pm/PackageBackwardCompatibility;->modifySharedLibraries(Landroid/content/pm/PackageParser$Package;)V +Landroid/util/MapCollections$MapIterator;->next()Ljava/lang/Object; +Landroid/util/MapCollections$MapIterator;->next()Ljava/util/Map$Entry; +Landroid/util/MapCollections$MapIterator;->getKey()Ljava/lang/Object; Landroid/content/pm/Signature;->areExactMatch([Landroid/content/pm/Signature;[Landroid/content/pm/Signature;)Z -Lcom/android/internal/util/ArrayUtils;->contains(Ljava/util/Collection;Ljava/lang/Object;)Z -Lcom/android/internal/util/ArrayUtils;->contains([II)Z +Lcom/android/internal/util/ArrayUtils;->containsAll([Ljava/lang/Object;[Ljava/lang/Object;)Z Lcom/android/internal/util/ArrayUtils;->contains([Ljava/lang/Object;Ljava/lang/Object;)Z -Lcom/android/internal/util/ConcurrentUtils$1;->newThread(Ljava/lang/Runnable;)Ljava/lang/Thread; -Landroid/os/PowerManager;-><init>(Landroid/content/Context;Landroid/os/IPowerManager;Landroid/os/Handler;)V -Landroid/content/res/AssetManager;->getResourceArray(I[I)I -Landroid/content/res/AssetManager;->getResourceArraySize(I)I -Landroid/app/WindowConfiguration;-><init>()V -Landroid/view/SurfaceControl;->getPhysicalDisplayIds()[J -Lcom/android/internal/os/BackgroundThread;->getHandler()Landroid/os/Handler; -Landroid/net/Uri$StringUri;->buildUpon()Landroid/net/Uri$Builder; -Lcom/android/internal/os/AtomicFile;->readFully()[B -Lcom/android/internal/util/ArrayUtils;->indexOf([Ljava/lang/Object;Ljava/lang/Object;)I -Landroid/content/res/ResourcesImpl;->loadXmlResourceParser(Ljava/lang/String;IILjava/lang/String;)Landroid/content/res/XmlResourceParser; -Landroid/content/res/Resources;->loadXmlResourceParser(ILjava/lang/String;)Landroid/content/res/XmlResourceParser; -Landroid/content/res/Resources;->getXml(I)Landroid/content/res/XmlResourceParser; -Landroid/content/res/XmlBlock$Parser;->next()I -Landroid/content/res/XmlBlock$Parser;->nextTag()I -Landroid/content/res/XmlBlock$Parser;->nextText()Ljava/lang/String; -Lcom/google/android/collect/Sets;->newArraySet()Landroid/util/ArraySet; -Lcom/google/android/collect/Sets;->newArraySet([Ljava/lang/Object;)Landroid/util/ArraySet; -Landroid/util/ArraySet;->contains(Ljava/lang/Object;)Z -Lcom/android/internal/os/BatteryStatsImpl$Uid;->getSensorTimerLocked(IZ)Lcom/android/internal/os/BatteryStatsImpl$DualTimer; Landroid/content/pm/PackageParser$SigningDetails;->hasCertificate(Landroid/content/pm/Signature;)Z -Landroid/content/pm/PackageParser$SigningDetails;->hasCertificateInternal(Landroid/content/pm/Signature;I)Z -Landroid/content/res/XmlBlock$Parser;->getAttributeValue(I)Ljava/lang/String; -Landroid/content/res/XmlBlock$Parser;->getAttributeValue(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; -Lcom/android/internal/os/BatteryStatsImpl;->detachIfNotNull(Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V -Lcom/android/internal/os/BatteryStatsImpl;->detachIfNotNull([Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V -Lcom/android/internal/os/BatteryStatsImpl;->detachIfNotNull([[Lcom/android/internal/os/BatteryStatsImpl$TimeBaseObs;)V -Landroid/util/Spline$MonotoneCubicSpline;-><init>([F[F)V -Landroid/content/res/Configuration;->setTo(Landroid/content/res/Configuration;)V -Landroid/content/res/Configuration;->setToDefaults()V -Lcom/android/server/SystemConfig;->readSplitPermission(Lorg/xmlpull/v1/XmlPullParser;Ljava/io/File;)V -Lcom/android/internal/os/RpmStats;->getSubsystem(Ljava/lang/String;)Lcom/android/internal/os/RpmStats$PowerStateSubsystem; -Lcom/android/internal/os/BatteryStatsImpl$TimeBase;->computeRealtime(JI)J -Landroid/os/Parcel;->dataPosition()I -Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->getCurrentDurationMsLocked(J)J -Lcom/android/internal/os/KernelCpuUidTimeReader$KernelCpuUidFreqTimeReader;->checkPrecondition(Lcom/android/internal/os/KernelCpuProcStringReader$ProcFileIterator;)Z -Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->computeRunTimeLocked(J)J -Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->computeCurrentCountLocked()I -Lcom/android/internal/os/KernelMemoryBandwidthStats;->parseStats(Ljava/io/BufferedReader;)V -Landroid/util/MapCollections;->getEntrySet()Ljava/util/Set; -Landroid/util/MapCollections$EntrySet;->iterator()Ljava/util/Iterator; -Lcom/android/internal/os/BatteryStatsImpl$Uid;->writeJobCompletionsToParcelLocked(Landroid/os/Parcel;)V +Landroid/util/ArrayMap;->putAll(Ljava/util/Map;)V +Landroid/os/Parcel;->createStringArrayList()Ljava/util/ArrayList; +Landroid/content/pm/PackageParser$Package;->internStringArrayList(Ljava/util/List;)V +Lcom/android/internal/util/ArrayUtils;->contains(Ljava/util/Collection;Ljava/lang/Object;)Z +Landroid/util/ArraySet;->size()I +Landroid/util/SparseArray;->keyAt(I)I +Landroid/content/pm/PackageParser;->isApkFile(Ljava/io/File;)Z +Landroid/content/pm/PackageParser;->isApkPath(Ljava/lang/String;)Z +Landroid/os/Parcel;->readParcelableCreator(Ljava/lang/ClassLoader;)Landroid/os/Parcelable$Creator; +Landroid/os/Parcel;->readParcelable(Ljava/lang/ClassLoader;)Landroid/os/Parcelable; Landroid/os/Parcel;->readBundle()Landroid/os/Bundle; Landroid/os/Parcel;->readBundle(Ljava/lang/ClassLoader;)Landroid/os/Bundle; -Landroid/content/res/Resources;->getString(I)Ljava/lang/String; -Landroid/content/res/Resources;->getString(I[Ljava/lang/Object;)Ljava/lang/String; -Landroid/content/res/Resources;->getStringArray(I)[Ljava/lang/String; -Landroid/os/ThreadLocalWorkSource;->setUid(I)J -Landroid/content/pm/PackageParser;->parseClusterPackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package; -Landroid/content/pm/PackageParser;->parseClusterPackageLite(Ljava/io/File;I)Landroid/content/pm/PackageParser$PackageLite; -Landroid/content/pm/split/DefaultSplitAssetLoader;->getBaseAssetManager()Landroid/content/res/AssetManager; -Landroid/content/pm/PackageParser;->parseBaseApk(Ljava/io/File;Landroid/content/res/AssetManager;I)Landroid/content/pm/PackageParser$Package; -Landroid/content/pm/PackageParser;->parseBaseApk(Ljava/lang/String;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Landroid/content/pm/PackageParser$Package; -Landroid/content/pm/PackageParser;->parseBaseApkCommon(Landroid/content/pm/PackageParser$Package;Ljava/util/Set;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Landroid/content/pm/PackageParser$Package; -Landroid/content/pm/PackageParser;->cacheResult(Ljava/io/File;ILandroid/content/pm/PackageParser$Package;)V -Landroid/content/pm/PackageParser;->parseMonolithicPackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package; -Landroid/content/pm/PackageParser;->parseMonolithicPackageLite(Ljava/io/File;I)Landroid/content/pm/PackageParser$PackageLite; -Landroid/content/pm/PackageParser;->parseApkLite(Ljava/io/File;I)Landroid/content/pm/PackageParser$ApkLite; -Landroid/content/pm/PackageParser;->parseApkLite(Ljava/lang/String;Lorg/xmlpull/v1/XmlPullParser;Landroid/util/AttributeSet;Landroid/content/pm/PackageParser$SigningDetails;)Landroid/content/pm/PackageParser$ApkLite; -Landroid/content/pm/PackageParser;->parseApkLiteInner(Ljava/io/File;Ljava/io/FileDescriptor;Ljava/lang/String;I)Landroid/content/pm/PackageParser$ApkLite; -Landroid/content/pm/PackageParser;->toCacheEntry(Landroid/content/pm/PackageParser$Package;)[B -Landroid/content/pm/PackageParser;->parseBaseApplication(Landroid/content/pm/PackageParser$Package;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Z -Landroid/os/Parcel;->writeParcelable(Landroid/os/Parcelable;I)V -Landroid/os/Parcel;->writeParcelableArray([Landroid/os/Parcelable;I)V -Landroid/os/Parcel;->writeParcelableCreator(Landroid/os/Parcelable;)V -Landroid/os/Parcel;->writeParcelableList(Ljava/util/List;I)V -Landroid/content/pm/PackageParser$Package;->writeToParcel(Landroid/os/Parcel;I)V -Landroid/content/res/Resources;->obtainAttributes(Landroid/util/AttributeSet;[I)Landroid/content/res/TypedArray; -Landroid/content/res/Resources;->obtainAttributes(Landroid/content/res/Resources;Landroid/content/res/Resources$Theme;Landroid/util/AttributeSet;[I)Landroid/content/res/TypedArray; -Landroid/content/pm/split/DefaultSplitAssetLoader;->close()V -Landroid/content/res/AssetManager;->openXmlResourceParser(ILjava/lang/String;)Landroid/content/res/XmlResourceParser; -Landroid/content/res/AssetManager;->close()V -Landroid/content/res/AssetManager;->openXmlBlockAsset(ILjava/lang/String;)Landroid/content/res/XmlBlock; -Landroid/content/pm/PackageParser;->generateAppDetailsHiddenActivity(Landroid/content/pm/PackageParser$Package;I[Ljava/lang/String;Z)Landroid/content/pm/PackageParser$Activity; -Landroid/content/pm/split/DefaultSplitAssetLoader;->loadApkAssets(Ljava/lang/String;I)Landroid/content/res/ApkAssets; -Landroid/content/pm/PackageParser$Activity;->writeToParcel(Landroid/os/Parcel;I)V -Landroid/os/FileUtils;->trimFilename(Ljava/lang/StringBuilder;I)V -Landroid/content/res/ApkAssets;->openXml(Ljava/lang/String;)Landroid/content/res/XmlResourceParser; -Landroid/content/res/Configuration;->setLocales(Landroid/os/LocaleList;)V -Landroid/content/pm/PackageParser;->buildTaskAffinityName(Ljava/lang/String;Ljava/lang/String;Ljava/lang/CharSequence;[Ljava/lang/String;)Ljava/lang/String; -Landroid/content/res/AssetManager;->retrieveAttributes(Landroid/content/res/XmlBlock$Parser;[I[I[I)Z -Landroid/content/pm/PackageParser;->buildCompoundName(Ljava/lang/String;Ljava/lang/CharSequence;Ljava/lang/String;[Ljava/lang/String;)Ljava/lang/String; -Landroid/content/pm/ActivityInfo;->writeToParcel(Landroid/os/Parcel;I)V -Landroid/content/res/XmlBlock$Parser;->close()V -Landroid/content/pm/PackageParser;->validateName(Ljava/lang/String;ZZ)Ljava/lang/String; -Landroid/util/ArraySet;->equals(Ljava/lang/Object;)Z -Landroid/content/pm/PackageItemInfo;->writeToParcel(Landroid/os/Parcel;I)V -Landroid/content/pm/PackageParserCacheHelper$WriteHelper;->finishAndUninstall()V -Landroid/content/res/TypedArray;->loadStringValueAt(I)Ljava/lang/CharSequence; -Landroid/content/pm/ApplicationInfo;->writeToParcel(Landroid/os/Parcel;I)V -Landroid/os/FileUtils;->isValidExtFilename(Ljava/lang/String;)Z -Landroid/content/res/AssetManager;->findCookieForPath(Ljava/lang/String;)I -Landroid/content/res/TypedArray;->getNonConfigurationString(II)Ljava/lang/String; -Landroid/content/res/TypedArray;->peekValue(I)Landroid/util/TypedValue; -Landroid/app/ActivityThread;->attach(ZJ)V -Landroid/content/res/TypedArray;->getValueAt(ILandroid/util/TypedValue;)Z -Landroid/content/res/XmlBlock$Parser;->getAttributeName(I)Ljava/lang/String; -Landroid/content/res/XmlBlock$Parser;->getAttributeNameResource(I)I -Landroid/content/pm/PackageParser$ApkLite;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;ZIIIILjava/util/List;Landroid/content/pm/PackageParser$SigningDetails;ZZZZZZZII)V -Landroid/app/ResourcesManager;->createAssetManager(Landroid/content/res/ResourcesKey;)Landroid/content/res/AssetManager; -Landroid/content/res/AssetManager$Builder;->build()Landroid/content/res/AssetManager; -Landroid/os/FileUtils;->deleteContents(Ljava/io/File;)Z -Landroid/os/FileUtils;->deleteContentsAndDir(Ljava/io/File;)Z -Landroid/content/res/ResourcesImpl;->adjustLanguageTag(Ljava/lang/String;)Ljava/lang/String; -Landroid/sysprop/DisplayProperties;->tryParseBoolean(Ljava/lang/String;)Ljava/lang/Boolean; -Landroid/content/pm/PackageParserCacheHelper$WriteHelper;-><init>(Landroid/os/Parcel;)V +Landroid/text/TextUtils$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/text/TextUtils$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/CharSequence; +Landroid/content/pm/PackageItemInfo;-><init>(Landroid/os/Parcel;)V +Landroid/content/pm/PackageParser$Component;->createIntentsList(Landroid/os/Parcel;)Ljava/util/ArrayList; +Landroid/content/pm/PackageParser$Component;-><init>(Landroid/os/Parcel;)V +Landroid/content/pm/PackageParser$Permission$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/content/pm/PackageParser$Permission$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/PackageParser$Permission; +Landroid/content/pm/PackageParser$Permission;-><init>(Landroid/os/Parcel;Landroid/content/pm/PackageParser$1;)V +Landroid/content/pm/PackageParser$Permission;-><init>(Landroid/os/Parcel;)V +Landroid/content/pm/PermissionInfo$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/content/pm/PermissionInfo$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/PermissionInfo; +Landroid/content/pm/PermissionInfo;-><init>(Landroid/os/Parcel;Landroid/content/pm/PermissionInfo$1;)V +Landroid/content/pm/PermissionInfo;-><init>(Landroid/os/Parcel;)V +Landroid/os/Parcel;->readBoolean()Z +Landroid/util/ArrayMap;->indexOfNull()I +Landroid/util/MapCollections$ArrayIterator;-><init>(Landroid/util/MapCollections;I)V +Landroid/util/ArrayMap$1;->colGetSize()I +Landroid/util/ArrayMap;->getCollection()Landroid/util/MapCollections; +Landroid/util/MapCollections;->getValues()Ljava/util/Collection; +Landroid/util/MapCollections$ValuesCollection;->iterator()Ljava/util/Iterator; +Landroid/util/ArrayMap;->values()Ljava/util/Collection; +Landroid/os/Parcel;->readFloat()F +Landroid/content/pm/PackageBackwardCompatibility;->updatePackage(Landroid/content/pm/PackageParser$Package;)V +Landroid/os/Parcel;->setDataPosition(I)V +Landroid/content/pm/PackageParser$Activity;-><init>(Landroid/os/Parcel;)V +Landroid/content/pm/ComponentInfo;-><init>(Landroid/os/Parcel;)V +Landroid/util/SparseArray;->clear()V +Lcom/android/internal/util/ArrayUtils;->remove(Ljava/util/ArrayList;Ljava/lang/Object;)Ljava/util/ArrayList; +Landroid/content/pm/PackageParser$Activity$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/content/pm/PackageParser$Activity$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/PackageParser$Activity; +Landroid/content/pm/PackageParser$Activity;-><init>(Landroid/os/Parcel;Landroid/content/pm/PackageParser$1;)V +Landroid/content/pm/ActivityInfo$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/ActivityInfo; +Landroid/content/pm/ActivityInfo;-><init>(Landroid/os/Parcel;Landroid/content/pm/ActivityInfo$1;)V +Landroid/content/pm/ActivityInfo;-><init>(Landroid/os/Parcel;)V +Landroid/content/pm/ActivityInfo$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/content/ComponentName;->hashCode()I +Landroid/content/pm/PackageParser$Component;->getComponentName()Landroid/content/ComponentName; +Landroid/os/Parcel;->createIntArray()[I +Landroid/content/ComponentName;-><init>(Ljava/lang/String;Ljava/lang/String;)V +Landroid/util/ArraySet;->contains(Ljava/lang/Object;)Z +Landroid/os/Parcel;->createTypedArrayList(Landroid/os/Parcelable$Creator;)Ljava/util/ArrayList; +Landroid/os/Parcel;->obtain()Landroid/os/Parcel; +Landroid/os/UserHandle;->getAppId(I)I +Landroid/util/ArrayMap;->clear()V +Landroid/util/ArraySet;->remove(Ljava/lang/Object;)Z +Landroid/content/IntentFilter;->actionsIterator()Ljava/util/Iterator; +Landroid/content/IntentFilter;-><init>(Landroid/os/Parcel;)V +Landroid/os/Parcel;->updateNativeSize(J)V +Landroid/content/IntentFilter;->setAutoVerify(Z)V +Landroid/content/IntentFilter;->setVisibilityToInstantApp(I)V +Landroid/os/Parcel;->readCharSequence()Ljava/lang/CharSequence; +Landroid/content/pm/PackageParser$IntentInfo;-><init>(Landroid/os/Parcel;)V +Landroid/os/SystemProperties;->getBoolean(Ljava/lang/String;Z)Z +Landroid/os/Parcel;->recycle()V +Landroid/util/ArraySet;->valueAt(I)Ljava/lang/Object; +Landroid/util/ArraySet;->valueAtUnchecked(I)Ljava/lang/Object; +Landroid/content/pm/PackageParser$Package;->isPrivileged()Z +Landroid/content/pm/ApplicationInfo;->isPrivilegedApp()Z +Landroid/content/IntentFilter;->schemesIterator()Ljava/util/Iterator; +Landroid/content/IntentFilter;->typesIterator()Ljava/util/Iterator; +Landroid/content/IntentFilter;->debugCheck()Z +Landroid/util/ArrayMap;-><init>(I)V +Landroid/util/ArrayMap;->containsKey(Ljava/lang/Object;)Z +Landroid/content/IntentFilter;->getOrder()I +Landroid/content/pm/PackageSharedLibraryUpdater;->isLibraryPresent(Ljava/util/ArrayList;Ljava/util/ArrayList;Ljava/lang/String;)Z Landroid/content/pm/PackageParser$Package;->getLongVersionCode()J -Lcom/android/internal/util/function/pooled/OmniFunction;->run()V -Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; -Landroid/os/SystemProperties;->get(Ljava/lang/String;)Ljava/lang/String; -Landroid/os/SystemProperties;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; -Landroid/os/SystemProperties;->getInt(Ljava/lang/String;I)I -Landroid/os/SystemProperties;->getLong(Ljava/lang/String;J)J -Landroid/content/res/ThemedResourceCache;->onConfigurationChange(I)V -Landroid/content/res/TypedArray;->recycle()V -Landroid/content/res/Configuration;->fixUpLocaleList()V -Landroid/content/res/XmlBlock;->newParser(I)Landroid/content/res/XmlResourceParser; -Landroid/content/pm/ComponentInfo;->writeToParcel(Landroid/os/Parcel;I)V -Landroid/content/res/ApkAssets;->getAssetPath()Ljava/lang/String; -Landroid/util/MapCollections$MapIterator;->next()Ljava/lang/Object; -Landroid/content/res/ResourcesImpl;->flushLayoutCache()V -Landroid/os/FileUtils;->buildValidExtFilename(Ljava/lang/String;)Ljava/lang/String; -Landroid/content/res/ApkAssets;->getStringFromPool(I)Ljava/lang/CharSequence; -Landroid/content/pm/Signature;->equals(Ljava/lang/Object;)Z +Landroid/content/pm/PackageInfo;->composeLongVersionCode(II)J +Lcom/android/internal/util/ArrayUtils;->isEmpty(Ljava/util/Collection;)Z +Landroid/content/pm/ApplicationInfo;->isStaticSharedLibrary()Z +Landroid/content/pm/ApplicationInfo;->getCodePath()Ljava/lang/String; +Landroid/content/pm/ApplicationInfo;->getResourcePath()Ljava/lang/String; +Landroid/content/pm/ApplicationInfo;->isSystemApp()Z +Landroid/util/ArraySet;->equals(Ljava/lang/Object;)Z +Landroid/os/Environment;->getDataDirectory(Ljava/lang/String;)Ljava/io/File; +Landroid/content/pm/PackageParser$ActivityIntentInfo;-><init>(Landroid/os/Parcel;)V +Landroid/content/pm/PackageSharedLibraryUpdater;->prefixImplicitDependency(Landroid/content/pm/PackageParser$Package;Ljava/lang/String;Ljava/lang/String;)V +Landroid/content/pm/PackageParser$Service;-><init>(Landroid/os/Parcel;)V +Landroid/content/pm/PackageSharedLibraryUpdater;->removeLibrary(Landroid/content/pm/PackageParser$Package;Ljava/lang/String;)V +Landroid/content/pm/PackageParser$Service$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/PackageParser$Service; +Landroid/content/pm/ServiceInfo;-><init>(Landroid/os/Parcel;Landroid/content/pm/ServiceInfo$1;)V +Landroid/content/pm/ServiceInfo;-><init>(Landroid/os/Parcel;)V +Landroid/content/pm/PackageParser$Service$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/content/pm/PackageParser$Service;-><init>(Landroid/os/Parcel;Landroid/content/pm/PackageParser$1;)V +Landroid/content/pm/ServiceInfo$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/ServiceInfo; +Landroid/content/pm/ServiceInfo$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/os/Parcel;->readArrayMapInternal(Landroid/util/ArrayMap;ILjava/lang/ClassLoader;)V +Landroid/os/Parcel;->readValue(Ljava/lang/ClassLoader;)Ljava/lang/Object; +Landroid/util/ArrayMap;->append(Ljava/lang/Object;Ljava/lang/Object;)V +Landroid/util/ArrayMap;->validate()V Landroid/content/pm/PackageUserState;->equals(Ljava/lang/Object;)Z -Landroid/util/ArrayMap$1;->colGetEntry(II)Ljava/lang/Object; -Lcom/android/internal/os/BackgroundThread;->ensureThreadLocked()V -Landroid/app/ActivityThread;-><init>()V -Landroid/app/ActivityThread;->getSystemContext()Landroid/app/ContextImpl; -Landroid/app/ContextImpl;->createSystemContext(Landroid/app/ActivityThread;)Landroid/app/ContextImpl; -Landroid/app/ContextImpl;-><init>(Landroid/app/ContextImpl;Landroid/app/ActivityThread;Landroid/app/LoadedApk;Ljava/lang/String;Landroid/os/IBinder;Landroid/os/UserHandle;ILjava/lang/ClassLoader;Ljava/lang/String;)V -Landroid/app/ResourcesManager;->getDisplayMetrics()Landroid/util/DisplayMetrics; -Landroid/app/ResourcesManager;->getDisplayMetrics(ILandroid/view/DisplayAdjustments;)Landroid/util/DisplayMetrics; +Landroid/content/IntentFilter;->getPriority()I +Landroid/os/Parcel;->createTypedArray(Landroid/os/Parcelable$Creator;)[Ljava/lang/Object; +Landroid/os/BaseBundle;->readFromParcelInner(Landroid/os/Parcel;I)V +Landroid/os/Parcel;->hasReadWriteHelper()Z +Landroid/os/BaseBundle;->initializeFromParcelLocked(Landroid/os/Parcel;ZZ)V +Landroid/os/BaseBundle;->isEmptyParcel(Landroid/os/Parcel;)Z +Landroid/content/pm/PackageParser$ServiceIntentInfo;-><init>(Landroid/os/Parcel;)V +Landroid/content/pm/PackageParser$Provider;-><init>(Landroid/os/Parcel;)V +Landroid/os/Parcel;->freeBuffer()V +Landroid/content/IntentFilter$AuthorityEntry;-><init>(Landroid/os/Parcel;)V +Landroid/content/pm/PackageParser$Provider$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/content/pm/PackageParser$Provider$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/PackageParser$Provider; +Landroid/content/pm/PackageParser$Provider;-><init>(Landroid/os/Parcel;Landroid/content/pm/PackageParser$1;)V +Landroid/content/pm/ProviderInfo$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/content/pm/ProviderInfo$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/ProviderInfo; +Landroid/content/pm/ProviderInfo;-><init>(Landroid/os/Parcel;Landroid/content/pm/ProviderInfo$1;)V +Landroid/content/pm/ProviderInfo;-><init>(Landroid/os/Parcel;)V +Landroid/util/MapCollections;->getEntrySet()Ljava/util/Set; +Landroid/content/pm/PackageParser$SigningDetails;->checkCapability(Landroid/content/pm/PackageParser$SigningDetails;I)Z +Landroid/content/IntentFilter;->countActions()I +Landroid/content/IntentFilter;->countCategories()I +Landroid/content/IntentFilter;->getAction(I)Ljava/lang/String; +Landroid/content/IntentFilter;->hasAction(Ljava/lang/String;)Z +Landroid/content/pm/PackageParser$SigningDetails;->hasCertificate(Landroid/content/pm/Signature;I)Z +Landroid/content/pm/PackageItemInfo;-><init>()V +Landroid/util/DisplayMetrics;-><init>()V +Landroid/content/pm/FeatureInfo$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/content/pm/FeatureInfo$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/FeatureInfo; +Landroid/content/pm/FeatureInfo;-><init>(Landroid/os/Parcel;Landroid/content/pm/FeatureInfo$1;)V +Landroid/content/pm/FeatureInfo;-><init>(Landroid/os/Parcel;)V +Landroid/util/DisplayMetrics;->setToDefaults()V +Landroid/os/Parcel;->unmarshall([BII)V +Landroid/content/pm/PackageParser$Package;-><init>(Landroid/os/Parcel;)V +Landroid/content/pm/ApplicationInfo;-><init>()V +Landroid/content/pm/PackageParser;->setCallback(Landroid/content/pm/PackageParser$Callback;)V +Landroid/content/pm/PackageParser;->getCachedResult(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package; +Landroid/os/Parcel;->setReadWriteHelper(Landroid/os/Parcel$ReadWriteHelper;)V +Landroid/content/pm/PackageParser;->setSeparateProcesses([Ljava/lang/String;)V +Landroid/content/pm/PackageParser;->setOnlyCoreApps(Z)V +Landroid/content/pm/PackageParser;->setDisplayMetrics(Landroid/util/DisplayMetrics;)V +Landroid/content/pm/PackageParser;->setCacheDir(Ljava/io/File;)V +Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;IZ)Landroid/content/pm/PackageParser$Package; +Landroid/content/pm/PackageParser;->getCacheKey(Ljava/io/File;I)Ljava/lang/String; +Landroid/content/pm/PackageParser;-><init>()V +Landroid/content/pm/PackageSharedLibraryUpdater;->prefixRequiredLibrary(Landroid/content/pm/PackageParser$Package;Ljava/lang/String;)V +Landroid/content/pm/PackageSharedLibraryUpdater;->prefix(Ljava/util/ArrayList;Ljava/lang/Object;)Ljava/util/ArrayList; +Landroid/content/pm/PackageParser$SigningDetails$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/content/pm/PackageParser$SigningDetails$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/PackageParser$SigningDetails; +Landroid/os/Parcel;->readArraySet(Ljava/lang/ClassLoader;)Landroid/util/ArraySet; +Landroid/content/pm/PackageParser$Package;->readKeySetMapping(Landroid/os/Parcel;)Landroid/util/ArrayMap; +Landroid/os/Parcel;->createByteArray()[B +Landroid/content/pm/ApplicationInfo$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/content/pm/ApplicationInfo$1;->createFromParcel(Landroid/os/Parcel;)Landroid/content/pm/ApplicationInfo; +Landroid/content/pm/ApplicationInfo;-><init>(Landroid/os/Parcel;Landroid/content/pm/ApplicationInfo$1;)V +Landroid/content/pm/ApplicationInfo;-><init>(Landroid/os/Parcel;)V +Landroid/util/ArraySet$1;->colGetEntry(II)Ljava/lang/Object; +Landroid/content/IntentFilter;->getCategory(I)Ljava/lang/String; +Landroid/content/IntentFilter;->hasCategory(Ljava/lang/String;)Z +Landroid/content/pm/ApplicationInfo;->isUpdatedSystemApp()Z +Landroid/content/IntentFilter;->countDataSchemes()I +Landroid/content/IntentFilter;->countDataTypes()I +Landroid/content/IntentFilter;->countDataAuthorities()I Landroid/content/pm/PackageParser$Package;->setApplicationVolumeUuid(Ljava/lang/String;)V +Landroid/os/storage/StorageManager;->convert(Ljava/lang/String;)Ljava/util/UUID; +Landroid/content/pm/PackageParser$Package;->setApplicationInfoCodePath(Ljava/lang/String;)V +Landroid/content/pm/ApplicationInfo;->setCodePath(Ljava/lang/String;)V +Landroid/content/pm/PackageParser$Package;->setApplicationInfoBaseCodePath(Ljava/lang/String;)V +Landroid/content/pm/ApplicationInfo;->setBaseCodePath(Ljava/lang/String;)V +Landroid/content/pm/PackageParser$Package;->setApplicationInfoSplitCodePaths([Ljava/lang/String;)V +Landroid/content/pm/ApplicationInfo;->setSplitCodePaths([Ljava/lang/String;)V +Landroid/content/pm/PackageParser$Package;->setApplicationInfoResourcePath(Ljava/lang/String;)V +Landroid/content/pm/ApplicationInfo;->setResourcePath(Ljava/lang/String;)V +Landroid/content/pm/PackageParser$Package;->setApplicationInfoBaseResourcePath(Ljava/lang/String;)V +Landroid/content/pm/ApplicationInfo;->setBaseResourcePath(Ljava/lang/String;)V +Landroid/content/pm/PackageParser$Package;->setApplicationInfoSplitResourcePaths([Ljava/lang/String;)V +Landroid/content/pm/ApplicationInfo;->setSplitResourcePaths([Ljava/lang/String;)V Landroid/content/pm/AndroidHidlUpdater;->updatePackage(Landroid/content/pm/PackageParser$Package;)V -Landroid/content/res/ApkAssets;->close()V -Landroid/content/res/XmlBlock$Parser;->getAttributeBooleanValue(IZ)Z -Landroid/content/res/XmlBlock$Parser;->getAttributeBooleanValue(Ljava/lang/String;Ljava/lang/String;Z)Z -Landroid/content/pm/PackageParser;->setMaxAspectRatio(Landroid/content/pm/PackageParser$Package;)V -Landroid/content/pm/PackageParserCacheHelper$WriteHelper;->writeString(Landroid/os/Parcel;Ljava/lang/String;)V -Landroid/os/Parcel;->writeTypedList(Ljava/util/List;)V -Landroid/os/Parcel;->writeTypedList(Ljava/util/List;I)V -Landroid/content/res/Configuration;->getLocales()Landroid/os/LocaleList; -Landroid/view/DisplayEventReceiver;-><init>(Landroid/os/Looper;I)V -Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->doInvoke()Ljava/lang/Object; -Landroid/content/pm/PackageSharedLibraryUpdater;->prefixImplicitDependency(Landroid/content/pm/PackageParser$Package;Ljava/lang/String;Ljava/lang/String;)V -Landroid/util/MapCollections$MapIterator;->getKey()Ljava/lang/Object; -Landroid/util/MapCollections$ValuesCollection;->iterator()Ljava/util/Iterator; -Lcom/android/internal/os/BatteryStatsImpl$SystemClocks;->elapsedRealtime()J -Landroid/app/LoadedApk;->makeApplication(ZLandroid/app/Instrumentation;)Landroid/app/Application; -Landroid/content/pm/IntentFilterVerificationInfo;->getIntFromXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;I)I -Landroid/content/res/ResourcesImpl;->calcConfigChanges(Landroid/content/res/Configuration;)I -Landroid/content/pm/PackageBackwardCompatibility$AndroidTestRunnerSplitUpdater;->updatePackage(Landroid/content/pm/PackageParser$Package;)V -Landroid/util/SparseArray;->valueAt(I)Ljava/lang/Object; +Landroid/content/pm/PackageParser$Package;->getChildPackageNames()Ljava/util/List; +Landroid/content/pm/SELinuxUtil;->assignSeinfoUser(Landroid/content/pm/PackageUserState;)Ljava/lang/String; +Landroid/content/pm/ApplicationInfo;->initForUser(I)V +Landroid/os/UserHandle;->getUid(II)I +Landroid/os/Environment;->getDataUserDePackageDirectory(Ljava/lang/String;ILjava/lang/String;)Ljava/io/File; +Landroid/os/Environment;->getDataUserDeDirectory(Ljava/lang/String;I)Ljava/io/File; +Landroid/os/Environment;->getDataUserDeDirectory(Ljava/lang/String;)Ljava/io/File; +Landroid/os/Environment;->getDataUserCePackageDirectory(Ljava/lang/String;ILjava/lang/String;)Ljava/io/File; +Landroid/os/Environment;->getDataUserCeDirectory(Ljava/lang/String;I)Ljava/io/File; +Landroid/os/Environment;->getDataUserCeDirectory(Ljava/lang/String;)Ljava/io/File; +Landroid/content/pm/SharedLibraryInfo;->getPath()Ljava/lang/String; +Landroid/content/pm/ApplicationInfo;->isInstantApp()Z +Landroid/permission/PermissionManager$SplitPermissionInfo;->getNewPermissions()Ljava/util/List; +Landroid/permission/PermissionManager$SplitPermissionInfo;->getSplitPermission()Ljava/lang/String; +Landroid/content/pm/PackageParser$SigningDetails;->hasAncestorOrSelf(Landroid/content/pm/PackageParser$SigningDetails;)Z +Landroid/content/pm/PackageParser$Package;->isVendor()Z +Landroid/content/pm/ApplicationInfo;->isVendor()Z +Landroid/util/ArraySet;->iterator()Ljava/util/Iterator; +Landroid/util/ArraySet;->getCollection()Landroid/util/MapCollections; +Landroid/util/MapCollections;->getKeySet()Ljava/util/Set; +Landroid/util/MapCollections$KeySet;->iterator()Ljava/util/Iterator; +Landroid/util/ArraySet$1;->colGetSize()I +Lcom/android/server/SystemConfig;->getInstance()Lcom/android/server/SystemConfig; +Landroid/content/pm/PackageParser$Package;->isProduct()Z +Landroid/content/pm/ApplicationInfo;->isProduct()Z +Landroid/content/pm/PackageParser$Package;->isSystem()Z +Landroid/content/pm/PackageParser$Package;->isUpdatedSystemApp()Z +Lcom/android/server/SystemConfig;->getProductPrivAppPermissions(Ljava/lang/String;)Landroid/util/ArraySet; +Landroid/text/TextUtils;->equals(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Z +Lcom/android/internal/util/FastXmlSerializer;->escapeAndAppendString(Ljava/lang/String;)V +Lcom/android/internal/util/FastXmlSerializer;->append(Ljava/lang/String;II)V +Lcom/android/internal/util/FastXmlSerializer;->append(Ljava/lang/String;)V +Lcom/android/internal/util/FastXmlSerializer;->append(C)V +Lcom/android/internal/util/FastXmlSerializer;->attribute(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/xmlpull/v1/XmlSerializer; +Lcom/android/internal/util/FastXmlSerializer;->appendIndent(I)V +Lcom/android/internal/util/FastXmlSerializer;->startTag(Ljava/lang/String;Ljava/lang/String;)Lorg/xmlpull/v1/XmlSerializer; +Lcom/android/internal/util/FastXmlSerializer;->endTag(Ljava/lang/String;Ljava/lang/String;)Lorg/xmlpull/v1/XmlSerializer; +Landroid/content/pm/Signature;->toChars([C[I)[C +Landroid/content/pm/Signature;->hashCode()I +Landroid/content/pm/IntentFilterVerificationInfo;->writeToXml(Lorg/xmlpull/v1/XmlSerializer;)V +Landroid/util/ArrayMap;->entrySet()Ljava/util/Set; +Landroid/util/MapCollections$EntrySet;->iterator()Ljava/util/Iterator; +Landroid/util/MapCollections$MapIterator;-><init>(Landroid/util/MapCollections;)V +Landroid/util/MapCollections$EntrySet;-><init>(Landroid/util/MapCollections;)V +Lcom/android/internal/util/ArrayUtils;->isEmpty([Ljava/lang/Object;)Z +Landroid/util/Base64$Encoder;->process([BIIZ)Z +Landroid/os/FileUtils;->bytesToFile(Ljava/lang/String;[B)V +Landroid/os/FileUtils;->$closeResource(Ljava/lang/Throwable;Ljava/lang/AutoCloseable;)V +Landroid/util/ArraySet;->removeAt(I)Ljava/lang/Object; +Landroid/util/ArraySet;->shouldShrink()Z +Landroid/util/MapCollections;-><init>()V +Landroid/content/IntentFilter;->getAutoVerify()Z +Landroid/content/IntentFilter;->match(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/net/Uri;Ljava/util/Set;Ljava/lang/String;)I +Landroid/content/IntentFilter;->matchAction(Ljava/lang/String;)Z +Landroid/content/pm/ApplicationInfo;->setVersionCode(J)V +Landroid/os/Process;->isIsolated(I)Z +Landroid/content/pm/PackageUserState;->isAvailable(I)Z +Landroid/content/pm/PackageParser;->checkUseInstalledOrHidden(ILandroid/content/pm/PackageUserState;Landroid/content/pm/ApplicationInfo;)Z +Landroid/content/pm/PackageParser$Package;->isMatch(I)Z +Landroid/content/pm/PackageParser;->copyNeeded(ILandroid/content/pm/PackageParser$Package;Landroid/content/pm/PackageUserState;Landroid/os/Bundle;I)Z +Landroid/content/pm/PackageParser;->updateApplicationInfo(Landroid/content/pm/ApplicationInfo;ILandroid/content/pm/PackageUserState;)V +Landroid/content/pm/PackageParser;->generateApplicationInfo(Landroid/content/pm/PackageParser$Package;ILandroid/content/pm/PackageUserState;I)Landroid/content/pm/ApplicationInfo; +Landroid/content/pm/FallbackCategoryProvider;->getFallbackCategory(Ljava/lang/String;)I +Landroid/os/storage/StorageManager;->isFileEncryptedNativeOnly()Z +Landroid/os/storage/StorageManager;->isEncrypted()Z +Landroid/content/pm/PackageParser;->generatePackageInfo(Landroid/content/pm/PackageParser$Package;[IIJJLjava/util/Set;Landroid/content/pm/PackageUserState;I)Landroid/content/pm/PackageInfo; +Landroid/content/pm/PackageInfo;-><init>()V +Landroid/os/Parcel;->writeInterfaceToken(Ljava/lang/String;)V +Landroid/os/BinderProxy;->transact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z +Landroid/os/Binder;->checkParcel(Landroid/os/IBinder;ILandroid/os/Parcel;Ljava/lang/String;)V +Landroid/os/Binder;->isTracingEnabled()Z +Landroid/os/Parcel;->readException()V +Landroid/os/Parcel;->readExceptionCode()I +Landroid/os/UserHandle;->getUserId(I)I +Landroid/util/proto/ProtoInputStream;->fillBuffer()V +Landroid/util/proto/ProtoInputStream;->getOffset()I +Landroid/util/proto/ProtoStream;->getOffsetFromToken(J)I +Landroid/util/proto/ProtoInputStream;->incOffset(I)V +Landroid/util/proto/ProtoInputStream;->readVarint()J +Landroid/util/proto/ProtoInputStream;->nextField()I +Landroid/util/proto/ProtoInputStream;->readTag()V +Landroid/util/proto/ProtoInputStream;->assertFreshData()V +Landroid/util/proto/ProtoInputStream;->assertFieldNumber(J)V +Landroid/util/proto/ProtoInputStream;->assertWireType(I)V +Landroid/util/proto/ProtoInputStream;->getFieldNumber()I +Landroid/util/proto/ProtoInputStream;->checkPacked(J)V +Lcom/android/internal/util/ArrayUtils;->newUnpaddedIntArray(I)[I +Landroid/util/proto/ProtoInputStream;->readLong(J)J +Landroid/util/SparseIntArray;-><init>(I)V +Landroid/util/SparseIntArray;-><init>()V +Landroid/util/proto/ProtoInputStream;->readInt(J)I +Landroid/util/proto/ProtoInputStream;->start(J)J +Landroid/util/proto/ProtoStream;->makeToken(IZIII)J +Landroid/util/proto/ProtoInputStream;->end(J)V +Landroid/util/proto/ProtoInputStream;->readString(J)Ljava/lang/String; +Landroid/util/proto/ProtoInputStream;->readRawString(I)Ljava/lang/String; +Landroid/util/ArraySet;->addAll(Ljava/util/Collection;)Z +Landroid/app/usage/UsageStats;-><init>()V +Landroid/content/res/Configuration;->readFromProto(Landroid/util/proto/ProtoInputStream;J)V +Landroid/util/proto/ProtoInputStream;->nextField(J)Z +Lcom/android/internal/util/Preconditions;->checkNotNull(Ljava/lang/Object;)Ljava/lang/Object; +Landroid/net/Uri;->access$300()Ljava/lang/String; +Landroid/net/UriCodec;->appendDecoded(Ljava/lang/StringBuilder;Ljava/lang/String;ZLjava/nio/charset/Charset;Z)V +Landroid/net/UriCodec;->flushDecodingByteAccumulator(Ljava/lang/StringBuilder;Ljava/nio/charset/CharsetDecoder;Ljava/nio/ByteBuffer;Z)V +Landroid/net/Uri$PathPart;->getPathSegments()Landroid/net/Uri$PathSegments; +Landroid/net/Uri$Part;->nonNull(Landroid/net/Uri$Part;)Landroid/net/Uri$Part; +Landroid/net/Uri$HierarchicalUri;->getPathSegments()Ljava/util/List; +Landroid/os/UserHandle;->getCallingUserId()I +Lcom/android/internal/util/FastPrintWriter;->appendLocked(Ljava/lang/String;II)V +Landroid/net/Uri;->decode(Ljava/lang/String;)Ljava/lang/String; +Landroid/net/UriCodec;->decode(Ljava/lang/String;ZLjava/nio/charset/Charset;Z)Ljava/lang/String; +Landroid/text/TextUtils;->safeIntern(Ljava/lang/String;)Ljava/lang/String; +Landroid/view/animation/PathInterpolator;->initPath(Landroid/graphics/Path;)V +Landroid/app/WindowConfiguration;->setAppBounds(Landroid/graphics/Rect;)V +Landroid/app/WindowConfiguration;->setBounds(Landroid/graphics/Rect;)V +Landroid/app/WindowConfiguration;->setWindowingMode(I)V +Landroid/app/WindowConfiguration;->setActivityType(I)V +Landroid/app/WindowConfiguration;->setAlwaysOnTop(I)V +Landroid/app/WindowConfiguration;->setRotation(I)V +Landroid/app/WindowConfiguration;->setDisplayWindowingMode(I)V +Landroid/os/LocaleList;->isEmpty()Z +Landroid/content/res/AssetManager;->getResourceValue(IILandroid/util/TypedValue;Z)Z +Landroid/content/res/Configuration;->fixUpLocaleList()V +Landroid/content/res/Resources;->obtainTempTypedValue()Landroid/util/TypedValue; +Landroid/content/res/Resources;->releaseTempTypedValue(Landroid/util/TypedValue;)V +Landroid/graphics/Rect;->setEmpty()V +Landroid/net/UriCodec;->getNextCharacter(Ljava/lang/String;IILjava/lang/String;)C +Landroid/net/UriCodec;->hexCharToValue(C)I +Landroid/net/Uri$AbstractPart;->getDecoded()Ljava/lang/String; +Landroid/net/Uri$PathSegments;->size()I +Landroid/app/WindowConfiguration;->setToDefaults()V +Lcom/android/internal/util/LineBreakBufferedWriter;->write(Ljava/lang/String;II)V +Landroid/net/Uri;->encode(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; +Landroid/net/Uri;->isAllowed(CLjava/lang/String;)Z +Landroid/os/BaseBundle;->unparcel()V +Landroid/content/Intent;->getAction()Ljava/lang/String; +Landroid/os/Process;->myUid()I +Landroid/content/res/ResourcesImpl;->getValue(ILandroid/util/TypedValue;Z)V +Landroid/graphics/Rect;->set(Landroid/graphics/Rect;)V +Landroid/content/res/Configuration;->setTo(Landroid/content/res/Configuration;)V +Landroid/app/WindowConfiguration;->setTo(Landroid/app/WindowConfiguration;)V +Landroid/util/ArrayMap;->ensureCapacity(I)V +Landroid/util/TypedValue;->complexToFloat(I)F +Landroid/content/res/ThemedResourceCache;->pruneEntriesLocked(Landroid/util/LongSparseArray;I)Z +Landroid/util/TypedValue;->applyDimension(IFLandroid/util/DisplayMetrics;)F +Landroid/os/MessageQueue;->enqueueMessage(Landroid/os/Message;J)Z +Landroid/os/Message;->markInUse()V +Landroid/os/Binder;-><init>()V +Landroid/os/Binder;-><init>(Ljava/lang/String;)V +Landroid/os/UserHandle;->isSameApp(II)Z +Landroid/app/WindowConfiguration;-><init>()V +Landroid/app/WindowConfiguration;->unset()V +Landroid/content/Intent;->getPackage()Ljava/lang/String; +Lcom/android/internal/util/ArrayUtils;->unstableRemoveIf(Ljava/util/ArrayList;Ljava/util/function/Predicate;)I +Landroid/util/TypedValue;->complexToDimensionPixelSize(ILandroid/util/DisplayMetrics;)I +Landroid/net/Uri$HierarchicalUri;->getAuthority()Ljava/lang/String; +Landroid/app/IApplicationThread$Stub;->asBinder()Landroid/os/IBinder; +Landroid/os/UserHandle;->getIdentifier()I +Landroid/util/MemoryIntArray;->enforceNotClosed()V +Landroid/util/MemoryIntArray;->isClosed()Z +Landroid/os/MessageQueue;->next()Landroid/os/Message; +Landroid/app/ContextImpl;->getResources()Landroid/content/res/Resources; +Landroid/net/Uri$Builder;->path(Landroid/net/Uri$PathPart;)Landroid/net/Uri$Builder; +Landroid/util/Singleton;->get()Ljava/lang/Object; +Lcom/android/internal/util/MessageUtils;->findMessageNames([Ljava/lang/Class;[Ljava/lang/String;)Landroid/util/SparseArray; +Landroid/app/ActivityManager;->getService()Landroid/app/IActivityManager; +Landroid/content/ContentProvider;->access$100(Landroid/content/ContentProvider;Ljava/lang/String;)Ljava/lang/String; +Landroid/content/ContentProvider;->setCallingPackage(Ljava/lang/String;)Ljava/lang/String; +Landroid/content/ContentProvider;->onCallingPackageChanged()V +Landroid/app/ContextImpl;->getUserId()I +Landroid/util/TimingsTraceLog;->assertSameThread()V +Landroid/net/Uri$StringUri;->getAuthorityPart()Landroid/net/Uri$Part; +Landroid/os/Binder;->attachInterface(Landroid/os/IInterface;Ljava/lang/String;)V +Landroid/net/Uri$Builder;->authority(Landroid/net/Uri$Part;)Landroid/net/Uri$Builder; +Landroid/app/NotificationChannel;->safeInt(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;I)I +Landroid/app/NotificationChannel;->tryParseInt(Ljava/lang/String;I)I +Landroid/app/NotificationChannel;->safeBool(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Z)Z +Landroid/net/Uri;-><init>(Landroid/net/Uri$1;)V +Landroid/net/Uri;-><init>()V +Landroid/net/Uri$AbstractHierarchicalUri;-><init>(Landroid/net/Uri$1;)V +Landroid/net/Uri$AbstractHierarchicalUri;-><init>()V +Landroid/app/NotificationChannel;->getTrimmedString(Ljava/lang/String;)Ljava/lang/String; +Landroid/app/ActivityManager;->isLowRamDeviceStatic()Z +Landroid/content/IntentFilter;->matchCategories(Ljava/util/Set;)Ljava/lang/String; Landroid/util/ArraySet;->ensureCapacity(I)V -Landroid/os/storage/StorageManager;->convert(Ljava/lang/String;)Ljava/util/UUID; -Landroid/os/storage/StorageManager;->convert(Ljava/util/UUID;)Ljava/lang/String; -Landroid/content/pm/PackageParser;->checkOverlayRequiredSystemProperty(Ljava/lang/String;Ljava/lang/String;)Z +Landroid/util/ArraySet$1;-><init>(Landroid/util/ArraySet;)V +Landroid/util/MapCollections$KeySet;-><init>(Landroid/util/MapCollections;)V +Landroid/provider/Settings$GenerationTracker;->getCurrentGeneration()I +Landroid/app/NotificationChannel;->getAudioAttributes()Landroid/media/AudioAttributes; +Landroid/app/NotificationChannel;->getName()Ljava/lang/CharSequence; +Landroid/app/NotificationChannel;->getImportance()I +Landroid/app/NotificationChannel;->getOriginalImportance()I +Lcom/android/internal/util/ArrayUtils;->size([Ljava/lang/Object;)I +Landroid/app/NotificationChannel;->canShowBadge()Z +Landroid/app/NotificationChannel;->getGroup()Ljava/lang/String; +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->setIfInBounds([Ljava/lang/Object;ILjava/lang/Object;)V +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->mask(II)I +Landroid/os/Message;->obtain()Landroid/os/Message; +Landroid/os/Handler;->enqueueMessage(Landroid/os/MessageQueue;Landroid/os/Message;J)Z +Landroid/os/ThreadLocalWorkSource;->getUid()I +Landroid/os/Handler;->sendMessageAtTime(Landroid/os/Message;J)Z +Landroid/app/NotificationChannel;->isBlockableSystem()Z +Landroid/app/NotificationChannel;->getId()Ljava/lang/String; +Landroid/app/NotificationChannel;->getDescription()Ljava/lang/String; +Landroid/app/NotificationChannel;->shouldVibrate()Z +Landroid/app/NotificationChannel;->getUserLockedFields()I +Landroid/app/NotificationChannel;->shouldShowLights()Z +Landroid/app/NotificationChannel;->isDeleted()Z +Landroid/app/NotificationChannel;->isFgServiceShown()Z +Landroid/app/NotificationChannel;->writeXml(Lorg/xmlpull/v1/XmlSerializer;)V +Landroid/app/NotificationChannel;->writeXml(Lorg/xmlpull/v1/XmlSerializer;ZLandroid/content/Context;)V +Landroid/app/NotificationChannel;->canBypassDnd()Z +Landroid/app/NotificationChannel;->getLockscreenVisibility()I +Landroid/app/NotificationChannel;->getSound()Landroid/net/Uri; +Landroid/media/AudioAttributes;->getUsage()I +Landroid/media/AudioAttributes;->getContentType()I +Landroid/media/AudioAttributes;->getFlags()I +Landroid/app/NotificationChannel;->getLightColor()I +Landroid/app/NotificationChannel;->getVibrationPattern()[J +Landroid/app/NotificationChannel;->canBubble()Z +Landroid/net/Uri$StringUri;->toString()Ljava/lang/String; +Landroid/os/Handler;->sendMessageDelayed(Landroid/os/Message;J)Z +Landroid/os/Message;->recycleUnchecked()V +Landroid/net/Uri$PathPart;->getEncoded()Ljava/lang/String; +Landroid/net/Uri$PathSegments;->get(I)Ljava/lang/Object; +Landroid/net/Uri$PathSegments;->get(I)Ljava/lang/String; +Landroid/net/Uri$PathSegmentsBuilder;->add(Ljava/lang/String;)V +Landroid/content/ContentProvider;->getAuthorityWithoutUserId(Ljava/lang/String;)Ljava/lang/String; +Landroid/os/UserHandle;->myUserId()I +Landroid/provider/Settings$NameValueCache;->getStringForUser(Landroid/content/ContentResolver;Ljava/lang/String;I)Ljava/lang/String; +Landroid/net/Uri$StringUri;->getAuthority()Ljava/lang/String; +Landroid/os/BaseBundle;->getString(Ljava/lang/String;)Ljava/lang/String; +Landroid/os/Bundle;->setDefusable(Landroid/os/Bundle;Z)Landroid/os/Bundle; +Landroid/provider/Settings$ContentProviderHolder;->getProvider(Landroid/content/ContentResolver;)Landroid/content/IContentProvider; +Landroid/content/ContentResolver;->getPackageName()Ljava/lang/String; +Landroid/provider/Settings$ContentProviderHolder;->access$000(Landroid/provider/Settings$ContentProviderHolder;)Landroid/net/Uri; +Landroid/content/ContentProvider$Transport;->call(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Bundle;)Landroid/os/Bundle; +Landroid/content/ContentProvider;->access$200(Landroid/content/ContentProvider;Ljava/lang/String;)V +Landroid/content/ContentProvider;->validateIncomingAuthority(Ljava/lang/String;)V +Landroid/content/ContentProvider;->matchesOurAuthorities(Ljava/lang/String;)Z +Landroid/content/ContentProvider;->call(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Bundle;)Landroid/os/Bundle; +Landroid/provider/Settings;->isInSystemServer()Z +Landroid/os/BaseBundle;-><init>(Ljava/lang/ClassLoader;I)V +Landroid/os/BaseBundle;->putInt(Ljava/lang/String;I)V +Landroid/os/Bundle;-><init>()V +Landroid/os/BaseBundle;-><init>()V +Landroid/os/BaseBundle;->getInt(Ljava/lang/String;I)I +Landroid/os/Bundle;->setDefusable(Z)V +Landroid/os/BaseBundle;->containsKey(Ljava/lang/String;)Z +Landroid/app/ActivityManager;->handleIncomingUser(IIIZZLjava/lang/String;Ljava/lang/String;)I +Landroid/provider/Settings$System;->getStringForUser(Landroid/content/ContentResolver;Ljava/lang/String;I)Ljava/lang/String; +Landroid/provider/Settings$System;->getIntForUser(Landroid/content/ContentResolver;Ljava/lang/String;II)I +Landroid/media/AudioSystem;->getOutputDeviceName(I)Ljava/lang/String; +Landroid/app/ContextImpl;->getContentResolver()Landroid/content/ContentResolver; +Landroid/content/IntentFilter;->matchData(Ljava/lang/String;Ljava/lang/String;Landroid/net/Uri;)I +Landroid/content/Intent;->getFlags()I +Landroid/util/Slog;->i(Ljava/lang/String;Ljava/lang/String;)I +Lcom/android/server/LocalServices;->getService(Ljava/lang/Class;)Ljava/lang/Object; +Lcom/android/internal/util/BitUtils;->unpackBits(J)[I +Landroid/util/SparseIntArray;->get(II)I +Landroid/os/BaseBundle;->copyInternal(Landroid/os/BaseBundle;Z)V +Landroid/app/ActivityThread;->getPackageManager()Landroid/content/pm/IPackageManager; +Landroid/app/AppGlobals;->getPackageManager()Landroid/content/pm/IPackageManager; +Landroid/os/BaseBundle;-><init>(Z)V +Lcom/android/internal/util/XmlUtils;->readThisArrayMapXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;[Ljava/lang/String;Lcom/android/internal/util/XmlUtils$ReadMapCallback;)Landroid/util/ArrayMap; +Landroid/os/BaseBundle;->deepCopyValue(Ljava/lang/Object;)Ljava/lang/Object; +Lcom/android/internal/util/XmlUtils;->readThisValueXml(Lorg/xmlpull/v1/XmlPullParser;[Ljava/lang/String;Lcom/android/internal/util/XmlUtils$ReadMapCallback;Z)Ljava/lang/Object; +Landroid/os/PersistableBundle;-><init>(Landroid/util/ArrayMap;)V +Lcom/android/internal/util/BitUtils;->packBits([I)J +Landroid/os/PersistableBundle;->isValidType(Ljava/lang/Object;)Z +Lcom/android/internal/util/XmlUtils;->readThisPrimitiveValueXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)Ljava/lang/Object; +Landroid/net/UidRange;->hashCode()I +Landroid/util/Pair;-><init>(Ljava/lang/Object;Ljava/lang/Object;)V +Landroid/os/LocaleList;->hashCode()I +Landroid/content/IIntentReceiver$Stub;->asBinder()Landroid/os/IBinder; +Landroid/app/job/JobInfo;->getRequiredNetwork()Landroid/net/NetworkRequest; +Landroid/content/IntentFilter;->addAction(Ljava/lang/String;)V +Lcom/android/internal/os/ProcTimeInStateReader;->initializeTimeInStateFormat(Ljava/nio/file/Path;)V +Landroid/net/Uri$AbstractPart;-><init>(Ljava/lang/String;Ljava/lang/String;)V +Landroid/os/MessageQueue;->removeMessages(Landroid/os/Handler;ILjava/lang/Object;)V +Landroid/os/ServiceManager;->getIServiceManager()Landroid/os/IServiceManager; +Landroid/util/Slog;->d(Ljava/lang/String;Ljava/lang/String;)I +Lcom/android/internal/util/StatLogger;->getTime()J +Landroid/util/TimingsTraceLog;->traceBegin(Ljava/lang/String;)V +Landroid/util/TimingsTraceLog;->traceEnd()V +Landroid/util/TimingsTraceLog;->logDuration(Ljava/lang/String;J)V +Landroid/net/Uri$HierarchicalUri;-><init>(Ljava/lang/String;Landroid/net/Uri$Part;Landroid/net/Uri$PathPart;Landroid/net/Uri$Part;Landroid/net/Uri$Part;Landroid/net/Uri$1;)V +Landroid/net/Uri$HierarchicalUri;-><init>(Ljava/lang/String;Landroid/net/Uri$Part;Landroid/net/Uri$PathPart;Landroid/net/Uri$Part;Landroid/net/Uri$Part;)V +Landroid/net/Uri$Builder;-><init>()V +Landroid/net/Uri$Builder;->scheme(Ljava/lang/String;)Landroid/net/Uri$Builder; +Landroid/net/Uri$Builder;->query(Landroid/net/Uri$Part;)Landroid/net/Uri$Builder; +Landroid/net/Uri$Builder;->fragment(Landroid/net/Uri$Part;)Landroid/net/Uri$Builder; +Landroid/net/Uri$Builder;->build()Landroid/net/Uri; +Landroid/net/Uri$Builder;->hasSchemeOrAuthority()Z +Landroid/net/Uri$PathPart;->makeAbsolute(Landroid/net/Uri$PathPart;)Landroid/net/Uri$PathPart; +Landroid/app/ContextImpl;->getSystemService(Ljava/lang/String;)Ljava/lang/Object; +Landroid/app/SystemServiceRegistry;->getSystemService(Landroid/app/ContextImpl;Ljava/lang/String;)Ljava/lang/Object; +Landroid/util/ArrayMap;->isEmpty()Z +Landroid/app/SystemServiceRegistry$CachedServiceFetcher;->getService(Landroid/app/ContextImpl;)Ljava/lang/Object; +Lcom/android/internal/util/StateMachine$SmHandler;->completeConstruction()V +Landroid/os/SystemProperties;->getInt(Ljava/lang/String;I)I +Landroid/os/ThreadLocalWorkSource;->setUid(I)J +Landroid/os/ThreadLocalWorkSource;->getToken()J +Landroid/os/ThreadLocalWorkSource;->restore(J)V +Landroid/os/ThreadLocalWorkSource;->parseUidFromToken(J)I +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->fillInArg(Ljava/lang/Object;)Z +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->access$000(II)I +Landroid/os/Handler;->dispatchMessage(Landroid/os/Message;)V +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +Lcom/android/internal/util/ArrayUtils;->contains([II)Z +Landroid/os/Handler;-><init>(Landroid/os/Looper;Landroid/os/Handler$Callback;Z)V +Landroid/os/UserHandle;->isIsolated(I)Z +Landroid/app/ContextImpl;->checkPermission(Ljava/lang/String;II)I +Landroid/app/ContextImpl;->checkCallingOrSelfPermission(Ljava/lang/String;)I +Landroid/net/Uri$StringUri;->findSchemeSeparator()I +Landroid/content/pm/PackageUserState;->isMatch(Landroid/content/pm/ComponentInfo;I)Z +Landroid/content/pm/PackageUserState;->isEnabled(Landroid/content/pm/ComponentInfo;I)Z +Landroid/content/pm/PackageUserState;->reportIfDebug(ZI)Z +Landroid/content/pm/PackageParser$Package;->isExternal()Z +Landroid/content/pm/ApplicationInfo;->isExternal()Z +Landroid/content/pm/ApplicationInfo;->isSystemExt()Z +Landroid/util/Spline$MonotoneCubicSpline;->interpolate(F)F +Landroid/app/job/JobInfo;->getId()I +Landroid/util/Spline$MonotoneCubicSpline;-><init>([F[F)V +Landroid/content/res/ApkAssets;->getStringFromPool(I)Ljava/lang/CharSequence; +Landroid/util/MemoryIntArray;->size()I +Landroid/os/Process;->myTid()I +Landroid/app/-$$Lambda$ResourcesManager$QJ7UiVk_XS90KuXAsIjIEym1DnM;->test(Ljava/lang/Object;)Z +Landroid/app/ResourcesManager;->lambda$static$0(Ljava/lang/ref/WeakReference;)Z +Landroid/app/ResourcesManager;->getOrCreateResourcesLocked(Ljava/lang/ClassLoader;Landroid/content/res/ResourcesImpl;Landroid/content/res/CompatibilityInfo;)Landroid/content/res/Resources; +Landroid/graphics/Rect;->isEmpty()Z +Landroid/content/res/ResourcesImpl;->flushLayoutCache()V +Landroid/os/LocaleList;->get(I)Ljava/util/Locale; +Landroid/content/res/ThemedResourceCache;->onConfigurationChange(I)V Landroid/content/res/ThemedResourceCache;->prune(I)Z -Landroid/content/res/ThemedResourceCache;->pruneEntriesLocked(Landroid/util/LongSparseArray;I)Z -Landroid/util/Pools$SynchronizedPool;->acquire()Ljava/lang/Object; -Landroid/content/res/XmlBlock$Parser;->getAttributeCount()I -Landroid/content/pm/PackageParser;->parseMetaData(Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;Landroid/os/Bundle;[Ljava/lang/String;)Landroid/os/Bundle; -Landroid/content/res/Resources;->getDisplayMetrics()Landroid/util/DisplayMetrics; -Landroid/text/TextUtils;->writeToParcel(Ljava/lang/CharSequence;Landroid/os/Parcel;I)V -Landroid/view/DisplayAdjustments;->setCompatibilityInfo(Landroid/content/res/CompatibilityInfo;)V -Landroid/content/res/CompatibilityInfo;->applyToDisplayMetrics(Landroid/util/DisplayMetrics;)V +Landroid/content/res/Configuration;->compareTo(Landroid/content/res/Configuration;)I +Landroid/content/res/Resources;->getClassLoader()Ljava/lang/ClassLoader; +Lcom/android/internal/os/CachedDeviceState;->access$200(Lcom/android/internal/os/CachedDeviceState;)Z +Landroid/graphics/Rect;->equals(Ljava/lang/Object;)Z +Landroid/content/res/Configuration;->equals(Landroid/content/res/Configuration;)Z +Lcom/android/internal/os/CachedDeviceState$Readonly;->isCharging()Z +Landroid/util/MemoryIntArray;->enforceValidIndex(I)V +Landroid/util/MemoryIntArray;->get(I)I +Lcom/android/internal/os/LooperStats;->deviceStateAllowsCollection()Z +Landroid/content/res/AssetManager;->isUpToDate()Z +Landroid/content/res/ApkAssets;->isUpToDate()Z +Landroid/content/res/Resources;->getImpl()Landroid/content/res/ResourcesImpl; +Landroid/util/SparseBooleanArray;->put(IZ)V +Lcom/android/internal/util/GrowingArrayUtils;->insert([ZIIZ)[Z +Landroid/os/Parcel;->readLongArray([J)V +Landroid/os/Handler;->sendMessage(Landroid/os/Message;)Z +Landroid/app/ActivityThread;->getApplicationThread()Landroid/app/ActivityThread$ApplicationThread; +Landroid/content/res/TypedArray;->getBoolean(IZ)Z +Landroid/content/res/TypedArray;->getInt(II)I +Landroid/content/res/TypedArray;->getResourceId(II)I Landroid/content/res/TypedArray;->getString(I)Ljava/lang/String; -Lcom/android/internal/os/BatteryStatsImpl$SamplingTimer;->getUpdateVersion()I -Landroid/os/ResultReceiver;->send(ILandroid/os/Bundle;)V -Lcom/android/internal/os/ProcessCpuTracker;->getCpuTimeForPid(I)J -Landroid/os/FileUtils;->contains(Ljava/io/File;Ljava/io/File;)Z -Landroid/os/FileUtils;->contains(Ljava/lang/String;Ljava/lang/String;)Z -Landroid/content/pm/PackageParser$SigningDetails;->checkCapability(Landroid/content/pm/PackageParser$SigningDetails;I)Z -Landroid/util/MapCollections$MapIterator;->getValue()Ljava/lang/Object; -Landroid/os/BinderProxy$ProxyMap;->get(J)Landroid/os/BinderProxy; -Landroid/util/TimingsTraceLog;-><init>(Ljava/lang/String;J)V -Landroid/os/PowerManager;->newWakeLock(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock; -Landroid/content/ComponentName;->hashCode()I -Landroid/util/MapCollections$ArrayIterator;->hasNext()Z -Landroid/app/IActivityTaskManager$Stub;-><init>()V -Lcom/android/internal/os/ProcessCpuTracker;-><init>(Z)V -Lcom/android/internal/util/RingBuffer;-><init>(Ljava/lang/Class;I)V -Lcom/android/server/LocalServices;->getService(Ljava/lang/Class;)Ljava/lang/Object; -Lcom/android/internal/util/XmlUtils;->readStringAttribute(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)Ljava/lang/String; -Lcom/android/internal/os/BatteryStatsImpl;->setPowerProfileLocked(Lcom/android/internal/os/PowerProfile;)V -Lcom/android/internal/os/BatteryStatsImpl;->readDailyStatsLocked()V -Lcom/android/internal/widget/LockPatternUtils;-><init>(Landroid/content/Context;)V -Landroid/text/SpannableStringBuilder;->replace(IILjava/lang/CharSequence;)Landroid/text/Editable; -Landroid/text/SpannableStringBuilder;->replace(IILjava/lang/CharSequence;)Landroid/text/SpannableStringBuilder; -Landroid/text/SpannableStringBuilder;->replace(IILjava/lang/CharSequence;II)Landroid/text/SpannableStringBuilder; -Landroid/content/res/Resources;->newTheme()Landroid/content/res/Resources$Theme; -Landroid/os/Parcel;->obtain()Landroid/os/Parcel; -Landroid/os/Parcel;->obtain(J)Landroid/os/Parcel; +Landroid/content/res/TypedArray;->loadStringValueAt(I)Ljava/lang/CharSequence; +Landroid/content/res/XmlBlock$Parser;->getPooledString(I)Ljava/lang/CharSequence; +Landroid/view/inputmethod/InputMethodInfo;-><init>(Landroid/content/Context;Landroid/content/pm/ResolveInfo;Ljava/util/List;)V +Landroid/view/inputmethod/InputMethodInfo;->getSubtypeAt(I)Landroid/view/inputmethod/InputMethodSubtype; +Landroid/view/inputmethod/InputMethodSubtypeArray;->get(I)Landroid/view/inputmethod/InputMethodSubtype; +Landroid/view/inputmethod/InputMethodSubtype;->hashCode()I +Landroid/provider/Settings$GenerationTracker;->readCurrentGeneration()I +Landroid/text/TextUtils$SimpleStringSplitter;->next()Ljava/lang/String; +Landroid/view/inputmethod/InputMethodSubtype;->sort(Landroid/content/Context;ILandroid/view/inputmethod/InputMethodInfo;Ljava/util/List;)Ljava/util/List; Landroid/content/res/Configuration;->updateFrom(Landroid/content/res/Configuration;)I -Landroid/app/ContextImpl;->createAppContext(Landroid/app/ActivityThread;Landroid/app/LoadedApk;)Landroid/app/ContextImpl; -Landroid/app/ContextImpl;->createAppContext(Landroid/app/ActivityThread;Landroid/app/LoadedApk;Ljava/lang/String;)Landroid/app/ContextImpl; -Landroid/util/SparseArray;->clear()V -Landroid/util/ArrayMap;->remove(Ljava/lang/Object;)Ljava/lang/Object; -Landroid/util/ArrayMap;->removeAt(I)Ljava/lang/Object; -Landroid/os/Parcel;->writeBundle(Landroid/os/Bundle;)V -Landroid/content/pm/PackageParser;->hasDomainURLs(Landroid/content/pm/PackageParser$Package;)Z -Landroid/util/Pools$SynchronizedPool;->release(Ljava/lang/Object;)Z -Landroid/os/Parcel;->setDataPosition(I)V -Landroid/os/LocaleList;->getDefault()Landroid/os/LocaleList; +Landroid/app/WindowConfiguration;->updateFrom(Landroid/app/WindowConfiguration;)I +Landroid/app/AppOpsManager;->permissionToOpCode(Ljava/lang/String;)I +Landroid/util/SparseIntArray;->put(II)V +Landroid/app/AppOpsManager;->opToSwitch(I)I +Landroid/app/ApplicationPackageManager;->updateFlagsForPackage(II)I +Landroid/app/ContextImpl;->getOpPackageName()Ljava/lang/String; +Landroid/content/pm/PermissionInfo;->isHardRestricted()Z +Landroid/app/ContextImpl;->getPackageManager()Landroid/content/pm/PackageManager; +Landroid/content/pm/PermissionInfo;->isSoftRestricted()Z +Landroid/app/ApplicationPackageManager;->getUserId()I +Landroid/app/ApplicationPackageManager;->getPermissionInfo(Ljava/lang/String;I)Landroid/content/pm/PermissionInfo; +Landroid/content/pm/PackageParser;->generatePermissionInfo(Landroid/content/pm/PackageParser$Permission;I)Landroid/content/pm/PermissionInfo; +Landroid/content/pm/PermissionInfo;->isRestricted()Z +Landroid/app/ApplicationPackageManager;->getPermissionFlags(Ljava/lang/String;Ljava/lang/String;Landroid/os/UserHandle;)I +Landroid/os/Process;->myPid()I +Lcom/android/internal/util/IntPair;->of(II)J +Landroid/util/SparseIntArray;->indexOfKey(I)I +Landroid/util/SparseBooleanArray;->get(IZ)Z +Landroid/util/SparseBooleanArray;->get(I)Z +Landroid/app/ApplicationPackageManager;->getPackageInfoAsUser(Ljava/lang/String;II)Landroid/content/pm/PackageInfo; +Landroid/os/Binder;->getInterfaceDescriptor()Ljava/lang/String; +Landroid/os/Binder;->queryLocalInterface(Ljava/lang/String;)Landroid/os/IInterface; +Landroid/content/ContentResolver;->getUserId()I +Landroid/net/NetworkStatsHistory$DataStreamUtils;->readVarLong(Ljava/io/DataInputStream;)J +Landroid/content/pm/PackageItemInfo;-><init>(Landroid/content/pm/PackageItemInfo;)V +Landroid/system/suspend/WakeLockInfo$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/system/suspend/WakeLockInfo$1;->createFromParcel(Landroid/os/Parcel;)Landroid/system/suspend/WakeLockInfo; +Landroid/system/suspend/WakeLockInfo;-><init>()V +Landroid/system/suspend/WakeLockInfo;->readFromParcel(Landroid/os/Parcel;)V +Lcom/android/internal/os/KernelWakelockReader;->updateWakelockStats([Landroid/system/suspend/WakeLockInfo;Lcom/android/internal/os/KernelWakelockStats;)Lcom/android/internal/os/KernelWakelockStats; +Landroid/net/NetworkStatsHistory$DataStreamUtils;->readVarLongArray(Ljava/io/DataInputStream;)[J +Landroid/net/NetworkStatsHistory;->setLong([JIJ)V +Landroid/net/NetworkStatsHistory;->addLong([JIJ)V +Landroid/net/NetworkStatsHistory;->getLong([JIJ)J +Lcom/android/internal/util/ProcFileReader;->finishLine()V +Landroid/content/res/Resources;->getText(I)Ljava/lang/CharSequence; +Landroid/content/res/AssetManager;->getResourceText(I)Ljava/lang/CharSequence; +Landroid/util/TypedValue;->coerceToString()Ljava/lang/CharSequence; +Landroid/util/SparseIntArray;->valueAt(I)I +Landroid/content/res/Resources;->getString(I)Ljava/lang/String; +Lcom/android/internal/os/LooperStats;->messageDispatchStarting()Ljava/lang/Object; +Lcom/android/internal/os/LooperStats;->messageDispatched(Ljava/lang/Object;Landroid/os/Message;)V +Landroid/os/storage/StorageManager;->convert(Ljava/util/UUID;)Ljava/lang/String; +Landroid/os/Parcel;->readSparseArray(Ljava/lang/ClassLoader;)Landroid/util/SparseArray; +Landroid/util/SparseIntArray;->get(I)I +Landroid/content/pm/ApplicationInfo;-><init>(Landroid/content/pm/ApplicationInfo;)V +Landroid/os/UserHandle;->isApp(I)Z +Landroid/util/SparseIntArray;->delete(I)V +Landroid/util/SparseIntArray;->size()I +Landroid/util/SparseIntArray;->keyAt(I)I +Lcom/android/internal/util/ArrayUtils;->convertToIntArray(Ljava/util/List;)[I +Landroid/os/Parcel;->writeIntArray([I)V +Landroid/os/Parcel;->obtain(J)Landroid/os/Parcel; +Landroid/app/ContextImpl;->getOuterContext()Landroid/content/Context; +Landroid/content/pm/PackageParser;->generateProviderInfo(Landroid/content/pm/PackageParser$Provider;ILandroid/content/pm/PackageUserState;I)Landroid/content/pm/ProviderInfo; +Landroid/view/DisplayAdjustments;->getCompatibilityInfo()Landroid/content/res/CompatibilityInfo; +Landroid/net/Uri$StringUri;->getScheme()Ljava/lang/String; +Landroid/net/Uri$StringUri;->getPathPart()Landroid/net/Uri$PathPart; +Landroid/app/WindowConfiguration;->compareTo(Landroid/app/WindowConfiguration;)I +Landroid/content/res/Configuration;->hashCode()I +Landroid/content/res/Configuration;->setToDefaults()V +Landroid/os/LocaleList;->getEmptyLocaleList()Landroid/os/LocaleList; +Landroid/content/res/Configuration;-><init>(Landroid/content/res/Configuration;)V +Landroid/os/Parcel;->readStrongBinder()Landroid/os/IBinder; +Landroid/util/Pair;->create(Ljava/lang/Object;Ljava/lang/Object;)Landroid/util/Pair; +Landroid/os/UserHandle;->isCore(I)Z +Landroid/app/ContextImpl;->enforce(Ljava/lang/String;IZILjava/lang/String;)V +Landroid/app/ContextImpl;->enforceCallingOrSelfPermission(Ljava/lang/String;Ljava/lang/String;)V +Landroid/content/res/CompatibilityInfo;->supportsScreen()Z +Landroid/content/res/CompatibilityInfo;->isScalingRequired()Z +Landroid/app/job/JobInfo;->getFlags()I +Landroid/content/SyncAdapterType;->equals(Ljava/lang/Object;)Z +Landroid/content/pm/RegisteredServicesCache;->containsType(Ljava/util/ArrayList;Ljava/lang/Object;)Z +Landroid/os/Looper;->showSlowLog(JJJLjava/lang/String;Landroid/os/Message;)Z +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->setFlags(II)V +Landroid/os/Parcel;->init(J)V +Landroid/content/res/Resources;->getInteger(I)I +Landroid/net/Uri$StringUri;->isHierarchical()Z +Landroid/net/Uri$StringUri;->getQueryPart()Landroid/net/Uri$Part; +Landroid/net/Uri$PathPart;->from(Ljava/lang/String;Ljava/lang/String;)Landroid/net/Uri$PathPart; +Landroid/net/Uri$PathPart;-><init>(Ljava/lang/String;Ljava/lang/String;)V +Landroid/net/Uri$PathPart;->fromEncoded(Ljava/lang/String;)Landroid/net/Uri$PathPart; +Landroid/content/IntentFilter;-><init>(Landroid/content/IntentFilter;)V +Landroid/util/proto/EncodedBuffer;->writeRawByte(B)V +Landroid/content/Intent;->getComponent()Landroid/content/ComponentName; +Landroid/util/proto/EncodedBuffer;->writeRawVarint32(I)V +Landroid/util/proto/EncodedBuffer;->writeRawFixed32(I)V +Landroid/util/proto/ProtoOutputStream;->assertNotCompacted()V +Landroid/util/proto/ProtoOutputStream;->writeTag(II)V +Landroid/util/proto/ProtoOutputStream;->write(JLjava/lang/String;)V +Landroid/util/proto/ProtoOutputStream;->writeStringImpl(ILjava/lang/String;)V +Landroid/os/Parcel;->dataSize()I +Landroid/util/proto/EncodedBuffer;->writeRawBuffer([BII)V +Landroid/util/proto/ProtoOutputStream;->writeUtf8String(ILjava/lang/String;)V +Landroid/util/proto/ProtoOutputStream;->writeKnownLengthHeader(II)V +Landroid/util/proto/EncodedBuffer;->writeRawBuffer([B)V +Landroid/util/proto/ProtoStream;->getRepeatedFromToken(J)Z +Landroid/util/proto/EncodedBuffer;->getWritePos()I +Landroid/util/proto/EncodedBuffer;->getRawFixed32At(I)I +Landroid/util/proto/EncodedBuffer;->editRawFixed32(II)V +Landroid/util/proto/EncodedBuffer;->writeRawVarint64(J)V +Landroid/os/StrictMode;->onBinderStrictModePolicyChange(I)V +Landroid/util/proto/EncodedBuffer;->getRawVarint32Size(I)I +Landroid/util/proto/EncodedBuffer;->readRawByte()B +Landroid/util/proto/EncodedBuffer;->getReadPos()I +Landroid/util/proto/ProtoOutputStream;->editEncodedSize(I)I +Landroid/util/proto/EncodedBuffer;->readRawFixed32()I +Landroid/util/proto/EncodedBuffer;->getReadableSize()I +Landroid/util/proto/ProtoOutputStream;->readRawTag()I +Landroid/util/proto/EncodedBuffer;->readRawUnsigned()J +Landroid/os/MessageQueue;->removeMessages(Landroid/os/Handler;Ljava/lang/Runnable;Ljava/lang/Object;)V +Landroid/net/Uri$PathSegmentsBuilder;->build()Landroid/net/Uri$PathSegments; +Landroid/net/Uri$PathSegments;-><init>([Ljava/lang/String;I)V +Landroid/util/proto/EncodedBuffer;->skipRead(I)V +Landroid/app/IApplicationThread$Stub$Proxy;->asBinder()Landroid/os/IBinder; +Landroid/app/ApplicationPackageManager;->getPackageInfo(Ljava/lang/String;I)Landroid/content/pm/PackageInfo; +Landroid/util/proto/ProtoOutputStream;->compactSizes(I)V +Landroid/util/proto/EncodedBuffer;->writeFromThisBuffer(II)V +Landroid/app/WindowConfiguration;->getWindowingMode()I +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->unmask(II)I +Landroid/app/ContextImpl;->registerReceiverInternal(Landroid/content/BroadcastReceiver;ILandroid/content/IntentFilter;Ljava/lang/String;Landroid/os/Handler;Landroid/content/Context;I)Landroid/content/Intent; +Landroid/app/ActivityThread;->getInstrumentation()Landroid/app/Instrumentation; +Landroid/app/LoadedApk;->getReceiverDispatcher(Landroid/content/BroadcastReceiver;Landroid/content/Context;Landroid/os/Handler;Landroid/app/Instrumentation;Z)Landroid/content/IIntentReceiver; +Landroid/app/LoadedApk$ReceiverDispatcher;->getIIntentReceiver()Landroid/content/IIntentReceiver; +Landroid/util/SparseArray;->gc()V +Landroid/net/Uri$StringUri;->buildUpon()Landroid/net/Uri$Builder; +Landroid/net/Uri$StringUri;->getFragmentPart()Landroid/net/Uri$Part; +Landroid/net/Uri$PathPart;->appendEncodedSegment(Landroid/net/Uri$PathPart;Ljava/lang/String;)Landroid/net/Uri$PathPart; +Landroid/content/ContentResolver;->getContentService()Landroid/content/IContentService; +Lcom/android/internal/os/BinderDeathDispatcher;->linkToDeath(Landroid/os/IInterface;Landroid/os/IBinder$DeathRecipient;)I +Landroid/net/NetworkCapabilities;->appendStringRepresentationOfBitMaskToStringBuilder(Ljava/lang/StringBuilder;JLandroid/net/NetworkCapabilities$NameOf;Ljava/lang/String;)V +Landroid/os/Parcel;->writeStringArray([Ljava/lang/String;)V +Lcom/android/internal/util/StatLogger;->logDurationStat(IJ)J +Lcom/android/internal/util/CollectionUtils;->size(Ljava/util/Collection;)I +Landroid/content/ComponentName;->getPackageName()Ljava/lang/String; +Landroid/os/MessageQueue;->removeCallbacksAndMessages(Landroid/os/Handler;Ljava/lang/Object;)V +Lcom/android/internal/util/GrowingArrayUtils;->append([III)[I +Landroid/content/pm/ApplicationInfo;->isDirectBootAware()Z +Landroid/content/res/Configuration;->unset()V +Landroid/util/FastImmutableArraySet$FastIterator;->hasNext()Z +Landroid/util/FastImmutableArraySet;->iterator()Ljava/util/Iterator; +Landroid/util/FastImmutableArraySet$FastIterator;->next()Ljava/lang/Object; +Landroid/app/WindowConfiguration;->getActivityType()I +Landroid/app/WindowConfiguration;->getBounds()Landroid/graphics/Rect; +Landroid/content/res/Configuration;-><init>()V +Landroid/util/proto/ProtoOutputStream;->write(JI)V +Landroid/util/proto/ProtoOutputStream;->writeInt32Impl(II)V +Landroid/os/Parcel;->writeStrongBinder(Landroid/os/IBinder;)V +Landroid/os/Parcel;->writeValue(Ljava/lang/Object;)V +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->popArg(I)Ljava/lang/Object; +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->isInvocationArgAtIndex(I)Z +Landroid/util/ArrayMap;->putAll(Landroid/util/ArrayMap;)V +Landroid/os/Looper;->myLooper()Landroid/os/Looper; +Landroid/net/NetworkScoreManager;->getActiveScorerPackage()Ljava/lang/String; +Landroid/appwidget/AppWidgetManager;->isBoundWidgetPackage(Ljava/lang/String;I)Z +Landroid/os/SystemProperties;->get(Ljava/lang/String;)Ljava/lang/String; +Landroid/content/res/Configuration;->getLocales()Landroid/os/LocaleList; Landroid/content/res/ConfigurationBoundResourceCache;->onConfigurationChange(I)V -Landroid/util/DisplayMetrics;->setToDefaults()V -Landroid/content/pm/PackageParser;->computeMinSdkVersion(ILjava/lang/String;I[Ljava/lang/String;[Ljava/lang/String;)I -Lcom/android/internal/os/ProcessCpuTracker;->onMeasureProcessName(Ljava/lang/String;)I -Lcom/android/server/SystemConfig$SharedLibraryEntry;-><init>(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V -Landroid/util/MapCollections;->getKeySet()Ljava/util/Set; -Landroid/content/ComponentName;->unflattenFromString(Ljava/lang/String;)Landroid/content/ComponentName; -Landroid/util/Slog;->e(Ljava/lang/String;Ljava/lang/String;)I -Landroid/util/Slog;->e(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I -Landroid/os/SynchronousResultReceiver;->awaitResult(J)Landroid/os/SynchronousResultReceiver$Result; -Landroid/os/SynchronousResultReceiver;->onReceiveResult(ILandroid/os/Bundle;)V -Landroid/view/SurfaceControl;->getHdrCapabilities(Landroid/os/IBinder;)Landroid/view/Display$HdrCapabilities; +Landroid/content/Intent;->getCategories()Ljava/util/Set; +Landroid/os/LocaleList;->equals(Ljava/lang/Object;)Z +Landroid/content/res/CompatibilityInfo;->hashCode()I +Landroid/os/Message;->sendToTarget()V +Landroid/os/Handler;->getPostMessage(Ljava/lang/Runnable;)Landroid/os/Message; +Landroid/app/ApplicationPackageManager;->getPackagesForUid(I)[Ljava/lang/String; +Lcom/android/internal/util/function/pooled/PooledLambdaImpl$LambdaType;->encode(II)I +Landroid/os/BinderProxy$ProxyMap;->hash(J)I +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->getFlags(I)I +Lcom/android/internal/util/function/pooled/PooledLambdaImpl$LambdaType;->decodeArgCount(I)I +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->isRecycled()Z +Landroid/os/Handler;->post(Ljava/lang/Runnable;)Z +Landroid/os/SystemClock$2;->millis()J +Landroid/os/Binder;->execTransact(IJJI)Z +Landroid/os/Binder;->execTransactInternal(IJJII)Z +Landroid/os/Parcel;->enforceInterface(Ljava/lang/String;)V +Landroid/database/IContentObserver$Stub;->asBinder()Landroid/os/IBinder; +Landroid/os/StrictMode;->clearGatheredViolations()V +Landroid/os/Binder;->linkToDeath(Landroid/os/IBinder$DeathRecipient;I)V +Landroid/os/Parcel;->writeNoException()V +Landroid/os/StrictMode;->hasGatheredViolations()Z +Landroid/os/Handler;->obtainMessage(IIILjava/lang/Object;)Landroid/os/Message; +Landroid/os/Message;->obtain(Landroid/os/Handler;IIILjava/lang/Object;)Landroid/os/Message; +Landroid/os/StrictMode$AndroidBlockGuardPolicy;->setThreadPolicyMask(I)V +Landroid/os/Looper;->loop()V +Landroid/app/usage/UsageEvents$Event;->getClassName()Ljava/lang/String; +Landroid/app/usage/UsageStats;->update(Ljava/lang/String;JII)V +Lcom/android/internal/os/BinderCallsStats;->callStarted(Landroid/os/Binder;II)Lcom/android/internal/os/BinderInternal$CallSession; +Landroid/os/Parcel;->readCallingWorkSourceUid()I +Lcom/android/internal/os/BinderCallsStats;->callEnded(Lcom/android/internal/os/BinderInternal$CallSession;III)V +Landroid/os/Parcel;->writeParcelable(Landroid/os/Parcelable;I)V +Landroid/os/Parcel;->writeFloat(F)V +Landroid/view/DisplayCutout;->getSafeInsetTop()I +Landroid/content/res/Resources;->getDimensionPixelSize(I)I +Landroid/os/Parcel;->writeParcelableCreator(Landroid/os/Parcelable;)V +Landroid/content/Intent;->getScheme()Ljava/lang/String; +Landroid/os/Handler;-><init>(Landroid/os/Looper;)V +Landroid/os/BaseBundle;->putString(Ljava/lang/String;Ljava/lang/String;)V +Landroid/content/SyncAdaptersCache;->getSyncAdapterPackagesForAuthority(Ljava/lang/String;I)[Ljava/lang/String; +Landroid/view/Display;->hasAccess(IIII)Z +Landroid/view/DisplayInfo;->writeToParcel(Landroid/os/Parcel;I)V +Landroid/view/DisplayInfo;->hasAccess(I)Z +Landroid/os/BinderProxy$ProxyMap;->get(J)Landroid/os/BinderProxy; +Landroid/os/Parcel;->writeArrayMapInternal(Landroid/util/ArrayMap;)V +Landroid/content/Intent;->getData()Landroid/net/Uri; +Landroid/util/ArraySet;->addAll(Landroid/util/ArraySet;)V +Landroid/os/Binder$PropagateWorkSourceTransactListener;->onTransactStarted(Landroid/os/IBinder;I)Ljava/lang/Object; +Landroid/os/Binder$PropagateWorkSourceTransactListener;->onTransactEnded(Ljava/lang/Object;)V +Landroid/os/RemoteCallbackList;->beginBroadcast()I +Landroid/os/BinderProxy;->getInstance(JJ)Landroid/os/BinderProxy; +Landroid/content/Intent;->setAction(Ljava/lang/String;)Landroid/content/Intent; +Landroid/view/Display$HdrCapabilities;->writeToParcel(Landroid/os/Parcel;I)V +Landroid/graphics/Rect;->set(IIII)V +Landroid/content/res/Configuration;->equals(Ljava/lang/Object;)Z +Landroid/os/Message;->obtain(Landroid/os/Handler;ILjava/lang/Object;)Landroid/os/Message; +Landroid/util/proto/ProtoOutputStream;->start(J)J +Landroid/util/proto/ProtoOutputStream;->startObjectImpl(IZ)J +Landroid/util/proto/ProtoOutputStream;->getTagSize(I)I +Landroid/util/proto/ProtoOutputStream;->end(J)V +Landroid/util/proto/ProtoOutputStream;->endObjectImpl(JZ)V +Landroid/util/proto/ProtoStream;->getDepthFromToken(J)I +Landroid/util/proto/ProtoOutputStream;->writeUnsignedVarintFromSignedInt(I)V +Landroid/os/Handler;->obtainMessage(ILjava/lang/Object;)Landroid/os/Message; +Landroid/graphics/Rect;->width()I +Landroid/app/ApplicationPackageManager;->updateFlagsForApplication(II)I +Lcom/android/internal/os/ZygoteArguments;->parseArgs([Ljava/lang/String;)V +Landroid/os/RemoteCallbackList;->finishBroadcast()V +Landroid/os/BinderProxy;->queryLocalInterface(Ljava/lang/String;)Landroid/os/IInterface; +Landroid/content/Intent;-><init>(Landroid/content/Intent;I)V +Landroid/content/Intent;->addFlags(I)Landroid/content/Intent; +Landroid/content/ContentResolver;->registerContentObserver(Landroid/net/Uri;ZLandroid/database/ContentObserver;I)V +Landroid/database/ContentObserver;->getContentObserver()Landroid/database/IContentObserver; +Landroid/net/Uri$StringUri;->parsePath(Ljava/lang/String;I)Ljava/lang/String; +Landroid/content/Intent;-><init>(Ljava/lang/String;)V +Landroid/graphics/Rect;->height()I +Landroid/provider/Settings$Global;->getStringForUser(Landroid/content/ContentResolver;Ljava/lang/String;I)Ljava/lang/String; +Landroid/util/LongSparseArray;->valueAt(I)Ljava/lang/Object; +Landroid/os/Handler;->removeMessages(I)V +Landroid/net/Uri$Part;->from(Ljava/lang/String;Ljava/lang/String;)Landroid/net/Uri$Part; +Landroid/os/Parcel;->writeBundle(Landroid/os/Bundle;)V +Landroid/os/BaseBundle;->getBoolean(Ljava/lang/String;Z)Z +Landroid/os/BinderProxy$ProxyMap;->set(JLandroid/os/BinderProxy;)V +Landroid/provider/Settings$Global;->getString(Landroid/content/ContentResolver;Ljava/lang/String;)Ljava/lang/String; +Landroid/util/ArraySet;->isEmpty()Z +Landroid/app/ActivityManager;->checkComponentPermission(Ljava/lang/String;IIZ)I +Landroid/database/IContentObserver$Stub$Proxy;->asBinder()Landroid/os/IBinder; +Landroid/os/Parcel;->writeTypedArray([Landroid/os/Parcelable;I)V +Landroid/os/BinderProxy;-><init>(J)V +Landroid/content/IIntentReceiver$Stub$Proxy;->asBinder()Landroid/os/IBinder; +Landroid/os/Parcel;->writeTypedList(Ljava/util/List;I)V +Landroid/app/ApplicationPackageManager;->getApplicationInfoAsUser(Ljava/lang/String;II)Landroid/content/pm/ApplicationInfo; +Landroid/app/ApplicationPackageManager;->maybeAdjustApplicationInfo(Landroid/content/pm/ApplicationInfo;)Landroid/content/pm/ApplicationInfo; +Landroid/app/ContextImpl;->getUser()Landroid/os/UserHandle; +Landroid/content/pm/PackageManager;->getApplicationInfoAsUser(Ljava/lang/String;ILandroid/os/UserHandle;)Landroid/content/pm/ApplicationInfo; +Landroid/app/AppOpsManager;->strOpToOp(Ljava/lang/String;)I +Landroid/app/AppOpsManager;->opToPublicName(I)Ljava/lang/String; +Landroid/app/AppOpsManager;->unsafeCheckOpRaw(Ljava/lang/String;ILjava/lang/String;)I +Landroid/database/sqlite/SQLiteClosable;->releaseReference()V +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->acquire(Lcom/android/internal/util/function/pooled/PooledLambdaImpl$Pool;Ljava/lang/Object;IIILjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lcom/android/internal/util/function/pooled/PooledLambda; +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->acquire(Lcom/android/internal/util/function/pooled/PooledLambdaImpl$Pool;)Lcom/android/internal/util/function/pooled/PooledLambdaImpl; +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->recycleOnUse()Lcom/android/internal/util/function/pooled/PooledRunnable; +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->recycleOnUse()Lcom/android/internal/util/function/pooled/OmniFunction; +Landroid/os/Message;->setCallback(Ljava/lang/Runnable;)Landroid/os/Message; +Landroid/util/LongSparseLongArray;->indexOfKey(J)I +Lcom/android/internal/util/function/pooled/OmniFunction;->run()V +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->doInvoke()Ljava/lang/Object; +Lcom/android/internal/util/function/pooled/PooledLambdaImpl$LambdaType;->decodeReturnType(I)I +Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->access$100(II)I Lcom/android/internal/util/function/pooled/PooledLambdaImpl;->doRecycle()V -Landroid/os/Handler;->postAtFrontOfQueue(Ljava/lang/Runnable;)Z +Landroid/util/Pair;->hashCode()I +Landroid/content/pm/ApplicationInfo;->hasRequestedLegacyExternalStorage()Z +Landroid/util/ArrayMap;->remove(Ljava/lang/Object;)Ljava/lang/Object; +Landroid/util/ArraySet;->clear()V +Landroid/app/IActivityManager$Stub;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z +Landroid/text/TextUtils;->writeToParcel(Ljava/lang/CharSequence;Landroid/os/Parcel;I)V +Landroid/os/Parcel;->writeMapInternal(Ljava/util/Map;)V +Landroid/os/RemoteCallbackList;->getBroadcastItem(I)Landroid/os/IInterface; +Landroid/app/WindowConfiguration;->canReceiveKeys()Z +Landroid/graphics/Point;->offset(II)V +Landroid/content/Intent;-><init>(Landroid/content/Intent;)V +Landroid/os/Binder;->allowBlocking(Landroid/os/IBinder;)Landroid/os/IBinder; +Landroid/os/Bundle;->hasFileDescriptors()Z +Lcom/android/internal/app/procstats/ProcessStats;->updateTrackingAssociationsLocked(IJ)V +Lcom/android/internal/app/procstats/SparseMappingTable$Table;->assertConsistency()V +Lcom/android/internal/app/procstats/SparseMappingTable;->access$100(Lcom/android/internal/app/procstats/SparseMappingTable;)Ljava/util/ArrayList; +Landroid/os/RemoteCallbackList;->getBroadcastCookie(I)Ljava/lang/Object; +Landroid/net/Uri$StringUri;->parseAuthority(Ljava/lang/String;I)Ljava/lang/String; +Landroid/os/ServiceManager;->getService(Ljava/lang/String;)Landroid/os/IBinder; +Landroid/os/ServiceManager;->rawGetService(Ljava/lang/String;)Landroid/os/IBinder; +Landroid/os/ServiceManagerProxy;->getService(Ljava/lang/String;)Landroid/os/IBinder; +Landroid/os/IServiceManager$Stub$Proxy;->checkService(Ljava/lang/String;)Landroid/os/IBinder; +Landroid/content/pm/PackageItemInfo;->writeToParcel(Landroid/os/Parcel;I)V +Landroid/net/Uri$Part$EmptyPart;->isEmpty()Z +Landroid/os/BaseBundle;-><init>(Landroid/os/BaseBundle;)V +Landroid/os/Bundle;-><init>(Landroid/os/Bundle;)V +Landroid/net/Uri$Part;->readFrom(Landroid/os/Parcel;)Landroid/net/Uri$Part; +Landroid/content/ComponentName;->equals(Ljava/lang/Object;)Z +Landroid/util/ArraySet;-><init>(Landroid/util/ArraySet;)V +Landroid/os/Parcel;->createStringArray()[Ljava/lang/String; +Landroid/os/Message;->setAsynchronous(Z)V +Landroid/os/Parcel;->writeTypedList(Ljava/util/List;)V +Landroid/os/Message;->obtain(Landroid/os/Handler;I)Landroid/os/Message; +Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;->refreshTimersLocked(JLjava/util/ArrayList;Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;)J +Landroid/os/Handler;->obtainMessage(I)Landroid/os/Message; +Landroid/os/storage/StorageManager;->isUserKeyUnlocked(I)Z +Landroid/hardware/display/IDisplayManager$Stub;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z +Landroid/os/Bundle;->writeToParcel(Landroid/os/Parcel;I)V +Landroid/os/Parcel;->pushAllowFds(Z)Z +Landroid/os/BaseBundle;->writeToParcelInner(Landroid/os/Parcel;I)V +Landroid/os/Parcel;->restoreAllowFds(Z)V +Landroid/content/pm/ApplicationInfo;->isEncryptionAware()Z +Lcom/android/internal/app/procstats/ProcessState;->setCombinedState(IJ)V +Landroid/os/Message;->obtain(Landroid/os/Handler;III)Landroid/os/Message; +Landroid/hardware/display/DisplayManagerInternal$DisplayPowerRequest;->isBrightOrDim()Z +Landroid/content/pm/ParceledListSlice;-><init>(Ljava/util/List;)V +Landroid/content/pm/BaseParceledListSlice;-><init>(Ljava/util/List;)V +Lcom/android/internal/app/procstats/AssociationState$SourceState;->trackProcState(IIJ)V +Landroid/content/Intent;->resolveTypeIfNeeded(Landroid/content/ContentResolver;)Ljava/lang/String; +Landroid/net/Uri$Part;->fromEncoded(Ljava/lang/String;)Landroid/net/Uri$Part; +Landroid/os/MessageQueue;->hasMessages(Landroid/os/Handler;Ljava/lang/Runnable;Ljava/lang/Object;)Z +Lcom/android/internal/app/procstats/AssociationState$SourceState;->getAssociationState()Lcom/android/internal/app/procstats/AssociationState; +Lcom/android/internal/app/procstats/AssociationState;->getProcess()Lcom/android/internal/app/procstats/ProcessState; +Lcom/android/internal/app/procstats/ProcessState;->getCombinedState()I +Lcom/android/internal/app/procstats/AssociationState$SourceState;->startActive(J)V +Landroid/net/Uri$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object; +Landroid/net/Uri$1;->createFromParcel(Landroid/os/Parcel;)Landroid/net/Uri; +Landroid/content/Intent;->getSelector()Landroid/content/Intent; +Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;->startRunningLocked(J)V +Lcom/android/internal/app/ProcessMap;->get(Ljava/lang/String;I)Ljava/lang/Object; +Landroid/app/IApplicationThread$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IApplicationThread; +Landroid/app/IApplicationThread$Stub$Proxy;-><init>(Landroid/os/IBinder;)V +Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->startRunningLocked(J)V +Lcom/android/internal/os/BatteryStatsImpl$StopwatchTimer;->stopRunningLocked(J)V +Landroid/net/Uri$Part;-><init>(Ljava/lang/String;Ljava/lang/String;)V +Lcom/android/internal/os/BatteryStatsImpl$DurationTimer;->stopRunningLocked(J)V +Lcom/android/internal/os/BatteryStatsImpl;->mapUid(I)I +Landroid/content/Intent;->hasFileDescriptors()Z +Landroid/content/pm/ComponentInfo;-><init>(Landroid/content/pm/ComponentInfo;)V +Landroid/os/ZygoteProcess;->zygoteSendArgsAndGetResult(Landroid/os/ZygoteProcess$ZygoteState;ZLjava/util/ArrayList;)Landroid/os/Process$ProcessStartResult; +Landroid/os/Handler;->obtainMessage(III)Landroid/os/Message; +Landroid/os/BaseBundle;->getBoolean(Ljava/lang/String;)Z +Landroid/view/DisplayCutout$ParcelableWrapper;->writeCutoutToParcel(Landroid/view/DisplayCutout;Landroid/os/Parcel;I)V +Landroid/view/DisplayAddress$Physical;->writeToParcel(Landroid/os/Parcel;I)V +Lcom/android/internal/os/BatteryStatsImpl;->getUidStatsLocked(I)Lcom/android/internal/os/BatteryStatsImpl$Uid; +Landroid/content/pm/ResolveInfo;-><init>()V +Landroid/util/KeyValueListParser$IntValue;->getValue()I +Landroid/os/Parcel;->writeList(Ljava/util/List;)V +Landroid/view/SurfaceControl;->checkNotReleased()V +Landroid/content/pm/IPackageManager$Stub;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z +Landroid/os/IPowerManager$Stub;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z +Landroid/graphics/Rect;->writeToParcel(Landroid/os/Parcel;I)V +Landroid/content/pm/ParceledListSlice;->getList()Ljava/util/List; +Landroid/content/pm/BaseParceledListSlice;->getList()Ljava/util/List; +Landroid/os/Parcel;->writeBoolean(Z)V +Landroid/telecom/PhoneAccount;->hasCapabilities(I)Z +Landroid/content/IIntentReceiver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IIntentReceiver; +Landroid/os/BaseBundle;->isParcelled()Z +Landroid/os/PowerSaveState$Builder;-><init>()V +Landroid/os/PowerSaveState$Builder;->setGlobalBatterySaverEnabled(Z)Landroid/os/PowerSaveState$Builder; +Landroid/os/PowerSaveState$Builder;->setBatterySaverEnabled(Z)Landroid/os/PowerSaveState$Builder; +Landroid/os/PowerSaveState$Builder;->build()Landroid/os/PowerSaveState; +Landroid/os/PowerSaveState;-><init>(Landroid/os/PowerSaveState$Builder;)V +Landroid/os/PowerSaveState$Builder;->access$000(Landroid/os/PowerSaveState$Builder;)Z +Landroid/os/PowerSaveState$Builder;->access$100(Landroid/os/PowerSaveState$Builder;)I +Landroid/os/PowerSaveState$Builder;->access$200(Landroid/os/PowerSaveState$Builder;)F +Landroid/os/PowerSaveState$Builder;->access$300(Landroid/os/PowerSaveState$Builder;)Z +Lcom/android/internal/os/BatteryStatsImpl$Uid;->createAggregatedPartialWakelockTimerLocked()Lcom/android/internal/os/BatteryStatsImpl$DualTimer; +Landroid/content/pm/ApplicationInfo;->writeToParcel(Landroid/os/Parcel;I)V +Landroid/os/Parcel;->writeSparseArray(Landroid/util/SparseArray;)V +Landroid/os/PowerSaveState$Builder;->setBrightnessFactor(F)Landroid/os/PowerSaveState$Builder; +Landroid/hardware/display/DisplayManagerInternal$DisplayPowerRequest;->equals(Landroid/hardware/display/DisplayManagerInternal$DisplayPowerRequest;)Z +Landroid/hardware/display/DisplayManagerInternal$DisplayPowerRequest;->floatEquals(FF)Z +Landroid/view/Choreographer;->doCallbacks(IJ)V +Lcom/android/internal/os/BatteryStatsImpl$DualTimer;->startRunningLocked(J)V +Landroid/graphics/Point;->set(II)V +Landroid/view/SurfaceControl;->access$800(Landroid/view/SurfaceControl;)V +Landroid/graphics/Point;->equals(Ljava/lang/Object;)Z +Lcom/android/internal/os/BatteryStatsImpl;->getPowerManagerWakeLockLevel(I)I +Landroid/content/Context;->getSystemService(Ljava/lang/Class;)Ljava/lang/Object; +Landroid/app/ContextImpl;->getSystemServiceName(Ljava/lang/Class;)Ljava/lang/String; +Landroid/app/SystemServiceRegistry;->getSystemServiceName(Ljava/lang/Class;)Ljava/lang/String; +Lcom/android/internal/os/BatteryStatsImpl$DualTimer;->stopRunningLocked(J)V +Landroid/app/AppOpsManager;->getToken(Lcom/android/internal/app/IAppOpsService;)Landroid/os/IBinder; +Landroid/os/Bundle;->forPair(Ljava/lang/String;Ljava/lang/String;)Landroid/os/Bundle; +Landroid/os/Bundle;-><init>(I)V +Landroid/os/BaseBundle;-><init>(I)V +Landroid/os/HwParcel;-><init>()V +Landroid/view/SurfaceControl$Transaction;->merge(Landroid/view/SurfaceControl$Transaction;)Landroid/view/SurfaceControl$Transaction; +Landroid/view/SurfaceControl;->access$4100(JJ)V +Landroid/view/Choreographer$CallbackQueue;->extractDueCallbacksLocked(J)Landroid/view/Choreographer$CallbackRecord; +Landroid/graphics/Rect;->offset(II)V +Landroid/os/PowerManager;->validateWakeLockParameters(ILjava/lang/String;)V +Landroid/app/AppOpsManager;->checkPackage(ILjava/lang/String;)V +Landroid/util/SparseArray;->indexOfKey(I)I +Landroid/content/Intent;->resolveType(Landroid/content/ContentResolver;)Ljava/lang/String; +Lcom/android/internal/os/BatteryStatsImpl;->noteStartWakeLocked(IILandroid/os/WorkSource$WorkChain;Ljava/lang/String;Ljava/lang/String;IZJJ)V +Lcom/android/internal/os/BatteryStatsImpl;->aggregateLastWakeupUptimeLocked(J)V +Lcom/android/internal/os/BatteryStatsImpl$Uid;->noteStartWakeLocked(ILjava/lang/String;IJ)V +Lcom/android/internal/os/BatteryStatsImpl$OverflowArrayMap;->startObject(Ljava/lang/String;)Ljava/lang/Object; +Lcom/android/internal/os/BatteryStatsImpl$Uid;->getPidStatsLocked(I)Landroid/os/BatteryStats$Uid$Pid; +Landroid/content/ComponentName;->writeToParcel(Landroid/content/ComponentName;Landroid/os/Parcel;)V +Landroid/content/ContextWrapper;->getContentResolver()Landroid/content/ContentResolver; +Landroid/content/Intent;->writeToParcel(Landroid/os/Parcel;I)V +Landroid/content/res/Resources;->getBoolean(I)Z +Landroid/net/Uri;->writeToParcel(Landroid/os/Parcel;Landroid/net/Uri;)V +Landroid/view/InsetsSource;->getType()I diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt index eb53b7c20dbc..9f48f8a12b13 100644 --- a/config/hiddenapi-greylist.txt +++ b/config/hiddenapi-greylist.txt @@ -1174,214 +1174,11 @@ Lcom/android/internal/statusbar/IStatusBar$Stub;->asInterface(Landroid/os/IBinde Lcom/android/internal/statusbar/IStatusBarService$Stub;-><init>()V Lcom/android/internal/statusbar/IStatusBarService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/statusbar/IStatusBarService; Lcom/android/internal/telecom/ITelecomService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telecom/ITelecomService; -Lcom/android/internal/telephony/Call$State;->ALERTING:Lcom/android/internal/telephony/Call$State; -Lcom/android/internal/telephony/Call$State;->DIALING:Lcom/android/internal/telephony/Call$State; -Lcom/android/internal/telephony/Call$State;->DISCONNECTED:Lcom/android/internal/telephony/Call$State; -Lcom/android/internal/telephony/Call$State;->DISCONNECTING:Lcom/android/internal/telephony/Call$State; -Lcom/android/internal/telephony/Call$State;->HOLDING:Lcom/android/internal/telephony/Call$State; -Lcom/android/internal/telephony/Call$State;->IDLE:Lcom/android/internal/telephony/Call$State; -Lcom/android/internal/telephony/Call$State;->INCOMING:Lcom/android/internal/telephony/Call$State; -Lcom/android/internal/telephony/Call$State;->values()[Lcom/android/internal/telephony/Call$State; -Lcom/android/internal/telephony/Call$State;->WAITING:Lcom/android/internal/telephony/Call$State; -Lcom/android/internal/telephony/Call;-><init>()V -Lcom/android/internal/telephony/CallerInfoAsyncQuery$CallerInfoAsyncQueryHandler;-><init>(Lcom/android/internal/telephony/CallerInfoAsyncQuery;Landroid/content/Context;)V -Lcom/android/internal/telephony/CallerInfoAsyncQuery$CookieWrapper;-><init>()V -Lcom/android/internal/telephony/CallerInfoAsyncQuery;->release()V -Lcom/android/internal/telephony/CallForwardInfo;-><init>()V -Lcom/android/internal/telephony/CallTracker;-><init>()V -Lcom/android/internal/telephony/cat/AppInterface$CommandType;->values()[Lcom/android/internal/telephony/cat/AppInterface$CommandType; -Lcom/android/internal/telephony/cat/ResponseData;-><init>()V -Lcom/android/internal/telephony/cat/ResultCode;->values()[Lcom/android/internal/telephony/cat/ResultCode; -Lcom/android/internal/telephony/cat/RilMessageDecoder;->mCurrentRilMessage:Lcom/android/internal/telephony/cat/RilMessage; -Lcom/android/internal/telephony/cat/RilMessageDecoder;->sendCmdForExecution(Lcom/android/internal/telephony/cat/RilMessage;)V -Lcom/android/internal/telephony/cat/RilMessageDecoder;->sendStartDecodingMessageParams(Lcom/android/internal/telephony/cat/RilMessage;)V -Lcom/android/internal/telephony/cat/ValueObject;-><init>()V -Lcom/android/internal/telephony/cat/ValueParser;->retrieveDeviceIdentities(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Lcom/android/internal/telephony/cat/DeviceIdentities; -Lcom/android/internal/telephony/cdma/sms/BearerData$CodingException;-><init>(Ljava/lang/String;)V -Lcom/android/internal/telephony/cdma/sms/BearerData$TimeStamp;-><init>()V -Lcom/android/internal/telephony/cdma/sms/BearerData;-><init>()V -Lcom/android/internal/telephony/cdma/sms/BearerData;->countAsciiSeptets(Ljava/lang/CharSequence;Z)I -Lcom/android/internal/telephony/cdma/sms/BearerData;->decodeUserDataPayload(Lcom/android/internal/telephony/cdma/sms/UserData;Z)V -Lcom/android/internal/telephony/cdma/sms/BearerData;->displayMode:I -Lcom/android/internal/telephony/cdma/sms/BearerData;->encode(Lcom/android/internal/telephony/cdma/sms/BearerData;)[B -Lcom/android/internal/telephony/cdma/sms/BearerData;->encode7bitAscii(Ljava/lang/String;Z)[B -Lcom/android/internal/telephony/cdma/sms/BearerData;->getBitsForNumFields(II)I -Lcom/android/internal/telephony/cdma/sms/BearerData;->hasUserDataHeader:Z -Lcom/android/internal/telephony/cdma/sms/BearerData;->messageId:I -Lcom/android/internal/telephony/cdma/sms/BearerData;->msgCenterTimeStamp:Lcom/android/internal/telephony/cdma/sms/BearerData$TimeStamp; -Lcom/android/internal/telephony/cdma/sms/BearerData;->priority:I -Lcom/android/internal/telephony/cdma/sms/BearerData;->priorityIndicatorSet:Z -Lcom/android/internal/telephony/cdma/sms/BearerData;->userData:Lcom/android/internal/telephony/cdma/sms/UserData; -Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;-><init>()V -Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->digitMode:I -Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->numberMode:I -Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->numberOfDigits:I -Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->numberPlan:I -Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->parse(Ljava/lang/String;)Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress; -Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;-><init>()V -Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;->bearerData:[B -Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;->serviceCategory:I -Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;->teleService:I -Lcom/android/internal/telephony/cdma/sms/UserData;-><init>()V -Lcom/android/internal/telephony/cdma/sms/UserData;->charToAscii:Landroid/util/SparseIntArray; -Lcom/android/internal/telephony/cdma/sms/UserData;->msgEncoding:I -Lcom/android/internal/telephony/cdma/sms/UserData;->msgEncodingSet:Z -Lcom/android/internal/telephony/cdma/sms/UserData;->numFields:I -Lcom/android/internal/telephony/cdma/sms/UserData;->payload:[B -Lcom/android/internal/telephony/cdma/sms/UserData;->payloadStr:Ljava/lang/String; -Lcom/android/internal/telephony/cdma/sms/UserData;->userDataHeader:Lcom/android/internal/telephony/SmsHeader; -Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;-><init>()V -Lcom/android/internal/telephony/cdma/SmsMessage;-><init>()V -Lcom/android/internal/telephony/cdma/SmsMessage;->calculateLength(Ljava/lang/CharSequence;ZZ)Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails; -Lcom/android/internal/telephony/cdma/SmsMessage;->createFromEfRecord(I[B)Lcom/android/internal/telephony/cdma/SmsMessage; -Lcom/android/internal/telephony/cdma/SmsMessage;->createFromPdu([B)Lcom/android/internal/telephony/cdma/SmsMessage; -Lcom/android/internal/telephony/cdma/SmsMessage;->getIncomingSmsFingerprint()[B -Lcom/android/internal/telephony/cdma/SmsMessage;->getMessageType()I -Lcom/android/internal/telephony/cdma/SmsMessage;->getNextMessageId()I -Lcom/android/internal/telephony/cdma/SmsMessage;->getNumOfVoicemails()I -Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Lcom/android/internal/telephony/cdma/sms/UserData;Z)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu; -Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Lcom/android/internal/telephony/cdma/sms/UserData;ZI)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu; -Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;I[BZ)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu; -Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLcom/android/internal/telephony/SmsHeader;)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu; -Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLcom/android/internal/telephony/SmsHeader;I)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu; -Lcom/android/internal/telephony/cdma/SmsMessage;->getTeleService()I -Lcom/android/internal/telephony/cdma/SmsMessage;->isStatusReportMessage()Z -Lcom/android/internal/telephony/cdma/SmsMessage;->mBearerData:Lcom/android/internal/telephony/cdma/sms/BearerData; -Lcom/android/internal/telephony/cdma/SmsMessage;->mEnvelope:Lcom/android/internal/telephony/cdma/sms/SmsEnvelope; -Lcom/android/internal/telephony/cdma/SmsMessage;->parseSms()V -Lcom/android/internal/telephony/cdma/SmsMessage;->privateGetSubmitPdu(Ljava/lang/String;ZLcom/android/internal/telephony/cdma/sms/UserData;)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu; -Lcom/android/internal/telephony/DctConstants$Activity;->DATAIN:Lcom/android/internal/telephony/DctConstants$Activity; -Lcom/android/internal/telephony/DctConstants$Activity;->DATAINANDOUT:Lcom/android/internal/telephony/DctConstants$Activity; -Lcom/android/internal/telephony/DctConstants$Activity;->DATAOUT:Lcom/android/internal/telephony/DctConstants$Activity; -Lcom/android/internal/telephony/DctConstants$Activity;->DORMANT:Lcom/android/internal/telephony/DctConstants$Activity; -Lcom/android/internal/telephony/DctConstants$Activity;->values()[Lcom/android/internal/telephony/DctConstants$Activity; -Lcom/android/internal/telephony/DctConstants$State;->CONNECTED:Lcom/android/internal/telephony/DctConstants$State; -Lcom/android/internal/telephony/DctConstants$State;->CONNECTING:Lcom/android/internal/telephony/DctConstants$State; -Lcom/android/internal/telephony/DctConstants$State;->DISCONNECTING:Lcom/android/internal/telephony/DctConstants$State; -Lcom/android/internal/telephony/DctConstants$State;->FAILED:Lcom/android/internal/telephony/DctConstants$State; -Lcom/android/internal/telephony/DctConstants$State;->IDLE:Lcom/android/internal/telephony/DctConstants$State; -Lcom/android/internal/telephony/DctConstants$State;->RETRYING:Lcom/android/internal/telephony/DctConstants$State; -Lcom/android/internal/telephony/DctConstants$State;->values()[Lcom/android/internal/telephony/DctConstants$State; -Lcom/android/internal/telephony/DriverCall$State;->values()[Lcom/android/internal/telephony/DriverCall$State; -Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler$SmsCbConcatInfo;-><init>(Lcom/android/internal/telephony/gsm/SmsCbHeader;Landroid/telephony/SmsCbLocation;)V -Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler$SmsCbConcatInfo;->matchesLocation(Ljava/lang/String;II)Z -Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler;->mSmsCbPageMap:Ljava/util/HashMap; -Lcom/android/internal/telephony/gsm/GsmInboundSmsHandler;->acknowledgeLastIncomingSms(ZILandroid/os/Message;)V -Lcom/android/internal/telephony/gsm/GsmMmiCode;-><init>(Lcom/android/internal/telephony/GsmCdmaPhone;Lcom/android/internal/telephony/uicc/UiccCardApplication;)V -Lcom/android/internal/telephony/gsm/GsmMmiCode;->getCLIRMode()I -Lcom/android/internal/telephony/gsm/GsmMmiCode;->getScString()Ljava/lang/CharSequence; -Lcom/android/internal/telephony/gsm/GsmMmiCode;->isActivate()Z -Lcom/android/internal/telephony/gsm/GsmMmiCode;->isDeactivate()Z -Lcom/android/internal/telephony/gsm/GsmMmiCode;->isErasure()Z -Lcom/android/internal/telephony/gsm/GsmMmiCode;->isInterrogate()Z -Lcom/android/internal/telephony/gsm/GsmMmiCode;->isRegister()Z -Lcom/android/internal/telephony/gsm/GsmMmiCode;->isServiceCodeCallBarring(Ljava/lang/String;)Z -Lcom/android/internal/telephony/gsm/GsmMmiCode;->isServiceCodeCallForwarding(Ljava/lang/String;)Z -Lcom/android/internal/telephony/gsm/GsmMmiCode;->isTemporaryModeCLIR()Z -Lcom/android/internal/telephony/gsm/GsmMmiCode;->makeEmptyNull(Ljava/lang/String;)Ljava/lang/String; -Lcom/android/internal/telephony/gsm/GsmMmiCode;->mContext:Landroid/content/Context; -Lcom/android/internal/telephony/gsm/GsmMmiCode;->mDialingNumber:Ljava/lang/String; -Lcom/android/internal/telephony/gsm/GsmMmiCode;->mIccRecords:Lcom/android/internal/telephony/uicc/IccRecords; -Lcom/android/internal/telephony/gsm/GsmMmiCode;->mPhone:Lcom/android/internal/telephony/GsmCdmaPhone; -Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSc:Ljava/lang/String; -Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSia:Ljava/lang/String; -Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSib:Ljava/lang/String; -Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSic:Ljava/lang/String; -Lcom/android/internal/telephony/gsm/GsmMmiCode;->newFromDialString(Ljava/lang/String;Lcom/android/internal/telephony/GsmCdmaPhone;Lcom/android/internal/telephony/uicc/UiccCardApplication;)Lcom/android/internal/telephony/gsm/GsmMmiCode; -Lcom/android/internal/telephony/gsm/GsmMmiCode;->processCode()V -Lcom/android/internal/telephony/gsm/GsmMmiCode;->siToServiceClass(Ljava/lang/String;)I -Lcom/android/internal/telephony/gsm/GsmMmiCode;->sPatternSuppService:Ljava/util/regex/Pattern; -Lcom/android/internal/telephony/gsm/GsmSmsAddress;-><init>([BII)V -Lcom/android/internal/telephony/gsm/GsmSmsAddress;->isCphsVoiceMessageClear()Z -Lcom/android/internal/telephony/gsm/GsmSmsAddress;->isCphsVoiceMessageSet()Z -Lcom/android/internal/telephony/gsm/GsmSMSDispatcher;->getFormat()Ljava/lang/String; -Lcom/android/internal/telephony/gsm/GsmSMSDispatcher;->mGsmInboundSmsHandler:Lcom/android/internal/telephony/gsm/GsmInboundSmsHandler; -Lcom/android/internal/telephony/gsm/GsmSMSDispatcher;->sendSms(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V -Lcom/android/internal/telephony/gsm/SimTlv;-><init>([BII)V -Lcom/android/internal/telephony/gsm/SimTlv;->getData()[B -Lcom/android/internal/telephony/gsm/SimTlv;->getTag()I -Lcom/android/internal/telephony/gsm/SimTlv;->isValidObject()Z -Lcom/android/internal/telephony/gsm/SimTlv;->mHasValidTlvObject:Z -Lcom/android/internal/telephony/gsm/SimTlv;->nextObject()Z -Lcom/android/internal/telephony/gsm/SmsCbHeader;-><init>([B)V -Lcom/android/internal/telephony/gsm/SmsCbHeader;->getGeographicalScope()I -Lcom/android/internal/telephony/gsm/SmsCbHeader;->getNumberOfPages()I -Lcom/android/internal/telephony/gsm/SmsCbHeader;->getPageIndex()I -Lcom/android/internal/telephony/gsm/SmsCbHeader;->getSerialNumber()I -Lcom/android/internal/telephony/gsm/SmsCbHeader;->getServiceCategory()I -Lcom/android/internal/telephony/gsm/SmsCbHeader;->mMessageIdentifier:I -Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;-><init>([B)V -Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->getByte()I -Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->getUserData()[B -Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->getUserDataUCS2(I)Ljava/lang/String; -Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->mCur:I -Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->mPdu:[B -Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->mUserDataSeptetPadding:I -Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;-><init>()V -Lcom/android/internal/telephony/gsm/SmsMessage;-><init>()V -Lcom/android/internal/telephony/gsm/SmsMessage;->calculateLength(Ljava/lang/CharSequence;Z)Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails; -Lcom/android/internal/telephony/gsm/SmsMessage;->createFromEfRecord(I[B)Lcom/android/internal/telephony/gsm/SmsMessage; -Lcom/android/internal/telephony/gsm/SmsMessage;->createFromPdu([B)Lcom/android/internal/telephony/gsm/SmsMessage; -Lcom/android/internal/telephony/gsm/SmsMessage;->encodeUCS2(Ljava/lang/String;[B)[B -Lcom/android/internal/telephony/gsm/SmsMessage;->getStatus()I -Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu; -Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZI)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu; -Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z[B)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu; -Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z[BIII)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu; -Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z[BIIII)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu; -Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPduHead(Ljava/lang/String;Ljava/lang/String;BZLcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;)Ljava/io/ByteArrayOutputStream; -Lcom/android/internal/telephony/gsm/SmsMessage;->isMWIClearMessage()Z -Lcom/android/internal/telephony/gsm/SmsMessage;->isMwiDontStore()Z -Lcom/android/internal/telephony/gsm/SmsMessage;->isMWISetMessage()Z -Lcom/android/internal/telephony/gsm/SmsMessage;->isStatusReportMessage()Z -Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->loadEfFilesFromUsim()Ljava/util/ArrayList; -Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->log(Ljava/lang/String;)V -Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler; -Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->mLock:Ljava/lang/Object; -Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->mPhoneBookRecords:Ljava/util/ArrayList; -Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->reset()V -Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;-><init>()V -Lcom/android/internal/telephony/GsmCdmaConnection$MyHandler;-><init>(Lcom/android/internal/telephony/GsmCdmaConnection;Landroid/os/Looper;)V -Lcom/android/internal/telephony/IccCardConstants$State;->ABSENT:Lcom/android/internal/telephony/IccCardConstants$State; -Lcom/android/internal/telephony/IccCardConstants$State;->CARD_IO_ERROR:Lcom/android/internal/telephony/IccCardConstants$State; -Lcom/android/internal/telephony/IccCardConstants$State;->NETWORK_LOCKED:Lcom/android/internal/telephony/IccCardConstants$State; -Lcom/android/internal/telephony/IccCardConstants$State;->NOT_READY:Lcom/android/internal/telephony/IccCardConstants$State; -Lcom/android/internal/telephony/IccCardConstants$State;->PERM_DISABLED:Lcom/android/internal/telephony/IccCardConstants$State; -Lcom/android/internal/telephony/IccCardConstants$State;->PIN_REQUIRED:Lcom/android/internal/telephony/IccCardConstants$State; -Lcom/android/internal/telephony/IccCardConstants$State;->PUK_REQUIRED:Lcom/android/internal/telephony/IccCardConstants$State; -Lcom/android/internal/telephony/IccCardConstants$State;->READY:Lcom/android/internal/telephony/IccCardConstants$State; -Lcom/android/internal/telephony/IccCardConstants$State;->UNKNOWN:Lcom/android/internal/telephony/IccCardConstants$State; -Lcom/android/internal/telephony/IccCardConstants$State;->values()[Lcom/android/internal/telephony/IccCardConstants$State; -Lcom/android/internal/telephony/IccProvider;-><init>()V Lcom/android/internal/telephony/IIccPhoneBook$Stub$Proxy;->mRemote:Landroid/os/IBinder; Lcom/android/internal/telephony/IIccPhoneBook$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IIccPhoneBook; -Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsInEf(I)Ljava/util/List; -Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsInEfForSubscriber(II)Ljava/util/List; -Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsSize(I)[I -Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsSizeForSubscriber(II)[I -Lcom/android/internal/telephony/IIccPhoneBook;->updateAdnRecordsInEfBySearch(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z Lcom/android/internal/telephony/IMms$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IMms; -Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker$ExternalCallStateListener;-><init>(Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker;)V -Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker$ExternalConnectionListener;-><init>(Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker;)V -Lcom/android/internal/telephony/imsphone/ImsPhone;->notifyCallForwardingIndicator()V -Lcom/android/internal/telephony/imsphone/ImsPhone;->notifyPreciseCallStateChanged()V -Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->getImsCall()Lcom/android/ims/ImsCall; -Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->findConnection(Lcom/android/ims/ImsCall;)Lcom/android/internal/telephony/imsphone/ImsPhoneConnection; -Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->getEcbmInterface()Lcom/android/ims/ImsEcbm; -Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mCallExpectedToResume:Lcom/android/ims/ImsCall; -Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mImsCallListener:Lcom/android/ims/ImsCall$Listener; -Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mImsManager:Lcom/android/ims/ImsManager; -Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mUssdSession:Lcom/android/ims/ImsCall; -Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->processCallStateChange(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;I)V -Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->processCallStateChange(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;IZ)V -Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->setVideoCallProvider(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;Lcom/android/ims/ImsCall;)V -Lcom/android/internal/telephony/imsphone/ImsPhoneConnection$MyHandler;-><init>(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;Landroid/os/Looper;)V -Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mImsCall:Lcom/android/ims/ImsCall; -Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->update(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;)Z -Lcom/android/internal/telephony/InboundSmsHandler$SmsBroadcastReceiver;-><init>(Lcom/android/internal/telephony/InboundSmsHandler;Lcom/android/internal/telephony/InboundSmsTracker;)V Lcom/android/internal/telephony/IPhoneStateListener$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneStateListener; Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-><init>(Landroid/os/IBinder;)V -Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String; Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneSubInfo; Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->TRANSACTION_getDeviceId:I Lcom/android/internal/telephony/ISms$Stub;-><init>()V @@ -1389,8 +1186,6 @@ Lcom/android/internal/telephony/ISms$Stub;->asInterface(Landroid/os/IBinder;)Lco Lcom/android/internal/telephony/ISub$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Lcom/android/internal/telephony/ISub$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ISub; Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-><init>(Landroid/os/IBinder;)V -Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String; -Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->isRadioOn(Ljava/lang/String;)Z Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->mRemote:Landroid/os/IBinder; Lcom/android/internal/telephony/ITelephony$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephony; Lcom/android/internal/telephony/ITelephony$Stub;->DESCRIPTOR:Ljava/lang/String; @@ -1400,82 +1195,6 @@ Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Lcom/android/internal/telephony/ITelephonyRegistry$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephonyRegistry; Lcom/android/internal/telephony/IWapPushManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IWapPushManager; -Lcom/android/internal/telephony/PhoneConstants$DataState;->CONNECTED:Lcom/android/internal/telephony/PhoneConstants$DataState; -Lcom/android/internal/telephony/PhoneConstants$DataState;->CONNECTING:Lcom/android/internal/telephony/PhoneConstants$DataState; -Lcom/android/internal/telephony/PhoneConstants$DataState;->DISCONNECTED:Lcom/android/internal/telephony/PhoneConstants$DataState; -Lcom/android/internal/telephony/PhoneConstants$DataState;->SUSPENDED:Lcom/android/internal/telephony/PhoneConstants$DataState; -Lcom/android/internal/telephony/PhoneConstants$DataState;->values()[Lcom/android/internal/telephony/PhoneConstants$DataState; -Lcom/android/internal/telephony/PhoneConstants$State;->IDLE:Lcom/android/internal/telephony/PhoneConstants$State; -Lcom/android/internal/telephony/PhoneConstants$State;->OFFHOOK:Lcom/android/internal/telephony/PhoneConstants$State; -Lcom/android/internal/telephony/PhoneConstants$State;->RINGING:Lcom/android/internal/telephony/PhoneConstants$State; -Lcom/android/internal/telephony/PhoneConstants$State;->values()[Lcom/android/internal/telephony/PhoneConstants$State; -Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_ALLOWED:I -Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_PAYPHONE:I -Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_RESTRICTED:I -Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_UNKNOWN:I -Lcom/android/internal/telephony/RILConstants;->PREFERRED_NETWORK_MODE:I -Lcom/android/internal/telephony/sip/SipPhone$SipCall;->hold()V -Lcom/android/internal/telephony/sip/SipPhone$SipCall;->switchWith(Lcom/android/internal/telephony/sip/SipPhone$SipCall;)V -Lcom/android/internal/telephony/sip/SipPhone$SipCall;->unhold()V -Lcom/android/internal/telephony/sip/SipPhone;->log(Ljava/lang/String;)V -Lcom/android/internal/telephony/sip/SipPhone;->loge(Ljava/lang/String;)V -Lcom/android/internal/telephony/sip/SipPhone;->mBackgroundCall:Lcom/android/internal/telephony/sip/SipPhone$SipCall; -Lcom/android/internal/telephony/sip/SipPhone;->mForegroundCall:Lcom/android/internal/telephony/sip/SipPhone$SipCall; -Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->DBG:Z -Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->mTranslationTableCDMA:Landroid/util/SparseIntArray; -Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->mTranslationTableCommon:Landroid/util/SparseIntArray; -Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->mTranslationTableGSM:Landroid/util/SparseIntArray; -Lcom/android/internal/telephony/SmsApplication$SmsApplicationData;->mApplicationName:Ljava/lang/String; -Lcom/android/internal/telephony/SmsApplication;->configurePreferredActivity(Landroid/content/pm/PackageManager;Landroid/content/ComponentName;I)V -Lcom/android/internal/telephony/SmsApplication;->getApplicationCollection(Landroid/content/Context;)Ljava/util/Collection; -Lcom/android/internal/telephony/SmsApplication;->getDefaultMmsApplication(Landroid/content/Context;Z)Landroid/content/ComponentName; -Lcom/android/internal/telephony/SmsApplication;->getDefaultRespondViaMessageApplication(Landroid/content/Context;Z)Landroid/content/ComponentName; -Lcom/android/internal/telephony/SmsApplication;->getDefaultSmsApplication(Landroid/content/Context;Z)Landroid/content/ComponentName; -Lcom/android/internal/telephony/SmsApplication;->getSmsApplicationData(Ljava/lang/String;Landroid/content/Context;)Lcom/android/internal/telephony/SmsApplication$SmsApplicationData; -Lcom/android/internal/telephony/SmsApplication;->isDefaultSmsApplication(Landroid/content/Context;Ljava/lang/String;)Z -Lcom/android/internal/telephony/SmsApplication;->setDefaultApplication(Ljava/lang/String;Landroid/content/Context;)V -Lcom/android/internal/telephony/SmsApplication;->shouldWriteMessageForPackage(Ljava/lang/String;Landroid/content/Context;)Z -Lcom/android/internal/telephony/SMSDispatcher$DataSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V -Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Ljava/util/ArrayList;[Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V -Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSenderCallback;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSender;)V -Lcom/android/internal/telephony/SMSDispatcher$SmsSenderCallback;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsSender;)V -Lcom/android/internal/telephony/SMSDispatcher$TextSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V -Lcom/android/internal/telephony/SmsHeader$ConcatRef;-><init>()V -Lcom/android/internal/telephony/SmsHeader$PortAddrs;-><init>()V -Lcom/android/internal/telephony/SmsMessageBase;-><init>()V -Lcom/android/internal/telephony/TelephonyProperties;->PROPERTY_ICC_OPERATOR_NUMERIC:Ljava/lang/String; -Lcom/android/internal/telephony/test/InterpreterEx;-><init>(Ljava/lang/String;)V -Lcom/android/internal/telephony/test/SimulatedCommands;->acceptCall(Landroid/os/Message;)V -Lcom/android/internal/telephony/test/SimulatedCommands;->mDcSuccess:Z -Lcom/android/internal/telephony/test/SimulatedCommands;->resultFail(Landroid/os/Message;Ljava/lang/Object;Ljava/lang/Throwable;)V -Lcom/android/internal/telephony/test/SimulatedCommands;->resultSuccess(Landroid/os/Message;Ljava/lang/Object;)V -Lcom/android/internal/telephony/test/SimulatedCommands;->simulatedCallState:Lcom/android/internal/telephony/test/SimulatedGsmCallState; -Lcom/android/internal/telephony/test/SimulatedCommands;->unimplemented(Landroid/os/Message;)V -Lcom/android/internal/telephony/test/SimulatedCommandsVerifier;->getInstance()Lcom/android/internal/telephony/test/SimulatedCommandsVerifier; -Lcom/android/internal/telephony/test/SimulatedCommandsVerifier;->setCallForward(IIILjava/lang/String;ILandroid/os/Message;)V -Lcom/android/internal/telephony/test/SimulatedGsmCallState;->conference()Z -Lcom/android/internal/telephony/test/SimulatedGsmCallState;->onChld(CC)Z -Lcom/android/internal/telephony/test/SimulatedGsmCallState;->releaseActiveAcceptHeldOrWaiting()Z -Lcom/android/internal/telephony/test/SimulatedGsmCallState;->releaseHeldOrUDUB()Z -Lcom/android/internal/telephony/test/SimulatedGsmCallState;->separateCall(I)Z -Lcom/android/internal/telephony/test/SimulatedGsmCallState;->switchActiveAndHeldOrWaiting()Z -Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState; -Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType; -Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState; -Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;-><init>()V -Lcom/android/internal/telephony/uicc/IccRefreshResponse;-><init>()V -Lcom/android/internal/telephony/uicc/IccUtils;->adnStringFieldToString([BII)Ljava/lang/String; -Lcom/android/internal/telephony/uicc/IccUtils;->bcdToString([BII)Ljava/lang/String; -Lcom/android/internal/telephony/uicc/IccUtils;->bytesToHexString([B)Ljava/lang/String; -Lcom/android/internal/telephony/uicc/IccUtils;->cdmaBcdByteToInt(B)I -Lcom/android/internal/telephony/uicc/IccUtils;->cdmaBcdToString([BII)Ljava/lang/String; -Lcom/android/internal/telephony/uicc/IccUtils;->gsmBcdByteToInt(B)I -Lcom/android/internal/telephony/uicc/IccUtils;->hexCharToInt(C)I -Lcom/android/internal/telephony/uicc/IccUtils;->hexStringToBytes(Ljava/lang/String;)[B -Lcom/android/internal/telephony/uicc/IccUtils;->networkNameToString([BII)Ljava/lang/String; -Lcom/android/internal/telephony/uicc/IccUtils;->parseToBnW([BI)Landroid/graphics/Bitmap; -Lcom/android/internal/telephony/uicc/IccUtils;->parseToRGB([BIZ)Landroid/graphics/Bitmap; -Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->values()[Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState; Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Lcom/android/internal/util/MemInfoReader;-><init>()V Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V @@ -1488,283 +1207,5 @@ Lcom/android/server/net/BaseNetworkObserver;-><init>()V Lcom/android/server/ResettableTimeout$T;-><init>(Lcom/android/server/ResettableTimeout;)V Lcom/google/android/gles_jni/EGLImpl;-><init>()V Lcom/google/android/gles_jni/GLImpl;-><init>()V -Lcom/google/android/mms/ContentType;->getAudioTypes()Ljava/util/ArrayList; -Lcom/google/android/mms/ContentType;->getImageTypes()Ljava/util/ArrayList; -Lcom/google/android/mms/ContentType;->getVideoTypes()Ljava/util/ArrayList; -Lcom/google/android/mms/ContentType;->isAudioType(Ljava/lang/String;)Z -Lcom/google/android/mms/ContentType;->isDrmType(Ljava/lang/String;)Z -Lcom/google/android/mms/ContentType;->isImageType(Ljava/lang/String;)Z -Lcom/google/android/mms/ContentType;->isSupportedAudioType(Ljava/lang/String;)Z -Lcom/google/android/mms/ContentType;->isSupportedImageType(Ljava/lang/String;)Z -Lcom/google/android/mms/ContentType;->isSupportedType(Ljava/lang/String;)Z -Lcom/google/android/mms/ContentType;->isSupportedVideoType(Ljava/lang/String;)Z -Lcom/google/android/mms/ContentType;->isTextType(Ljava/lang/String;)Z -Lcom/google/android/mms/ContentType;->isVideoType(Ljava/lang/String;)Z -Lcom/google/android/mms/InvalidHeaderValueException;-><init>(Ljava/lang/String;)V -Lcom/google/android/mms/MmsException;-><init>()V -Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/String;)V -Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/String;Ljava/lang/Throwable;)V -Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/Throwable;)V -Lcom/google/android/mms/pdu/AcknowledgeInd;-><init>(I[B)V -Lcom/google/android/mms/pdu/AcknowledgeInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V -Lcom/google/android/mms/pdu/AcknowledgeInd;->setReportAllowed(I)V -Lcom/google/android/mms/pdu/AcknowledgeInd;->setTransactionId([B)V -Lcom/google/android/mms/pdu/Base64;->decodeBase64([B)[B -Lcom/google/android/mms/pdu/CharacterSets;->getMibEnumValue(Ljava/lang/String;)I -Lcom/google/android/mms/pdu/CharacterSets;->getMimeName(I)Ljava/lang/String; -Lcom/google/android/mms/pdu/DeliveryInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V -Lcom/google/android/mms/pdu/DeliveryInd;->getDate()J -Lcom/google/android/mms/pdu/DeliveryInd;->getMessageId()[B -Lcom/google/android/mms/pdu/DeliveryInd;->getStatus()I -Lcom/google/android/mms/pdu/DeliveryInd;->getTo()[Lcom/google/android/mms/pdu/EncodedStringValue; -Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(I[B)V -Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(Ljava/lang/String;)V -Lcom/google/android/mms/pdu/EncodedStringValue;-><init>([B)V -Lcom/google/android/mms/pdu/EncodedStringValue;->appendTextString([B)V -Lcom/google/android/mms/pdu/EncodedStringValue;->concat([Lcom/google/android/mms/pdu/EncodedStringValue;)Ljava/lang/String; -Lcom/google/android/mms/pdu/EncodedStringValue;->copy(Lcom/google/android/mms/pdu/EncodedStringValue;)Lcom/google/android/mms/pdu/EncodedStringValue; -Lcom/google/android/mms/pdu/EncodedStringValue;->encodeStrings([Ljava/lang/String;)[Lcom/google/android/mms/pdu/EncodedStringValue; -Lcom/google/android/mms/pdu/EncodedStringValue;->extract(Ljava/lang/String;)[Lcom/google/android/mms/pdu/EncodedStringValue; -Lcom/google/android/mms/pdu/EncodedStringValue;->getCharacterSet()I -Lcom/google/android/mms/pdu/EncodedStringValue;->getString()Ljava/lang/String; -Lcom/google/android/mms/pdu/EncodedStringValue;->getTextString()[B -Lcom/google/android/mms/pdu/EncodedStringValue;->setCharacterSet(I)V -Lcom/google/android/mms/pdu/EncodedStringValue;->setTextString([B)V -Lcom/google/android/mms/pdu/GenericPdu;-><init>()V -Lcom/google/android/mms/pdu/GenericPdu;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue; -Lcom/google/android/mms/pdu/GenericPdu;->getMessageType()I -Lcom/google/android/mms/pdu/GenericPdu;->getPduHeaders()Lcom/google/android/mms/pdu/PduHeaders; -Lcom/google/android/mms/pdu/GenericPdu;->mPduHeaders:Lcom/google/android/mms/pdu/PduHeaders; -Lcom/google/android/mms/pdu/GenericPdu;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/GenericPdu;->setMessageType(I)V -Lcom/google/android/mms/pdu/MultimediaMessagePdu;-><init>()V -Lcom/google/android/mms/pdu/MultimediaMessagePdu;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V -Lcom/google/android/mms/pdu/MultimediaMessagePdu;->addTo(Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getBody()Lcom/google/android/mms/pdu/PduBody; -Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getDate()J -Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getPriority()I -Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getSubject()Lcom/google/android/mms/pdu/EncodedStringValue; -Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getTo()[Lcom/google/android/mms/pdu/EncodedStringValue; -Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setBody(Lcom/google/android/mms/pdu/PduBody;)V -Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setDate(J)V -Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setPriority(I)V -Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setSubject(Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/NotificationInd;-><init>()V -Lcom/google/android/mms/pdu/NotificationInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V -Lcom/google/android/mms/pdu/NotificationInd;->getContentClass()I -Lcom/google/android/mms/pdu/NotificationInd;->getContentLocation()[B -Lcom/google/android/mms/pdu/NotificationInd;->getDeliveryReport()I -Lcom/google/android/mms/pdu/NotificationInd;->getExpiry()J -Lcom/google/android/mms/pdu/NotificationInd;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue; -Lcom/google/android/mms/pdu/NotificationInd;->getMessageClass()[B -Lcom/google/android/mms/pdu/NotificationInd;->getMessageSize()J -Lcom/google/android/mms/pdu/NotificationInd;->getSubject()Lcom/google/android/mms/pdu/EncodedStringValue; -Lcom/google/android/mms/pdu/NotificationInd;->getTransactionId()[B -Lcom/google/android/mms/pdu/NotificationInd;->setContentClass(I)V -Lcom/google/android/mms/pdu/NotificationInd;->setContentLocation([B)V -Lcom/google/android/mms/pdu/NotificationInd;->setDeliveryReport(I)V -Lcom/google/android/mms/pdu/NotificationInd;->setExpiry(J)V -Lcom/google/android/mms/pdu/NotificationInd;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/NotificationInd;->setMessageClass([B)V -Lcom/google/android/mms/pdu/NotificationInd;->setMessageSize(J)V -Lcom/google/android/mms/pdu/NotificationInd;->setSubject(Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/NotificationInd;->setTransactionId([B)V -Lcom/google/android/mms/pdu/NotifyRespInd;-><init>(I[BI)V -Lcom/google/android/mms/pdu/NotifyRespInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V -Lcom/google/android/mms/pdu/NotifyRespInd;->setReportAllowed(I)V -Lcom/google/android/mms/pdu/NotifyRespInd;->setStatus(I)V -Lcom/google/android/mms/pdu/NotifyRespInd;->setTransactionId([B)V -Lcom/google/android/mms/pdu/PduBody;-><init>()V -Lcom/google/android/mms/pdu/PduBody;->addPart(ILcom/google/android/mms/pdu/PduPart;)V -Lcom/google/android/mms/pdu/PduBody;->addPart(Lcom/google/android/mms/pdu/PduPart;)Z -Lcom/google/android/mms/pdu/PduBody;->getPart(I)Lcom/google/android/mms/pdu/PduPart; -Lcom/google/android/mms/pdu/PduBody;->getPartByContentId(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart; -Lcom/google/android/mms/pdu/PduBody;->getPartByContentLocation(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart; -Lcom/google/android/mms/pdu/PduBody;->getPartByFileName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart; -Lcom/google/android/mms/pdu/PduBody;->getPartByName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart; -Lcom/google/android/mms/pdu/PduBody;->getPartIndex(Lcom/google/android/mms/pdu/PduPart;)I -Lcom/google/android/mms/pdu/PduBody;->getPartsNum()I -Lcom/google/android/mms/pdu/PduBody;->removePart(I)Lcom/google/android/mms/pdu/PduPart; -Lcom/google/android/mms/pdu/PduComposer$BufferStack;->copy()V -Lcom/google/android/mms/pdu/PduComposer$BufferStack;->mark()Lcom/google/android/mms/pdu/PduComposer$PositionMarker; -Lcom/google/android/mms/pdu/PduComposer$BufferStack;->newbuf()V -Lcom/google/android/mms/pdu/PduComposer$BufferStack;->pop()V -Lcom/google/android/mms/pdu/PduComposer$PositionMarker;->getLength()I -Lcom/google/android/mms/pdu/PduComposer;-><init>(Landroid/content/Context;Lcom/google/android/mms/pdu/GenericPdu;)V -Lcom/google/android/mms/pdu/PduComposer;->appendEncodedString(Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/PduComposer;->appendHeader(I)I -Lcom/google/android/mms/pdu/PduComposer;->appendLongInteger(J)V -Lcom/google/android/mms/pdu/PduComposer;->appendOctet(I)V -Lcom/google/android/mms/pdu/PduComposer;->appendQuotedString(Ljava/lang/String;)V -Lcom/google/android/mms/pdu/PduComposer;->appendQuotedString([B)V -Lcom/google/android/mms/pdu/PduComposer;->appendShortInteger(I)V -Lcom/google/android/mms/pdu/PduComposer;->appendTextString(Ljava/lang/String;)V -Lcom/google/android/mms/pdu/PduComposer;->appendTextString([B)V -Lcom/google/android/mms/pdu/PduComposer;->appendUintvarInteger(J)V -Lcom/google/android/mms/pdu/PduComposer;->appendValueLength(J)V -Lcom/google/android/mms/pdu/PduComposer;->arraycopy([BII)V -Lcom/google/android/mms/pdu/PduComposer;->make()[B -Lcom/google/android/mms/pdu/PduComposer;->mContentTypeMap:Ljava/util/HashMap; -Lcom/google/android/mms/pdu/PduComposer;->mMessage:Ljava/io/ByteArrayOutputStream; -Lcom/google/android/mms/pdu/PduComposer;->mPdu:Lcom/google/android/mms/pdu/GenericPdu; -Lcom/google/android/mms/pdu/PduComposer;->mPduHeader:Lcom/google/android/mms/pdu/PduHeaders; -Lcom/google/android/mms/pdu/PduComposer;->mPosition:I -Lcom/google/android/mms/pdu/PduComposer;->mResolver:Landroid/content/ContentResolver; -Lcom/google/android/mms/pdu/PduComposer;->mStack:Lcom/google/android/mms/pdu/PduComposer$BufferStack; -Lcom/google/android/mms/pdu/PduContentTypes;->contentTypes:[Ljava/lang/String; -Lcom/google/android/mms/pdu/PduHeaders;-><init>()V -Lcom/google/android/mms/pdu/PduHeaders;->appendEncodedStringValue(Lcom/google/android/mms/pdu/EncodedStringValue;I)V -Lcom/google/android/mms/pdu/PduHeaders;->getEncodedStringValue(I)Lcom/google/android/mms/pdu/EncodedStringValue; -Lcom/google/android/mms/pdu/PduHeaders;->getEncodedStringValues(I)[Lcom/google/android/mms/pdu/EncodedStringValue; -Lcom/google/android/mms/pdu/PduHeaders;->getLongInteger(I)J -Lcom/google/android/mms/pdu/PduHeaders;->getOctet(I)I -Lcom/google/android/mms/pdu/PduHeaders;->getTextString(I)[B -Lcom/google/android/mms/pdu/PduHeaders;->setEncodedStringValue(Lcom/google/android/mms/pdu/EncodedStringValue;I)V -Lcom/google/android/mms/pdu/PduHeaders;->setLongInteger(JI)V -Lcom/google/android/mms/pdu/PduHeaders;->setOctet(II)V Lcom/google/android/mms/pdu/PduParser;->$assertionsDisabled:Z -Lcom/google/android/mms/pdu/PduParser;-><init>([BZ)V -Lcom/google/android/mms/pdu/PduParser;->checkPartPosition(Lcom/google/android/mms/pdu/PduPart;)I -Lcom/google/android/mms/pdu/PduParser;->log(Ljava/lang/String;)V -Lcom/google/android/mms/pdu/PduParser;->parse()Lcom/google/android/mms/pdu/GenericPdu; -Lcom/google/android/mms/pdu/PduParser;->parseContentType(Ljava/io/ByteArrayInputStream;Ljava/util/HashMap;)[B -Lcom/google/android/mms/pdu/PduParser;->parsePartHeaders(Ljava/io/ByteArrayInputStream;Lcom/google/android/mms/pdu/PduPart;I)Z -Lcom/google/android/mms/pdu/PduParser;->parseShortInteger(Ljava/io/ByteArrayInputStream;)I -Lcom/google/android/mms/pdu/PduParser;->parseUnsignedInt(Ljava/io/ByteArrayInputStream;)I -Lcom/google/android/mms/pdu/PduParser;->parseValueLength(Ljava/io/ByteArrayInputStream;)I -Lcom/google/android/mms/pdu/PduParser;->parseWapString(Ljava/io/ByteArrayInputStream;I)[B -Lcom/google/android/mms/pdu/PduPart;-><init>()V -Lcom/google/android/mms/pdu/PduPart;->generateLocation()Ljava/lang/String; -Lcom/google/android/mms/pdu/PduPart;->getCharset()I -Lcom/google/android/mms/pdu/PduPart;->getContentDisposition()[B -Lcom/google/android/mms/pdu/PduPart;->getContentId()[B -Lcom/google/android/mms/pdu/PduPart;->getContentLocation()[B -Lcom/google/android/mms/pdu/PduPart;->getContentTransferEncoding()[B -Lcom/google/android/mms/pdu/PduPart;->getContentType()[B -Lcom/google/android/mms/pdu/PduPart;->getData()[B -Lcom/google/android/mms/pdu/PduPart;->getDataLength()I -Lcom/google/android/mms/pdu/PduPart;->getDataUri()Landroid/net/Uri; -Lcom/google/android/mms/pdu/PduPart;->getFilename()[B -Lcom/google/android/mms/pdu/PduPart;->getName()[B -Lcom/google/android/mms/pdu/PduPart;->setCharset(I)V -Lcom/google/android/mms/pdu/PduPart;->setContentDisposition([B)V -Lcom/google/android/mms/pdu/PduPart;->setContentId([B)V -Lcom/google/android/mms/pdu/PduPart;->setContentLocation([B)V -Lcom/google/android/mms/pdu/PduPart;->setContentTransferEncoding([B)V -Lcom/google/android/mms/pdu/PduPart;->setContentType([B)V -Lcom/google/android/mms/pdu/PduPart;->setData([B)V -Lcom/google/android/mms/pdu/PduPart;->setDataUri(Landroid/net/Uri;)V -Lcom/google/android/mms/pdu/PduPart;->setFilename([B)V -Lcom/google/android/mms/pdu/PduPart;->setName([B)V -Lcom/google/android/mms/pdu/PduPersister;->ADDRESS_FIELDS:[I -Lcom/google/android/mms/pdu/PduPersister;->CHARSET_COLUMN_NAME_MAP:Ljava/util/HashMap; -Lcom/google/android/mms/pdu/PduPersister;->ENCODED_STRING_COLUMN_NAME_MAP:Ljava/util/HashMap; -Lcom/google/android/mms/pdu/PduPersister;->getByteArrayFromPartColumn(Landroid/database/Cursor;I)[B -Lcom/google/android/mms/pdu/PduPersister;->getBytes(Ljava/lang/String;)[B -Lcom/google/android/mms/pdu/PduPersister;->getIntegerFromPartColumn(Landroid/database/Cursor;I)Ljava/lang/Integer; -Lcom/google/android/mms/pdu/PduPersister;->getPartContentType(Lcom/google/android/mms/pdu/PduPart;)Ljava/lang/String; -Lcom/google/android/mms/pdu/PduPersister;->getPduPersister(Landroid/content/Context;)Lcom/google/android/mms/pdu/PduPersister; -Lcom/google/android/mms/pdu/PduPersister;->getPendingMessages(J)Landroid/database/Cursor; -Lcom/google/android/mms/pdu/PduPersister;->load(Landroid/net/Uri;)Lcom/google/android/mms/pdu/GenericPdu; -Lcom/google/android/mms/pdu/PduPersister;->loadRecipients(ILjava/util/HashSet;Ljava/util/HashMap;Z)V -Lcom/google/android/mms/pdu/PduPersister;->LONG_COLUMN_NAME_MAP:Ljava/util/HashMap; -Lcom/google/android/mms/pdu/PduPersister;->mContentResolver:Landroid/content/ContentResolver; -Lcom/google/android/mms/pdu/PduPersister;->mContext:Landroid/content/Context; -Lcom/google/android/mms/pdu/PduPersister;->MESSAGE_BOX_MAP:Ljava/util/HashMap; -Lcom/google/android/mms/pdu/PduPersister;->move(Landroid/net/Uri;Landroid/net/Uri;)Landroid/net/Uri; -Lcom/google/android/mms/pdu/PduPersister;->mTelephonyManager:Landroid/telephony/TelephonyManager; -Lcom/google/android/mms/pdu/PduPersister;->OCTET_COLUMN_NAME_MAP:Ljava/util/HashMap; -Lcom/google/android/mms/pdu/PduPersister;->PART_PROJECTION:[Ljava/lang/String; -Lcom/google/android/mms/pdu/PduPersister;->PDU_CACHE_INSTANCE:Lcom/google/android/mms/util/PduCache; -Lcom/google/android/mms/pdu/PduPersister;->persist(Lcom/google/android/mms/pdu/GenericPdu;Landroid/net/Uri;ZZLjava/util/HashMap;)Landroid/net/Uri; -Lcom/google/android/mms/pdu/PduPersister;->persistAddress(JI[Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/PduPersister;->persistPart(Lcom/google/android/mms/pdu/PduPart;JLjava/util/HashMap;)Landroid/net/Uri; -Lcom/google/android/mms/pdu/PduPersister;->TEXT_STRING_COLUMN_NAME_MAP:Ljava/util/HashMap; -Lcom/google/android/mms/pdu/PduPersister;->toIsoString([B)Ljava/lang/String; -Lcom/google/android/mms/pdu/PduPersister;->updateAddress(JI[Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/PduPersister;->updateHeaders(Landroid/net/Uri;Lcom/google/android/mms/pdu/SendReq;)V -Lcom/google/android/mms/pdu/PduPersister;->updateParts(Landroid/net/Uri;Lcom/google/android/mms/pdu/PduBody;Ljava/util/HashMap;)V -Lcom/google/android/mms/pdu/QuotedPrintable;->decodeQuotedPrintable([B)[B -Lcom/google/android/mms/pdu/ReadOrigInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V -Lcom/google/android/mms/pdu/ReadOrigInd;->getMessageId()[B -Lcom/google/android/mms/pdu/ReadOrigInd;->getReadStatus()I -Lcom/google/android/mms/pdu/ReadRecInd;-><init>(Lcom/google/android/mms/pdu/EncodedStringValue;[BII[Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/ReadRecInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V -Lcom/google/android/mms/pdu/ReadRecInd;->getMessageId()[B -Lcom/google/android/mms/pdu/ReadRecInd;->setDate(J)V -Lcom/google/android/mms/pdu/RetrieveConf;-><init>()V -Lcom/google/android/mms/pdu/RetrieveConf;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V -Lcom/google/android/mms/pdu/RetrieveConf;->addCc(Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/RetrieveConf;->getCc()[Lcom/google/android/mms/pdu/EncodedStringValue; -Lcom/google/android/mms/pdu/RetrieveConf;->getContentType()[B -Lcom/google/android/mms/pdu/RetrieveConf;->getDeliveryReport()I -Lcom/google/android/mms/pdu/RetrieveConf;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue; -Lcom/google/android/mms/pdu/RetrieveConf;->getMessageClass()[B -Lcom/google/android/mms/pdu/RetrieveConf;->getMessageId()[B -Lcom/google/android/mms/pdu/RetrieveConf;->getReadReport()I -Lcom/google/android/mms/pdu/RetrieveConf;->getRetrieveStatus()I -Lcom/google/android/mms/pdu/RetrieveConf;->getRetrieveText()Lcom/google/android/mms/pdu/EncodedStringValue; -Lcom/google/android/mms/pdu/RetrieveConf;->getTransactionId()[B -Lcom/google/android/mms/pdu/RetrieveConf;->setContentType([B)V -Lcom/google/android/mms/pdu/RetrieveConf;->setDeliveryReport(I)V -Lcom/google/android/mms/pdu/RetrieveConf;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/RetrieveConf;->setMessageClass([B)V -Lcom/google/android/mms/pdu/RetrieveConf;->setMessageId([B)V -Lcom/google/android/mms/pdu/RetrieveConf;->setReadReport(I)V -Lcom/google/android/mms/pdu/RetrieveConf;->setRetrieveStatus(I)V -Lcom/google/android/mms/pdu/RetrieveConf;->setRetrieveText(Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/RetrieveConf;->setTransactionId([B)V -Lcom/google/android/mms/pdu/SendConf;-><init>()V -Lcom/google/android/mms/pdu/SendConf;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V -Lcom/google/android/mms/pdu/SendConf;->getMessageId()[B -Lcom/google/android/mms/pdu/SendConf;->getResponseStatus()I -Lcom/google/android/mms/pdu/SendConf;->getTransactionId()[B -Lcom/google/android/mms/pdu/SendReq;-><init>()V -Lcom/google/android/mms/pdu/SendReq;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V -Lcom/google/android/mms/pdu/SendReq;->addBcc(Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/SendReq;->addCc(Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/SendReq;->getBcc()[Lcom/google/android/mms/pdu/EncodedStringValue; -Lcom/google/android/mms/pdu/SendReq;->getCc()[Lcom/google/android/mms/pdu/EncodedStringValue; -Lcom/google/android/mms/pdu/SendReq;->getContentType()[B -Lcom/google/android/mms/pdu/SendReq;->getDeliveryReport()I -Lcom/google/android/mms/pdu/SendReq;->getExpiry()J -Lcom/google/android/mms/pdu/SendReq;->getMessageClass()[B -Lcom/google/android/mms/pdu/SendReq;->getMessageSize()J -Lcom/google/android/mms/pdu/SendReq;->getReadReport()I -Lcom/google/android/mms/pdu/SendReq;->getTransactionId()[B -Lcom/google/android/mms/pdu/SendReq;->setBcc([Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/SendReq;->setCc([Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/SendReq;->setContentType([B)V -Lcom/google/android/mms/pdu/SendReq;->setDeliveryReport(I)V -Lcom/google/android/mms/pdu/SendReq;->setExpiry(J)V -Lcom/google/android/mms/pdu/SendReq;->setMessageClass([B)V -Lcom/google/android/mms/pdu/SendReq;->setMessageSize(J)V -Lcom/google/android/mms/pdu/SendReq;->setReadReport(I)V -Lcom/google/android/mms/pdu/SendReq;->setTo([Lcom/google/android/mms/pdu/EncodedStringValue;)V -Lcom/google/android/mms/pdu/SendReq;->setTransactionId([B)V -Lcom/google/android/mms/util/AbstractCache;-><init>()V -Lcom/google/android/mms/util/AbstractCache;->get(Ljava/lang/Object;)Ljava/lang/Object; -Lcom/google/android/mms/util/AbstractCache;->purge(Ljava/lang/Object;)Ljava/lang/Object; -Lcom/google/android/mms/util/AbstractCache;->purgeAll()V -Lcom/google/android/mms/util/AbstractCache;->put(Ljava/lang/Object;Ljava/lang/Object;)Z -Lcom/google/android/mms/util/DownloadDrmHelper;->isDrmConvertNeeded(Ljava/lang/String;)Z -Lcom/google/android/mms/util/DownloadDrmHelper;->modifyDrmFwLockFileExtension(Ljava/lang/String;)Ljava/lang/String; -Lcom/google/android/mms/util/DrmConvertSession;->close(Ljava/lang/String;)I -Lcom/google/android/mms/util/DrmConvertSession;->convert([BI)[B -Lcom/google/android/mms/util/DrmConvertSession;->open(Landroid/content/Context;Ljava/lang/String;)Lcom/google/android/mms/util/DrmConvertSession; -Lcom/google/android/mms/util/PduCache;-><init>()V -Lcom/google/android/mms/util/PduCache;->getInstance()Lcom/google/android/mms/util/PduCache; -Lcom/google/android/mms/util/PduCache;->isUpdating(Landroid/net/Uri;)Z -Lcom/google/android/mms/util/PduCache;->purge(Landroid/net/Uri;)Lcom/google/android/mms/util/PduCacheEntry; -Lcom/google/android/mms/util/PduCache;->purgeAll()V -Lcom/google/android/mms/util/PduCacheEntry;-><init>(Lcom/google/android/mms/pdu/GenericPdu;IJ)V -Lcom/google/android/mms/util/PduCacheEntry;->getMessageBox()I -Lcom/google/android/mms/util/PduCacheEntry;->getPdu()Lcom/google/android/mms/pdu/GenericPdu; -Lcom/google/android/mms/util/PduCacheEntry;->getThreadId()J -Lcom/google/android/mms/util/SqliteWrapper;->checkSQLiteException(Landroid/content/Context;Landroid/database/sqlite/SQLiteException;)V -Lcom/google/android/mms/util/SqliteWrapper;->delete(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;[Ljava/lang/String;)I -Lcom/google/android/mms/util/SqliteWrapper;->insert(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;)Landroid/net/Uri; -Lcom/google/android/mms/util/SqliteWrapper;->query(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor; -Lcom/google/android/mms/util/SqliteWrapper;->requery(Landroid/content/Context;Landroid/database/Cursor;)Z -Lcom/google/android/mms/util/SqliteWrapper;->update(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;)I Lcom/google/android/util/AbstractMessageParser$Token$Type;->values()[Lcom/google/android/util/AbstractMessageParser$Token$Type; diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 827e5408403a..4730bd0880a3 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -391,7 +391,8 @@ public abstract class AccessibilityService extends Service { void onPerformGestureResult(int sequence, boolean completedSuccessfully); void onFingerprintCapturingGesturesChanged(boolean active); void onFingerprintGesture(int gesture); - void onAccessibilityButtonClicked(); + /** Accessbility button clicked callbacks for different displays */ + void onAccessibilityButtonClicked(int displayId); void onAccessibilityButtonAvailabilityChanged(boolean available); } @@ -459,7 +460,8 @@ public abstract class AccessibilityService extends Service { private final SparseArray<MagnificationController> mMagnificationControllers = new SparseArray<>(0); private SoftKeyboardController mSoftKeyboardController; - private AccessibilityButtonController mAccessibilityButtonController; + private final SparseArray<AccessibilityButtonController> mAccessibilityButtonControllers = + new SparseArray<>(0); private int mGestureStatusCallbackSequence; @@ -1521,17 +1523,40 @@ public abstract class AccessibilityService extends Service { */ @NonNull public final AccessibilityButtonController getAccessibilityButtonController() { + return getAccessibilityButtonController(Display.DEFAULT_DISPLAY); + } + + /** + * Returns the controller of specified logical display for the accessibility button within the + * system's navigation area. This instance may be used to query the accessibility button's + * state and register listeners for interactions with and state changes for the accessibility + * button when {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} is set. + * <p> + * <strong>Note:</strong> Not all devices are capable of displaying the accessibility button + * within a navigation area, and as such, use of this class should be considered only as an + * optional feature or shortcut on supported device implementations. + * </p> + * + * @param displayId The logic display id, use {@link Display#DEFAULT_DISPLAY} for default + * display. + * @return the accessibility button controller for this {@link AccessibilityService} + */ + @NonNull + public final AccessibilityButtonController getAccessibilityButtonController(int displayId) { synchronized (mLock) { - if (mAccessibilityButtonController == null) { - mAccessibilityButtonController = new AccessibilityButtonController( + AccessibilityButtonController controller = mAccessibilityButtonControllers.get( + displayId); + if (controller == null) { + controller = new AccessibilityButtonController( AccessibilityInteractionClient.getInstance().getConnection(mConnectionId)); + mAccessibilityButtonControllers.put(displayId, controller); } - return mAccessibilityButtonController; + return controller; } } - private void onAccessibilityButtonClicked() { - getAccessibilityButtonController().dispatchAccessibilityButtonClicked(); + private void onAccessibilityButtonClicked(int displayId) { + getAccessibilityButtonController(displayId).dispatchAccessibilityButtonClicked(); } private void onAccessibilityButtonAvailabilityChanged(boolean available) { @@ -1737,8 +1762,8 @@ public abstract class AccessibilityService extends Service { } @Override - public void onAccessibilityButtonClicked() { - AccessibilityService.this.onAccessibilityButtonClicked(); + public void onAccessibilityButtonClicked(int displayId) { + AccessibilityService.this.onAccessibilityButtonClicked(displayId); } @Override @@ -1852,8 +1877,10 @@ public abstract class AccessibilityService extends Service { mCaller.sendMessage(mCaller.obtainMessageI(DO_ON_FINGERPRINT_GESTURE, gesture)); } - public void onAccessibilityButtonClicked() { - final Message message = mCaller.obtainMessage(DO_ACCESSIBILITY_BUTTON_CLICKED); + /** Accessibility button clicked callbacks for different displays */ + public void onAccessibilityButtonClicked(int displayId) { + final Message message = mCaller.obtainMessageI(DO_ACCESSIBILITY_BUTTON_CLICKED, + displayId); mCaller.sendMessage(message); } @@ -1987,7 +2014,7 @@ public abstract class AccessibilityService extends Service { case (DO_ACCESSIBILITY_BUTTON_CLICKED): { if (mConnectionId != AccessibilityInteractionClient.NO_ID) { - mCallback.onAccessibilityButtonClicked(); + mCallback.onAccessibilityButtonClicked(message.arg1); } } return; diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl index 407ba59c3297..e0d5e4438f23 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl @@ -52,7 +52,7 @@ import android.view.KeyEvent; void onFingerprintGesture(int gesture); - void onAccessibilityButtonClicked(); + void onAccessibilityButtonClicked(int displayId); void onAccessibilityButtonAvailabilityChanged(boolean available); } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 50f945b095cb..a6784780d72f 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -191,6 +191,8 @@ import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.lang.reflect.Method; import java.net.InetAddress; +import java.nio.file.Files; +import java.nio.file.Path; import java.text.DateFormat; import java.util.ArrayList; import java.util.Arrays; @@ -2492,13 +2494,15 @@ public final class ActivityThread extends ClientTransactionHandler { } } - private static final String HEAP_FULL_COLUMN - = "%13s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s"; - private static final String HEAP_COLUMN - = "%13s %8s %8s %8s %8s %8s %8s %8s"; + private static final String HEAP_FULL_COLUMN = + "%13s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s"; + private static final String HEAP_COLUMN = + "%13s %8s %8s %8s %8s %8s %8s %8s %8s"; private static final String ONE_COUNT_COLUMN = "%21s %8d"; private static final String TWO_COUNT_COLUMNS = "%21s %8d %21s %8d"; - private static final String ONE_COUNT_COLUMN_HEADER = "%21s %8s"; + private static final String THREE_COUNT_COLUMNS = "%21s %8d %21s %8s %21s %8d"; + private static final String TWO_COUNT_COLUMN_HEADER = "%21s %8s %21s %8s"; + private static final String ONE_ALT_COUNT_COLUMN = "%21s %8s %21s %8d"; // Formatting for checkin service - update version if row format changes private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 4; @@ -2619,43 +2623,43 @@ public final class ActivityThread extends ClientTransactionHandler { if (dumpFullInfo) { printRow(pw, HEAP_FULL_COLUMN, "", "Pss", "Pss", "Shared", "Private", "Shared", "Private", memInfo.hasSwappedOutPss ? "SwapPss" : "Swap", - "Heap", "Heap", "Heap"); + "Rss", "Heap", "Heap", "Heap"); printRow(pw, HEAP_FULL_COLUMN, "", "Total", "Clean", "Dirty", "Dirty", - "Clean", "Clean", "Dirty", + "Clean", "Clean", "Dirty", "Total", "Size", "Alloc", "Free"); printRow(pw, HEAP_FULL_COLUMN, "", "------", "------", "------", "------", - "------", "------", "------", "------", "------", "------"); + "------", "------", "------", "------", "------", "------", "------"); printRow(pw, HEAP_FULL_COLUMN, "Native Heap", memInfo.nativePss, memInfo.nativeSwappablePss, memInfo.nativeSharedDirty, memInfo.nativePrivateDirty, memInfo.nativeSharedClean, memInfo.nativePrivateClean, memInfo.hasSwappedOutPss ? memInfo.nativeSwappedOutPss : memInfo.nativeSwappedOut, - nativeMax, nativeAllocated, nativeFree); + memInfo.nativeRss, nativeMax, nativeAllocated, nativeFree); printRow(pw, HEAP_FULL_COLUMN, "Dalvik Heap", memInfo.dalvikPss, memInfo.dalvikSwappablePss, memInfo.dalvikSharedDirty, memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean, memInfo.dalvikPrivateClean, memInfo.hasSwappedOutPss ? memInfo.dalvikSwappedOutPss : memInfo.dalvikSwappedOut, - dalvikMax, dalvikAllocated, dalvikFree); + memInfo.dalvikRss, dalvikMax, dalvikAllocated, dalvikFree); } else { printRow(pw, HEAP_COLUMN, "", "Pss", "Private", "Private", memInfo.hasSwappedOutPss ? "SwapPss" : "Swap", - "Heap", "Heap", "Heap"); + "Rss", "Heap", "Heap", "Heap"); printRow(pw, HEAP_COLUMN, "", "Total", "Dirty", - "Clean", "Dirty", "Size", "Alloc", "Free"); + "Clean", "Dirty", "Total", "Size", "Alloc", "Free"); printRow(pw, HEAP_COLUMN, "", "------", "------", "------", - "------", "------", "------", "------", "------"); + "------", "------", "------", "------", "------", "------"); printRow(pw, HEAP_COLUMN, "Native Heap", memInfo.nativePss, memInfo.nativePrivateDirty, memInfo.nativePrivateClean, memInfo.hasSwappedOutPss ? memInfo.nativeSwappedOutPss : - memInfo.nativeSwappedOut, + memInfo.nativeSwappedOut, memInfo.nativeRss, nativeMax, nativeAllocated, nativeFree); printRow(pw, HEAP_COLUMN, "Dalvik Heap", memInfo.dalvikPss, memInfo.dalvikPrivateDirty, memInfo.dalvikPrivateClean, memInfo.hasSwappedOutPss ? memInfo.dalvikSwappedOutPss : - memInfo.dalvikSwappedOut, + memInfo.dalvikSwappedOut, memInfo.dalvikRss, dalvikMax, dalvikAllocated, dalvikFree); } @@ -2667,6 +2671,7 @@ public final class ActivityThread extends ClientTransactionHandler { int otherPrivateClean = memInfo.otherPrivateClean; int otherSwappedOut = memInfo.otherSwappedOut; int otherSwappedOutPss = memInfo.otherSwappedOutPss; + int otherRss = memInfo.otherRss; for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) { final int myPss = memInfo.getOtherPss(i); @@ -2677,21 +2682,22 @@ public final class ActivityThread extends ClientTransactionHandler { final int myPrivateClean = memInfo.getOtherPrivateClean(i); final int mySwappedOut = memInfo.getOtherSwappedOut(i); final int mySwappedOutPss = memInfo.getOtherSwappedOutPss(i); + final int myRss = memInfo.getOtherRss(i); if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0 - || mySharedClean != 0 || myPrivateClean != 0 + || mySharedClean != 0 || myPrivateClean != 0 || myRss != 0 || (memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut) != 0) { if (dumpFullInfo) { printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i), myPss, mySwappablePss, mySharedDirty, myPrivateDirty, mySharedClean, myPrivateClean, memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut, - "", "", ""); + myRss, "", "", ""); } else { printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i), myPss, myPrivateDirty, myPrivateClean, memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut, - "", "", ""); + myRss, "", "", ""); } otherPss -= myPss; otherSwappablePss -= mySwappablePss; @@ -2701,6 +2707,7 @@ public final class ActivityThread extends ClientTransactionHandler { otherPrivateClean -= myPrivateClean; otherSwappedOut -= mySwappedOut; otherSwappedOutPss -= mySwappedOutPss; + otherRss -= myRss; } } @@ -2708,25 +2715,25 @@ public final class ActivityThread extends ClientTransactionHandler { printRow(pw, HEAP_FULL_COLUMN, "Unknown", otherPss, otherSwappablePss, otherSharedDirty, otherPrivateDirty, otherSharedClean, otherPrivateClean, memInfo.hasSwappedOutPss ? otherSwappedOutPss : otherSwappedOut, - "", "", ""); + otherRss, "", "", ""); printRow(pw, HEAP_FULL_COLUMN, "TOTAL", memInfo.getTotalPss(), memInfo.getTotalSwappablePss(), memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(), memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(), memInfo.hasSwappedOutPss ? memInfo.getTotalSwappedOutPss() : - memInfo.getTotalSwappedOut(), + memInfo.getTotalSwappedOut(), memInfo.getTotalRss(), nativeMax+dalvikMax, nativeAllocated+dalvikAllocated, nativeFree+dalvikFree); } else { printRow(pw, HEAP_COLUMN, "Unknown", otherPss, otherPrivateDirty, otherPrivateClean, memInfo.hasSwappedOutPss ? otherSwappedOutPss : otherSwappedOut, - "", "", ""); + otherRss, "", "", ""); printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(), memInfo.getTotalPrivateDirty(), memInfo.getTotalPrivateClean(), memInfo.hasSwappedOutPss ? memInfo.getTotalSwappedOutPss() : - memInfo.getTotalSwappedOut(), + memInfo.getTotalSwappedOut(), memInfo.getTotalPss(), nativeMax+dalvikMax, nativeAllocated+dalvikAllocated, nativeFree+dalvikFree); } @@ -2745,6 +2752,7 @@ public final class ActivityThread extends ClientTransactionHandler { final int myPrivateClean = memInfo.getOtherPrivateClean(i); final int mySwappedOut = memInfo.getOtherSwappedOut(i); final int mySwappedOutPss = memInfo.getOtherSwappedOutPss(i); + final int myRss = memInfo.getOtherRss(i); if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0 || mySharedClean != 0 || myPrivateClean != 0 || (memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut) != 0) { @@ -2753,13 +2761,13 @@ public final class ActivityThread extends ClientTransactionHandler { myPss, mySwappablePss, mySharedDirty, myPrivateDirty, mySharedClean, myPrivateClean, memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut, - "", "", ""); + myRss, "", "", ""); } else { printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i), myPss, myPrivateDirty, myPrivateClean, memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut, - "", "", ""); + myRss, "", "", ""); } } } @@ -2768,31 +2776,36 @@ public final class ActivityThread extends ClientTransactionHandler { pw.println(" "); pw.println(" App Summary"); - printRow(pw, ONE_COUNT_COLUMN_HEADER, "", "Pss(KB)"); - printRow(pw, ONE_COUNT_COLUMN_HEADER, "", "------"); - printRow(pw, ONE_COUNT_COLUMN, - "Java Heap:", memInfo.getSummaryJavaHeap()); - printRow(pw, ONE_COUNT_COLUMN, - "Native Heap:", memInfo.getSummaryNativeHeap()); - printRow(pw, ONE_COUNT_COLUMN, - "Code:", memInfo.getSummaryCode()); - printRow(pw, ONE_COUNT_COLUMN, - "Stack:", memInfo.getSummaryStack()); - printRow(pw, ONE_COUNT_COLUMN, - "Graphics:", memInfo.getSummaryGraphics()); + printRow(pw, TWO_COUNT_COLUMN_HEADER, "", "Pss(KB)", "", "Rss(KB)"); + printRow(pw, TWO_COUNT_COLUMN_HEADER, "", "------", "", "------"); + printRow(pw, TWO_COUNT_COLUMNS, + "Java Heap:", memInfo.getSummaryJavaHeap(), "", memInfo.getSummaryJavaHeapRss()); + printRow(pw, TWO_COUNT_COLUMNS, + "Native Heap:", memInfo.getSummaryNativeHeap(), "", + memInfo.getSummaryNativeHeapRss()); + printRow(pw, TWO_COUNT_COLUMNS, + "Code:", memInfo.getSummaryCode(), "", memInfo.getSummaryCodeRss()); + printRow(pw, TWO_COUNT_COLUMNS, + "Stack:", memInfo.getSummaryStack(), "", memInfo.getSummaryStackRss()); + printRow(pw, TWO_COUNT_COLUMNS, + "Graphics:", memInfo.getSummaryGraphics(), "", memInfo.getSummaryGraphicsRss()); printRow(pw, ONE_COUNT_COLUMN, - "Private Other:", memInfo.getSummaryPrivateOther()); + "Private Other:", memInfo.getSummaryPrivateOther()); printRow(pw, ONE_COUNT_COLUMN, - "System:", memInfo.getSummarySystem()); + "System:", memInfo.getSummarySystem()); + printRow(pw, ONE_ALT_COUNT_COLUMN, + "Unknown:", "", "", memInfo.getSummaryUnknownRss()); pw.println(" "); if (memInfo.hasSwappedOutPss) { - printRow(pw, TWO_COUNT_COLUMNS, - "TOTAL:", memInfo.getSummaryTotalPss(), - "TOTAL SWAP PSS:", memInfo.getSummaryTotalSwapPss()); + printRow(pw, THREE_COUNT_COLUMNS, + "TOTAL PSS:", memInfo.getSummaryTotalPss(), + "TOTAL RSS:", memInfo.getTotalRss(), + "TOTAL SWAP PSS:", memInfo.getSummaryTotalSwapPss()); } else { - printRow(pw, TWO_COUNT_COLUMNS, - "TOTAL:", memInfo.getSummaryTotalPss(), - "TOTAL SWAP (KB):", memInfo.getSummaryTotalSwap()); + printRow(pw, THREE_COUNT_COLUMNS, + "TOTAL PSS:", memInfo.getSummaryTotalPss(), + "TOTAL RSS:", memInfo.getTotalRss(), + "TOTAL SWAP (KB):", memInfo.getSummaryTotalSwap()); } } @@ -2804,7 +2817,7 @@ public final class ActivityThread extends ClientTransactionHandler { private static void dumpMemoryInfo(ProtoOutputStream proto, long fieldId, String name, int pss, int cleanPss, int sharedDirty, int privateDirty, int sharedClean, int privateClean, - boolean hasSwappedOutPss, int dirtySwap, int dirtySwapPss) { + boolean hasSwappedOutPss, int dirtySwap, int dirtySwapPss, int rss) { final long token = proto.start(fieldId); proto.write(MemInfoDumpProto.ProcessMemory.MemoryInfo.NAME, name); @@ -2819,6 +2832,7 @@ public final class ActivityThread extends ClientTransactionHandler { } else { proto.write(MemInfoDumpProto.ProcessMemory.MemoryInfo.DIRTY_SWAP_KB, dirtySwap); } + proto.write(MemInfoDumpProto.ProcessMemory.MemoryInfo.TOTAL_RSS_KB, rss); proto.end(token); } @@ -2837,7 +2851,8 @@ public final class ActivityThread extends ClientTransactionHandler { memInfo.nativePss, memInfo.nativeSwappablePss, memInfo.nativeSharedDirty, memInfo.nativePrivateDirty, memInfo.nativeSharedClean, memInfo.nativePrivateClean, memInfo.hasSwappedOutPss, - memInfo.nativeSwappedOut, memInfo.nativeSwappedOutPss); + memInfo.nativeSwappedOut, memInfo.nativeSwappedOutPss, + memInfo.nativeRss); proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_SIZE_KB, nativeMax); proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_ALLOC_KB, nativeAllocated); proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_FREE_KB, nativeFree); @@ -2848,7 +2863,8 @@ public final class ActivityThread extends ClientTransactionHandler { memInfo.dalvikPss, memInfo.dalvikSwappablePss, memInfo.dalvikSharedDirty, memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean, memInfo.dalvikPrivateClean, memInfo.hasSwappedOutPss, - memInfo.dalvikSwappedOut, memInfo.dalvikSwappedOutPss); + memInfo.dalvikSwappedOut, memInfo.dalvikSwappedOutPss, + memInfo.dalvikRss); proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_SIZE_KB, dalvikMax); proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_ALLOC_KB, dalvikAllocated); proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_FREE_KB, dalvikFree); @@ -2862,6 +2878,7 @@ public final class ActivityThread extends ClientTransactionHandler { int otherPrivateClean = memInfo.otherPrivateClean; int otherSwappedOut = memInfo.otherSwappedOut; int otherSwappedOutPss = memInfo.otherSwappedOutPss; + int otherRss = memInfo.otherRss; for (int i = 0; i < Debug.MemoryInfo.NUM_OTHER_STATS; i++) { final int myPss = memInfo.getOtherPss(i); @@ -2872,14 +2889,15 @@ public final class ActivityThread extends ClientTransactionHandler { final int myPrivateClean = memInfo.getOtherPrivateClean(i); final int mySwappedOut = memInfo.getOtherSwappedOut(i); final int mySwappedOutPss = memInfo.getOtherSwappedOutPss(i); + final int myRss = memInfo.getOtherRss(i); if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0 - || mySharedClean != 0 || myPrivateClean != 0 + || mySharedClean != 0 || myPrivateClean != 0 || myRss != 0 || (memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut) != 0) { dumpMemoryInfo(proto, MemInfoDumpProto.ProcessMemory.OTHER_HEAPS, Debug.MemoryInfo.getOtherLabel(i), myPss, mySwappablePss, mySharedDirty, myPrivateDirty, mySharedClean, myPrivateClean, - memInfo.hasSwappedOutPss, mySwappedOut, mySwappedOutPss); + memInfo.hasSwappedOutPss, mySwappedOut, mySwappedOutPss, myRss); otherPss -= myPss; otherSwappablePss -= mySwappablePss; @@ -2889,20 +2907,21 @@ public final class ActivityThread extends ClientTransactionHandler { otherPrivateClean -= myPrivateClean; otherSwappedOut -= mySwappedOut; otherSwappedOutPss -= mySwappedOutPss; + otherRss -= myRss; } } dumpMemoryInfo(proto, MemInfoDumpProto.ProcessMemory.UNKNOWN_HEAP, "Unknown", otherPss, otherSwappablePss, otherSharedDirty, otherPrivateDirty, otherSharedClean, otherPrivateClean, - memInfo.hasSwappedOutPss, otherSwappedOut, otherSwappedOutPss); + memInfo.hasSwappedOutPss, otherSwappedOut, otherSwappedOutPss, otherRss); final long tToken = proto.start(MemInfoDumpProto.ProcessMemory.TOTAL_HEAP); dumpMemoryInfo(proto, MemInfoDumpProto.ProcessMemory.HeapInfo.MEM_INFO, "TOTAL", memInfo.getTotalPss(), memInfo.getTotalSwappablePss(), memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(), memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(), memInfo.hasSwappedOutPss, memInfo.getTotalSwappedOut(), - memInfo.getTotalSwappedOutPss()); + memInfo.getTotalSwappedOutPss(), memInfo.getTotalRss()); proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_SIZE_KB, nativeMax + dalvikMax); proto.write(MemInfoDumpProto.ProcessMemory.HeapInfo.HEAP_ALLOC_KB, @@ -2923,6 +2942,7 @@ public final class ActivityThread extends ClientTransactionHandler { final int myPrivateClean = memInfo.getOtherPrivateClean(i); final int mySwappedOut = memInfo.getOtherSwappedOut(i); final int mySwappedOutPss = memInfo.getOtherSwappedOutPss(i); + final int myRss = memInfo.getOtherRss(i); if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0 || mySharedClean != 0 || myPrivateClean != 0 || (memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut) != 0) { @@ -2930,7 +2950,7 @@ public final class ActivityThread extends ClientTransactionHandler { Debug.MemoryInfo.getOtherLabel(i), myPss, mySwappablePss, mySharedDirty, myPrivateDirty, mySharedClean, myPrivateClean, - memInfo.hasSwappedOutPss, mySwappedOut, mySwappedOutPss); + memInfo.hasSwappedOutPss, mySwappedOut, mySwappedOutPss, myRss); } } } @@ -2958,6 +2978,19 @@ public final class ActivityThread extends ClientTransactionHandler { proto.write(MemInfoDumpProto.ProcessMemory.AppSummary.TOTAL_SWAP_PSS, memInfo.getSummaryTotalSwap()); } + proto.write(MemInfoDumpProto.ProcessMemory.AppSummary.JAVA_HEAP_RSS_KB, + memInfo.getSummaryJavaHeapRss()); + proto.write(MemInfoDumpProto.ProcessMemory.AppSummary.NATIVE_HEAP_RSS_KB, + memInfo.getSummaryNativeHeapRss()); + proto.write(MemInfoDumpProto.ProcessMemory.AppSummary.CODE_RSS_KB, + memInfo.getSummaryCodeRss()); + proto.write(MemInfoDumpProto.ProcessMemory.AppSummary.STACK_RSS_KB, + memInfo.getSummaryStackRss()); + proto.write(MemInfoDumpProto.ProcessMemory.AppSummary.GRAPHICS_RSS_KB, + memInfo.getSummaryGraphicsRss()); + proto.write(MemInfoDumpProto.ProcessMemory.AppSummary.UNKNOWN_RSS_KB, + memInfo.getSummaryUnknownRss()); + proto.end(asToken); } @@ -6404,6 +6437,26 @@ public final class ActivityThread extends ClientTransactionHandler { NetworkSecurityConfigProvider.install(appContext); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + + if (isAppDebuggable) { + try { + // Load all the agents in the code_cache/startup_agents directory. + // We pass the absolute path to the data_dir as an argument. + Path startup_path = appContext.getCodeCacheDir().toPath().resolve("startup_agents"); + if (Files.exists(startup_path)) { + for (Path p : Files.newDirectoryStream(startup_path)) { + handleAttachAgent( + p.toAbsolutePath().toString() + + "=" + + appContext.getDataDir().toPath().toAbsolutePath().toString(), + data.info); + } + } + } catch (Exception e) { + // Ignored. + } + } + // Continue loading instrumentation. if (ii != null) { ApplicationInfo instrApp; diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index 41733b3af058..9720e9f47f83 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -50,6 +50,7 @@ import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.MotionEvent; +import android.view.SurfaceControl; import android.view.ViewConfiguration; import android.view.Window; import android.view.WindowManagerGlobal; @@ -528,6 +529,12 @@ public class Instrumentation { } while (mWaitingActivities.contains(aw)); waitForEnterAnimationComplete(aw.activity); + + // Apply an empty transaction to ensure SF has a chance to update before + // the Activity is ready (b/138263890). + try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) { + t.apply(true); + } return aw.activity; } } diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index c58972e5310e..635b9b02a944 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -112,7 +112,6 @@ import android.net.lowpan.ILowpanManager; import android.net.lowpan.LowpanManager; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; -import android.net.wifi.IWifiManager; import android.net.wifi.IWifiScanner; import android.net.wifi.RttManager; import android.net.wifi.WifiManager; @@ -730,10 +729,8 @@ public final class SystemServiceRegistry { registerService(Context.WIFI_SERVICE, WifiManager.class, new CachedServiceFetcher<WifiManager>() { @Override - public WifiManager createService(ContextImpl ctx) throws ServiceNotFoundException { - IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_SERVICE); - IWifiManager service = IWifiManager.Stub.asInterface(b); - return new WifiManager(ctx.getOuterContext(), service, + public WifiManager createService(ContextImpl ctx) { + return new WifiManager(ctx.getOuterContext(), ConnectivityThread.getInstanceLooper()); }}); @@ -1166,7 +1163,8 @@ public final class SystemServiceRegistry { @Override public AppPredictionManager createService(ContextImpl ctx) throws ServiceNotFoundException { - return new AppPredictionManager(ctx); + IBinder b = ServiceManager.getService(Context.APP_PREDICTION_SERVICE); + return b == null ? null : new AppPredictionManager(ctx); } }); diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 2b74b99c8071..f9b96c50e0b8 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -242,7 +242,7 @@ public final class UiAutomation { mUiAutomationConnection.connect(mClient, flags); mFlags = flags; } catch (RemoteException re) { - throw new RuntimeException("Error while connecting UiAutomation", re); + throw new RuntimeException("Error while connecting " + this, re); } synchronized (mLock) { @@ -255,7 +255,7 @@ public final class UiAutomation { final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; final long remainingTimeMillis = CONNECT_TIMEOUT_MILLIS - elapsedTimeMillis; if (remainingTimeMillis <= 0) { - throw new RuntimeException("Error while connecting UiAutomation"); + throw new RuntimeException("Error while connecting " + this); } try { mLock.wait(remainingTimeMillis); @@ -290,7 +290,7 @@ public final class UiAutomation { synchronized (mLock) { if (mIsConnecting) { throw new IllegalStateException( - "Cannot call disconnect() while connecting!"); + "Cannot call disconnect() while connecting " + this); } throwIfNotConnectedLocked(); mConnectionId = CONNECTION_ID_UNDEFINED; @@ -299,7 +299,7 @@ public final class UiAutomation { // Calling out without a lock held. mUiAutomationConnection.disconnect(); } catch (RemoteException re) { - throw new RuntimeException("Error while disconnecting UiAutomation", re); + throw new RuntimeException("Error while disconnecting " + this, re); } finally { mRemoteCallbackThread.quit(); mRemoteCallbackThread = null; @@ -1184,19 +1184,29 @@ public final class UiAutomation { return result; } + @Override + public String toString() { + final StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("UiAutomation@").append(Integer.toHexString(hashCode())); + stringBuilder.append("[id=").append(mConnectionId); + stringBuilder.append(", flags=").append(mFlags); + stringBuilder.append("]"); + return stringBuilder.toString(); + } + private boolean isConnectedLocked() { return mConnectionId != CONNECTION_ID_UNDEFINED; } private void throwIfConnectedLocked() { if (mConnectionId != CONNECTION_ID_UNDEFINED) { - throw new IllegalStateException("UiAutomation not connected!"); + throw new IllegalStateException("UiAutomation not connected, " + this); } } private void throwIfNotConnectedLocked() { if (!isConnectedLocked()) { - throw new IllegalStateException("UiAutomation not connected!"); + throw new IllegalStateException("UiAutomation not connected, " + this); } } @@ -1220,6 +1230,9 @@ public final class UiAutomation { mConnectionId = connectionId; mLock.notifyAll(); } + if (Build.IS_DEBUGGABLE) { + Log.v(LOG_TAG, "Init " + UiAutomation.this); + } } @Override @@ -1289,7 +1302,7 @@ public final class UiAutomation { } @Override - public void onAccessibilityButtonClicked() { + public void onAccessibilityButtonClicked(int displayId) { /* do nothing */ } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 49cfd41f1773..ff5a043b9336 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -4991,26 +4991,60 @@ public class DevicePolicyManager { * call {@link android.security.KeyChain#choosePrivateKeyAlias} first. * * The grantee app will receive the {@link android.security.KeyChain#ACTION_KEY_ACCESS_CHANGED} - * broadcast when access to a key is granted or revoked. + * broadcast when access to a key is granted. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or * {@code null} if calling from a delegated certificate installer. * @param alias The alias of the key to grant access to. * @param packageName The name of the (already installed) package to grant access to. - * @param hasGrant Whether to grant access to the alias or revoke it. * @return {@code true} if the grant was set successfully, {@code false} otherwise. * - * @throws SecurityException if the caller is not a device owner, a profile owner or + * @throws SecurityException if the caller is not a device owner, a profile owner or * delegated certificate chooser. * @throws IllegalArgumentException if {@code packageName} or {@code alias} are empty, or if * {@code packageName} is not a name of an installed package. + * @see #revokeKeyPairFromApp */ - public boolean setKeyGrantForApp(@Nullable ComponentName admin, @NonNull String alias, - @NonNull String packageName, boolean hasGrant) { - throwIfParentInstance("addKeyGrant"); + public boolean grantKeyPairToApp(@Nullable ComponentName admin, @NonNull String alias, + @NonNull String packageName) { + throwIfParentInstance("grantKeyPairToApp"); + try { + return mService.setKeyGrantForApp( + admin, mContext.getPackageName(), alias, packageName, true); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + return false; + } + + /** + * Called by a device or profile owner, or delegated certificate chooser (an app that has been + * delegated the {@link #DELEGATION_CERT_SELECTION} privilege), to revoke an application's + * grant to a KeyChain key pair. + * Calls by the application to {@link android.security.KeyChain#getPrivateKey} + * will fail after the grant is revoked. + * + * The grantee app will receive the {@link android.security.KeyChain#ACTION_KEY_ACCESS_CHANGED} + * broadcast when access to a key is revoked. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. + * @param alias The alias of the key to revoke access from. + * @param packageName The name of the (already installed) package to revoke access from. + * @return {@code true} if the grant was revoked successfully, {@code false} otherwise. + * + * @throws SecurityException if the caller is not a device owner, a profile owner or + * delegated certificate chooser. + * @throws IllegalArgumentException if {@code packageName} or {@code alias} are empty, or if + * {@code packageName} is not a name of an installed package. + * @see #grantKeyPairToApp + */ + public boolean revokeKeyPairFromApp(@Nullable ComponentName admin, @NonNull String alias, + @NonNull String packageName) { + throwIfParentInstance("revokeKeyPairFromApp"); try { return mService.setKeyGrantForApp( - admin, mContext.getPackageName(), alias, packageName, hasGrant); + admin, mContext.getPackageName(), alias, packageName, false); } catch (RemoteException e) { e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java index 0ccd49f2e028..5e530eedd818 100644 --- a/core/java/android/app/slice/SliceProvider.java +++ b/core/java/android/app/slice/SliceProvider.java @@ -355,7 +355,8 @@ public abstract class SliceProvider extends ContentProvider { @Override public Bundle call(String method, String arg, Bundle extras) { if (method.equals(METHOD_SLICE)) { - Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI)); + Uri uri = getUriWithoutUserId(validateIncomingUriOrNull( + extras.getParcelable(EXTRA_BIND_URI))); List<SliceSpec> supportedSpecs = extras.getParcelableArrayList(EXTRA_SUPPORTED_SPECS); String callingPackage = getCallingPackage(); @@ -369,7 +370,7 @@ public abstract class SliceProvider extends ContentProvider { } else if (method.equals(METHOD_MAP_INTENT)) { Intent intent = extras.getParcelable(EXTRA_INTENT); if (intent == null) return null; - Uri uri = onMapIntentToUri(intent); + Uri uri = validateIncomingUriOrNull(onMapIntentToUri(intent)); List<SliceSpec> supportedSpecs = extras.getParcelableArrayList(EXTRA_SUPPORTED_SPECS); Bundle b = new Bundle(); if (uri != null) { @@ -383,24 +384,27 @@ public abstract class SliceProvider extends ContentProvider { } else if (method.equals(METHOD_MAP_ONLY_INTENT)) { Intent intent = extras.getParcelable(EXTRA_INTENT); if (intent == null) return null; - Uri uri = onMapIntentToUri(intent); + Uri uri = validateIncomingUriOrNull(onMapIntentToUri(intent)); Bundle b = new Bundle(); b.putParcelable(EXTRA_SLICE, uri); return b; } else if (method.equals(METHOD_PIN)) { - Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI)); + Uri uri = getUriWithoutUserId(validateIncomingUriOrNull( + extras.getParcelable(EXTRA_BIND_URI))); if (Binder.getCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("Only the system can pin/unpin slices"); } handlePinSlice(uri); } else if (method.equals(METHOD_UNPIN)) { - Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI)); + Uri uri = getUriWithoutUserId(validateIncomingUriOrNull( + extras.getParcelable(EXTRA_BIND_URI))); if (Binder.getCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("Only the system can pin/unpin slices"); } handleUnpinSlice(uri); } else if (method.equals(METHOD_GET_DESCENDANTS)) { - Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI)); + Uri uri = getUriWithoutUserId( + validateIncomingUriOrNull(extras.getParcelable(EXTRA_BIND_URI))); Bundle b = new Bundle(); b.putParcelableArrayList(EXTRA_SLICE_DESCENDANTS, new ArrayList<>(handleGetDescendants(uri))); @@ -416,6 +420,10 @@ public abstract class SliceProvider extends ContentProvider { return super.call(method, arg, extras); } + private Uri validateIncomingUriOrNull(Uri uri) { + return uri == null ? null : validateIncomingUri(uri); + } + private Collection<Uri> handleGetDescendants(Uri uri) { mCallback = "onGetSliceDescendants"; return onGetSliceDescendants(uri); diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java index e4114c66bac7..ac40150376da 100644 --- a/core/java/android/companion/AssociationRequest.java +++ b/core/java/android/companion/AssociationRequest.java @@ -127,6 +127,12 @@ public final class AssociationRequest implements Parcelable { public Builder() {} /** + * Whether only a single device should match the provided filter. + * + * When scanning for a single device with a specifc {@link BluetoothDeviceFilter} mac + * address, bonded devices are also searched among. This allows to obtain the necessary app + * privileges even if the device is already paired. + * * @param singleDevice if true, scanning for a device will stop as soon as at least one * fitting device is found */ diff --git a/services/core/java/com/android/server/compat/IPlatformCompat.aidl b/core/java/android/compat/IPlatformCompat.aidl index 8ab08f9047cb..3d8a9d5c5e86 100644 --- a/services/core/java/com/android/server/compat/IPlatformCompat.aidl +++ b/core/java/android/compat/IPlatformCompat.aidl @@ -14,12 +14,16 @@ * limitations under the License. */ -package com.android.server.compat; +package android.compat; import android.content.pm.ApplicationInfo; /** - * System private API for talking with the PlatformCompat service. + * Platform private API for talking with the PlatformCompat service. + * + * <p> Should be used for gating and logging from non-app processes. + * For app processes please use android.compat.Compatibility API. + * * {@hide} */ interface IPlatformCompat diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 4ea3726bee6d..f297c0631a30 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -17,6 +17,7 @@ package android.content; import static android.Manifest.permission.INTERACT_ACROSS_USERS; +import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_DEFAULT; import static android.app.AppOpsManager.MODE_ERRORED; @@ -645,9 +646,11 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall } boolean checkUser(int pid, int uid, Context context) { - return UserHandle.getUserId(uid) == context.getUserId() - || mSingleUser - || context.checkPermission(INTERACT_ACROSS_USERS, pid, uid) + if (UserHandle.getUserId(uid) == context.getUserId() || mSingleUser) { + return true; + } + return context.checkPermission(INTERACT_ACROSS_USERS, pid, uid) == PERMISSION_GRANTED + || context.checkPermission(INTERACT_ACROSS_USERS_FULL, pid, uid) == PERMISSION_GRANTED; } @@ -1030,10 +1033,12 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall /** @hide */ public final void setTransportLoggingEnabled(boolean enabled) { - if (enabled) { - mTransport.mInterface = new LoggingContentInterface(getClass().getSimpleName(), this); - } else { - mTransport.mInterface = this; + if (mTransport != null) { + if (enabled) { + mTransport.mInterface = new LoggingContentInterface(getClass().getSimpleName(), this); + } else { + mTransport.mInterface = this; + } } } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 73bc908632b2..2c53faa5c890 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -38,6 +38,7 @@ import android.app.ActivityManager; import android.app.IApplicationThread; import android.app.IServiceConnection; import android.app.VrManager; +import android.compat.IPlatformCompat; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; @@ -3228,6 +3229,7 @@ public abstract class Context { ROLE_SERVICE, //@hide ROLE_CONTROLLER_SERVICE, CAMERA_SERVICE, + //@hide: PLATFORM_COMPAT_SERVICE, PRINT_SERVICE, CONSUMER_IR_SERVICE, //@hide: TRUST_SERVICE, @@ -3735,6 +3737,14 @@ public abstract class Context { public static final String NETWORK_STACK_SERVICE = "network_stack"; /** + * Use with {@link android.os.ServiceManager.getService()} to retrieve a + * {@link android.net.WifiStackClient} IBinder for communicating with the network stack + * @hide + * @see android.net.WifiStackClient + */ + public static final String WIFI_STACK_SERVICE = "wifi_stack"; + + /** * Use with {@link #getSystemService(String)} to retrieve a * {@link android.net.IpSecManager} for encrypting Sockets or Networks with * IPSec. @@ -4109,6 +4119,9 @@ public abstract class Context { /** * Official published name of the app prediction service. * + * <p><b>NOTE: </b> this service is optional; callers of + * {@code Context.getSystemServiceName(APP_PREDICTION_SERVICE)} should check for {@code null}. + * * @hide * @see #getSystemService(String) */ @@ -4586,6 +4599,13 @@ public abstract class Context { public static final String STATS_MANAGER = "stats"; /** + * Use with {@link android.os.ServiceManager.getService()} to retrieve a + * {@link IPlatformCompat} IBinder for communicating with the platform compat service. + * @hide + */ + public static final String PLATFORM_COMPAT_SERVICE = "platform_compat"; + + /** * Service to capture a bugreport. * @see #getSystemService(String) * @see android.os.BugreportManager diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 895eba6cdec2..c561013e6768 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -38,6 +38,8 @@ import android.app.PackageDeleteObserver; import android.app.PackageInstallObserver; import android.app.admin.DevicePolicyManager; import android.app.usage.StorageStatsManager; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledAfter; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -3369,6 +3371,17 @@ public abstract class PackageManager { */ public static final int VERSION_CODE_HIGHEST = -1; + /** + * Apps targeting Android R and above will need to declare the packages and intents they intend + * to use to get details about other apps on a device. Such declarations must be made via the + * {@code <queries>} tag in the manifest. + * + * @hide + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) + public static final long FILTER_APPLICATION_QUERY = 135549675L; + /** {@hide} */ public int getUserId() { return UserHandle.myUserId(); diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 2f198acde06d..f50502e0a331 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -675,12 +675,6 @@ public abstract class PackageManagerInternal { "android.content.pm.extra.ENABLE_ROLLBACK_INSTALL_FLAGS"; /** - * Extra field name for the set of installed users for a given rollback package. - */ - public static final String EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS = - "android.content.pm.extra.ENABLE_ROLLBACK_INSTALLED_USERS"; - - /** * Extra field name for the user id an install is associated with when * enabling rollback. */ diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index 7865d75d839c..fcdc81cf7533 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -16,14 +16,32 @@ package android.content.pm; +import android.annotation.IntDef; import android.annotation.UnsupportedAppUsage; +import android.annotation.UserIdInt; import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; import android.os.UserManager; +import android.util.DebugUtils; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * Per-user information. + * + * <p>There are 3 base properties of users: {@link #FLAG_SYSTEM}, {@link #FLAG_FULL}, and + * {@link #FLAG_MANAGED_PROFILE}. Every user must have one of the following combination of these + * flags: + * <ul> + * <li>FLAG_SYSTEM (user {@link UserHandle#USER_SYSTEM} on a headless-user-0 device)</li> + * <li>FLAG_SYSTEM and FLAG_FULL (user {@link UserHandle#USER_SYSTEM} on a regular device)</li> + * <li>FLAG_FULL (non-profile secondary user)</li> + * <li>FLAG_MANAGED_PROFILE (profile users)</li> + * </ul> + * Users can have also have additional flags (such as FLAG_GUEST) as appropriate. + * * @hide */ public class UserInfo implements Parcelable { @@ -93,10 +111,45 @@ public class UserInfo implements Parcelable { */ public static final int FLAG_DEMO = 0x00000200; + /** + * Indicates that this user is a non-profile human user. + * + * <p>When creating a new (non-system) user, this flag will always be forced true unless the + * user is a {@link #FLAG_MANAGED_PROFILE}. If user {@link UserHandle#USER_SYSTEM} is also a + * human user, it must also be flagged as FULL. + */ + public static final int FLAG_FULL = 0x00000400; + + /** + * Indicates that this user is {@link UserHandle#USER_SYSTEM}. Not applicable to created users. + */ + public static final int FLAG_SYSTEM = 0x00000800; + + /** + * @hide + */ + @IntDef(flag = true, prefix = "FLAG_", value = { + FLAG_PRIMARY, + FLAG_ADMIN, + FLAG_GUEST, + FLAG_RESTRICTED, + FLAG_INITIALIZED, + FLAG_MANAGED_PROFILE, + FLAG_DISABLED, + FLAG_QUIET_MODE, + FLAG_EPHEMERAL, + FLAG_DEMO, + FLAG_FULL, + FLAG_SYSTEM + }) + @Retention(RetentionPolicy.SOURCE) + public @interface UserInfoFlag { + } + public static final int NO_PROFILE_GROUP_ID = UserHandle.USER_NULL; @UnsupportedAppUsage - public int id; + public @UserIdInt int id; @UnsupportedAppUsage public int serialNumber; @UnsupportedAppUsage @@ -104,7 +157,7 @@ public class UserInfo implements Parcelable { @UnsupportedAppUsage public String iconPath; @UnsupportedAppUsage - public int flags; + public @UserInfoFlag int flags; @UnsupportedAppUsage public long creationTime; @UnsupportedAppUsage @@ -188,6 +241,10 @@ public class UserInfo implements Parcelable { return (flags & FLAG_DEMO) == FLAG_DEMO; } + public boolean isFull() { + return (flags & FLAG_FULL) == FLAG_FULL; + } + /** * Returns true if the user is a split system user. * <p>If {@link UserManager#isSplitSystemUser split system user mode} is not enabled, @@ -264,13 +321,23 @@ public class UserInfo implements Parcelable { @Override public String toString() { + // NOTE: do not change this string, it's used by 'pm list users', which in turn is + // used and parsed by TestDevice. In other words, if you change it, you'd have to change + // TestDevice, TestDeviceTest, and possibly others.... return "UserInfo{" + id + ":" + name + ":" + Integer.toHexString(flags) + "}"; } + /** @hide */ + public static String flagsToString(int flags) { + return DebugUtils.flagsToString(UserInfo.class, "FLAG_", flags); + } + + @Override public int describeContents() { return 0; } + @Override public void writeToParcel(Parcel dest, int parcelableFlags) { dest.writeInt(id); dest.writeString(name); diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java index 201475130753..c89796d4b1da 100644 --- a/core/java/android/content/rollback/PackageRollbackInfo.java +++ b/core/java/android/content/rollback/PackageRollbackInfo.java @@ -76,10 +76,10 @@ public final class PackageRollbackInfo implements Parcelable { private final boolean mIsApex; /* - * The list of users the package is installed for. + * The list of users for which snapshots have been saved. */ // NOTE: Not a part of the Parcelable representation of this object. - private final IntArray mInstalledUsers; + private final IntArray mSnapshottedUsers; /** * A mapping between user and an inode of theirs CE data snapshot. @@ -148,8 +148,8 @@ public final class PackageRollbackInfo implements Parcelable { } /** @hide */ - public IntArray getInstalledUsers() { - return mInstalledUsers; + public IntArray getSnapshottedUsers() { + return mSnapshottedUsers; } /** @hide */ @@ -179,14 +179,14 @@ public final class PackageRollbackInfo implements Parcelable { public PackageRollbackInfo(VersionedPackage packageRolledBackFrom, VersionedPackage packageRolledBackTo, @NonNull IntArray pendingBackups, @NonNull ArrayList<RestoreInfo> pendingRestores, - boolean isApex, @NonNull IntArray installedUsers, + boolean isApex, @NonNull IntArray snapshottedUsers, @NonNull SparseLongArray ceSnapshotInodes) { this.mVersionRolledBackFrom = packageRolledBackFrom; this.mVersionRolledBackTo = packageRolledBackTo; this.mPendingBackups = pendingBackups; this.mPendingRestores = pendingRestores; this.mIsApex = isApex; - this.mInstalledUsers = installedUsers; + this.mSnapshottedUsers = snapshottedUsers; this.mCeSnapshotInodes = ceSnapshotInodes; } @@ -196,7 +196,7 @@ public final class PackageRollbackInfo implements Parcelable { this.mIsApex = in.readBoolean(); this.mPendingRestores = null; this.mPendingBackups = null; - this.mInstalledUsers = null; + this.mSnapshottedUsers = null; this.mCeSnapshotInodes = null; } diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java index 73b8a48d9153..1609f53d3d3b 100644 --- a/core/java/android/content/rollback/RollbackManager.java +++ b/core/java/android/content/rollback/RollbackManager.java @@ -74,7 +74,10 @@ public final class RollbackManager { } /** - * Returns a list of all currently available rollbacks. + * Returns a list of all currently available rollbacks. This includes ones for very recently + * installed packages (even if onFinished has not yet been called). As a result, packages that + * very recently failed to install may also be included, but those rollbacks will fail with + * 'rollback not available'. * * @throws SecurityException if the caller does not have appropriate permissions. */ diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java index 099ae291c8f4..e78fb7f00797 100644 --- a/core/java/android/hardware/Sensor.java +++ b/core/java/android/hardware/Sensor.java @@ -339,6 +339,8 @@ public final class Sensor { * for {@link #TYPE_STEP_COUNTER} instead. It is defined as a * {@link Sensor#REPORTING_MODE_SPECIAL_TRIGGER} sensor. * <p> + * This sensor requires permission {@code android.permission.ACTIVITY_RECOGNITION}. + * <p> * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details. */ public static final int TYPE_STEP_DETECTOR = 18; @@ -384,8 +386,6 @@ public final class Sensor { * gyroscope. This sensor uses lower power than the other rotation vectors, because it doesn't * use the gyroscope. However, it is more noisy and will work best outdoors. * <p> - * This sensor requires permission {@code android.permission.ACTIVITY_RECOGNITION}. - * <p> * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details. */ public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20; diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index 1142a07bc66c..fb6b231632f1 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -100,9 +100,12 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan /** * @hide */ - public static final int DISMISSED_REASON_POSITIVE = 1; + public static final int DISMISSED_REASON_CONFIRMED = 1; /** + * Dialog is done animating away after user clicked on the button set via + * {@link BiometricPrompt.Builder#setNegativeButton(CharSequence, Executor, + * DialogInterface.OnClickListener)}. * @hide */ public static final int DISMISSED_REASON_NEGATIVE = 2; @@ -112,6 +115,25 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ public static final int DISMISSED_REASON_USER_CANCEL = 3; + /** + * Authenticated, confirmation not required. Dialog animated away. + * @hide + */ + public static final int DISMISSED_REASON_CONFIRM_NOT_REQUIRED = 4; + + /** + * Error message shown on SystemUI. When BiometricService receives this, the UI is already + * gone. + * @hide + */ + public static final int DISMISSED_REASON_ERROR = 5; + + /** + * Dialog dismissal requested by BiometricService. + * @hide + */ + public static final int DISMISSED_REASON_SERVER_REQUESTED = 6; + private static class ButtonInfo { Executor executor; DialogInterface.OnClickListener listener; @@ -362,7 +384,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan @Override public void onDialogDismissed(int reason) throws RemoteException { // Check the reason and invoke OnClickListener(s) if necessary - if (reason == DISMISSED_REASON_POSITIVE) { + if (reason == DISMISSED_REASON_CONFIRMED) { mPositiveButtonInfo.executor.execute(() -> { mPositiveButtonInfo.listener.onClick(null, DialogInterface.BUTTON_POSITIVE); }); diff --git a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl index 180daaf97ada..ca6114e4d842 100644 --- a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl +++ b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl @@ -27,8 +27,8 @@ oneway interface IBiometricServiceReceiverInternal { // Notify BiometricService that authentication was successful. If user confirmation is required, // the auth token must be submitted into KeyStore. void onAuthenticationSucceeded(boolean requireConfirmation, in byte[] token); - // Notify BiometricService that an error has occurred. - void onAuthenticationFailed(int cookie, boolean requireConfirmation); + // Notify BiometricService authentication was rejected. + void onAuthenticationFailed(); // Notify BiometricService than an error has occured. Forward to the correct receiver depending // on the cookie. void onError(int cookie, int error, String message); diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java index 0fb93e532cd3..beff0f7607f8 100644 --- a/core/java/android/hardware/radio/TunerCallbackAdapter.java +++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java @@ -211,10 +211,12 @@ class TunerCallbackAdapter extends ITunerCallback.Stub { @Override public void onProgramListUpdated(ProgramList.Chunk chunk) { - synchronized (mLock) { - if (mProgramList == null) return; - mProgramList.apply(Objects.requireNonNull(chunk)); - } + mHandler.post(() -> { + synchronized (mLock) { + if (mProgramList == null) return; + mProgramList.apply(Objects.requireNonNull(chunk)); + } + }); } @Override diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java index 0513feef801f..356b3448430a 100644 --- a/core/java/android/inputmethodservice/SoftInputWindow.java +++ b/core/java/android/inputmethodservice/SoftInputWindow.java @@ -21,6 +21,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.app.Dialog; import android.content.Context; +import android.content.pm.PackageManager; import android.graphics.Rect; import android.os.Debug; import android.os.IBinder; @@ -50,6 +51,7 @@ public class SoftInputWindow extends Dialog { final int mWindowType; final int mGravity; final boolean mTakesFocus; + final boolean mAutomotiveHideNavBarForKeyboard; private final Rect mBounds = new Rect(); @Retention(SOURCE) @@ -134,6 +136,8 @@ public class SoftInputWindow extends Dialog { mWindowType = windowType; mGravity = gravity; mTakesFocus = takesFocus; + mAutomotiveHideNavBarForKeyboard = context.getResources().getBoolean( + com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard); initDockWindow(); } @@ -247,6 +251,11 @@ public class SoftInputWindow extends Dialog { windowModFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; } + if (isAutomotive() && mAutomotiveHideNavBarForKeyboard) { + windowSetFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; + windowModFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; + } + getWindow().setFlags(windowSetFlags, windowModFlags); } @@ -338,6 +347,10 @@ public class SoftInputWindow extends Dialog { mWindowState = newState; } + private boolean isAutomotive() { + return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); + } + private static String stateToString(@SoftInputWindowState int state) { switch (state) { case SoftInputWindowState.TOKEN_PENDING: diff --git a/core/java/android/net/util/MultinetworkPolicyTracker.java b/core/java/android/net/util/MultinetworkPolicyTracker.java index 30c5cd98b719..f7e494d830ac 100644 --- a/core/java/android/net/util/MultinetworkPolicyTracker.java +++ b/core/java/android/net/util/MultinetworkPolicyTracker.java @@ -16,28 +16,31 @@ package android.net.util; +import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI; +import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE; + +import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Resources; import android.database.ContentObserver; -import android.net.ConnectivityManager; import android.net.Uri; import android.os.Handler; -import android.os.Message; import android.os.UserHandle; import android.provider.Settings; +import android.telephony.PhoneStateListener; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.util.Slog; -import java.util.Arrays; -import java.util.List; - -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; -import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI; -import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE; +import java.util.Arrays; +import java.util.List; /** * A class to encapsulate management of the "Smart Networking" capability of @@ -69,6 +72,7 @@ public class MultinetworkPolicyTracker { private volatile boolean mAvoidBadWifi = true; private volatile int mMeteredMultipathPreference; + private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; public MultinetworkPolicyTracker(Context ctx, Handler handler) { this(ctx, handler, null); @@ -95,6 +99,14 @@ public class MultinetworkPolicyTracker { } }; + TelephonyManager.from(ctx).listen(new PhoneStateListener() { + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + mActiveSubId = subId; + reevaluate(); + } + }, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); + updateAvoidBadWifi(); updateMeteredMultipathPreference(); } @@ -131,7 +143,12 @@ public class MultinetworkPolicyTracker { * Whether the device or carrier configuration disables avoiding bad wifi by default. */ public boolean configRestrictsAvoidBadWifi() { - return (mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi) == 0); + return (getResourcesForActiveSubId().getInteger(R.integer.config_networkAvoidBadWifi) == 0); + } + + @NonNull + private Resources getResourcesForActiveSubId() { + return SubscriptionManager.getResourcesForSubId(mContext, mActiveSubId); } /** diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 1213eeaa747d..3cc28197503a 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -787,6 +787,68 @@ public final class Debug } /** + * Rss of Java Heap bytes in KB due to the application. + * @hide + */ + public int getSummaryJavaHeapRss() { + return dalvikRss + getOtherRss(OTHER_ART); + } + + /** + * Rss of Native Heap bytes in KB due to the application. + * @hide + */ + public int getSummaryNativeHeapRss() { + return nativeRss; + } + + /** + * Rss of code and other static resource bytes in KB due to + * the application. + * @hide + */ + public int getSummaryCodeRss() { + return getOtherRss(OTHER_SO) + + getOtherRss(OTHER_JAR) + + getOtherRss(OTHER_APK) + + getOtherRss(OTHER_TTF) + + getOtherRss(OTHER_DEX) + + getOtherRss(OTHER_OAT); + } + + /** + * Rss in KB of the stack due to the application. + * @hide + */ + public int getSummaryStackRss() { + return getOtherRss(OTHER_STACK); + } + + /** + * Rss in KB of graphics due to the application. + * @hide + */ + public int getSummaryGraphicsRss() { + return getOtherRss(OTHER_GL_DEV) + + getOtherRss(OTHER_GRAPHICS) + + getOtherRss(OTHER_GL); + } + + /** + * Rss in KB due to either the application or system that haven't otherwise been + * accounted for. + * @hide + */ + public int getSummaryUnknownRss() { + return getTotalRss() + - getSummaryJavaHeapRss() + - getSummaryNativeHeapRss() + - getSummaryCodeRss() + - getSummaryStackRss() + - getSummaryGraphicsRss(); + } + + /** * Total Pss in KB. * @hide */ diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java index 2e3b000f2b39..f302263f23ce 100644 --- a/core/java/android/os/UserManagerInternal.java +++ b/core/java/android/os/UserManagerInternal.java @@ -16,6 +16,7 @@ package android.os; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.content.Context; import android.content.pm.UserInfo; import android.graphics.Bitmap; @@ -224,4 +225,10 @@ public abstract class UserManagerInternal { /** @return a specific user restriction that's in effect currently. */ public abstract boolean hasUserRestriction(String restriction, int userId); + + /** + * Gets an {@link UserInfo} for the given {@code userId}, or {@code null} if not + * found. + */ + public abstract @Nullable UserInfo getUserInfo(@UserIdInt int userId); } diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java index e4f88c52889f..77fd946f7ccb 100644 --- a/core/java/android/os/image/DynamicSystemManager.java +++ b/core/java/android/os/image/DynamicSystemManager.java @@ -20,6 +20,7 @@ import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.content.Context; import android.gsi.GsiProgress; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; /** @@ -52,22 +53,39 @@ public class DynamicSystemManager { /** The DynamicSystemManager.Session represents a started session for the installation. */ public class Session { private Session() {} + /** - * Write a chunk of the DynamicSystem system image + * Set the file descriptor that points to a ashmem which will be used + * to fetch data during the submitFromAshmem. * - * @return {@code true} if the call succeeds. {@code false} if there is any native runtime - * error. + * @param ashmem fd that points to a ashmem + * @param size size of the ashmem file */ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) - public boolean write(byte[] buf) { + public boolean setAshmem(ParcelFileDescriptor ashmem, long size) { try { - return mService.write(buf); + return mService.setAshmem(ashmem, size); } catch (RemoteException e) { throw new RuntimeException(e.toString()); } } /** + * Submit bytes to the DSU partition from the ashmem previously set with + * setAshmem. + * + * @param size Number of bytes + * @return true on success, false otherwise. + */ + @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) + public boolean submitFromAshmem(int size) { + try { + return mService.submitFromAshmem(size); + } catch (RemoteException e) { + throw new RuntimeException(e.toString()); + } + } + /** * Finish write and make device to boot into the it after reboot. * * @return {@code true} if the call succeeds. {@code false} if there is any native runtime diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl index 2f4ab2d2420d..a6de170b5ce5 100644 --- a/core/java/android/os/image/IDynamicSystemService.aidl +++ b/core/java/android/os/image/IDynamicSystemService.aidl @@ -79,10 +79,20 @@ interface IDynamicSystemService boolean setEnable(boolean enable, boolean oneShot); /** - * Write a chunk of the DynamicSystem system image + * Set the file descriptor that points to a ashmem which will be used + * to fetch data during the submitFromAshmem. * - * @return true if the call succeeds + * @param fd fd that points to a ashmem + * @param size size of the ashmem file */ - boolean write(in byte[] buf); + boolean setAshmem(in ParcelFileDescriptor fd, long size); + /** + * Submit bytes to the DSU partition from the ashmem previously set with + * setAshmem. + * + * @param bytes number of bytes that can be read from stream. + * @return true on success, false otherwise. + */ + boolean submitFromAshmem(long bytes); } diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 2299aad6f79a..a959913f6fb0 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -3592,10 +3592,23 @@ public final class MediaStore { } /** @hide */ + public static Uri scanFile(ContentProviderClient client, File file) { + return scan(client, SCAN_FILE_CALL, file, false); + } + + /** @hide */ private static Uri scan(Context context, String method, File file, boolean originatedFromShell) { final ContentResolver resolver = context.getContentResolver(); try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) { + return scan(client, method, file, originatedFromShell); + } + } + + /** @hide */ + private static Uri scan(ContentProviderClient client, String method, File file, + boolean originatedFromShell) { + try { final Bundle in = new Bundle(); in.putParcelable(Intent.EXTRA_STREAM, Uri.fromFile(file)); in.putBoolean(EXTRA_ORIGINATED_FROM_SHELL, originatedFromShell); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 7df1ebe15d44..e48623572e95 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -16,16 +16,19 @@ package android.provider; -import static android.provider.SettingsValidators.ANY_INTEGER_VALIDATOR; -import static android.provider.SettingsValidators.ANY_STRING_VALIDATOR; -import static android.provider.SettingsValidators.BOOLEAN_VALIDATOR; -import static android.provider.SettingsValidators.COMPONENT_NAME_VALIDATOR; -import static android.provider.SettingsValidators.LENIENT_IP_ADDRESS_VALIDATOR; -import static android.provider.SettingsValidators.LOCALE_VALIDATOR; -import static android.provider.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR; -import static android.provider.SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR; -import static android.provider.SettingsValidators.PACKAGE_NAME_VALIDATOR; -import static android.provider.SettingsValidators.URI_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.JSON_OBJECT_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.LENIENT_IP_ADDRESS_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.LOCALE_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.TILE_LIST_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.TTS_LIST_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.URI_VALIDATOR; import android.Manifest; import android.annotation.IntDef; @@ -80,7 +83,12 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.UserHandle; -import android.provider.SettingsValidators.Validator; +import android.provider.settings.validators.ComponentNameListValidator; +import android.provider.settings.validators.DiscreteValueValidator; +import android.provider.settings.validators.InclusiveFloatRangeValidator; +import android.provider.settings.validators.InclusiveIntegerRangeValidator; +import android.provider.settings.validators.PackageNameListValidator; +import android.provider.settings.validators.Validator; import android.speech.tts.TextToSpeech; import android.telephony.SubscriptionManager; import android.text.TextUtils; @@ -3149,7 +3157,7 @@ public final class Settings { public static final String END_BUTTON_BEHAVIOR = "end_button_behavior"; private static final Validator END_BUTTON_BEHAVIOR_VALIDATOR = - new SettingsValidators.InclusiveIntegerRangeValidator(0, 3); + new InclusiveIntegerRangeValidator(0, 3); /** * END_BUTTON_BEHAVIOR value for "go home". @@ -3351,7 +3359,7 @@ public final class Settings { "bluetooth_discoverability"; private static final Validator BLUETOOTH_DISCOVERABILITY_VALIDATOR = - new SettingsValidators.InclusiveIntegerRangeValidator(0, 2); + new InclusiveIntegerRangeValidator(0, 2); /** * Bluetooth discoverability timeout. If this value is nonzero, then @@ -3495,7 +3503,7 @@ public final class Settings { public static final String PEAK_REFRESH_RATE = "peak_refresh_rate"; private static final Validator PEAK_REFRESH_RATE_VALIDATOR = - new SettingsValidators.InclusiveFloatRangeValidator(24f, Float.MAX_VALUE); + new InclusiveFloatRangeValidator(24f, Float.MAX_VALUE); /** * The amount of time in milliseconds before the device goes to sleep or begins @@ -3524,7 +3532,7 @@ public final class Settings { public static final String SCREEN_BRIGHTNESS_FOR_VR = "screen_brightness_for_vr"; private static final Validator SCREEN_BRIGHTNESS_FOR_VR_VALIDATOR = - new SettingsValidators.InclusiveIntegerRangeValidator(0, 255); + new InclusiveIntegerRangeValidator(0, 255); /** * Control whether to enable automatic brightness mode. @@ -3542,7 +3550,7 @@ public final class Settings { public static final String SCREEN_AUTO_BRIGHTNESS_ADJ = "screen_auto_brightness_adj"; private static final Validator SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR = - new SettingsValidators.InclusiveFloatRangeValidator(-1, 1); + new InclusiveFloatRangeValidator(-1, 1); /** * SCREEN_BRIGHTNESS_MODE value for manual mode. @@ -3676,7 +3684,7 @@ public final class Settings { "haptic_feedback_intensity"; private static final Validator VIBRATION_INTENSITY_VALIDATOR = - new SettingsValidators.InclusiveIntegerRangeValidator(0, 3); + new InclusiveIntegerRangeValidator(0, 3); /** * Ringer volume. This is used internally, changing this value will not @@ -3766,7 +3774,7 @@ public final class Settings { public static final String MASTER_BALANCE = "master_balance"; private static final Validator MASTER_BALANCE_VALIDATOR = - new SettingsValidators.InclusiveFloatRangeValidator(-1.f, 1.f); + new InclusiveFloatRangeValidator(-1.f, 1.f); /** * Whether the notifications should use the ring volume (value of 1) or @@ -4004,7 +4012,7 @@ public final class Settings { /** @hide */ public static final Validator TIME_12_24_VALIDATOR = - new SettingsValidators.DiscreteValueValidator(new String[] {"12", "24", null}); + new DiscreteValueValidator(new String[] {"12", "24", null}); /** * Date format string @@ -4090,7 +4098,7 @@ public final class Settings { /** @hide */ public static final Validator USER_ROTATION_VALIDATOR = - new SettingsValidators.InclusiveIntegerRangeValidator(0, 3); + new InclusiveIntegerRangeValidator(0, 3); /** * Control whether the rotation lock toggle in the System UI should be hidden. @@ -4179,7 +4187,7 @@ public final class Settings { /** @hide */ public static final Validator TTY_MODE_VALIDATOR = - new SettingsValidators.InclusiveIntegerRangeValidator(0, 3); + new InclusiveIntegerRangeValidator(0, 3); /** * Whether the sounds effects (key clicks, lid open ...) are enabled. The value is @@ -4381,7 +4389,7 @@ public final class Settings { /** @hide */ public static final Validator SIP_CALL_OPTIONS_VALIDATOR = - new SettingsValidators.DiscreteValueValidator( + new DiscreteValueValidator( new String[] {"SIP_ALWAYS", "SIP_ADDRESS_ONLY"}); /** @@ -4428,7 +4436,7 @@ public final class Settings { /** @hide */ public static final Validator POINTER_SPEED_VALIDATOR = - new SettingsValidators.InclusiveFloatRangeValidator(-7, 7); + new InclusiveFloatRangeValidator(-7, 7); /** * Whether lock-to-app will be triggered by long-press on recents. @@ -6352,7 +6360,7 @@ public final class Settings { public static final String LOCK_SCREEN_CUSTOM_CLOCK_FACE = "lock_screen_custom_clock_face"; private static final Validator LOCK_SCREEN_CUSTOM_CLOCK_FACE_VALIDATOR = - SettingsValidators.JSON_OBJECT_VALIDATOR; + JSON_OBJECT_VALIDATOR; /** * Indicates which clock face to show on lock screen and AOD while docked. @@ -6509,7 +6517,7 @@ public final class Settings { "enabled_accessibility_services"; private static final Validator ENABLED_ACCESSIBILITY_SERVICES_VALIDATOR = - new SettingsValidators.ComponentNameListValidator(":"); + new ComponentNameListValidator(":"); /** * List of the accessibility services to which the user has granted @@ -6521,7 +6529,7 @@ public final class Settings { "touch_exploration_granted_accessibility_services"; private static final Validator TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES_VALIDATOR = - new SettingsValidators.ComponentNameListValidator(":"); + new ComponentNameListValidator(":"); /** * Whether the Global Actions Panel is enabled. @@ -6696,7 +6704,7 @@ public final class Settings { "accessibility_display_magnification_scale"; private static final Validator ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE_VALIDATOR = - new SettingsValidators.InclusiveFloatRangeValidator(1.0f, Float.MAX_VALUE); + new InclusiveFloatRangeValidator(1.0f, Float.MAX_VALUE); /** * Unused mangnification setting @@ -6780,7 +6788,7 @@ public final class Settings { "accessibility_captioning_preset"; private static final Validator ACCESSIBILITY_CAPTIONING_PRESET_VALIDATOR = - new SettingsValidators.DiscreteValueValidator(new String[]{"-1", "0", "1", "2", + new DiscreteValueValidator(new String[]{"-1", "0", "1", "2", "3", "4"}); /** @@ -6824,7 +6832,7 @@ public final class Settings { "accessibility_captioning_edge_type"; private static final Validator ACCESSIBILITY_CAPTIONING_EDGE_TYPE_VALIDATOR = - new SettingsValidators.DiscreteValueValidator(new String[]{"0", "1", "2"}); + new DiscreteValueValidator(new String[]{"0", "1", "2"}); /** * Integer property that specifes the edge color for captions as a @@ -6870,7 +6878,7 @@ public final class Settings { "accessibility_captioning_typeface"; private static final Validator ACCESSIBILITY_CAPTIONING_TYPEFACE_VALIDATOR = - new SettingsValidators.DiscreteValueValidator(new String[]{"DEFAULT", + new DiscreteValueValidator(new String[]{"DEFAULT", "MONOSPACE", "SANS_SERIF", "SERIF"}); /** @@ -6882,7 +6890,7 @@ public final class Settings { "accessibility_captioning_font_scale"; private static final Validator ACCESSIBILITY_CAPTIONING_FONT_SCALE_VALIDATOR = - new SettingsValidators.InclusiveFloatRangeValidator(0.5f, 2.0f); + new InclusiveFloatRangeValidator(0.5f, 2.0f); /** * Setting that specifies whether display color inversion is enabled. @@ -6923,7 +6931,7 @@ public final class Settings { "accessibility_display_daltonizer"; private static final Validator ACCESSIBILITY_DISPLAY_DALTONIZER_VALIDATOR = - new SettingsValidators.DiscreteValueValidator( + new DiscreteValueValidator( new String[] {"-1", "0", "11", "12", "13"}); /** @@ -7030,6 +7038,8 @@ public final class Settings { */ public static final String DISPLAY_DENSITY_FORCED = "display_density_forced"; + static final Validator DISPLAY_DENSITY_FORCED_VALIDATOR = NON_NEGATIVE_INTEGER_VALIDATOR; + /** * Setting to always use the default text-to-speech settings regardless * of the application settings. @@ -7110,24 +7120,7 @@ public final class Settings { */ public static final String TTS_DEFAULT_LOCALE = "tts_default_locale"; - private static final Validator TTS_DEFAULT_LOCALE_VALIDATOR = new Validator() { - @Override - public boolean validate(@Nullable String value) { - if (value == null || value.length() == 0) { - return false; - } - String[] ttsLocales = value.split(","); - boolean valid = true; - for (String ttsLocale : ttsLocales) { - String[] parts = ttsLocale.split(":"); - valid |= ((parts.length == 2) - && (parts[0].length() > 0) - && ANY_STRING_VALIDATOR.validate(parts[0]) - && LOCALE_VALIDATOR.validate(parts[1])); - } - return valid; - } - }; + private static final Validator TTS_DEFAULT_LOCALE_VALIDATOR = TTS_LIST_VALIDATOR; /** * Space delimited list of plugin packages that are enabled. @@ -7135,7 +7128,7 @@ public final class Settings { public static final String TTS_ENABLED_PLUGINS = "tts_enabled_plugins"; private static final Validator TTS_ENABLED_PLUGINS_VALIDATOR = - new SettingsValidators.PackageNameListValidator(" "); + new PackageNameListValidator(" "); /** * @deprecated Use {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON} @@ -7329,7 +7322,7 @@ public final class Settings { "preferred_tty_mode"; private static final Validator PREFERRED_TTY_MODE_VALIDATOR = - new SettingsValidators.DiscreteValueValidator(new String[]{"0", "1", "2", "3"}); + new DiscreteValueValidator(new String[]{"0", "1", "2", "3"}); /** * Whether the enhanced voice privacy mode is enabled. @@ -7644,7 +7637,7 @@ public final class Settings { public static final String INCALL_POWER_BUTTON_BEHAVIOR = "incall_power_button_behavior"; private static final Validator INCALL_POWER_BUTTON_BEHAVIOR_VALIDATOR = - new SettingsValidators.DiscreteValueValidator(new String[]{"1", "2"}); + new DiscreteValueValidator(new String[]{"1", "2"}); /** * INCALL_POWER_BUTTON_BEHAVIOR value for "turn off screen". @@ -7865,7 +7858,7 @@ public final class Settings { public static final String UI_NIGHT_MODE = "ui_night_mode"; private static final Validator UI_NIGHT_MODE_VALIDATOR = - new SettingsValidators.InclusiveIntegerRangeValidator(0, 2); + new InclusiveIntegerRangeValidator(0, 2); /** * Whether screensavers are enabled. @@ -7885,7 +7878,7 @@ public final class Settings { public static final String SCREENSAVER_COMPONENTS = "screensaver_components"; private static final Validator SCREENSAVER_COMPONENTS_VALIDATOR = - new SettingsValidators.ComponentNameListValidator(","); + new ComponentNameListValidator(","); /** * If screensavers are enabled, whether the screensaver should be automatically launched @@ -8037,7 +8030,7 @@ public final class Settings { "enabled_notification_assistant"; private static final Validator ENABLED_NOTIFICATION_ASSISTANT_VALIDATOR = - new SettingsValidators.ComponentNameListValidator(":"); + new ComponentNameListValidator(":"); /** * Read only list of the service components that the current user has explicitly allowed to @@ -8052,7 +8045,7 @@ public final class Settings { public static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners"; private static final Validator ENABLED_NOTIFICATION_LISTENERS_VALIDATOR = - new SettingsValidators.ComponentNameListValidator(":"); + new ComponentNameListValidator(":"); /** * Read only list of the packages that the current user has explicitly allowed to @@ -8067,7 +8060,7 @@ public final class Settings { "enabled_notification_policy_access_packages"; private static final Validator ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES_VALIDATOR = - new SettingsValidators.PackageNameListValidator(":"); + new PackageNameListValidator(":"); /** * Defines whether managed profile ringtones should be synced from it's parent profile @@ -8364,16 +8357,6 @@ public final class Settings { BOOLEAN_VALIDATOR; /** - * Whether or not the face unlock education screen has been shown to the user. - * @hide - */ - public static final String FACE_UNLOCK_EDUCATION_INFO_DISPLAYED = - "face_unlock_education_info_displayed"; - - private static final Validator FACE_UNLOCK_EDUCATION_INFO_DISPLAYED_VALIDATOR = - BOOLEAN_VALIDATOR; - - /** * Whether or not debugging is enabled. * @hide */ @@ -8460,7 +8443,7 @@ public final class Settings { public static final String NIGHT_DISPLAY_AUTO_MODE = "night_display_auto_mode"; private static final Validator NIGHT_DISPLAY_AUTO_MODE_VALIDATOR = - new SettingsValidators.InclusiveIntegerRangeValidator(0, 2); + new InclusiveIntegerRangeValidator(0, 2); /** * Control the color temperature of Night Display, represented in Kelvin. @@ -8521,7 +8504,7 @@ public final class Settings { public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners"; private static final Validator ENABLED_VR_LISTENERS_VALIDATOR = - new SettingsValidators.ComponentNameListValidator(":"); + new ComponentNameListValidator(":"); /** * Behavior of the display while in VR mode. @@ -8533,7 +8516,7 @@ public final class Settings { public static final String VR_DISPLAY_MODE = "vr_display_mode"; private static final Validator VR_DISPLAY_MODE_VALIDATOR = - new SettingsValidators.DiscreteValueValidator(new String[]{"0", "1"}); + new DiscreteValueValidator(new String[]{"0", "1"}); /** * Lower the display persistence while the system is in VR mode. @@ -8647,25 +8630,12 @@ public final class Settings { /** * Holds comma separated list of ordering of QS tiles. + * * @hide */ public static final String QS_TILES = "sysui_qs_tiles"; - private static final Validator QS_TILES_VALIDATOR = new Validator() { - @Override - public boolean validate(@Nullable String value) { - if (value == null) { - return false; - } - String[] tiles = value.split(","); - boolean valid = true; - for (String tile : tiles) { - // tile can be any non-empty string as specified by OEM - valid |= ((tile.length() > 0) && ANY_STRING_VALIDATOR.validate(tile)); - } - return valid; - } - }; + private static final Validator QS_TILES_VALIDATOR = TILE_LIST_VALIDATOR; /** * Specifies whether the web action API is enabled. @@ -8731,21 +8701,7 @@ public final class Settings { */ public static final String QS_AUTO_ADDED_TILES = "qs_auto_tiles"; - private static final Validator QS_AUTO_ADDED_TILES_VALIDATOR = new Validator() { - @Override - public boolean validate(@Nullable String value) { - if (value == null) { - return false; - } - String[] tiles = value.split(","); - boolean valid = true; - for (String tile : tiles) { - // tile can be any non-empty string as specified by OEM - valid |= ((tile.length() > 0) && ANY_STRING_VALIDATOR.validate(tile)); - } - return valid; - } - }; + private static final Validator QS_AUTO_ADDED_TILES_VALIDATOR = TILE_LIST_VALIDATOR; /** * Whether the Lockdown button should be shown in the power menu. @@ -8906,7 +8862,7 @@ public final class Settings { "theme_customization_overlay_packages"; private static final Validator THEME_CUSTOMIZATION_OVERLAY_PACKAGES_VALIDATOR = - SettingsValidators.JSON_OBJECT_VALIDATOR; + JSON_OBJECT_VALIDATOR; /** * Navigation bar mode. @@ -8918,7 +8874,7 @@ public final class Settings { public static final String NAVIGATION_MODE = "navigation_mode"; private static final Validator NAVIGATION_MODE_VALIDATOR = - new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1", "2"}); + new DiscreteValueValidator(new String[] {"0", "1", "2"}); /** * Controls whether aware is enabled. @@ -9083,8 +9039,22 @@ public final class Settings { }; /** - * All settings in {@link SETTINGS_TO_BACKUP} array *must* have a non-null validator, - * otherwise they won't be restored. + * The settings values which should only be restored if the target device is the + * same as the source device + * + * NOTE: Settings are backed up and restored in the order they appear + * in this array. If you have one setting depending on another, + * make sure that they are ordered appropriately. + * + * @hide + */ + public static final String[] DEVICE_SPECIFIC_SETTINGS_TO_BACKUP = { + DISPLAY_DENSITY_FORCED, + }; + + /** + * All settings in {@link SETTINGS_TO_BACKUP} and {@link DEVICE_SPECIFIC_SETTINGS_TO_BACKUP} + * array *must* have a non-null validator, otherwise they won't be restored. * * @hide */ @@ -9207,8 +9177,6 @@ public final class Settings { VALIDATORS.put(FACE_UNLOCK_APP_ENABLED, FACE_UNLOCK_APP_ENABLED_VALIDATOR); VALIDATORS.put(FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION_VALIDATOR); - VALIDATORS.put(FACE_UNLOCK_EDUCATION_INFO_DISPLAYED, - FACE_UNLOCK_EDUCATION_INFO_DISPLAYED_VALIDATOR); VALIDATORS.put(ASSIST_GESTURE_ENABLED, ASSIST_GESTURE_ENABLED_VALIDATOR); VALIDATORS.put(ASSIST_GESTURE_SILENCE_ALERTS_ENABLED, ASSIST_GESTURE_SILENCE_ALERTS_ENABLED_VALIDATOR); @@ -9276,6 +9244,7 @@ public final class Settings { VALIDATORS.put(UI_NIGHT_MODE, UI_NIGHT_MODE_VALIDATOR); VALIDATORS.put(GLOBAL_ACTIONS_PANEL_ENABLED, GLOBAL_ACTIONS_PANEL_ENABLED_VALIDATOR); VALIDATORS.put(AWARE_LOCK_ENABLED, AWARE_LOCK_ENABLED_VALIDATOR); + VALIDATORS.put(DISPLAY_DENSITY_FORCED, DISPLAY_DENSITY_FORCED_VALIDATOR); } /** @@ -10607,22 +10576,6 @@ public final class Settings { BOOLEAN_VALIDATOR; /** - * Whether to notify the user of carrier networks. - * <p> - * If not connected and the scan results have a carrier network, we will - * put this notification up. If we attempt to connect to a network or - * the carrier network(s) disappear, we remove the notification. When we - * show the notification, we will not show it again for - * {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} time. - * @hide - */ - public static final String WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON = - "wifi_carrier_networks_available_notification_on"; - - private static final Validator WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR = - BOOLEAN_VALIDATOR; - - /** * {@hide} */ public static final String WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON = @@ -10757,7 +10710,7 @@ public final class Settings { "network_recommendations_enabled"; private static final Validator NETWORK_RECOMMENDATIONS_ENABLED_VALIDATOR = - new SettingsValidators.DiscreteValueValidator(new String[] {"-1", "0", "1"}); + new DiscreteValueValidator(new String[] {"-1", "0", "1"}); /** * Which package name to use for network recommendations. If null, network recommendations @@ -11082,12 +11035,6 @@ public final class Settings { public static final String WIFI_P2P_DEVICE_NAME = "wifi_p2p_device_name"; /** - * The min time between wifi disable and wifi enable - * @hide - */ - public static final String WIFI_REENABLE_DELAY_MS = "wifi_reenable_delay"; - - /** * Timeout for ephemeral networks when all known BSSIDs go out of range. We will disconnect * from an ephemeral network if there is no BSSID for that network with a non-null score that * has been seen in this time period. @@ -12614,7 +12561,7 @@ public final class Settings { public static final String EMERGENCY_TONE = "emergency_tone"; private static final Validator EMERGENCY_TONE_VALIDATOR = - new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1", "2"}); + new DiscreteValueValidator(new String[] {"0", "1", "2"}); /** * CDMA only settings @@ -12644,7 +12591,7 @@ public final class Settings { "enable_automatic_system_server_heap_dumps"; private static final Validator ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_VALIDATOR = - new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1"}); + new DiscreteValueValidator(new String[] {"0", "1"}); /** * See RIL_PreferredNetworkType in ril.h @@ -12838,7 +12785,7 @@ public final class Settings { "low_power_sticky_auto_disable_level"; private static final Validator LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL_VALIDATOR = - new SettingsValidators.InclusiveIntegerRangeValidator(0, 100); + new InclusiveIntegerRangeValidator(0, 100); /** * Whether sticky battery saver should be deactivated once the battery level has reached the @@ -12850,7 +12797,7 @@ public final class Settings { "low_power_sticky_auto_disable_enabled"; private static final Validator LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED_VALIDATOR = - new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1"}); + new DiscreteValueValidator(new String[] {"0", "1"}); /** * Battery level [1-100] at which low power mode automatically turns on. @@ -12865,7 +12812,7 @@ public final class Settings { public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level"; private static final Validator LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR = - new SettingsValidators.InclusiveIntegerRangeValidator(0, 100); + new InclusiveIntegerRangeValidator(0, 100); /** * Whether battery saver is currently set to trigger based on percentage, dynamic power @@ -12878,7 +12825,7 @@ public final class Settings { public static final String AUTOMATIC_POWER_SAVE_MODE = "automatic_power_save_mode"; private static final Validator AUTOMATIC_POWER_SAVE_MODE_VALIDATOR = - new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1"}); + new DiscreteValueValidator(new String[] {"0", "1"}); /** * The setting that backs the disable threshold for the setPowerSavingsWarning api in @@ -12891,7 +12838,7 @@ public final class Settings { public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = "dynamic_power_savings_disable_threshold"; private static final Validator DYNAMIC_POWER_SAVINGS_VALIDATOR = - new SettingsValidators.InclusiveIntegerRangeValidator(0, 100); + new InclusiveIntegerRangeValidator(0, 100); /** * The setting which backs the setDynamicPowerSaveHint api in PowerManager. @@ -13041,7 +12988,7 @@ public final class Settings { public static final String ENCODED_SURROUND_OUTPUT = "encoded_surround_output"; private static final Validator ENCODED_SURROUND_OUTPUT_VALIDATOR = - new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1", "2", "3"}); + new DiscreteValueValidator(new String[] {"0", "1", "2", "3"}); /** * Surround sounds formats that are enabled when ENCODED_SURROUND_OUTPUT is set to @@ -13792,7 +13739,7 @@ public final class Settings { public static final String POWER_BUTTON_LONG_PRESS = "power_button_long_press"; private static final Validator POWER_BUTTON_LONG_PRESS_VALIDATOR = - new SettingsValidators.InclusiveIntegerRangeValidator(0, 5); + new InclusiveIntegerRangeValidator(0, 5); /** * Overrides internal R.integer.config_veryLongPressOnPowerBehavior. @@ -13803,7 +13750,7 @@ public final class Settings { public static final String POWER_BUTTON_VERY_LONG_PRESS = "power_button_very_long_press"; private static final Validator POWER_BUTTON_VERY_LONG_PRESS_VALIDATOR = - new SettingsValidators.InclusiveIntegerRangeValidator(0, 1); + new InclusiveIntegerRangeValidator(0, 1); /** * Settings to backup. This is here so that it's in the same place as the settings @@ -13819,6 +13766,9 @@ public final class Settings { * in this array. If you have one setting depending on another, * make sure that they are ordered appropriately. * + * NOTE: This table should only be used for settings which should be restored + * between different types of devices {@see #DEVICE_SPECIFIC_SETTINGS_TO_BACKUP} + * * @hide */ public static final String[] SETTINGS_TO_BACKUP = { @@ -13835,7 +13785,6 @@ public final class Settings { NETWORK_RECOMMENDATIONS_ENABLED, WIFI_WAKEUP_ENABLED, WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, - WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON, USE_OPEN_WIFI_PACKAGE, WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED, EMERGENCY_TONE, @@ -13863,6 +13812,7 @@ public final class Settings { * @hide */ public static final Map<String, Validator> VALIDATORS = new ArrayMap<>(); + static { VALIDATORS.put(APPLY_RAMPING_RINGER, APPLY_RAMPING_RINGER_VALIDATOR); VALIDATORS.put(BUGREPORT_IN_POWER_MENU, BUGREPORT_IN_POWER_MENU_VALIDATOR); @@ -13903,8 +13853,6 @@ public final class Settings { VALIDATORS.put(PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_VALIDATOR); VALIDATORS.put(PRIVATE_DNS_SPECIFIER, PRIVATE_DNS_SPECIFIER_VALIDATOR); VALIDATORS.put(SOFT_AP_TIMEOUT_ENABLED, SOFT_AP_TIMEOUT_ENABLED_VALIDATOR); - VALIDATORS.put(WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON, - WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR); VALIDATORS.put(WIFI_SCAN_THROTTLE_ENABLED, WIFI_SCAN_THROTTLE_ENABLED_VALIDATOR); VALIDATORS.put(APP_AUTO_RESTRICTION_ENABLED, APP_AUTO_RESTRICTION_ENABLED_VALIDATOR); VALIDATORS.put(ZEN_DURATION, ZEN_DURATION_VALIDATOR); diff --git a/core/java/android/provider/TEST_MAPPING b/core/java/android/provider/TEST_MAPPING new file mode 100644 index 000000000000..52a6a4585581 --- /dev/null +++ b/core/java/android/provider/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "CtsProviderTestCases", + "options": [ + { + "include-annotation": "android.platform.test.annotations.Presubmit" + } + ] + } + ] +} diff --git a/core/java/android/provider/settings/validators/ComponentNameListValidator.java b/core/java/android/provider/settings/validators/ComponentNameListValidator.java new file mode 100644 index 000000000000..b6b867a5d513 --- /dev/null +++ b/core/java/android/provider/settings/validators/ComponentNameListValidator.java @@ -0,0 +1,40 @@ +/* + * 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.provider.settings.validators; + +import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR; + +/** + * Validate a list of compoments. + * + * @hide + */ +public final class ComponentNameListValidator extends ListValidator { + public ComponentNameListValidator(String separator) { + super(separator); + } + + @Override + protected boolean isEntryValid(String entry) { + return entry != null; + } + + @Override + protected boolean isItemValid(String item) { + return COMPONENT_NAME_VALIDATOR.validate(item); + } +} diff --git a/core/java/android/provider/settings/validators/DiscreteValueValidator.java b/core/java/android/provider/settings/validators/DiscreteValueValidator.java new file mode 100644 index 000000000000..183651f77f5a --- /dev/null +++ b/core/java/android/provider/settings/validators/DiscreteValueValidator.java @@ -0,0 +1,39 @@ +/* + * 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.provider.settings.validators; + +import android.annotation.Nullable; + +import com.android.internal.util.ArrayUtils; + +/** + * Validate a value exists in an array of known good values + * + * @hide + */ +public final class DiscreteValueValidator implements Validator { + private final String[] mValues; + + public DiscreteValueValidator(String[] values) { + mValues = values; + } + + @Override + public boolean validate(@Nullable String value) { + return ArrayUtils.contains(mValues, value); + } +} diff --git a/core/java/android/provider/settings/validators/InclusiveFloatRangeValidator.java b/core/java/android/provider/settings/validators/InclusiveFloatRangeValidator.java new file mode 100644 index 000000000000..38400ac676a8 --- /dev/null +++ b/core/java/android/provider/settings/validators/InclusiveFloatRangeValidator.java @@ -0,0 +1,44 @@ +/* + * 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.provider.settings.validators; + +import android.annotation.Nullable; + +/** + * Validate a float value lies within a given (boundary inclusive) range. + * + * @hide + */ +public final class InclusiveFloatRangeValidator implements Validator { + private final float mMin; + private final float mMax; + + public InclusiveFloatRangeValidator(float min, float max) { + mMin = min; + mMax = max; + } + + @Override + public boolean validate(@Nullable String value) { + try { + final float floatValue = Float.parseFloat(value); + return floatValue >= mMin && floatValue <= mMax; + } catch (NumberFormatException | NullPointerException e) { + return false; + } + } +} diff --git a/core/java/android/provider/settings/validators/InclusiveIntegerRangeValidator.java b/core/java/android/provider/settings/validators/InclusiveIntegerRangeValidator.java new file mode 100644 index 000000000000..e53c252c7d35 --- /dev/null +++ b/core/java/android/provider/settings/validators/InclusiveIntegerRangeValidator.java @@ -0,0 +1,44 @@ +/* + * 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.provider.settings.validators; + +import android.annotation.Nullable; + +/** + * Validate an integer value lies within a given (boundary inclusive) range. + * + * @hide + */ +public final class InclusiveIntegerRangeValidator implements Validator { + private final int mMin; + private final int mMax; + + public InclusiveIntegerRangeValidator(int min, int max) { + mMin = min; + mMax = max; + } + + @Override + public boolean validate(@Nullable String value) { + try { + final int intValue = Integer.parseInt(value); + return intValue >= mMin && intValue <= mMax; + } catch (NumberFormatException e) { + return false; + } + } +} diff --git a/core/java/android/provider/settings/validators/ListValidator.java b/core/java/android/provider/settings/validators/ListValidator.java new file mode 100644 index 000000000000..a6001d2e10c1 --- /dev/null +++ b/core/java/android/provider/settings/validators/ListValidator.java @@ -0,0 +1,51 @@ +/* + * 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.provider.settings.validators; + +import android.annotation.Nullable; + +/** + * Validate the elements in a list. + * + * @hide + */ +abstract class ListValidator implements Validator { + + private String mListSplitRegex; + + ListValidator(String listSplitRegex) { + mListSplitRegex = listSplitRegex; + } + + public boolean validate(@Nullable String value) { + if (!isEntryValid(value)) { + return false; + } + String[] items = value.split(","); + for (String item : items) { + if (!isItemValid(item)) { + return false; + } + } + return true; + } + + protected abstract boolean isEntryValid(String entry); + + protected abstract boolean isItemValid(String item); +} + diff --git a/core/java/android/provider/settings/validators/PackageNameListValidator.java b/core/java/android/provider/settings/validators/PackageNameListValidator.java new file mode 100644 index 000000000000..bc7fc13bdc6d --- /dev/null +++ b/core/java/android/provider/settings/validators/PackageNameListValidator.java @@ -0,0 +1,40 @@ +/* + * 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.provider.settings.validators; + +import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR; + +/** + * Validate a list of package names. + * + * @hide + */ +public final class PackageNameListValidator extends ListValidator { + public PackageNameListValidator(String separator) { + super(separator); + } + + @Override + protected boolean isEntryValid(String entry) { + return entry != null; + } + + @Override + protected boolean isItemValid(String item) { + return PACKAGE_NAME_VALIDATOR.validate(item); + } +} diff --git a/core/java/android/provider/SettingsValidators.java b/core/java/android/provider/settings/validators/SettingsValidators.java index 405121378d1f..562c638d0b5a 100644 --- a/core/java/android/provider/SettingsValidators.java +++ b/core/java/android/provider/settings/validators/SettingsValidators.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 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,15 +14,13 @@ * limitations under the License. */ -package android.provider; +package android.provider.settings.validators; import android.annotation.Nullable; import android.content.ComponentName; import android.net.Uri; import android.text.TextUtils; -import com.android.internal.util.ArrayUtils; - import org.json.JSONException; import org.json.JSONObject; @@ -179,108 +177,7 @@ public class SettingsValidators { } }; - public interface Validator { - /** - * Returns whether the input value is valid. Subclasses should handle the case where the - * input value is {@code null}. - */ - boolean validate(@Nullable String value); - } - - public static final class DiscreteValueValidator implements Validator { - private final String[] mValues; - - public DiscreteValueValidator(String[] values) { - mValues = values; - } - - @Override - public boolean validate(@Nullable String value) { - return ArrayUtils.contains(mValues, value); - } - } - - public static final class InclusiveIntegerRangeValidator implements Validator { - private final int mMin; - private final int mMax; - - public InclusiveIntegerRangeValidator(int min, int max) { - mMin = min; - mMax = max; - } - - @Override - public boolean validate(@Nullable String value) { - try { - final int intValue = Integer.parseInt(value); - return intValue >= mMin && intValue <= mMax; - } catch (NumberFormatException e) { - return false; - } - } - } - - public static final class InclusiveFloatRangeValidator implements Validator { - private final float mMin; - private final float mMax; - - public InclusiveFloatRangeValidator(float min, float max) { - mMin = min; - mMax = max; - } - - @Override - public boolean validate(@Nullable String value) { - try { - final float floatValue = Float.parseFloat(value); - return floatValue >= mMin && floatValue <= mMax; - } catch (NumberFormatException | NullPointerException e) { - return false; - } - } - } - - public static final class ComponentNameListValidator implements Validator { - private final String mSeparator; + public static final Validator TTS_LIST_VALIDATOR = new TTSListValidator(); - public ComponentNameListValidator(String separator) { - mSeparator = separator; - } - - @Override - public boolean validate(@Nullable String value) { - if (value == null) { - return false; - } - String[] elements = value.split(mSeparator); - for (String element : elements) { - if (!COMPONENT_NAME_VALIDATOR.validate(element)) { - return false; - } - } - return true; - } - } - - public static final class PackageNameListValidator implements Validator { - private final String mSeparator; - - public PackageNameListValidator(String separator) { - mSeparator = separator; - } - - @Override - public boolean validate(@Nullable String value) { - if (value == null) { - return false; - } - String[] elements = value.split(mSeparator); - for (String element : elements) { - if (!PACKAGE_NAME_VALIDATOR.validate(element)) { - return false; - } - } - return true; - } - } + public static final Validator TILE_LIST_VALIDATOR = new TileListValidator(); } diff --git a/core/java/android/provider/settings/validators/TTSListValidator.java b/core/java/android/provider/settings/validators/TTSListValidator.java new file mode 100644 index 000000000000..6c73471a8e8e --- /dev/null +++ b/core/java/android/provider/settings/validators/TTSListValidator.java @@ -0,0 +1,45 @@ +/* + * 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.provider.settings.validators; + +import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR; +import static android.provider.settings.validators.SettingsValidators.LOCALE_VALIDATOR; + +/** + * Ensure a restored value is a string in the format the text-to-speech system handles + * + * @hide + */ +final class TTSListValidator extends ListValidator { + + TTSListValidator() { + super(","); + } + + protected boolean isEntryValid(String entry) { + return entry != null && entry.length() > 0; + } + + protected boolean isItemValid(String item) { + String[] parts = item.split(":"); + // Replaces any old language separator (-) with the new one (_) + return ((parts.length == 2) + && (parts[0].length() > 0) + && ANY_STRING_VALIDATOR.validate(parts[0]) + && LOCALE_VALIDATOR.validate(parts[1].replace('-', '_'))); + } +} diff --git a/core/java/android/provider/settings/validators/TileListValidator.java b/core/java/android/provider/settings/validators/TileListValidator.java new file mode 100644 index 000000000000..c69644252bcd --- /dev/null +++ b/core/java/android/provider/settings/validators/TileListValidator.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 android.provider.settings.validators; + +import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR; + +/** + * Ensure a restored value is suitable to be used as a tile name + * + * @hide + */ +final class TileListValidator extends ListValidator { + TileListValidator() { + super(","); + } + + protected boolean isEntryValid(String entry) { + return entry != null; + } + + protected boolean isItemValid(String item) { + return item.length() > 0 && ANY_STRING_VALIDATOR.validate(item); + } +} diff --git a/core/java/android/provider/settings/validators/Validator.java b/core/java/android/provider/settings/validators/Validator.java new file mode 100644 index 000000000000..393a03ddf916 --- /dev/null +++ b/core/java/android/provider/settings/validators/Validator.java @@ -0,0 +1,32 @@ +/* + * 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.provider.settings.validators; + +import android.annotation.Nullable; + +/** + * Interface for a settings value validator. + * + * @hide + */ +public interface Validator { + /** + * Returns whether the input value is valid. Subclasses should handle the case where the + * input value is {@code null}. + */ + boolean validate(@Nullable String value); +} diff --git a/core/java/android/service/gatekeeper/GateKeeperResponse.java b/core/java/android/service/gatekeeper/GateKeeperResponse.java index 66fee1e90aff..7ed733cb4f4c 100644 --- a/core/java/android/service/gatekeeper/GateKeeperResponse.java +++ b/core/java/android/service/gatekeeper/GateKeeperResponse.java @@ -31,6 +31,8 @@ public final class GateKeeperResponse implements Parcelable { public static final int RESPONSE_OK = 0; public static final int RESPONSE_RETRY = 1; + public static final GateKeeperResponse ERROR = createGenericResponse(RESPONSE_ERROR); + private final int mResponseCode; private int mTimeout; diff --git a/core/java/android/util/Half.java b/core/java/android/util/Half.java index 70d049a6e985..fe536a6e4e68 100644 --- a/core/java/android/util/Half.java +++ b/core/java/android/util/Half.java @@ -20,6 +20,8 @@ import android.annotation.HalfFloat; import android.annotation.NonNull; import android.annotation.Nullable; +import libcore.util.FP16; + /** * <p>The {@code Half} class is a wrapper and a utility class to manipulate half-precision 16-bit * <a href="https://en.wikipedia.org/wiki/Half-precision_floating-point_format">IEEE 754</a> @@ -148,25 +150,6 @@ public final class Half extends Number implements Comparable<Half> { */ public static final @HalfFloat short POSITIVE_ZERO = (short) 0x0000; - private static final int FP16_SIGN_SHIFT = 15; - private static final int FP16_SIGN_MASK = 0x8000; - private static final int FP16_EXPONENT_SHIFT = 10; - private static final int FP16_EXPONENT_MASK = 0x1f; - private static final int FP16_SIGNIFICAND_MASK = 0x3ff; - private static final int FP16_EXPONENT_BIAS = 15; - private static final int FP16_COMBINED = 0x7fff; - private static final int FP16_EXPONENT_MAX = 0x7c00; - - private static final int FP32_SIGN_SHIFT = 31; - private static final int FP32_EXPONENT_SHIFT = 23; - private static final int FP32_EXPONENT_MASK = 0xff; - private static final int FP32_SIGNIFICAND_MASK = 0x7fffff; - private static final int FP32_EXPONENT_BIAS = 127; - private static final int FP32_QNAN_MASK = 0x400000; - - private static final int FP32_DENORMAL_MAGIC = 126 << 23; - private static final float FP32_DENORMAL_FLOAT = Float.intBitsToFloat(FP32_DENORMAL_MAGIC); - private final @HalfFloat short mValue; /** @@ -414,16 +397,7 @@ public final class Half extends Number implements Comparable<Half> { * than {@code y} */ public static int compare(@HalfFloat short x, @HalfFloat short y) { - if (less(x, y)) return -1; - if (greater(x, y)) return 1; - - // Collapse NaNs, akin to halfToIntBits(), but we want to keep - // (signed) short value types to preserve the ordering of -0.0 - // and +0.0 - short xBits = (x & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : x; - short yBits = (y & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : y; - - return (xBits == yBits ? 0 : (xBits < yBits ? -1 : 1)); + return FP16.compare(x, y); } /** @@ -440,7 +414,7 @@ public final class Half extends Number implements Comparable<Half> { * @see #halfToIntBits(short) */ public static @HalfFloat short halfToShortBits(@HalfFloat short h) { - return (h & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : h; + return (h & FP16.EXPONENT_SIGNIFICAND_MASK) > FP16.POSITIVE_INFINITY ? NaN : h; } /** @@ -459,7 +433,7 @@ public final class Half extends Number implements Comparable<Half> { * @see #intBitsToHalf(int) */ public static int halfToIntBits(@HalfFloat short h) { - return (h & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : h & 0xffff; + return (h & FP16.EXPONENT_SIGNIFICAND_MASK) > FP16.POSITIVE_INFINITY ? NaN : h & 0xffff; } /** @@ -505,7 +479,7 @@ public final class Half extends Number implements Comparable<Half> { * of the second parameter */ public static @HalfFloat short copySign(@HalfFloat short magnitude, @HalfFloat short sign) { - return (short) ((sign & FP16_SIGN_MASK) | (magnitude & FP16_COMBINED)); + return (short) ((sign & FP16.SIGN_MASK) | (magnitude & FP16.EXPONENT_SIGNIFICAND_MASK)); } /** @@ -523,7 +497,7 @@ public final class Half extends Number implements Comparable<Half> { * @return The absolute value of the specified half-precision float */ public static @HalfFloat short abs(@HalfFloat short h) { - return (short) (h & FP16_COMBINED); + return (short) (h & FP16.EXPONENT_SIGNIFICAND_MASK); } /** @@ -538,26 +512,18 @@ public final class Half extends Number implements Comparable<Half> { * the result is zero (with the same sign)</li> * </ul> * + * <p class=note> + * <strong>Note:</strong> Unlike the identically named + * <code class=prettyprint>int java.lang.Math.round(float)</code> method, + * this returns a Half value stored in a short, <strong>not</strong> an + * actual short integer result. + * * @param h A half-precision float value * @return The value of the specified half-precision float rounded to the nearest * half-precision float value */ public static @HalfFloat short round(@HalfFloat short h) { - int bits = h & 0xffff; - int e = bits & 0x7fff; - int result = bits; - - if (e < 0x3c00) { - result &= FP16_SIGN_MASK; - result |= (0x3c00 & (e >= 0x3800 ? 0xffff : 0x0)); - } else if (e < 0x6400) { - e = 25 - (e >> 10); - int mask = (1 << e) - 1; - result += (1 << (e - 1)); - result &= ~mask; - } - - return (short) result; + return FP16.rint(h); } /** @@ -577,21 +543,7 @@ public final class Half extends Number implements Comparable<Half> { * greater than or equal to the specified half-precision float value */ public static @HalfFloat short ceil(@HalfFloat short h) { - int bits = h & 0xffff; - int e = bits & 0x7fff; - int result = bits; - - if (e < 0x3c00) { - result &= FP16_SIGN_MASK; - result |= 0x3c00 & -(~(bits >> 15) & (e != 0 ? 1 : 0)); - } else if (e < 0x6400) { - e = 25 - (e >> 10); - int mask = (1 << e) - 1; - result += mask & ((bits >> 15) - 1); - result &= ~mask; - } - - return (short) result; + return FP16.ceil(h); } /** @@ -611,21 +563,7 @@ public final class Half extends Number implements Comparable<Half> { * less than or equal to the specified half-precision float value */ public static @HalfFloat short floor(@HalfFloat short h) { - int bits = h & 0xffff; - int e = bits & 0x7fff; - int result = bits; - - if (e < 0x3c00) { - result &= FP16_SIGN_MASK; - result |= 0x3c00 & (bits > 0x8000 ? 0xffff : 0x0); - } else if (e < 0x6400) { - e = 25 - (e >> 10); - int mask = (1 << e) - 1; - result += mask & -(bits >> 15); - result &= ~mask; - } - - return (short) result; + return FP16.floor(h); } /** @@ -644,19 +582,7 @@ public final class Half extends Number implements Comparable<Half> { * half-precision float value */ public static @HalfFloat short trunc(@HalfFloat short h) { - int bits = h & 0xffff; - int e = bits & 0x7fff; - int result = bits; - - if (e < 0x3c00) { - result &= FP16_SIGN_MASK; - } else if (e < 0x6400) { - e = 25 - (e >> 10); - int mask = (1 << e) - 1; - result &= ~mask; - } - - return (short) result; + return FP16.trunc(h); } /** @@ -672,15 +598,7 @@ public final class Half extends Number implements Comparable<Half> { * @return The smaller of the two specified half-precision values */ public static @HalfFloat short min(@HalfFloat short x, @HalfFloat short y) { - if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN; - if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN; - - if ((x & FP16_COMBINED) == 0 && (y & FP16_COMBINED) == 0) { - return (x & FP16_SIGN_MASK) != 0 ? x : y; - } - - return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) < - ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y; + return FP16.min(x, y); } /** @@ -697,15 +615,7 @@ public final class Half extends Number implements Comparable<Half> { * @return The larger of the two specified half-precision values */ public static @HalfFloat short max(@HalfFloat short x, @HalfFloat short y) { - if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN; - if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN; - - if ((x & FP16_COMBINED) == 0 && (y & FP16_COMBINED) == 0) { - return (x & FP16_SIGN_MASK) != 0 ? y : x; - } - - return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) > - ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y; + return FP16.max(x, y); } /** @@ -719,11 +629,7 @@ public final class Half extends Number implements Comparable<Half> { * @return True if x is less than y, false otherwise */ public static boolean less(@HalfFloat short x, @HalfFloat short y) { - if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - - return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) < - ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); + return FP16.less(x, y); } /** @@ -737,11 +643,7 @@ public final class Half extends Number implements Comparable<Half> { * @return True if x is less than or equal to y, false otherwise */ public static boolean lessEquals(@HalfFloat short x, @HalfFloat short y) { - if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - - return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <= - ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); + return FP16.lessEquals(x, y); } /** @@ -755,11 +657,7 @@ public final class Half extends Number implements Comparable<Half> { * @return True if x is greater than y, false otherwise */ public static boolean greater(@HalfFloat short x, @HalfFloat short y) { - if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - - return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) > - ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); + return FP16.greater(x, y); } /** @@ -773,11 +671,7 @@ public final class Half extends Number implements Comparable<Half> { * @return True if x is greater than y, false otherwise */ public static boolean greaterEquals(@HalfFloat short x, @HalfFloat short y) { - if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - - return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >= - ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); + return FP16.greaterEquals(x, y); } /** @@ -791,10 +685,7 @@ public final class Half extends Number implements Comparable<Half> { * @return True if x is equal to y, false otherwise */ public static boolean equals(@HalfFloat short x, @HalfFloat short y) { - if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - - return x == y || ((x | y) & FP16_COMBINED) == 0; + return FP16.equals(x, y); } /** @@ -804,7 +695,7 @@ public final class Half extends Number implements Comparable<Half> { * @return 1 if the value is positive, -1 if the value is negative */ public static int getSign(@HalfFloat short h) { - return (h & FP16_SIGN_MASK) == 0 ? 1 : -1; + return (h & FP16.SIGN_MASK) == 0 ? 1 : -1; } /** @@ -818,7 +709,7 @@ public final class Half extends Number implements Comparable<Half> { * @return The unbiased exponent of the specified value */ public static int getExponent(@HalfFloat short h) { - return ((h >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK) - FP16_EXPONENT_BIAS; + return ((h >>> FP16.EXPONENT_SHIFT) & FP16.SHIFTED_EXPONENT_MASK) - FP16.EXPONENT_BIAS; } /** @@ -829,7 +720,7 @@ public final class Half extends Number implements Comparable<Half> { * @return The significand, or significand, of the specified vlaue */ public static int getSignificand(@HalfFloat short h) { - return h & FP16_SIGNIFICAND_MASK; + return h & FP16.SIGNIFICAND_MASK; } /** @@ -841,7 +732,7 @@ public final class Half extends Number implements Comparable<Half> { * false otherwise */ public static boolean isInfinite(@HalfFloat short h) { - return (h & FP16_COMBINED) == FP16_EXPONENT_MAX; + return FP16.isInfinite(h); } /** @@ -852,7 +743,7 @@ public final class Half extends Number implements Comparable<Half> { * @return True if the value is a NaN, false otherwise */ public static boolean isNaN(@HalfFloat short h) { - return (h & FP16_COMBINED) > FP16_EXPONENT_MAX; + return FP16.isNaN(h); } /** @@ -866,7 +757,7 @@ public final class Half extends Number implements Comparable<Half> { * @return True if the value is normalized, false otherwise */ public static boolean isNormalized(@HalfFloat short h) { - return (h & FP16_EXPONENT_MAX) != 0 && (h & FP16_EXPONENT_MAX) != FP16_EXPONENT_MAX; + return FP16.isNormalized(h); } /** @@ -885,35 +776,7 @@ public final class Half extends Number implements Comparable<Half> { * @return A normalized single-precision float value */ public static float toFloat(@HalfFloat short h) { - int bits = h & 0xffff; - int s = bits & FP16_SIGN_MASK; - int e = (bits >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK; - int m = (bits ) & FP16_SIGNIFICAND_MASK; - - int outE = 0; - int outM = 0; - - if (e == 0) { // Denormal or 0 - if (m != 0) { - // Convert denorm fp16 into normalized fp32 - float o = Float.intBitsToFloat(FP32_DENORMAL_MAGIC + m); - o -= FP32_DENORMAL_FLOAT; - return s == 0 ? o : -o; - } - } else { - outM = m << 13; - if (e == 0x1f) { // Infinite or NaN - outE = 0xff; - if (outM != 0) { // SNaNs are quieted - outM |= FP32_QNAN_MASK; - } - } else { - outE = e - FP16_EXPONENT_BIAS + FP32_EXPONENT_BIAS; - } - } - - int out = (s << 16) | (outE << FP32_EXPONENT_SHIFT) | outM; - return Float.intBitsToFloat(out); + return FP16.toFloat(h); } /** @@ -940,44 +803,7 @@ public final class Half extends Number implements Comparable<Half> { */ @SuppressWarnings("StatementWithEmptyBody") public static @HalfFloat short toHalf(float f) { - int bits = Float.floatToRawIntBits(f); - int s = (bits >>> FP32_SIGN_SHIFT ); - int e = (bits >>> FP32_EXPONENT_SHIFT) & FP32_EXPONENT_MASK; - int m = (bits ) & FP32_SIGNIFICAND_MASK; - - int outE = 0; - int outM = 0; - - if (e == 0xff) { // Infinite or NaN - outE = 0x1f; - outM = m != 0 ? 0x200 : 0; - } else { - e = e - FP32_EXPONENT_BIAS + FP16_EXPONENT_BIAS; - if (e >= 0x1f) { // Overflow - outE = 0x31; - } else if (e <= 0) { // Underflow - if (e < -10) { - // The absolute fp32 value is less than MIN_VALUE, flush to +/-0 - } else { - // The fp32 value is a normalized float less than MIN_NORMAL, - // we convert to a denorm fp16 - m = (m | 0x800000) >> (1 - e); - if ((m & 0x1000) != 0) m += 0x2000; - outM = m >> 13; - } - } else { - outE = e; - outM = m >> 13; - if ((m & 0x1000) != 0) { - // Round to nearest "0.5" up - int out = (outE << FP16_EXPONENT_SHIFT) | outM; - out++; - return (short) (out | (s << FP16_SIGN_SHIFT)); - } - } - } - - return (short) ((s << FP16_SIGN_SHIFT) | (outE << FP16_EXPONENT_SHIFT) | outM); + return FP16.toHalf(f); } /** @@ -1073,40 +899,6 @@ public final class Half extends Number implements Comparable<Half> { */ @NonNull public static String toHexString(@HalfFloat short h) { - StringBuilder o = new StringBuilder(); - - int bits = h & 0xffff; - int s = (bits >>> FP16_SIGN_SHIFT ); - int e = (bits >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK; - int m = (bits ) & FP16_SIGNIFICAND_MASK; - - if (e == 0x1f) { // Infinite or NaN - if (m == 0) { - if (s != 0) o.append('-'); - o.append("Infinity"); - } else { - o.append("NaN"); - } - } else { - if (s == 1) o.append('-'); - if (e == 0) { - if (m == 0) { - o.append("0x0.0p0"); - } else { - o.append("0x0."); - String significand = Integer.toHexString(m); - o.append(significand.replaceFirst("0{2,}$", "")); - o.append("p-14"); - } - } else { - o.append("0x1."); - String significand = Integer.toHexString(m); - o.append(significand.replaceFirst("0{2,}$", "")); - o.append('p'); - o.append(Integer.toString(e - FP16_EXPONENT_BIAS)); - } - } - - return o.toString(); + return FP16.toHexString(h); } } diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java index 8b5659b3fa31..3a1df3ec861e 100644 --- a/core/java/android/util/LocalLog.java +++ b/core/java/android/util/LocalLog.java @@ -60,9 +60,19 @@ public final class LocalLog { } public synchronized void dump(PrintWriter pw) { + dump("", pw); + } + + /** + * Dumps the content of local log to print writer with each log entry predeced with indent + * + * @param indent indent that precedes each log entry + * @param pw printer writer to write into + */ + public synchronized void dump(String indent, PrintWriter pw) { Iterator<String> itr = mLog.iterator(); while (itr.hasNext()) { - pw.println(itr.next()); + pw.printf("%s%s\n", indent, itr.next()); } } diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java index f8b38e9d215d..07cecd38620d 100644 --- a/core/java/android/util/TimeUtils.java +++ b/core/java/android/util/TimeUtils.java @@ -62,9 +62,9 @@ public class TimeUtils { } /** - * Tries to return a frozen ICU time zone that would have had the specified offset - * and DST value at the specified moment in the specified country. - * Returns null if no suitable zone could be found. + * Returns a frozen ICU time zone that has / would have had the specified offset and DST value + * at the specified moment in the specified country. Returns null if no suitable zone could be + * found. */ private static android.icu.util.TimeZone getIcuTimeZone( int offset, boolean dst, long when, String country) { @@ -73,8 +73,15 @@ public class TimeUtils { } android.icu.util.TimeZone bias = android.icu.util.TimeZone.getDefault(); - return TimeZoneFinder.getInstance() - .lookupTimeZoneByCountryAndOffset(country, offset, dst, when, bias); + CountryTimeZones countryTimeZones = + TimeZoneFinder.getInstance().lookupCountryTimeZones(country); + if (countryTimeZones == null) { + return null; + } + + CountryTimeZones.OffsetResult offsetResult = + countryTimeZones.lookupByOffsetWithBias(offset, dst, when, bias); + return offsetResult != null ? offsetResult.mTimeZone : null; } /** diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java index 42275a3e3165..d7d7e210e5f4 100644 --- a/core/java/android/view/accessibility/AccessibilityRecord.java +++ b/core/java/android/view/accessibility/AccessibilityRecord.java @@ -856,6 +856,8 @@ public class AccessibilityRecord { mScrollY = record.mScrollY; mMaxScrollX = record.mMaxScrollX; mMaxScrollY = record.mMaxScrollY; + mScrollDeltaX = record.mScrollDeltaX; + mScrollDeltaY = record.mScrollDeltaY; mAddedCount = record.mAddedCount; mRemovedCount = record.mRemovedCount; mClassName = record.mClassName; @@ -882,6 +884,8 @@ public class AccessibilityRecord { mScrollY = 0; mMaxScrollX = 0; mMaxScrollY = 0; + mScrollDeltaX = UNDEFINED; + mScrollDeltaY = UNDEFINED; mAddedCount = UNDEFINED; mRemovedCount = UNDEFINED; mClassName = null; @@ -921,6 +925,8 @@ public class AccessibilityRecord { append(builder, "ScrollY", mScrollY); append(builder, "MaxScrollX", mMaxScrollX); append(builder, "MaxScrollY", mMaxScrollY); + append(builder, "ScrollDeltaX", mScrollDeltaX); + append(builder, "ScrollDeltaY", mScrollDeltaY); append(builder, "AddedCount", mAddedCount); append(builder, "RemovedCount", mRemovedCount); append(builder, "ParcelableData", mParcelableData); diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index cee79439d1b3..1e7440bd5a43 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -480,6 +480,8 @@ public final class MainContentCaptureSession extends ContentCaptureSession { return; } + mNextFlushForTextChanged = false; + final int numberEvents = mEvents.size(); final String reasonString = getFlushReasonAsString(reason); if (sDebug) { @@ -495,10 +497,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession { try { mHandler.removeMessages(MSG_FLUSH); - if (reason == FLUSH_REASON_TEXT_CHANGE_TIMEOUT) { - mNextFlushForTextChanged = false; - } - final ParceledListSlice<ContentCaptureEvent> events = clearEvents(); mDirectServiceInterface.sendEvents(events, reason, mManager.mOptions); } catch (RemoteException e) { diff --git a/core/java/android/webkit/PermissionRequest.java b/core/java/android/webkit/PermissionRequest.java index 18ec334d0283..ac145b1d81a5 100644 --- a/core/java/android/webkit/PermissionRequest.java +++ b/core/java/android/webkit/PermissionRequest.java @@ -32,7 +32,7 @@ import android.net.Uri; * avoid unintentionally granting requests for new permissions, you should pass the * specific permissions you intend to grant to {@link #grant(String[]) grant()}, * and avoid writing code like this example: - * <pre> + * <pre class="prettyprint"> * permissionRequest.grant(permissionRequest.getResources()) // This is wrong!!! * </pre> * See the WebView's release notes for information about new protected resources. diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java index 95fe963d7891..4db630808ef1 100644 --- a/core/java/android/webkit/WebChromeClient.java +++ b/core/java/android/webkit/WebChromeClient.java @@ -519,15 +519,17 @@ public class WebChromeClient { * may not be supported and applications wishing to support these sources * or more advanced file operations should build their own Intent. * - * <pre> - * How to use: - * 1. Build an intent using {@link #createIntent} - * 2. Fire the intent using {@link android.app.Activity#startActivityForResult}. - * 3. Check for ActivityNotFoundException and take a user friendly action if thrown. - * 4. Listen the result using {@link android.app.Activity#onActivityResult} - * 5. Parse the result using {@link #parseResult} only if media capture was not requested. - * 6. Send the result using filePathCallback of {@link WebChromeClient#onShowFileChooser} - * </pre> + * <p>How to use: + * <ol> + * <li>Build an intent using {@link #createIntent}</li> + * <li>Fire the intent using {@link android.app.Activity#startActivityForResult}.</li> + * <li>Check for ActivityNotFoundException and take a user friendly action if thrown.</li> + * <li>Listen the result using {@link android.app.Activity#onActivityResult}</li> + * <li>Parse the result using {@link #parseResult} only if media capture was not + * requested.</li> + * <li>Send the result using filePathCallback of {@link + * WebChromeClient#onShowFileChooser}</li> + * </ol> * * @return an Intent that supports basic file chooser sources. */ diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index a35659e307d5..e4b5eaa56aa6 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -762,7 +762,7 @@ public class WebView extends AbsoluteLayout * encoded. If the data is base64 encoded, the value of the encoding * parameter must be {@code "base64"}. HTML can be encoded with {@link * android.util.Base64#encodeToString(byte[],int)} like so: - * <pre> + * <pre class="prettyprint"> * String unencodedHtml = * "<html><body>'%28' is the code for '('</body></html>"; * String encodedHtml = Base64.encodeToString(unencodedHtml.getBytes(), Base64.NO_PADDING); @@ -1854,7 +1854,7 @@ public class WebView extends AbsoluteLayout * important security note below for implications. * <p> Note that injected objects will not appear in JavaScript until the page is next * (re)loaded. JavaScript should be enabled before injecting the object. For example: - * <pre> + * <pre class="prettyprint"> * class JsObject { * {@literal @}JavascriptInterface * public String toString() { return "injectedObject"; } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 85e9e4950cba..fe88a9140b37 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -2550,12 +2550,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te return; } - final boolean isItemEnabled; + boolean isItemEnabled = view.isEnabled() && isEnabled(); final ViewGroup.LayoutParams lp = view.getLayoutParams(); if (lp instanceof AbsListView.LayoutParams) { - isItemEnabled = ((AbsListView.LayoutParams) lp).isEnabled && isEnabled(); - } else { - isItemEnabled = false; + isItemEnabled &= ((AbsListView.LayoutParams) lp).isEnabled; } info.setEnabled(isItemEnabled); diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 00206fc38d1d..faeecda7250c 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -164,6 +164,8 @@ public class ChooserActivity extends ResolverActivity { public static final String LAUNCH_LOCATON_DIRECT_SHARE = "direct_share"; private static final int APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT = 20; public static final String APP_PREDICTION_INTENT_FILTER_KEY = "intent_filter"; + + private boolean mIsAppPredictorComponentAvailable; private AppPredictor mAppPredictor; private AppPredictor.Callback mAppPredictorCallback; private Map<ChooserTarget, AppTarget> mDirectShareAppTargetCache; @@ -617,6 +619,9 @@ public class ChooserActivity extends ResolverActivity { .addTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE, target.getType()) .addTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS, systemCost)); + // This is the only place this value is being set. Effectively final. + mIsAppPredictorComponentAvailable = isAppPredictionServiceAvailable(); + AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled(); if (appPredictor != null) { mDirectShareAppTargetCache = new HashMap<>(); @@ -707,6 +712,32 @@ public class ChooserActivity extends ResolverActivity { } /** + * Returns true if app prediction service is defined and the component exists on device. + */ + private boolean isAppPredictionServiceAvailable() { + final String appPredictionServiceName = + getString(R.string.config_defaultAppPredictionService); + if (appPredictionServiceName == null) { + return false; + } + final ComponentName appPredictionComponentName = + ComponentName.unflattenFromString(appPredictionServiceName); + if (appPredictionComponentName == null) { + return false; + } + + // Check if the app prediction component actually exists on the device. + Intent intent = new Intent(); + intent.setComponent(appPredictionComponentName); + if (getPackageManager().resolveService(intent, PackageManager.MATCH_ALL) == null) { + Log.e(TAG, "App prediction service is defined, but does not exist: " + + appPredictionServiceName); + return false; + } + return true; + } + + /** * Check if the profile currently used is a work profile. * @return true if it is work profile, false if it is parent profile (or no work profile is * set up) @@ -1693,6 +1724,9 @@ public class ChooserActivity extends ResolverActivity { @Nullable private AppPredictor getAppPredictor() { + if (!mIsAppPredictorComponentAvailable) { + return null; + } if (mAppPredictor == null && getPackageManager().getAppPredictionServicePackageName() != null) { final IntentFilter filter = getTargetIntentFilter(); diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java index 1d81c59a8f89..152d699f5e6b 100644 --- a/core/java/com/android/internal/content/PackageHelper.java +++ b/core/java/com/android/internal/content/PackageHelper.java @@ -35,7 +35,7 @@ import android.os.storage.StorageManager; import android.os.storage.StorageVolume; import android.os.storage.VolumeInfo; import android.provider.Settings; -import android.util.ArraySet; +import android.util.ArrayMap; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -166,6 +166,23 @@ public class PackageHelper { params.sizeBytes, testableInterface); } + private static boolean checkFitOnVolume(StorageManager storageManager, String volumePath, + SessionParams params) throws IOException { + if (volumePath == null) { + return false; + } + final int installFlags = translateAllocateFlags(params.installFlags); + final UUID target = storageManager.getUuidForPath(new File(volumePath)); + final long availBytes = storageManager.getAllocatableBytes(target, + installFlags | StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY); + if (params.sizeBytes <= availBytes) { + return true; + } + final long cacheClearable = storageManager.getAllocatableBytes(target, + installFlags | StorageManager.FLAG_ALLOCATE_CACHE_ONLY); + return params.sizeBytes <= availBytes + cacheClearable; + } + @VisibleForTesting public static String resolveInstallVolume(Context context, SessionParams params, TestableInterface testInterface) throws IOException { @@ -178,35 +195,23 @@ public class PackageHelper { ApplicationInfo existingInfo = testInterface.getExistingAppInfo(context, params.appPackageName); - // Figure out best candidate volume, and also if we fit on internal - final ArraySet<String> allCandidates = new ArraySet<>(); - boolean fitsOnInternal = false; - VolumeInfo bestCandidate = null; - long bestCandidateAvailBytes = Long.MIN_VALUE; + final ArrayMap<String, String> volumePaths = new ArrayMap<>(); + String internalVolumePath = null; for (VolumeInfo vol : storageManager.getVolumes()) { if (vol.type == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) { final boolean isInternalStorage = ID_PRIVATE_INTERNAL.equals(vol.id); - final UUID target = storageManager.getUuidForPath(new File(vol.path)); - final long availBytes = storageManager.getAllocatableBytes(target, - translateAllocateFlags(params.installFlags)); if (isInternalStorage) { - fitsOnInternal = (params.sizeBytes <= availBytes); + internalVolumePath = vol.path; } if (!isInternalStorage || allow3rdPartyOnInternal) { - if (availBytes >= params.sizeBytes) { - allCandidates.add(vol.fsUuid); - } - if (availBytes >= bestCandidateAvailBytes) { - bestCandidate = vol; - bestCandidateAvailBytes = availBytes; - } + volumePaths.put(vol.fsUuid, vol.path); } } } // System apps always forced to internal storage if (existingInfo != null && existingInfo.isSystemApp()) { - if (fitsOnInternal) { + if (checkFitOnVolume(storageManager, internalVolumePath, params)) { return StorageManager.UUID_PRIVATE_INTERNAL; } else { throw new IOException("Not enough space on existing volume " @@ -228,7 +233,7 @@ public class PackageHelper { throw new IOException("Not allowed to install non-system apps on internal storage"); } - if (fitsOnInternal) { + if (checkFitOnVolume(storageManager, internalVolumePath, params)) { return StorageManager.UUID_PRIVATE_INTERNAL; } else { throw new IOException("Requested internal only, but not enough space"); @@ -237,10 +242,14 @@ public class PackageHelper { // If app already exists somewhere, we must stay on that volume if (existingInfo != null) { - if (Objects.equals(existingInfo.volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL) - && fitsOnInternal) { - return StorageManager.UUID_PRIVATE_INTERNAL; - } else if (allCandidates.contains(existingInfo.volumeUuid)) { + String existingVolumePath = null; + if (Objects.equals(existingInfo.volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) { + existingVolumePath = internalVolumePath; + } else if (volumePaths.containsKey(existingInfo.volumeUuid)) { + existingVolumePath = volumePaths.get(existingInfo.volumeUuid); + } + + if (checkFitOnVolume(storageManager, existingVolumePath, params)) { return existingInfo.volumeUuid; } else { throw new IOException("Not enough space on existing volume " @@ -250,12 +259,36 @@ public class PackageHelper { // We're left with new installations with either preferring external or auto, so just pick // volume with most space - if (bestCandidate != null) { - return bestCandidate.fsUuid; + if (volumePaths.size() == 1) { + if (checkFitOnVolume(storageManager, volumePaths.valueAt(0), params)) { + return volumePaths.keyAt(0); + } } else { - throw new IOException("No special requests, but no room on allowed volumes. " - + " allow3rdPartyOnInternal? " + allow3rdPartyOnInternal); + String bestCandidate = null; + long bestCandidateAvailBytes = Long.MIN_VALUE; + for (String vol : volumePaths.keySet()) { + final String volumePath = volumePaths.get(vol); + final UUID target = storageManager.getUuidForPath(new File(volumePath)); + + // We need to take into account freeable cached space, because we're choosing the + // best candidate amongst a list, not just checking if we fit at all. + final long availBytes = storageManager.getAllocatableBytes(target, + translateAllocateFlags(params.installFlags)); + + if (availBytes >= bestCandidateAvailBytes) { + bestCandidate = vol; + bestCandidateAvailBytes = availBytes; + } + } + + if (bestCandidateAvailBytes >= params.sizeBytes) { + return bestCandidate; + } + } + + throw new IOException("No special requests, but no room on allowed volumes. " + + " allow3rdPartyOnInternal? " + allow3rdPartyOnInternal); } public static boolean fitsOnInternal(Context context, SessionParams params) throws IOException { diff --git a/core/java/com/android/internal/os/AtomicDirectory.java b/core/java/com/android/internal/os/AtomicDirectory.java index f24d12e0c3af..8ca7a7186cb4 100644 --- a/core/java/com/android/internal/os/AtomicDirectory.java +++ b/core/java/com/android/internal/os/AtomicDirectory.java @@ -17,13 +17,17 @@ package com.android.internal.os; import android.annotation.NonNull; -import android.annotation.Nullable; import android.os.FileUtils; +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; import android.util.ArrayMap; +import android.util.Log; import com.android.internal.util.Preconditions; import java.io.File; +import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.IOException; import java.util.Arrays; @@ -46,12 +50,13 @@ import java.util.Arrays; * backing directory when checking existence, making changes, and deleting. */ public final class AtomicDirectory { - private final @NonNull ArrayMap<File, FileOutputStream> mOpenFiles = new ArrayMap<>(); + + private static final String LOG_TAG = AtomicDirectory.class.getSimpleName(); + private final @NonNull File mBaseDirectory; private final @NonNull File mBackupDirectory; - private int mBaseDirectoryFd = -1; - private int mBackupDirectoryFd = -1; + private final @NonNull ArrayMap<File, FileOutputStream> mOpenFiles = new ArrayMap<>(); /** * Creates a new instance. @@ -65,15 +70,16 @@ public final class AtomicDirectory { } /** - * Gets the backup directory if present. This could be useful if you are - * writing new state to the dir but need to access the last persisted state - * at the same time. This means that this call is useful in between - * {@link #startWrite()} and {@link #finishWrite()} or {@link #failWrite()}. - * You should not modify the content returned by this method. + * Gets the backup directory which may or may not exist. This could be + * useful if you are writing new state to the directory but need to access + * the last persisted state at the same time. This means that this call is + * useful in between {@link #startWrite()} and {@link #finishWrite()} or + * {@link #failWrite()}. You should not modify the content returned by this + * method. * * @see #startRead() */ - public @Nullable File getBackupDirectory() { + public @NonNull File getBackupDirectory() { return mBackupDirectory; } @@ -88,7 +94,8 @@ public final class AtomicDirectory { */ public @NonNull File startRead() throws IOException { restore(); - return getOrCreateBaseDirectory(); + ensureBaseDirectory(); + return mBaseDirectory; } /** @@ -97,10 +104,7 @@ public final class AtomicDirectory { * @see #startRead() * @see #startWrite() */ - public void finishRead() { - mBaseDirectoryFd = -1; - mBackupDirectoryFd = -1; - } + public void finishRead() {} /** * Starts editing this directory. After calling this method you should @@ -119,7 +123,8 @@ public final class AtomicDirectory { */ public @NonNull File startWrite() throws IOException { backup(); - return getOrCreateBaseDirectory(); + ensureBaseDirectory(); + return mBaseDirectory; } /** @@ -133,13 +138,14 @@ public final class AtomicDirectory { * @see #closeWrite(FileOutputStream) */ public @NonNull FileOutputStream openWrite(@NonNull File file) throws IOException { - if (file.isDirectory() || !file.getParentFile().equals(getOrCreateBaseDirectory())) { - throw new IllegalArgumentException("Must be a file in " + getOrCreateBaseDirectory()); + if (file.isDirectory() || !file.getParentFile().equals(mBaseDirectory)) { + throw new IllegalArgumentException("Must be a file in " + mBaseDirectory); } - final FileOutputStream destination = new FileOutputStream(file); - if (mOpenFiles.put(file, destination) != null) { - throw new IllegalArgumentException("Already open file" + file.getCanonicalPath()); + if (mOpenFiles.containsKey(file)) { + throw new IllegalArgumentException("Already open file " + file.getAbsolutePath()); } + final FileOutputStream destination = new FileOutputStream(file); + mOpenFiles.put(file, destination); return destination; } @@ -152,20 +158,21 @@ public final class AtomicDirectory { */ public void closeWrite(@NonNull FileOutputStream destination) { final int indexOfValue = mOpenFiles.indexOfValue(destination); - if (mOpenFiles.removeAt(indexOfValue) == null) { + if (indexOfValue < 0) { throw new IllegalArgumentException("Unknown file stream " + destination); } + mOpenFiles.removeAt(indexOfValue); FileUtils.sync(destination); - try { - destination.close(); - } catch (IOException ignored) {} + FileUtils.closeQuietly(destination); } public void failWrite(@NonNull FileOutputStream destination) { final int indexOfValue = mOpenFiles.indexOfValue(destination); - if (indexOfValue >= 0) { - mOpenFiles.removeAt(indexOfValue); + if (indexOfValue < 0) { + throw new IllegalArgumentException("Unknown file stream " + destination); } + mOpenFiles.removeAt(indexOfValue); + FileUtils.closeQuietly(destination); } /** @@ -173,15 +180,15 @@ public final class AtomicDirectory { * * @see #startWrite() * - * @throws IllegalStateException is some files are not closed. + * @throws IllegalStateException if some files are not closed. */ public void finishWrite() { throwIfSomeFilesOpen(); - fsyncDirectoryFd(mBaseDirectoryFd); + + syncDirectory(mBaseDirectory); + syncParentDirectory(); deleteDirectory(mBackupDirectory); - fsyncDirectoryFd(mBackupDirectoryFd); - mBaseDirectoryFd = -1; - mBackupDirectoryFd = -1; + syncParentDirectory(); } /** @@ -191,11 +198,12 @@ public final class AtomicDirectory { */ public void failWrite() { throwIfSomeFilesOpen(); + try{ restore(); - } catch (IOException ignored) {} - mBaseDirectoryFd = -1; - mBackupDirectoryFd = -1; + } catch (IOException e) { + Log.e(LOG_TAG, "Failed to restore in failWrite()", e); + } } /** @@ -209,29 +217,28 @@ public final class AtomicDirectory { * Deletes this directory. */ public void delete() { + boolean deleted = false; if (mBaseDirectory.exists()) { - deleteDirectory(mBaseDirectory); - fsyncDirectoryFd(mBaseDirectoryFd); + deleted |= deleteDirectory(mBaseDirectory); } if (mBackupDirectory.exists()) { - deleteDirectory(mBackupDirectory); - fsyncDirectoryFd(mBackupDirectoryFd); + deleted |= deleteDirectory(mBackupDirectory); + } + if (deleted) { + syncParentDirectory(); } } - private @NonNull File getOrCreateBaseDirectory() throws IOException { - if (!mBaseDirectory.exists()) { - if (!mBaseDirectory.mkdirs()) { - throw new IOException("Couldn't create directory " + mBaseDirectory); - } - FileUtils.setPermissions(mBaseDirectory.getPath(), - FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, - -1, -1); + private void ensureBaseDirectory() throws IOException { + if (mBaseDirectory.exists()) { + return; } - if (mBaseDirectoryFd < 0) { - mBaseDirectoryFd = getDirectoryFd(mBaseDirectory.getCanonicalPath()); + + if (!mBaseDirectory.mkdirs()) { + throw new IOException("Failed to create directory " + mBaseDirectory); } - return mBaseDirectory; + FileUtils.setPermissions(mBaseDirectory.getPath(), + FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1); } private void throwIfSomeFilesOpen() { @@ -245,50 +252,56 @@ public final class AtomicDirectory { if (!mBaseDirectory.exists()) { return; } - if (mBaseDirectoryFd < 0) { - mBaseDirectoryFd = getDirectoryFd(mBaseDirectory.getCanonicalPath()); - } + if (mBackupDirectory.exists()) { deleteDirectory(mBackupDirectory); } if (!mBaseDirectory.renameTo(mBackupDirectory)) { - throw new IOException("Couldn't backup " + mBaseDirectory - + " to " + mBackupDirectory); + throw new IOException("Failed to backup " + mBaseDirectory + " to " + mBackupDirectory); } - mBackupDirectoryFd = mBaseDirectoryFd; - mBaseDirectoryFd = -1; - fsyncDirectoryFd(mBackupDirectoryFd); + syncParentDirectory(); } private void restore() throws IOException { if (!mBackupDirectory.exists()) { return; } - if (mBackupDirectoryFd == -1) { - mBackupDirectoryFd = getDirectoryFd(mBackupDirectory.getCanonicalPath()); - } + if (mBaseDirectory.exists()) { deleteDirectory(mBaseDirectory); } if (!mBackupDirectory.renameTo(mBaseDirectory)) { - throw new IOException("Couldn't restore " + mBackupDirectory - + " to " + mBaseDirectory); + throw new IOException("Failed to restore " + mBackupDirectory + " to " + + mBaseDirectory); } - mBaseDirectoryFd = mBackupDirectoryFd; - mBackupDirectoryFd = -1; - fsyncDirectoryFd(mBaseDirectoryFd); + syncParentDirectory(); } - private static void deleteDirectory(@NonNull File file) { - final File[] children = file.listFiles(); - if (children != null) { - for (File child : children) { - deleteDirectory(child); - } - } - file.delete(); + private static boolean deleteDirectory(@NonNull File directory) { + return FileUtils.deleteContentsAndDir(directory); } - private static native int getDirectoryFd(String path); - private static native void fsyncDirectoryFd(int fd); + private void syncParentDirectory() { + syncDirectory(mBaseDirectory.getParentFile()); + } + + // Standard Java IO doesn't allow opening a directory (will throw a FileNotFoundException + // instead), so we have to do it manually. + private static void syncDirectory(@NonNull File directory) { + String path = directory.getAbsolutePath(); + FileDescriptor fd; + try { + fd = Os.open(path, OsConstants.O_RDONLY, 0); + } catch (ErrnoException e) { + Log.e(LOG_TAG, "Failed to open " + path, e); + return; + } + try { + Os.fsync(fd); + } catch (ErrnoException e) { + Log.e(LOG_TAG, "Failed to fsync " + path, e); + } finally { + FileUtils.closeQuietly(fd); + } + } } diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index cf0394d466ea..9441825a1ed6 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -153,7 +153,7 @@ oneway interface IStatusBar // Used to show the dialog when BiometricService starts authentication void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver, int type, - boolean requireConfirmation, int userId); + boolean requireConfirmation, int userId, String opPackageName); // Used to hide the dialog when a biometric is authenticated void onBiometricAuthenticated(boolean authenticated, String failureReason); // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 85ae18e86793..4c3a177a013b 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -101,7 +101,7 @@ interface IStatusBarService // Used to show the dialog when BiometricService starts authentication void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver, int type, - boolean requireConfirmation, int userId); + boolean requireConfirmation, int userId, String opPackageName); // Used to hide the dialog when a biometric is authenticated void onBiometricAuthenticated(boolean authenticated, String failureReason); // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java index c73de8fad5b2..1bb2ba293186 100644 --- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java +++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java @@ -775,17 +775,54 @@ public class ResolverDrawerLayout extends ViewGroup { return false; } + private boolean performAccessibilityActionCommon(int action) { + switch (action) { + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: + case AccessibilityNodeInfo.ACTION_EXPAND: + case R.id.accessibilityActionScrollDown: + if (mCollapseOffset != 0) { + smoothScrollTo(0, 0); + return true; + } + break; + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: + case R.id.accessibilityActionScrollUp: + if (mCollapseOffset < mCollapsibleHeight) { + smoothScrollTo(mCollapsibleHeight, 0); + return true; + } else if ((mCollapseOffset < mCollapsibleHeight + mUncollapsibleHeight) + && isDismissable()) { + smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, 0); + mDismissOnScrollerFinished = true; + return true; + } + break; + case AccessibilityNodeInfo.ACTION_COLLAPSE: + if (mCollapseOffset < mCollapsibleHeight) { + smoothScrollTo(mCollapsibleHeight, 0); + return true; + } + break; + case AccessibilityNodeInfo.ACTION_DISMISS: + if ((mCollapseOffset < mCollapsibleHeight + mUncollapsibleHeight) + && isDismissable()) { + smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, 0); + mDismissOnScrollerFinished = true; + return true; + } + break; + } + + return false; + } + @Override public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) { if (super.onNestedPrePerformAccessibilityAction(target, action, args)) { return true; } - if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD && mCollapseOffset != 0) { - smoothScrollTo(0, 0); - return true; - } - return false; + return performAccessibilityActionCommon(action); } @Override @@ -802,9 +839,23 @@ public class ResolverDrawerLayout extends ViewGroup { if (isEnabled()) { if (mCollapseOffset != 0) { - info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); + info.addAction(AccessibilityAction.ACTION_SCROLL_FORWARD); + info.addAction(AccessibilityAction.ACTION_EXPAND); + info.addAction(AccessibilityAction.ACTION_SCROLL_DOWN); + info.setScrollable(true); + } + if ((mCollapseOffset < mCollapsibleHeight + mUncollapsibleHeight) + && ((mCollapseOffset < mCollapsibleHeight) || isDismissable())) { + info.addAction(AccessibilityAction.ACTION_SCROLL_BACKWARD); + info.addAction(AccessibilityAction.ACTION_SCROLL_UP); info.setScrollable(true); } + if (mCollapseOffset < mCollapsibleHeight) { + info.addAction(AccessibilityAction.ACTION_COLLAPSE); + } + if (mCollapseOffset < mCollapsibleHeight + mUncollapsibleHeight && isDismissable()) { + info.addAction(AccessibilityAction.ACTION_DISMISS); + } } // This view should never get accessibility focus, but it's interactive @@ -823,12 +874,7 @@ public class ResolverDrawerLayout extends ViewGroup { return true; } - if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD && mCollapseOffset != 0) { - smoothScrollTo(0, 0); - return true; - } - - return false; + return performAccessibilityActionCommon(action); } @Override diff --git a/core/jni/Android.bp b/core/jni/Android.bp index a54247572b80..fb68bc762245 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -195,7 +195,6 @@ cc_library_shared { "android_content_res_ObbScanner.cpp", "android_content_res_Configuration.cpp", "android_security_Scrypt.cpp", - "com_android_internal_os_AtomicDirectory.cpp", "com_android_internal_os_ClassLoaderFactory.cpp", "com_android_internal_os_FuseAppLoop.cpp", "com_android_internal_os_Zygote.cpp", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 533f403034a9..a3fd915c29b2 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -227,7 +227,6 @@ extern int register_android_content_res_Configuration(JNIEnv* env); extern int register_android_animation_PropertyValuesHolder(JNIEnv *env); extern int register_android_security_Scrypt(JNIEnv *env); extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env); -extern int register_com_android_internal_os_AtomicDirectory(JNIEnv *env); extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env); extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env); extern int register_com_android_internal_os_Zygote(JNIEnv *env); @@ -1602,7 +1601,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_animation_PropertyValuesHolder), REG_JNI(register_android_security_Scrypt), REG_JNI(register_com_android_internal_content_NativeLibraryHelper), - REG_JNI(register_com_android_internal_os_AtomicDirectory), REG_JNI(register_com_android_internal_os_FuseAppLoop), }; diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 78e8e1322db2..18a1b43d3f5f 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -237,10 +237,6 @@ Bitmap& toBitmap(jlong bitmapHandle) { } void imageInfo(JNIEnv* env, jobject bitmap, AndroidBitmapInfo* info) { - SkASSERT(info); - SkASSERT(env); - SkASSERT(bitmap); - SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); LocalScopedBitmap localBitmap(bitmapHandle); @@ -262,6 +258,9 @@ void imageInfo(JNIEnv* env, jobject bitmap, AndroidBitmapInfo* info) { case kAlpha_8_SkColorType: info->format = ANDROID_BITMAP_FORMAT_A_8; break; + case kRGBA_F16_SkColorType: + info->format = ANDROID_BITMAP_FORMAT_RGBA_F16; + break; default: info->format = ANDROID_BITMAP_FORMAT_NONE; break; diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp index 98162af7d27b..ec91cbf854a6 100644 --- a/core/jni/android/graphics/ImageDecoder.cpp +++ b/core/jni/android/graphics/ImageDecoder.cpp @@ -78,14 +78,18 @@ static jobject throw_exception(JNIEnv* env, ImageDecoder::Error error, const cha return nullptr; } -static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream, jobject source) { +static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream, + jobject source, jboolean preferAnimation) { if (!stream.get()) { return throw_exception(env, ImageDecoder::kSourceMalformedData, "Failed to create a stream", nullptr, source); } std::unique_ptr<ImageDecoder> decoder(new ImageDecoder); SkCodec::Result result; - auto codec = SkCodec::MakeFromStream(std::move(stream), &result, decoder->mPeeker.get()); + auto codec = SkCodec::MakeFromStream( + std::move(stream), &result, decoder->mPeeker.get(), + preferAnimation ? SkCodec::SelectionPolicy::kPreferAnimation + : SkCodec::SelectionPolicy::kPreferStillImage); if (jthrowable jexception = get_and_clear_exception(env)) { return throw_exception(env, ImageDecoder::kSourceException, "", jexception, source); } @@ -124,7 +128,7 @@ static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream, jobj } static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/, - jobject fileDescriptor, jobject source) { + jobject fileDescriptor, jboolean preferAnimation, jobject source) { int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor); struct stat fdStat; @@ -142,11 +146,11 @@ static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/, } std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file)); - return native_create(env, std::move(fileStream), source); + return native_create(env, std::move(fileStream), source, preferAnimation); } static jobject ImageDecoder_nCreateInputStream(JNIEnv* env, jobject /*clazz*/, - jobject is, jbyteArray storage, jobject source) { + jobject is, jbyteArray storage, jboolean preferAnimation, jobject source) { std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage, false)); if (!stream.get()) { @@ -157,31 +161,33 @@ static jobject ImageDecoder_nCreateInputStream(JNIEnv* env, jobject /*clazz*/, std::unique_ptr<SkStream> bufferedStream( SkFrontBufferedStream::Make(std::move(stream), SkCodec::MinBufferedBytesNeeded())); - return native_create(env, std::move(bufferedStream), source); + return native_create(env, std::move(bufferedStream), source, preferAnimation); } -static jobject ImageDecoder_nCreateAsset(JNIEnv* env, jobject /*clazz*/, jlong assetPtr, - jobject source) { +static jobject ImageDecoder_nCreateAsset(JNIEnv* env, jobject /*clazz*/, + jlong assetPtr, jboolean preferAnimation, jobject source) { Asset* asset = reinterpret_cast<Asset*>(assetPtr); std::unique_ptr<SkStream> stream(new AssetStreamAdaptor(asset)); - return native_create(env, std::move(stream), source); + return native_create(env, std::move(stream), source, preferAnimation); } -static jobject ImageDecoder_nCreateByteBuffer(JNIEnv* env, jobject /*clazz*/, jobject jbyteBuffer, - jint initialPosition, jint limit, jobject source) { +static jobject ImageDecoder_nCreateByteBuffer(JNIEnv* env, jobject /*clazz*/, + jobject jbyteBuffer, jint initialPosition, jint limit, + jboolean preferAnimation, jobject source) { std::unique_ptr<SkStream> stream = CreateByteBufferStreamAdaptor(env, jbyteBuffer, initialPosition, limit); if (!stream) { return throw_exception(env, ImageDecoder::kSourceMalformedData, "Failed to read ByteBuffer", nullptr, source); } - return native_create(env, std::move(stream), source); + return native_create(env, std::move(stream), source, preferAnimation); } -static jobject ImageDecoder_nCreateByteArray(JNIEnv* env, jobject /*clazz*/, jbyteArray byteArray, - jint offset, jint length, jobject source) { +static jobject ImageDecoder_nCreateByteArray(JNIEnv* env, jobject /*clazz*/, + jbyteArray byteArray, jint offset, jint length, + jboolean preferAnimation, jobject source) { std::unique_ptr<SkStream> stream(CreateByteArrayStreamAdaptor(env, byteArray, offset, length)); - return native_create(env, std::move(stream), source); + return native_create(env, std::move(stream), source, preferAnimation); } jint postProcessAndRelease(JNIEnv* env, jobject jimageDecoder, std::unique_ptr<Canvas> canvas) { @@ -514,11 +520,11 @@ static jobject ImageDecoder_nGetColorSpace(JNIEnv* env, jobject /*clazz*/, jlong } static const JNINativeMethod gImageDecoderMethods[] = { - { "nCreate", "(JLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateAsset }, - { "nCreate", "(Ljava/nio/ByteBuffer;IILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer }, - { "nCreate", "([BIILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray }, - { "nCreate", "(Ljava/io/InputStream;[BLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream }, - { "nCreate", "(Ljava/io/FileDescriptor;Landroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd }, + { "nCreate", "(JZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateAsset }, + { "nCreate", "(Ljava/nio/ByteBuffer;IIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer }, + { "nCreate", "([BIIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray }, + { "nCreate", "(Ljava/io/InputStream;[BZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream }, + { "nCreate", "(Ljava/io/FileDescriptor;ZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd }, { "nDecodeBitmap", "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZJZ)Landroid/graphics/Bitmap;", (void*) ImageDecoder_nDecodeBitmap }, { "nGetSampledSize","(JI)Landroid/util/Size;", (void*) ImageDecoder_nGetSampledSize }, diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 5cbf81c30a3f..096bf6977a9e 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -497,11 +497,8 @@ static void nativeSetMetadata(JNIEnv* env, jclass clazz, jlong transactionObj, auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); - std::vector<uint8_t> byteData(parcel->dataSize()); - memcpy(byteData.data(), parcel->data(), parcel->dataSize()); - SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject); - transaction->setMetadata(ctrl, id, std::move(byteData)); + transaction->setMetadata(ctrl, id, *parcel); } static void nativeSetColor(JNIEnv* env, jclass clazz, jlong transactionObj, diff --git a/core/jni/com_android_internal_os_AtomicDirectory.cpp b/core/jni/com_android_internal_os_AtomicDirectory.cpp deleted file mode 100644 index 76b0fc167264..000000000000 --- a/core/jni/com_android_internal_os_AtomicDirectory.cpp +++ /dev/null @@ -1,66 +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. - */ - -#include <nativehelper/ScopedUtfChars.h> -#include "jni.h" - -#include "core_jni_helpers.h" - -namespace android { - -static jint com_android_internal_os_AtomicDirectory_getDirectoryFd(JNIEnv* env, - jobject /*clazz*/, jstring path) { - ScopedUtfChars path8(env, path); - if (path8.c_str() == NULL) { - ALOGE("Invalid path: %s", path8.c_str()); - return -1; - } - int fd; - if ((fd = TEMP_FAILURE_RETRY(open(path8.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC))) == -1) { - ALOGE("Cannot open directory %s, error: %s\n", path8.c_str(), strerror(errno)); - return -1; - } - return fd; -} - -static void com_android_internal_os_AtomicDirectory_fsyncDirectoryFd(JNIEnv* env, - jobject /*clazz*/, jint fd) { - if (TEMP_FAILURE_RETRY(fsync(fd)) == -1) { - ALOGE("Cannot fsync directory %d, error: %s\n", fd, strerror(errno)); - } -} - -/* - * JNI registration. - */ -static const JNINativeMethod gRegisterMethods[] = { - /* name, signature, funcPtr */ - { "fsyncDirectoryFd", - "(I)V", - (void*) com_android_internal_os_AtomicDirectory_fsyncDirectoryFd - }, - { "getDirectoryFd", - "(Ljava/lang/String;)I", - (void*) com_android_internal_os_AtomicDirectory_getDirectoryFd - }, -}; - -int register_com_android_internal_os_AtomicDirectory(JNIEnv* env) { - return RegisterMethodsOrDie(env, "com/android/internal/os/AtomicDirectory", - gRegisterMethods, NELEM(gRegisterMethods)); -} - -}; // namespace android diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 795f7abc579f..d5b875b85d7d 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -117,7 +117,9 @@ typedef const std::function<void(std::string)>& fail_fn_t; static pid_t gSystemServerPid = 0; +static constexpr const char* kPropFuse = "persist.sys.fuse"; static constexpr const char* kZygoteClassName = "com/android/internal/os/Zygote"; + static jclass gZygoteClass; static jmethodID gCallPostForkSystemServerHooks; static jmethodID gCallPostForkChildHooks; @@ -704,15 +706,24 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode, return; } - const std::string& storage_source = ExternalStorageViews[mount_mode]; - - BindMount(storage_source, "/storage", fail_fn); - - // Mount user-specific symlink helper into place - userid_t user_id = multiuser_get_user_id(uid); + const userid_t user_id = multiuser_get_user_id(uid); const std::string user_source = StringPrintf("/mnt/user/%d", user_id); + bool isFuse = GetBoolProperty(kPropFuse, false); + CreateDir(user_source, 0751, AID_ROOT, AID_ROOT, fail_fn); - BindMount(user_source, "/storage/self", fail_fn); + + if (isFuse) { + // TODO(b/135341433): Bind mount the appropriate storage view for the app given its permissions + // media and media_location permission access. This should prevent the kernel from incorrectly + // sharing a cache across permission buckets + BindMount(user_source, "/storage", fail_fn); + } else { + const std::string& storage_source = ExternalStorageViews[mount_mode]; + BindMount(storage_source, "/storage", fail_fn); + + // Mount user-specific symlink helper into place + BindMount(user_source, "/storage/self", fail_fn); + } } static bool NeedsNoRandomizeWorkaround() { diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto index e43b6a04b93c..e62af74fd439 100644 --- a/core/proto/android/providers/settings.proto +++ b/core/proto/android/providers/settings.proto @@ -20,6 +20,7 @@ package android.providers.settings; option java_multiple_files = true; option java_outer_classname = "SettingsServiceProto"; +import "frameworks/base/core/proto/android/providers/settings/config.proto"; import "frameworks/base/core/proto/android/providers/settings/global.proto"; import "frameworks/base/core/proto/android/providers/settings/secure.proto"; import "frameworks/base/core/proto/android/providers/settings/system.proto"; @@ -33,6 +34,9 @@ message SettingsServiceDumpProto { // Global settings optional GlobalSettingsProto global_settings = 2; + + // Config settings + optional ConfigSettingsProto config_settings = 3; } message UserSettingsProto { diff --git a/core/proto/android/providers/settings/config.proto b/core/proto/android/providers/settings/config.proto new file mode 100644 index 000000000000..cc2419614d93 --- /dev/null +++ b/core/proto/android/providers/settings/config.proto @@ -0,0 +1,55 @@ +/* + * 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. + */ + +syntax = "proto2"; +package android.providers.settings; + +option java_multiple_files = true; + +import "frameworks/base/core/proto/android/providers/settings/common.proto"; +import "frameworks/base/core/proto/android/privacy.proto"; + +message ConfigSettingsProto { + option (android.msg_privacy).dest = DEST_EXPLICIT; + + repeated SettingsOperationProto historical_operations = 1; + repeated NamespaceProto extra_namespaces = 2; + repeated SettingProto activity_manager_native_boot_settings = 3; + repeated SettingProto activity_manager_settings = 4; + repeated SettingProto app_compat_settings = 5; + repeated SettingProto autofill_settings = 6; + repeated SettingProto connectivity_settings = 7; + repeated SettingProto content_capture_settings = 8; + repeated SettingProto dex_boot_settings = 9; + repeated SettingProto game_driver_settings = 10; + repeated SettingProto input_native_boot_settings = 11; + repeated SettingProto netd_native_settings = 12; + repeated SettingProto privacy_settings = 13; + repeated SettingProto rollback_boot_settings = 14; + repeated SettingProto rollback_settings = 15; + repeated SettingProto runtime_native_boot_settings = 16; + repeated SettingProto runtime_native_settings = 17; + repeated SettingProto runtime_settings = 18; + repeated SettingProto storage_settings = 19; + repeated SettingProto systemui_settings = 20; + repeated SettingProto telephony_settings = 21; + repeated SettingProto textclassifier_settings = 22; + + message NamespaceProto { + optional string namespace = 1; + repeated SettingProto settings = 2; + } +}
\ No newline at end of file diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index 00706941a18f..f2ca0a4e5fad 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -995,7 +995,7 @@ message GlobalSettingsProto { optional SettingProto display_certification_on = 4 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto display_wps_config = 5 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto networks_available_notification_on = 6 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto carrier_networks_available_notification_on = 7 [ (android.privacy).dest = DEST_AUTOMATIC ]; + reserved 7; reserved "carrier_networks_available_notification_on"; optional SettingProto networks_available_repeat_delay = 8 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto country_code = 9; optional SettingProto framework_scan_interval_ms = 10 [ (android.privacy).dest = DEST_AUTOMATIC ]; @@ -1013,7 +1013,7 @@ message GlobalSettingsProto { optional SettingProto watchdog_poor_network_test_enabled = 22 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto suspend_optimizations_enabled = 23 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto verbose_logging_enabled = 24 [ (android.privacy).dest = DEST_AUTOMATIC ]; - reserved 25; // connected_mac_randomization_enabled + reserved 25; reserved "connected_mac_randomization_enabled"; optional SettingProto max_dhcp_retry_count = 26 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto mobile_data_transition_wakelock_timeout_ms = 27 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Controls whether WiFi configurations created by a Device Owner app should @@ -1025,7 +1025,7 @@ message GlobalSettingsProto { optional SettingProto device_owner_configs_lockdown = 28 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto frequency_band = 29 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto p2p_device_name = 30; - optional SettingProto reenable_delay_ms = 31 [ (android.privacy).dest = DEST_AUTOMATIC ]; + reserved 31; reserved "reenable_delay_ms"; optional SettingProto ephemeral_out_of_range_timeout_ms = 32 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto on_when_proxy_disconnected = 33 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto bounce_delay_override_ms = 34 [ (android.privacy).dest = DEST_AUTOMATIC ]; diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index 7fb6f98ab662..a1ff9b94123f 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -261,6 +261,8 @@ message MemInfoDumpProto { // The dirty the pages that have been swapped out, proportional. int32 dirty_swap_pss_kb = 9; } + // The rss set size for the heap. + optional int32 total_rss_kb = 10; } message HeapInfo { option (.android.msg_privacy).dest = DEST_AUTOMATIC; @@ -294,6 +296,12 @@ message MemInfoDumpProto { int32 total_swap_pss = 8; int32 total_swap_kb = 9; } + optional int32 java_heap_rss_kb = 10; + optional int32 native_heap_rss_kb = 11; + optional int32 code_rss_kb = 12; + optional int32 stack_rss_kb = 13; + optional int32 graphics_rss_kb = 14; + optional int32 unknown_rss_kb = 15; } optional AppSummary app_summary = 9; } @@ -359,10 +367,16 @@ message MemInfoDumpProto { optional int32 id = 3; optional bool is_proc = 4; optional bool has_activities = 5; - optional int64 pss_kb = 6; + oneof ss_kb { + int64 pss_kb = 6; + int64 rss_kb = 9; + } optional int64 swap_pss_kb = 7; repeated MemItem sub_items = 8; } + repeated MemItem total_rss_by_process = 29; + repeated MemItem total_rss_by_oom_adjustment = 30; + repeated MemItem total_rss_by_category = 31; repeated MemItem total_pss_by_process = 5; repeated MemItem total_pss_by_oom_adjustment = 6; repeated MemItem total_pss_by_category = 7; @@ -414,6 +428,8 @@ message MemInfoDumpProto { optional bool is_low_ram_device = 27; optional bool is_high_end_gfx = 28; + + // Next Tag: 32 } message StickyBroadcastProto { diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index aac144c4d732..79167ab476c1 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -308,6 +308,8 @@ message ConstantsProto { // Whether or not TimeController should skip setting wakeup alarms for jobs that aren't // ready now. reserved 1; // skip_not_ready_jobs + // Whether or not TimeController will use a non-wakeup alarm for delay constraints. + optional bool use_non_wakeup_alarm_for_delay = 2; } optional TimeController time_controller = 25; diff --git a/core/proto/android/stats/otaupdate/updateengine_enums.proto b/core/proto/android/stats/otaupdate/updateengine_enums.proto new file mode 100644 index 000000000000..a6e9919ba606 --- /dev/null +++ b/core/proto/android/stats/otaupdate/updateengine_enums.proto @@ -0,0 +1,82 @@ +/* + * 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. + */ + +syntax = "proto2"; +package android.stats.otaupdate; + +// The payload type of an OTA update attempt on A/B devices. +enum PayloadType { + FULL = 10000; + DELTA = 10001; +} + +// The attempt result reported by the update engine for an OTA update. +enum AttemptResult { + UPDATE_SUCCEEDED = 10000; + INTERNAL_ERROR = 10001; + PAYLOAD_DOWNLOAD_ERROR = 10002; + METADATA_MALFORMED = 10003; + OPERATION_MALFORMED = 10004; + OPERATION_EXECUTION_ERROR = 10005; + METADATA_VERIFICATION_FAILED = 10006; + PAYLOAD_VERIFICATION_FAILED = 10007; + VERIFICATION_FAILED = 10008; + POSTINSTALL_FAILED = 10009; + ABNORMAL_TERMINATION = 10010; + UPDATE_CANCELED = 10011; + UPDATE_SUCCEEDED_NOT_ACTIVE = 10012; +} + +// The error code reported by the update engine after an OTA update attempt +// on A/B devices. More details in system/update_engine/common/error_code.h +enum ErrorCode { + SUCCESS = 10000; + ERROR = 10001; + FILESYSTEM_COPIER_ERROR = 10004; + POST_INSTALL_RUNNER_ERROR = 10005; + PAYLOAD_MISMATCHED_TYPE_ERROR = 10006; + INSTALL_DEVICE_OPEN_ERROR = 10007; + KERNEL_DEVICE_OPEN_ERROR = 10008; + DOWNLOAD_TRANSFER_ERROR = 10009; + PAYLOAD_HASH_MISMATCH_ERROR = 10010; + PAYLOAD_SIZE_MISMATCH_ERROR = 10011; + DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 10012; + DOWNLOAD_NEW_PARTITION_INFO_ERROR = 10013; + DOWNLOAD_WRITE_ERROR = 10014; + NEW_ROOTFS_VERIFICATION_ERROR = 10015; + SIGNED_DELTA_PAYLOAD_EXPECTED_ERROR = 10017; + DOWNLOAD_PAYLOAD_PUB_KEY_VERIFICATION_ERROR = 10018; + DOWNLOAD_STATE_INITIALIZATION_ERROR = 10020; + DOWNLOAD_INVALID_METADATA_MAGIC_STRING = 10021; + DOWNLOAD_SIGNATURE_MISSING_IN_MANIFEST = 10022; + DOWNLOAD_MANIFEST_PARSE_ERROR = 10023; + DOWNLOAD_METADATA_SIGNATURE_ERROR = 10024; + DOWNLOAD_METADATA_SIGNATURE_VERIFICATION_ERROR = 10025; + DOWNLOAD_METADATA_SIGNATURE_MISMATCH = 10026; + DOWNLOAD_OPERATION_HASH_VERIFICATION_ERROR = 10027; + DOWNLOAD_OPERATION_EXECUTION_ERROR = 10028; + DOWNLOAD_OPERATION_HASH_MISMATCH = 10029; + DOWNLOAD_INVALID_METADATA_SIZE = 10032; + DOWNLOAD_INVALID_METADATA_SIGNATURE = 10033; + DOWNLOAD_OPERATION_HASH_MISSING_ERROR = 10038; + DOWNLOAD_METADATA_SIGNATURE_MISSING_ERROR = 10039; + UNSUPPORTED_MAJOR_PAYLOAD_VERSION = 10044; + UNSUPPORTED_MINOR_PAYLOAD_VERSION = 10045; + FILESYSTEM_VERIFIER_ERROR = 10047; + USER_CANCELED = 10048; + PAYLOAD_TIMESTAMP_ERROR = 10051; + UPDATED_BUT_NOT_ACTIVE = 10052; +} diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index fa4e08520126..ceccd0dcdfec 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1707,6 +1707,7 @@ manifest. --> <string-array name="config_forceQueryablePackages" translatable="false"> <item>com.android.settings</item> + <item>com.android.providers.settings</item> <!-- Add packages here --> </string-array> @@ -4285,4 +4286,9 @@ <!-- The list of packages to automatically opt out of refresh rates higher than 60hz because of known compatibility issues. --> <string-array name="config_highRefreshRateBlacklist"></string-array> + + <!-- Whether or not to hide the navigation bar when the soft keyboard is visible in order to + create additional screen real estate outside beyond the keyboard. Note that the user needs + to have a confirmed way to dismiss the keyboard when desired. --> + <bool name="config_automotiveHideNavBarForKeyboard">false</bool> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index d1d7bf5100d6..cdfa0439c7ca 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3377,8 +3377,6 @@ <!-- Notification title for a nearby open wireless network.--> <string name="wifi_available_title">Connect to open Wi\u2011Fi network</string> - <!-- Notification title for a nearby carrier wireless network.--> - <string name="wifi_available_carrier_network_title">Connect to carrier Wi\u2011Fi network</string> <!-- Notification title when the system is connecting to the specified network. The network name is specified in the notification content. --> <string name="wifi_available_title_connecting">Connecting to Wi\u2011Fi network</string> <!-- Notification title when the system has connected to the network. The network name is specified in the notification content. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index f7ae453599bb..c37a457ad12e 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2070,7 +2070,6 @@ <java-symbol type="plurals" name="wifi_available" /> <java-symbol type="plurals" name="wifi_available_detailed" /> <java-symbol type="string" name="wifi_available_title" /> - <java-symbol type="string" name="wifi_available_carrier_network_title" /> <java-symbol type="string" name="wifi_available_title_connecting" /> <java-symbol type="string" name="wifi_available_title_connected" /> <java-symbol type="string" name="wifi_available_title_failed_to_connect" /> @@ -3847,4 +3846,6 @@ <java-symbol type="string" name="config_factoryResetPackage" /> <java-symbol type="array" name="config_highRefreshRateBlacklist" /> + <java-symbol type="bool" name="config_automotiveHideNavBarForKeyboard" /> + </resources> 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 index 3d9a1d9398c5..7c6271cbdf61 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java @@ -19,6 +19,7 @@ import static org.junit.Assert.*; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -43,6 +44,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; +import org.mockito.verification.VerificationWithTimeout; import java.util.Arrays; import java.util.HashSet; @@ -56,6 +58,8 @@ import java.util.List; public class StartProgramListUpdatesFanoutTest { private static final String TAG = "BroadcastRadioTests.hal2.StartProgramListUpdatesFanout"; + private static final VerificationWithTimeout CB_TIMEOUT = timeout(100); + // Mocks @Mock IBroadcastRadio mBroadcastRadioMock; @Mock ITunerSession mHalTunerSessionMock; @@ -200,10 +204,10 @@ public class StartProgramListUpdatesFanoutTest { // 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()); + verify(mAidlTunerCallbackMocks[0], CB_TIMEOUT.times(1)).onProgramListUpdated(any()); + verify(mAidlTunerCallbackMocks[1], CB_TIMEOUT.times(2)).onProgramListUpdated(any()); + verify(mAidlTunerCallbackMocks[2], CB_TIMEOUT.times(1)).onProgramListUpdated(any()); + verify(mAidlTunerCallbackMocks[3], CB_TIMEOUT.times(2)).onProgramListUpdated(any()); } @Test @@ -240,7 +244,7 @@ public class StartProgramListUpdatesFanoutTest { // 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()); + verify(mAidlTunerCallbackMocks[0], CB_TIMEOUT.times(1)).onProgramListUpdated(any()); verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], true, Arrays.asList(mModifiedAmFmInfo), null); @@ -313,6 +317,6 @@ public class StartProgramListUpdatesFanoutTest { } ProgramList.Chunk expectedChunk = new ProgramList.Chunk(purge, true, modifiedSet, removedSet); - verify(clientMock).onProgramListUpdated(expectedChunk); + verify(clientMock, CB_TIMEOUT).onProgramListUpdated(expectedChunk); } } diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 89ba3df287b4..97b7ae964f33 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -35,6 +35,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.lang.reflect.Field; +import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -543,7 +544,6 @@ public class SettingsBackupTest { Settings.Global.WIFI_ON, Settings.Global.WIFI_P2P_DEVICE_NAME, Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET, - Settings.Global.WIFI_REENABLE_DELAY_MS, Settings.Global.WIFI_RTT_BACKGROUND_EXEC_GAP_MS, Settings.Global.WIFI_SAVED_STATE, Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, @@ -625,7 +625,6 @@ public class SettingsBackupTest { Settings.Secure.DIALER_DEFAULT_APPLICATION, Settings.Secure.DISABLED_PRINT_SERVICES, Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS, - Settings.Secure.DISPLAY_DENSITY_FORCED, Settings.Secure.DOCKED_CLOCK_FACE, Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION, @@ -721,7 +720,6 @@ public class SettingsBackupTest { Settings.Secure.BIOMETRIC_DEBUG_ENABLED, Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED, - Settings.Secure.FACE_UNLOCK_EDUCATION_INFO_DISPLAYED, Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED); @Test @@ -742,9 +740,12 @@ public class SettingsBackupTest { @Test public void secureSettingsBackedUpOrBlacklisted() { + HashSet<String> keys = new HashSet<String>(); + Collections.addAll(keys, Settings.Secure.SETTINGS_TO_BACKUP); + Collections.addAll(keys, Settings.Secure.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP); checkSettingsBackedUpOrBlacklisted( getCandidateSettings(Settings.Secure.class), - newHashSet(Settings.Secure.SETTINGS_TO_BACKUP), + keys, BACKUP_BLACKLISTED_SECURE_SETTINGS); } @@ -758,9 +759,9 @@ public class SettingsBackupTest { is(empty())); assertThat( - "blacklisted settings backed up", - intersect(settingsToBackup, blacklist), - is(empty())); + "blacklisted settings backed up", + intersect(settingsToBackup, blacklist), + is(empty())); } private static Set<String> getCandidateSettings(Class<? extends Settings.NameValueTable> clazz) { diff --git a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java b/core/tests/coretests/src/android/provider/settings/validators/SettingsValidatorsTest.java index 8081e9e6c67b..5f042d3dce0f 100644 --- a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java +++ b/core/tests/coretests/src/android/provider/settings/validators/SettingsValidatorsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 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,7 +14,7 @@ * limitations under the License. */ -package android.provider; +package android.provider.settings.validators; import static com.google.common.truth.Truth.assertThat; @@ -23,7 +23,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.platform.test.annotations.Presubmit; -import android.provider.SettingsValidators.Validator; +import android.provider.Settings; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -138,7 +138,7 @@ public class SettingsValidatorsTest { @Test public void testDiscreteValueValidator() { String[] beerTypes = new String[]{"Ale", "American IPA", "Stout"}; - Validator v = new SettingsValidators.DiscreteValueValidator(beerTypes); + Validator v = new DiscreteValueValidator(beerTypes); assertTrue(v.validate("Ale")); assertTrue(v.validate("American IPA")); assertTrue(v.validate("Stout")); @@ -148,14 +148,14 @@ public class SettingsValidatorsTest { @Test public void testDiscreteValueValidator_onNullValue_returnsFalse() { String[] discreteTypes = new String[]{"Type1", "Type2"}; - Validator v = new SettingsValidators.DiscreteValueValidator(discreteTypes); + Validator v = new DiscreteValueValidator(discreteTypes); assertFalse(v.validate(null)); } @Test public void testInclusiveIntegerRangeValidator() { - Validator v = new SettingsValidators.InclusiveIntegerRangeValidator(0, 5); + Validator v = new InclusiveIntegerRangeValidator(0, 5); assertTrue(v.validate("0")); assertTrue(v.validate("2")); assertTrue(v.validate("5")); @@ -165,14 +165,14 @@ public class SettingsValidatorsTest { @Test public void testInclusiveIntegerRangeValidator_onNullValue_returnsFalse() { - Validator v = new SettingsValidators.InclusiveIntegerRangeValidator(0, 5); + Validator v = new InclusiveIntegerRangeValidator(0, 5); assertFalse(v.validate(null)); } @Test public void testInclusiveFloatRangeValidator() { - Validator v = new SettingsValidators.InclusiveFloatRangeValidator(0.0f, 5.0f); + Validator v = new InclusiveFloatRangeValidator(0.0f, 5.0f); assertTrue(v.validate("0.0")); assertTrue(v.validate("2.0")); assertTrue(v.validate("5.0")); @@ -182,14 +182,14 @@ public class SettingsValidatorsTest { @Test public void testInclusiveFloatRangeValidator_onNullValue_returnsFalse() { - Validator v = new SettingsValidators.InclusiveFloatRangeValidator(0.0f, 5.0f); + Validator v = new InclusiveFloatRangeValidator(0.0f, 5.0f); assertFalse(v.validate(null)); } @Test public void testComponentNameListValidator() { - Validator v = new SettingsValidators.ComponentNameListValidator(","); + Validator v = new ComponentNameListValidator(","); assertTrue(v.validate("com.android.localtransport/.LocalTransport," + "com.google.android.gms/.backup.migrate.service.D2dTransport")); assertFalse(v.validate("com.google.5android,android")); @@ -197,21 +197,21 @@ public class SettingsValidatorsTest { @Test public void testComponentNameListValidator_onNullValue_returnsFalse() { - Validator v = new SettingsValidators.ComponentNameListValidator(","); + Validator v = new ComponentNameListValidator(","); assertFalse(v.validate(null)); } @Test public void testPackageNameListValidator() { - Validator v = new SettingsValidators.PackageNameListValidator(","); + Validator v = new PackageNameListValidator(","); assertTrue(v.validate("com.android.localtransport.LocalTransport,com.google.android.gms")); assertFalse(v.validate("5com.android.internal.backup.LocalTransport,android")); } @Test public void testPackageNameListValidator_onNullValue_returnsFalse() { - Validator v = new SettingsValidators.PackageNameListValidator(","); + Validator v = new PackageNameListValidator(","); assertFalse(v.validate(null)); } @@ -255,6 +255,45 @@ public class SettingsValidatorsTest { } @Test + public void testTTSListValidator_withValidInput_returnsTrue() { + assertTrue( + SettingsValidators.TTS_LIST_VALIDATOR.validate( + "com.foo.ttsengine:en-US,com.bar.ttsengine:es_ES")); + } + + @Test + public void testTTSListValidator_withInvalidInput_returnsFalse() { + assertFalse( + SettingsValidators.TTS_LIST_VALIDATOR.validate( + "com.foo.ttsengine:eng-USA,INVALID")); + } + + @Test + public void testTTSListValidator_withEmptyInput_returnsFalse() { + assertFalse(SettingsValidators.TTS_LIST_VALIDATOR.validate("")); + } + + @Test + public void testTTSListValidator_withNullInput_returnsFalse() { + assertFalse(SettingsValidators.TTS_LIST_VALIDATOR.validate(null)); + } + + @Test + public void testTileListValidator_withValidInput_returnsTrue() { + assertTrue(SettingsValidators.TILE_LIST_VALIDATOR.validate("1,2,3,4")); + } + + @Test + public void testTileListValidator_withMissingValue_returnsFalse() { + assertFalse(SettingsValidators.TILE_LIST_VALIDATOR.validate("1,,3")); + } + + @Test + public void testTileListValidator_withNullInput_returnsFalse() { + assertFalse(SettingsValidators.TILE_LIST_VALIDATOR.validate(null)); + } + + @Test public void ensureAllBackedUpGlobalSettingsHaveValidators() { String offenders = getOffenders(concat(Settings.Global.SETTINGS_TO_BACKUP, Settings.Global.LEGACY_RESTORE_SETTINGS), Settings.Global.VALIDATORS); diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 89e26daed82a..4187c806c66a 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -24,6 +24,7 @@ applications that come with the platform <permission name="android.permission.PROVIDE_RESOLVER_RANKER_SERVICE" /> <permission name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE" /> <permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" /> + <permission name="android.permission.INTERACT_ACROSS_USERS" /> </privapp-permissions> <privapp-permissions package="com.android.apps.tag"> @@ -86,6 +87,7 @@ applications that come with the platform </privapp-permissions> <privapp-permissions package="com.android.mtp"> + <permission name="android.permission.ACCESS_MTP"/> <permission name="android.permission.MANAGE_USB"/> </privapp-permissions> @@ -192,7 +194,6 @@ applications that come with the platform </privapp-permissions> <privapp-permissions package="com.android.providers.media"> - <permission name="android.permission.ACCESS_MTP"/> <permission name="android.permission.INTERACT_ACROSS_USERS"/> <permission name="android.permission.MANAGE_USERS"/> <permission name="android.permission.USE_RESERVED_DISK"/> @@ -350,4 +351,19 @@ applications that come with the platform <permission name="android.permission.MANAGE_DYNAMIC_SYSTEM"/> </privapp-permissions> + <privapp-permissions package="com.android.server.wifistack"> + <permission name="android.permission.CHANGE_CONFIGURATION"/> + <permission name="android.permission.CONNECTIVITY_INTERNAL"/> + <permission name="android.permission.DUMP"/> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> + <permission name="android.permission.LOCAL_MAC_ADDRESS"/> + <permission name="android.permission.MANAGE_USERS"/> + <permission name="android.permission.PACKAGE_USAGE_STATS"/> + <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> + <permission name="android.permission.REQUEST_NETWORK_SCORES"/> + <permission name="android.permission.WRITE_SECURE_SETTINGS"/> + <permission name="android.permission.UPDATE_DEVICE_STATS"/> + <permission name="android.permission.UPDATE_APP_OPS_STATS"/> + <permission name="android.permission.LOCATION_HARDWARE"/> + </privapp-permissions> </permissions> diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java index 2d5babc5ebdb..150a941c061e 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -214,7 +214,7 @@ public final class ImageDecoder implements AutoCloseable { /* @hide */ @NonNull - abstract ImageDecoder createImageDecoder() throws IOException; + abstract ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException; }; private static class ByteArraySource extends Source { @@ -228,8 +228,8 @@ public final class ImageDecoder implements AutoCloseable { private final int mLength; @Override - public ImageDecoder createImageDecoder() throws IOException { - return nCreate(mData, mOffset, mLength, this); + public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException { + return nCreate(mData, mOffset, mLength, preferAnimation, this); } } @@ -240,14 +240,14 @@ public final class ImageDecoder implements AutoCloseable { private final ByteBuffer mBuffer; @Override - public ImageDecoder createImageDecoder() throws IOException { + public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException { if (!mBuffer.isDirect() && mBuffer.hasArray()) { int offset = mBuffer.arrayOffset() + mBuffer.position(); int length = mBuffer.limit() - mBuffer.position(); - return nCreate(mBuffer.array(), offset, length, this); + return nCreate(mBuffer.array(), offset, length, preferAnimation, this); } ByteBuffer buffer = mBuffer.slice(); - return nCreate(buffer, buffer.position(), buffer.limit(), this); + return nCreate(buffer, buffer.position(), buffer.limit(), preferAnimation, this); } } @@ -267,7 +267,7 @@ public final class ImageDecoder implements AutoCloseable { Resources getResources() { return mResources; } @Override - public ImageDecoder createImageDecoder() throws IOException { + public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException { AssetFileDescriptor assetFd = null; try { if (mUri.getScheme() == ContentResolver.SCHEME_CONTENT) { @@ -284,26 +284,26 @@ public final class ImageDecoder implements AutoCloseable { throw new FileNotFoundException(mUri.toString()); } - return createFromStream(is, true, this); + return createFromStream(is, true, preferAnimation, this); } - return createFromAssetFileDescriptor(assetFd, this); + return createFromAssetFileDescriptor(assetFd, preferAnimation, this); } } @NonNull private static ImageDecoder createFromFile(@NonNull File file, - @NonNull Source source) throws IOException { + boolean preferAnimation, @NonNull Source source) throws IOException { FileInputStream stream = new FileInputStream(file); FileDescriptor fd = stream.getFD(); try { Os.lseek(fd, 0, SEEK_CUR); } catch (ErrnoException e) { - return createFromStream(stream, true, source); + return createFromStream(stream, true, preferAnimation, source); } ImageDecoder decoder = null; try { - decoder = nCreate(fd, source); + decoder = nCreate(fd, preferAnimation, source); } finally { if (decoder == null) { IoUtils.closeQuietly(stream); @@ -317,12 +317,12 @@ public final class ImageDecoder implements AutoCloseable { @NonNull private static ImageDecoder createFromStream(@NonNull InputStream is, - boolean closeInputStream, Source source) throws IOException { + boolean closeInputStream, boolean preferAnimation, Source source) throws IOException { // Arbitrary size matches BitmapFactory. byte[] storage = new byte[16 * 1024]; ImageDecoder decoder = null; try { - decoder = nCreate(is, storage, source); + decoder = nCreate(is, storage, preferAnimation, source); } finally { if (decoder == null) { if (closeInputStream) { @@ -340,7 +340,7 @@ public final class ImageDecoder implements AutoCloseable { @NonNull private static ImageDecoder createFromAssetFileDescriptor(@NonNull AssetFileDescriptor assetFd, - Source source) throws IOException { + boolean preferAnimation, Source source) throws IOException { final FileDescriptor fd = assetFd.getFileDescriptor(); final long offset = assetFd.getStartOffset(); @@ -348,9 +348,9 @@ public final class ImageDecoder implements AutoCloseable { try { try { Os.lseek(fd, offset, SEEK_SET); - decoder = nCreate(fd, source); + decoder = nCreate(fd, preferAnimation, source); } catch (ErrnoException e) { - decoder = createFromStream(new FileInputStream(fd), true, source); + decoder = createFromStream(new FileInputStream(fd), true, preferAnimation, source); } } finally { if (decoder == null) { @@ -388,7 +388,7 @@ public final class ImageDecoder implements AutoCloseable { public int getDensity() { return mInputDensity; } @Override - public ImageDecoder createImageDecoder() throws IOException { + public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException { synchronized (this) { if (mInputStream == null) { @@ -396,7 +396,7 @@ public final class ImageDecoder implements AutoCloseable { } InputStream is = mInputStream; mInputStream = null; - return createFromStream(is, false, this); + return createFromStream(is, false, preferAnimation, this); } } } @@ -434,14 +434,14 @@ public final class ImageDecoder implements AutoCloseable { } @Override - public ImageDecoder createImageDecoder() throws IOException { + public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException { synchronized (this) { if (mAssetInputStream == null) { throw new IOException("Cannot reuse AssetInputStreamSource"); } AssetInputStream ais = mAssetInputStream; mAssetInputStream = null; - return createFromAsset(ais, this); + return createFromAsset(ais, preferAnimation, this); } } } @@ -469,7 +469,7 @@ public final class ImageDecoder implements AutoCloseable { } @Override - public ImageDecoder createImageDecoder() throws IOException { + public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException { TypedValue value = new TypedValue(); // This is just used in order to access the underlying Asset and // keep it alive. @@ -483,7 +483,7 @@ public final class ImageDecoder implements AutoCloseable { } } - return createFromAsset((AssetInputStream) is, this); + return createFromAsset((AssetInputStream) is, preferAnimation, this); } } @@ -491,11 +491,11 @@ public final class ImageDecoder implements AutoCloseable { * ImageDecoder will own the AssetInputStream. */ private static ImageDecoder createFromAsset(AssetInputStream ais, - Source source) throws IOException { + boolean preferAnimation, Source source) throws IOException { ImageDecoder decoder = null; try { long asset = ais.getNativeAsset(); - decoder = nCreate(asset, source); + decoder = nCreate(asset, preferAnimation, source); } finally { if (decoder == null) { IoUtils.closeQuietly(ais); @@ -517,9 +517,9 @@ public final class ImageDecoder implements AutoCloseable { private final String mFileName; @Override - public ImageDecoder createImageDecoder() throws IOException { + public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException { InputStream is = mAssets.open(mFileName); - return createFromAsset((AssetInputStream) is, this); + return createFromAsset((AssetInputStream) is, preferAnimation, this); } } @@ -531,8 +531,8 @@ public final class ImageDecoder implements AutoCloseable { private final File mFile; @Override - public ImageDecoder createImageDecoder() throws IOException { - return createFromFile(mFile, this); + public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException { + return createFromFile(mFile, preferAnimation, this); } } @@ -544,7 +544,7 @@ public final class ImageDecoder implements AutoCloseable { private final Callable<AssetFileDescriptor> mCallable; @Override - public ImageDecoder createImageDecoder() throws IOException { + public ImageDecoder createImageDecoder(boolean preferAnimation) throws IOException { AssetFileDescriptor assetFd = null; try { assetFd = mCallable.call(); @@ -555,7 +555,7 @@ public final class ImageDecoder implements AutoCloseable { throw new IOException(e); } } - return createFromAssetFileDescriptor(assetFd, this); + return createFromAssetFileDescriptor(assetFd, preferAnimation, this); } } @@ -1740,7 +1740,7 @@ public final class ImageDecoder implements AutoCloseable { @NonNull private static Drawable decodeDrawableImpl(@NonNull Source src, @Nullable OnHeaderDecodedListener listener) throws IOException { - try (ImageDecoder decoder = src.createImageDecoder()) { + try (ImageDecoder decoder = src.createImageDecoder(true /*preferAnimation*/)) { decoder.mSource = src; decoder.callHeaderDecoded(listener, src); @@ -1844,7 +1844,7 @@ public final class ImageDecoder implements AutoCloseable { @NonNull private static Bitmap decodeBitmapImpl(@NonNull Source src, @Nullable OnHeaderDecodedListener listener) throws IOException { - try (ImageDecoder decoder = src.createImageDecoder()) { + try (ImageDecoder decoder = src.createImageDecoder(false /*preferAnimation*/)) { decoder.mSource = src; decoder.callHeaderDecoded(listener, src); @@ -1971,15 +1971,17 @@ public final class ImageDecoder implements AutoCloseable { } } - private static native ImageDecoder nCreate(long asset, Source src) throws IOException; - private static native ImageDecoder nCreate(ByteBuffer buffer, int position, - int limit, Source src) throws IOException; + private static native ImageDecoder nCreate(long asset, + boolean preferAnimation, Source src) throws IOException; + private static native ImageDecoder nCreate(ByteBuffer buffer, int position, int limit, + boolean preferAnimation, Source src) throws IOException; private static native ImageDecoder nCreate(byte[] data, int offset, int length, - Source src) throws IOException; + boolean preferAnimation, Source src) throws IOException; private static native ImageDecoder nCreate(InputStream is, byte[] storage, - Source src) throws IOException; + boolean preferAnimation, Source src) throws IOException; // The fd must be seekable. - private static native ImageDecoder nCreate(FileDescriptor fd, Source src) throws IOException; + private static native ImageDecoder nCreate(FileDescriptor fd, + boolean preferAnimation, Source src) throws IOException; @NonNull private static native Bitmap nDecodeBitmap(long nativePtr, @NonNull ImageDecoder decoder, diff --git a/libs/hostgraphics/Android.bp b/libs/hostgraphics/Android.bp index aedb7522ab08..e713b98b867e 100644 --- a/libs/hostgraphics/Android.bp +++ b/libs/hostgraphics/Android.bp @@ -1,8 +1,15 @@ cc_library_host_static { name: "libhostgraphics", + cflags: [ + "-Wno-unused-parameter", + ], + srcs: [ ":libui_host_common", + "Fence.cpp", + "HostBufferQueue.cpp", + "PublicFormat.cpp", ], include_dirs: [ diff --git a/libs/hostgraphics/Fence.cpp b/libs/hostgraphics/Fence.cpp new file mode 100644 index 000000000000..9e54816651c4 --- /dev/null +++ b/libs/hostgraphics/Fence.cpp @@ -0,0 +1,23 @@ +/* + * 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. + */ + +#include <ui/Fence.h> + +namespace android { + +const sp<Fence> Fence::NO_FENCE = sp<Fence>(new Fence); + +} // namespace android
\ No newline at end of file diff --git a/libs/hostgraphics/HostBufferQueue.cpp b/libs/hostgraphics/HostBufferQueue.cpp new file mode 100644 index 000000000000..ec304378c6c4 --- /dev/null +++ b/libs/hostgraphics/HostBufferQueue.cpp @@ -0,0 +1,69 @@ +/* + * 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. + */ + +#include <gui/BufferQueue.h> + +namespace android { + +class HostBufferQueue : public IGraphicBufferProducer, public IGraphicBufferConsumer { +public: + HostBufferQueue() : mWidth(0), mHeight(0) { } + + virtual status_t setConsumerIsProtected(bool isProtected) { return OK; } + + virtual status_t detachBuffer(int slot) { return OK; } + + virtual status_t getReleasedBuffers(uint64_t* slotMask) { return OK; } + + virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) { + mWidth = w; + mHeight = h; + mBuffer = sp<GraphicBuffer>(new GraphicBuffer(mWidth, mHeight)); + return OK; + } + + virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat) { return OK; } + + virtual status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) { return OK; } + + virtual status_t discardFreeBuffers() { return OK; } + + virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen, + uint64_t maxFrameNumber = 0) { + buffer->mGraphicBuffer = mBuffer; + buffer->mSlot = 0; + return OK; + } + + virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) { return OK; } + + virtual status_t setConsumerUsageBits(uint64_t usage) { return OK; } +private: + sp<GraphicBuffer> mBuffer; + uint32_t mWidth; + uint32_t mHeight; +}; + +void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer, + sp<IGraphicBufferConsumer>* outConsumer) { + + sp<HostBufferQueue> obj(new HostBufferQueue()); + + *outProducer = obj; + *outConsumer = obj; +} + +} // namespace android diff --git a/libs/hostgraphics/PublicFormat.cpp b/libs/hostgraphics/PublicFormat.cpp new file mode 100644 index 000000000000..af6d2738c801 --- /dev/null +++ b/libs/hostgraphics/PublicFormat.cpp @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#include <ui/PublicFormat.h> + +namespace android { + +android_dataspace mapPublicFormatToHalDataspace(PublicFormat f) { + return static_cast<android_dataspace>(0); +} + +int mapPublicFormatToHalFormat(PublicFormat f) { + return static_cast<int>(f); +} + +PublicFormat mapHalFormatDataspaceToPublicFormat(int format, android_dataspace dataSpace) { + return static_cast<PublicFormat>(format); +} + +} // namespace android
\ No newline at end of file diff --git a/libs/hostgraphics/gui/BufferItem.h b/libs/hostgraphics/gui/BufferItem.h new file mode 100644 index 000000000000..01409e19c715 --- /dev/null +++ b/libs/hostgraphics/gui/BufferItem.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#ifndef ANDROID_GUI_BUFFERITEM_H +#define ANDROID_GUI_BUFFERITEM_H + +#include <ui/Fence.h> +#include <ui/Rect.h> + +#include <system/graphics.h> + +#include <utils/StrongPointer.h> + +namespace android { + +class Fence; +class GraphicBuffer; + +// The only thing we need here for layoutlib is mGraphicBuffer. The rest of the fields are added +// just to satisfy the calls from the android_media_ImageReader.h + +class BufferItem { +public: + enum { INVALID_BUFFER_SLOT = -1 }; + + BufferItem() : mGraphicBuffer(nullptr), mFence(Fence::NO_FENCE) {} + ~BufferItem() {} + + sp<GraphicBuffer> mGraphicBuffer; + + sp<Fence> mFence; + + Rect mCrop; + + uint32_t mTransform; + + uint32_t mScalingMode; + + int64_t mTimestamp; + + android_dataspace mDataSpace; + + uint64_t mFrameNumber; + + int mSlot; + + bool mTransformToDisplayInverse; +}; + +} + +#endif // ANDROID_GUI_BUFFERITEM_H diff --git a/libs/hostgraphics/gui/BufferItemConsumer.h b/libs/hostgraphics/gui/BufferItemConsumer.h new file mode 100644 index 000000000000..707b313eb102 --- /dev/null +++ b/libs/hostgraphics/gui/BufferItemConsumer.h @@ -0,0 +1,75 @@ +/* + * 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. + */ + +#ifndef ANDROID_GUI_BUFFERITEMCONSUMER_H +#define ANDROID_GUI_BUFFERITEMCONSUMER_H + +#include <utils/RefBase.h> + +#include <gui/ConsumerBase.h> +#include <gui/IGraphicBufferConsumer.h> + +namespace android { + +class BufferItemConsumer : public ConsumerBase { +public: + BufferItemConsumer( + const sp<IGraphicBufferConsumer>& consumer, + uint64_t consumerUsage, + int bufferCount, + bool controlledByApp) : mConsumer(consumer) { + } + + status_t acquireBuffer(BufferItem *item, nsecs_t presentWhen, bool waitForFence = true) { + return mConsumer->acquireBuffer(item, presentWhen, 0); + } + + status_t releaseBuffer( + const BufferItem &item, const sp<Fence>& releaseFence = Fence::NO_FENCE) { return OK; } + + void setName(const String8& name) { } + + void setFrameAvailableListener(const wp<FrameAvailableListener>& listener) { } + + status_t setDefaultBufferSize(uint32_t width, uint32_t height) { + return mConsumer->setDefaultBufferSize(width, height); + } + + status_t setDefaultBufferFormat(PixelFormat defaultFormat) { + return mConsumer->setDefaultBufferFormat(defaultFormat); + } + + status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) { + return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); + } + + void abandon() { } + + status_t detachBuffer(int slot) { return OK; } + + status_t discardFreeBuffers() { return OK; } + + void freeBufferLocked(int slotIndex) { } + + status_t addReleaseFenceLocked( + int slot, const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) { return OK; } +private: + sp<IGraphicBufferConsumer> mConsumer; +}; + +} // namespace android + +#endif // ANDROID_GUI_BUFFERITEMCONSUMER_H diff --git a/libs/hostgraphics/gui/BufferQueue.h b/libs/hostgraphics/gui/BufferQueue.h new file mode 100644 index 000000000000..aa3e7268e11c --- /dev/null +++ b/libs/hostgraphics/gui/BufferQueue.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#ifndef ANDROID_GUI_BUFFERQUEUE_H +#define ANDROID_GUI_BUFFERQUEUE_H + +#include <gui/BufferItem.h> +#include <gui/IGraphicBufferConsumer.h> +#include <gui/IGraphicBufferProducer.h> + +namespace android { + +class BufferQueue { +public: + enum { INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT }; + enum { NO_BUFFER_AVAILABLE = IGraphicBufferConsumer::NO_BUFFER_AVAILABLE }; + + static void createBufferQueue(sp<IGraphicBufferProducer>* outProducer, + sp<IGraphicBufferConsumer>* outConsumer); +}; + +} // namespace android + +#endif // ANDROID_GUI_BUFFERQUEUE_H diff --git a/libs/hostgraphics/gui/ConsumerBase.h b/libs/hostgraphics/gui/ConsumerBase.h new file mode 100644 index 000000000000..9002953c0848 --- /dev/null +++ b/libs/hostgraphics/gui/ConsumerBase.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#ifndef ANDROID_GUI_CONSUMERBASE_H +#define ANDROID_GUI_CONSUMERBASE_H + +#include <gui/BufferItem.h> + +#include <utils/RefBase.h> + +namespace android { + +class ConsumerBase : public virtual RefBase { +public: + struct FrameAvailableListener : public virtual RefBase { + // See IConsumerListener::onFrame{Available,Replaced} + virtual void onFrameAvailable(const BufferItem& item) = 0; + virtual void onFrameReplaced(const BufferItem& /* item */) {} + }; +}; + +} // namespace android + +#endif // ANDROID_GUI_CONSUMERBASE_H
\ No newline at end of file diff --git a/libs/hostgraphics/gui/IGraphicBufferConsumer.h b/libs/hostgraphics/gui/IGraphicBufferConsumer.h new file mode 100644 index 000000000000..9eb67b218800 --- /dev/null +++ b/libs/hostgraphics/gui/IGraphicBufferConsumer.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#pragma once + +#include <utils/RefBase.h> + +#include <ui/PixelFormat.h> + +#include <utils/Errors.h> + +namespace android { + +class BufferItem; +class Fence; +class GraphicBuffer; + +class IGraphicBufferConsumer : virtual public RefBase { +public: + enum { + // Returned by releaseBuffer, after which the consumer must free any references to the + // just-released buffer that it might have. + STALE_BUFFER_SLOT = 1, + // Returned by dequeueBuffer if there are no pending buffers available. + NO_BUFFER_AVAILABLE, + // Returned by dequeueBuffer if it's too early for the buffer to be acquired. + PRESENT_LATER, + }; + + virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen, + uint64_t maxFrameNumber = 0) = 0; + + virtual status_t detachBuffer(int slot) = 0; + + virtual status_t getReleasedBuffers(uint64_t* slotMask) = 0; + + virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) = 0; + + virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0; + + virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat) = 0; + + virtual status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) = 0; + + virtual status_t setConsumerUsageBits(uint64_t usage) = 0; + + virtual status_t setConsumerIsProtected(bool isProtected) = 0; + + virtual status_t discardFreeBuffers() = 0; +}; + +} // namespace android
\ No newline at end of file diff --git a/libs/hostgraphics/gui/IGraphicBufferProducer.h b/libs/hostgraphics/gui/IGraphicBufferProducer.h index 00422136ff76..a1efd0bcfa4c 100644 --- a/libs/hostgraphics/gui/IGraphicBufferProducer.h +++ b/libs/hostgraphics/gui/IGraphicBufferProducer.h @@ -19,6 +19,8 @@ #include <utils/RefBase.h> +#include <ui/GraphicBuffer.h> + namespace android { class IGraphicBufferProducer : virtual public RefBase { diff --git a/libs/hostgraphics/ui/Fence.h b/libs/hostgraphics/ui/Fence.h new file mode 100644 index 000000000000..04d535c3a211 --- /dev/null +++ b/libs/hostgraphics/ui/Fence.h @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#ifndef ANDROID_FENCE_H +#define ANDROID_FENCE_H + +#include <utils/String8.h> +#include <utils/RefBase.h> + +typedef int64_t nsecs_t; + +namespace android { + +class Fence : public LightRefBase<Fence> { +public: + Fence() { } + Fence(int) { } + static const sp<Fence> NO_FENCE; + static constexpr nsecs_t SIGNAL_TIME_PENDING = INT64_MAX; + static constexpr nsecs_t SIGNAL_TIME_INVALID = -1; + static sp<Fence> merge(const char* name, const sp<Fence>& f1, const sp<Fence>& f2) { + return NO_FENCE; + } + + static sp<Fence> merge(const String8& name, const sp<Fence>& f1, const sp<Fence>& f2) { + return NO_FENCE; + } + + enum class Status { + Invalid, // Fence is invalid + Unsignaled, // Fence is valid but has not yet signaled + Signaled, // Fence is valid and has signaled + }; + + status_t wait(int timeout) { return OK; } + + status_t waitForever(const char* logname) { return OK; } + + int dup() const { return 0; } + + inline Status getStatus() { + // The sync_wait call underlying wait() has been measured to be + // significantly faster than the sync_fence_info call underlying + // getSignalTime(), which might otherwise appear to be the more obvious + // way to check whether a fence has signaled. + switch (wait(0)) { + case NO_ERROR: + return Status::Signaled; + case -ETIME: + return Status::Unsignaled; + default: + return Status::Invalid; + } + } +}; + +} // namespace android + +#endif // ANDROID_FENCE_H diff --git a/libs/hostgraphics/ui/GraphicBuffer.h b/libs/hostgraphics/ui/GraphicBuffer.h new file mode 100644 index 000000000000..ac88e44dbc65 --- /dev/null +++ b/libs/hostgraphics/ui/GraphicBuffer.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#ifndef ANDROID_GRAPHIC_BUFFER_H +#define ANDROID_GRAPHIC_BUFFER_H + +#include <stdint.h> +#include <sys/types.h> + +#include <vector> + +#include <ui/PixelFormat.h> +#include <ui/Rect.h> + +#include <utils/RefBase.h> + +namespace android { + +class GraphicBuffer : virtual public RefBase { +public: + GraphicBuffer(uint32_t w, uint32_t h):width(w),height(h) { + data.resize(w*h); + } + uint32_t getWidth() const { return static_cast<uint32_t>(width); } + uint32_t getHeight() const { return static_cast<uint32_t>(height); } + uint32_t getStride() const { return static_cast<uint32_t>(width); } + uint64_t getUsage() const { return 0; } + PixelFormat getPixelFormat() const { return PIXEL_FORMAT_RGBA_8888; } + //uint32_t getLayerCount() const { return static_cast<uint32_t>(layerCount); } + Rect getBounds() const { return Rect(width, height); } + + status_t lockAsyncYCbCr(uint32_t inUsage, const Rect& rect, + android_ycbcr *ycbcr, int fenceFd) { return OK; } + + status_t lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr, int fenceFd, + int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr) { + *vaddr = data.data(); + return OK; + } + + status_t unlockAsync(int *fenceFd) { return OK; } + +private: + uint32_t width; + uint32_t height; + std::vector<uint32_t> data; +}; + +}; // namespace android + +#endif // ANDROID_GRAPHIC_BUFFER_H diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index 510016585afc..35abc57fbe57 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -138,14 +138,14 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe err = mCreateInstance(&instance_create, nullptr, &mInstance); LOG_ALWAYS_FATAL_IF(err < 0); + GET_INST_PROC(CreateDevice); GET_INST_PROC(DestroyInstance); + GET_INST_PROC(EnumerateDeviceExtensionProperties); GET_INST_PROC(EnumeratePhysicalDevices); - GET_INST_PROC(GetPhysicalDeviceProperties); - GET_INST_PROC(GetPhysicalDeviceQueueFamilyProperties); GET_INST_PROC(GetPhysicalDeviceFeatures2); GET_INST_PROC(GetPhysicalDeviceImageFormatProperties2); - GET_INST_PROC(CreateDevice); - GET_INST_PROC(EnumerateDeviceExtensionProperties); + GET_INST_PROC(GetPhysicalDeviceProperties); + GET_INST_PROC(GetPhysicalDeviceQueueFamilyProperties); uint32_t gpuCount; LOG_ALWAYS_FATAL_IF(mEnumeratePhysicalDevices(mInstance, &gpuCount, nullptr)); @@ -312,29 +312,27 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe LOG_ALWAYS_FATAL_IF(mCreateDevice(mPhysicalDevice, &deviceInfo, nullptr, &mDevice)); - GET_DEV_PROC(GetDeviceQueue); - GET_DEV_PROC(DeviceWaitIdle); - GET_DEV_PROC(DestroyDevice); - GET_DEV_PROC(CreateCommandPool); - GET_DEV_PROC(DestroyCommandPool); GET_DEV_PROC(AllocateCommandBuffers); - GET_DEV_PROC(FreeCommandBuffers); - GET_DEV_PROC(ResetCommandBuffer); GET_DEV_PROC(BeginCommandBuffer); - GET_DEV_PROC(EndCommandBuffer); GET_DEV_PROC(CmdPipelineBarrier); - GET_DEV_PROC(GetDeviceQueue); - GET_DEV_PROC(QueueSubmit); - GET_DEV_PROC(QueueWaitIdle); - GET_DEV_PROC(DeviceWaitIdle); + GET_DEV_PROC(CreateCommandPool); + GET_DEV_PROC(CreateFence); GET_DEV_PROC(CreateSemaphore); + GET_DEV_PROC(DestroyCommandPool); + GET_DEV_PROC(DestroyDevice); + GET_DEV_PROC(DestroyFence); GET_DEV_PROC(DestroySemaphore); - GET_DEV_PROC(ImportSemaphoreFdKHR); + GET_DEV_PROC(DeviceWaitIdle); + GET_DEV_PROC(EndCommandBuffer); + GET_DEV_PROC(FreeCommandBuffers); + GET_DEV_PROC(GetDeviceQueue); GET_DEV_PROC(GetSemaphoreFdKHR); - GET_DEV_PROC(CreateFence); - GET_DEV_PROC(DestroyFence); - GET_DEV_PROC(WaitForFences); + GET_DEV_PROC(ImportSemaphoreFdKHR); + GET_DEV_PROC(QueueSubmit); + GET_DEV_PROC(QueueWaitIdle); + GET_DEV_PROC(ResetCommandBuffer); GET_DEV_PROC(ResetFences); + GET_DEV_PROC(WaitForFences); } void VulkanManager::initialize() { diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 89d3cc4f5083..16f2917f8df8 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -20,6 +20,7 @@ cc_library_shared { ], shared_libs: [ + "libbinder", "libcutils", "liblog", "libutils", diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp index c1868d3a94d6..fd386e9f7a8a 100644 --- a/libs/input/SpriteController.cpp +++ b/libs/input/SpriteController.cpp @@ -245,7 +245,8 @@ void SpriteController::doUpdateSprites() { if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER - | DIRTY_VISIBILITY | DIRTY_HOTSPOT | DIRTY_DISPLAY_ID))))) { + | DIRTY_VISIBILITY | DIRTY_HOTSPOT | DIRTY_DISPLAY_ID + | DIRTY_ICON_STYLE))))) { needApplyTransaction = true; if (wantSurfaceVisibleAndDrawn @@ -274,6 +275,21 @@ void SpriteController::doUpdateSprites() { update.state.transformationMatrix.dtdy); } + if (wantSurfaceVisibleAndDrawn + && (becomingVisible + || (update.state.dirty & (DIRTY_HOTSPOT | DIRTY_ICON_STYLE)))) { + Parcel p; + p.writeInt32(update.state.icon.style); + p.writeFloat(update.state.icon.hotSpotX); + p.writeFloat(update.state.icon.hotSpotY); + + // Pass cursor metadata in the sprite surface so that when Android is running as a + // client OS (e.g. ARC++) the host OS can get the requested cursor metadata and + // update mouse cursor in the host OS. + t.setMetadata( + update.state.surfaceControl, METADATA_MOUSE_CURSOR, p); + } + int32_t surfaceLayer = mOverlayLayer + update.state.layer; if (wantSurfaceVisibleAndDrawn && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) { @@ -397,9 +413,14 @@ void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) { } else { dirty = DIRTY_BITMAP; } + + if (mLocked.state.icon.style != icon.style) { + mLocked.state.icon.style = icon.style; + dirty |= DIRTY_ICON_STYLE; + } } else if (mLocked.state.icon.isValid()) { mLocked.state.icon.bitmap.reset(); - dirty = DIRTY_BITMAP | DIRTY_HOTSPOT; + dirty = DIRTY_BITMAP | DIRTY_HOTSPOT | DIRTY_ICON_STYLE; } else { return; // setting to invalid icon and already invalid so nothing to do } diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h index 5b216f50d113..79a904f5fe65 100644 --- a/libs/input/SpriteController.h +++ b/libs/input/SpriteController.h @@ -55,11 +55,12 @@ struct SpriteTransformationMatrix { * Icon that a sprite displays, including its hotspot. */ struct SpriteIcon { - inline SpriteIcon() : hotSpotX(0), hotSpotY(0) { } - inline SpriteIcon(const SkBitmap& bitmap, float hotSpotX, float hotSpotY) : - bitmap(bitmap), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { } + inline SpriteIcon() : style(0), hotSpotX(0), hotSpotY(0) { } + inline SpriteIcon(const SkBitmap& bitmap, int32_t style, float hotSpotX, float hotSpotY) : + bitmap(bitmap), style(style), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { } SkBitmap bitmap; + int32_t style; float hotSpotX; float hotSpotY; @@ -69,11 +70,12 @@ struct SpriteIcon { bitmap.readPixels(bitmapCopy.info(), bitmapCopy.getPixels(), bitmapCopy.rowBytes(), 0, 0); } - return SpriteIcon(bitmapCopy, hotSpotX, hotSpotY); + return SpriteIcon(bitmapCopy, style, hotSpotX, hotSpotY); } inline void reset() { bitmap.reset(); + style = 0; hotSpotX = 0; hotSpotY = 0; } @@ -149,15 +151,15 @@ public: SpriteController(const sp<Looper>& looper, int32_t overlayLayer); /* Creates a new sprite, initially invisible. */ - sp<Sprite> createSprite(); + virtual sp<Sprite> createSprite(); /* Opens or closes a transaction to perform a batch of sprite updates as part of * a single operation such as setPosition and setAlpha. It is not necessary to * open a transaction when updating a single property. * Calls to openTransaction() nest and must be matched by an equal number * of calls to closeTransaction(). */ - void openTransaction(); - void closeTransaction(); + virtual void openTransaction(); + virtual void closeTransaction(); private: enum { @@ -174,6 +176,7 @@ private: DIRTY_VISIBILITY = 1 << 5, DIRTY_HOTSPOT = 1 << 6, DIRTY_DISPLAY_ID = 1 << 7, + DIRTY_ICON_STYLE = 1 << 8, }; /* Describes the state of a sprite. diff --git a/libs/input/TEST_MAPPING b/libs/input/TEST_MAPPING new file mode 100644 index 000000000000..fe74c62d4ec1 --- /dev/null +++ b/libs/input/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "libinputservice_test" + } + ] +} diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp new file mode 100644 index 000000000000..e83b2a78d180 --- /dev/null +++ b/libs/input/tests/Android.bp @@ -0,0 +1,45 @@ +// 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. + +cc_test { + name: "libinputservice_test", + srcs: [ + "PointerController_test.cpp", + ], + shared_libs: [ + "libinputservice", + "libgui", + "libhwui", + "libutils", + ], + static_libs: [ + "libgmock", + "libgtest", + ], + header_libs: [ + "libbase_headers", + "libinputflinger_headers", + ], + include_dirs: [ + "frameworks/base/libs", + ], + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], + test_suites: [ + "general-tests", + ], +} diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp new file mode 100644 index 000000000000..92efb4ea86ff --- /dev/null +++ b/libs/input/tests/PointerController_test.cpp @@ -0,0 +1,215 @@ +/* + * 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. + */ + +#include "mocks/MockSprite.h" +#include "mocks/MockSpriteController.h" + +#include <input/PointerController.h> +#include <input/SpriteController.h> + +#include <atomic> +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <thread> + +namespace android { + +enum TestCursorType { + CURSOR_TYPE_DEFAULT = 0, + CURSOR_TYPE_HOVER, + CURSOR_TYPE_TOUCH, + CURSOR_TYPE_ANCHOR, + CURSOR_TYPE_ADDITIONAL_1, + CURSOR_TYPE_ADDITIONAL_2, + CURSOR_TYPE_CUSTOM = -1, +}; + +using ::testing::AllOf; +using ::testing::Field; +using ::testing::NiceMock; +using ::testing::Mock; +using ::testing::Return; +using ::testing::Test; + +std::pair<float, float> getHotSpotCoordinatesForType(int32_t type) { + return std::make_pair(type * 10, type * 10 + 5); +} + +class MockPointerControllerPolicyInterface : public PointerControllerPolicyInterface { +public: + virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId) override; + virtual void loadPointerResources(PointerResources* outResources, int32_t displayId) override; + virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources, + std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) override; + virtual int32_t getDefaultPointerIconId() override; + virtual int32_t getCustomPointerIconId() override; + +private: + void loadPointerIconForType(SpriteIcon* icon, int32_t cursorType); +}; + +void MockPointerControllerPolicyInterface::loadPointerIcon(SpriteIcon* icon, int32_t) { + loadPointerIconForType(icon, CURSOR_TYPE_DEFAULT); +} + +void MockPointerControllerPolicyInterface::loadPointerResources(PointerResources* outResources, + int32_t) { + loadPointerIconForType(&outResources->spotHover, CURSOR_TYPE_HOVER); + loadPointerIconForType(&outResources->spotTouch, CURSOR_TYPE_TOUCH); + loadPointerIconForType(&outResources->spotAnchor, CURSOR_TYPE_ANCHOR); +} + +void MockPointerControllerPolicyInterface::loadAdditionalMouseResources( + std::map<int32_t, SpriteIcon>* outResources, + std::map<int32_t, PointerAnimation>* outAnimationResources, + int32_t) { + SpriteIcon icon; + PointerAnimation anim; + + for (int32_t cursorType : {CURSOR_TYPE_ADDITIONAL_1, CURSOR_TYPE_ADDITIONAL_2}) { + loadPointerIconForType(&icon, cursorType); + anim.animationFrames.push_back(icon); + anim.durationPerFrame = 10; + (*outResources)[cursorType] = icon; + (*outAnimationResources)[cursorType] = anim; + } +} + +int32_t MockPointerControllerPolicyInterface::getDefaultPointerIconId() { + return CURSOR_TYPE_DEFAULT; +} + +int32_t MockPointerControllerPolicyInterface::getCustomPointerIconId() { + return CURSOR_TYPE_CUSTOM; +} + +void MockPointerControllerPolicyInterface::loadPointerIconForType(SpriteIcon* icon, int32_t type) { + icon->style = type; + std::pair<float, float> hotSpot = getHotSpotCoordinatesForType(type); + icon->hotSpotX = hotSpot.first; + icon->hotSpotY = hotSpot.second; +} + +class PointerControllerTest : public Test { +protected: + PointerControllerTest(); + ~PointerControllerTest(); + + sp<MockSprite> mPointerSprite; + sp<MockPointerControllerPolicyInterface> mPolicy; + sp<MockSpriteController> mSpriteController; + sp<PointerController> mPointerController; + +private: + void loopThread(); + + std::atomic<bool> mRunning = true; + class MyLooper : public Looper { + public: + MyLooper() : Looper(false) {} + ~MyLooper() = default; + }; + sp<MyLooper> mLooper; + std::thread mThread; +}; + +PointerControllerTest::PointerControllerTest() : mPointerSprite(new NiceMock<MockSprite>), + mLooper(new MyLooper), mThread(&PointerControllerTest::loopThread, this) { + + mSpriteController = new NiceMock<MockSpriteController>(mLooper); + mPolicy = new MockPointerControllerPolicyInterface(); + + EXPECT_CALL(*mSpriteController, createSprite()) + .WillOnce(Return(mPointerSprite)); + + mPointerController = new PointerController(mPolicy, mLooper, mSpriteController); + + DisplayViewport viewport; + viewport.displayId = ADISPLAY_ID_DEFAULT; + viewport.logicalRight = 1600; + viewport.logicalBottom = 1200; + viewport.physicalRight = 800; + viewport.physicalBottom = 600; + viewport.deviceWidth = 400; + viewport.deviceHeight = 300; + mPointerController->setDisplayViewport(viewport); +} + +PointerControllerTest::~PointerControllerTest() { + mRunning.store(false, std::memory_order_relaxed); + mThread.join(); +} + +void PointerControllerTest::loopThread() { + Looper::setForThread(mLooper); + + while (mRunning.load(std::memory_order_relaxed)) { + mLooper->pollOnce(100); + } +} + +TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) { + mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE); + + std::pair<float, float> hotspot = getHotSpotCoordinatesForType(CURSOR_TYPE_DEFAULT); + EXPECT_CALL(*mPointerSprite, setVisible(true)); + EXPECT_CALL(*mPointerSprite, setAlpha(1.0f)); + EXPECT_CALL(*mPointerSprite, setIcon( + AllOf( + Field(&SpriteIcon::style, CURSOR_TYPE_DEFAULT), + Field(&SpriteIcon::hotSpotX, hotspot.first), + Field(&SpriteIcon::hotSpotY, hotspot.second)))); + mPointerController->reloadPointerResources(); +} + +TEST_F(PointerControllerTest, updatePointerIcon) { + mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE); + + int32_t type = CURSOR_TYPE_ADDITIONAL_1; + std::pair<float, float> hotspot = getHotSpotCoordinatesForType(type); + EXPECT_CALL(*mPointerSprite, setVisible(true)); + EXPECT_CALL(*mPointerSprite, setAlpha(1.0f)); + EXPECT_CALL(*mPointerSprite, setIcon( + AllOf( + Field(&SpriteIcon::style, type), + Field(&SpriteIcon::hotSpotX, hotspot.first), + Field(&SpriteIcon::hotSpotY, hotspot.second)))); + mPointerController->updatePointerIcon(type); +} + +TEST_F(PointerControllerTest, setCustomPointerIcon) { + mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE); + + int32_t style = CURSOR_TYPE_CUSTOM; + float hotSpotX = 15; + float hotSpotY = 20; + + SpriteIcon icon; + icon.style = style; + icon.hotSpotX = hotSpotX; + icon.hotSpotY = hotSpotY; + + EXPECT_CALL(*mPointerSprite, setVisible(true)); + EXPECT_CALL(*mPointerSprite, setAlpha(1.0f)); + EXPECT_CALL(*mPointerSprite, setIcon( + AllOf( + Field(&SpriteIcon::style, style), + Field(&SpriteIcon::hotSpotX, hotSpotX), + Field(&SpriteIcon::hotSpotY, hotSpotY)))); + mPointerController->setCustomPointerIcon(icon); +} + +} // namespace android diff --git a/libs/input/tests/mocks/MockSprite.h b/libs/input/tests/mocks/MockSprite.h new file mode 100644 index 000000000000..013b79c3a3bf --- /dev/null +++ b/libs/input/tests/mocks/MockSprite.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#ifndef _MOCK_SPRITE_H +#define _MOCK_SPRITE_H + +#include <input/SpriteController.h> + +#include <gmock/gmock.h> + +namespace android { + +class MockSprite : public Sprite { +public: + virtual ~MockSprite() = default; + + MOCK_METHOD(void, setIcon, (const SpriteIcon& icon), (override)); + MOCK_METHOD(void, setVisible, (bool), (override)); + MOCK_METHOD(void, setPosition, (float, float), (override)); + MOCK_METHOD(void, setLayer, (int32_t), (override)); + MOCK_METHOD(void, setAlpha, (float), (override)); + MOCK_METHOD(void, setTransformationMatrix, (const SpriteTransformationMatrix&), (override)); + MOCK_METHOD(void, setDisplayId, (int32_t), (override)); +}; + +} // namespace android + +#endif // _MOCK_SPRITE_H diff --git a/libs/input/tests/mocks/MockSpriteController.h b/libs/input/tests/mocks/MockSpriteController.h new file mode 100644 index 000000000000..a034f66c9abf --- /dev/null +++ b/libs/input/tests/mocks/MockSpriteController.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#ifndef _MOCK_SPRITE_CONTROLLER_H +#define _MOCK_SPRITE_CONTROLLER_H + +#include "MockSprite.h" + +#include <input/SpriteController.h> + +namespace android { + +class MockSpriteController : public SpriteController { + +public: + MockSpriteController(sp<Looper> looper) : SpriteController(looper, 0) {} + ~MockSpriteController() {} + + MOCK_METHOD(sp<Sprite>, createSprite, (), (override)); + MOCK_METHOD(void, openTransaction, (), (override)); + MOCK_METHOD(void, closeTransaction, (), (override)); +}; + +} // namespace android + +#endif // _MOCK_SPRITE_CONTROLLER_H diff --git a/location/lib/Android.bp b/location/lib/Android.bp index 16f1428d2ee2..db63889d7743 100644 --- a/location/lib/Android.bp +++ b/location/lib/Android.bp @@ -21,7 +21,9 @@ java_sdk_library { "androidx.annotation_annotation", ], api_packages: ["com.android.location.provider"], - srcs_lib: "framework", - srcs_lib_whitelist_dirs: ["location/java"], - srcs_lib_whitelist_pkgs: ["com.android.internal.location"], + srcs_lib: "framework-minus-apex", + // TODO(b/70046217): remove core/java and android below. It was added to provide definitions for + // types like android.os.Bundle + srcs_lib_whitelist_dirs: ["core/java", "location/java"], + srcs_lib_whitelist_pkgs: ["android", "com.android.internal.location"], } diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java index 148ffafad491..55583d58e0c2 100644 --- a/media/java/android/media/ExifInterface.java +++ b/media/java/android/media/ExifInterface.java @@ -37,6 +37,7 @@ import libcore.io.IoUtils; import libcore.io.Streams; import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.DataInput; import java.io.DataInputStream; @@ -1866,14 +1867,17 @@ public class ExifInterface { FileInputStream in = null; FileOutputStream out = null; + File originalFile = null; + if (mFilename != null) { + originalFile = new File(mFilename); + } File tempFile = null; try { // Move the original file to temporary file. if (mFilename != null) { tempFile = new File(mFilename + ".tmp"); - File originalFile = new File(mFilename); if (!originalFile.renameTo(tempFile)) { - throw new IOException("Could'nt rename to " + tempFile.getAbsolutePath()); + throw new IOException("Couldn't rename to " + tempFile.getAbsolutePath()); } } else if (mSeekableFileDescriptor != null) { tempFile = File.createTempFile("temp", "jpg"); @@ -1882,8 +1886,8 @@ public class ExifInterface { out = new FileOutputStream(tempFile); Streams.copy(in, out); } - } catch (ErrnoException e) { - throw e.rethrowAsIOException(); + } catch (Exception e) { + throw new IOException("Failed to copy original file to temp file", e); } finally { IoUtils.closeQuietly(in); IoUtils.closeQuietly(out); @@ -1900,9 +1904,18 @@ public class ExifInterface { Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET); out = new FileOutputStream(mSeekableFileDescriptor); } - saveJpegAttributes(in, out); - } catch (ErrnoException e) { - throw e.rethrowAsIOException(); + try (BufferedInputStream bufferedIn = new BufferedInputStream(in); + BufferedOutputStream bufferedOut = new BufferedOutputStream(out)) { + saveJpegAttributes(bufferedIn, bufferedOut); + } + } catch (Exception e) { + if (mFilename != null) { + if (!tempFile.renameTo(originalFile)) { + throw new IOException("Couldn't restore original file: " + + originalFile.getAbsolutePath()); + } + } + throw new IOException("Failed to save new file", e); } finally { IoUtils.closeQuietly(in); IoUtils.closeQuietly(out); diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java index 471fa2c4bad9..7eec8d9f6cc3 100644 --- a/media/java/android/media/MediaScannerConnection.java +++ b/media/java/android/media/MediaScannerConnection.java @@ -16,17 +16,20 @@ package android.media; +import android.annotation.UnsupportedAppUsage; import android.content.ComponentName; +import android.content.ContentProviderClient; import android.content.Context; -import android.content.Intent; import android.content.ServiceConnection; -import android.media.IMediaScannerListener; -import android.media.IMediaScannerService; import android.net.Uri; +import android.os.Build; import android.os.IBinder; -import android.os.RemoteException; +import android.provider.MediaStore; import android.util.Log; +import com.android.internal.os.BackgroundThread; + +import java.io.File; /** * MediaScannerConnection provides a way for applications to pass a @@ -38,20 +41,24 @@ import android.util.Log; * to the client of the MediaScannerConnection class. */ public class MediaScannerConnection implements ServiceConnection { - private static final String TAG = "MediaScannerConnection"; - private Context mContext; - private MediaScannerConnectionClient mClient; - private IMediaScannerService mService; - private boolean mConnected; // true if connect() has been called since last disconnect() + private final Context mContext; + private final MediaScannerConnectionClient mClient; + private ContentProviderClient mProvider; + + @Deprecated + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) + private IMediaScannerService mService; + @Deprecated + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) + private boolean mConnected; + @Deprecated + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) private final IMediaScannerListener.Stub mListener = new IMediaScannerListener.Stub() { + @Override public void scanCompleted(String path, Uri uri) { - MediaScannerConnectionClient client = mClient; - if (client != null) { - client.onScanCompleted(path, uri); - } } }; @@ -81,15 +88,6 @@ public class MediaScannerConnection implements ServiceConnection { * MediaScanner service has been established. */ public void onMediaScannerConnected(); - - /** - * Called to notify the client when the media scanner has finished - * scanning a file. - * @param path the path to the file that has been scanned. - * @param uri the Uri for the file if the scanning operation succeeded - * and the file was added to the media database, or null if scanning failed. - */ - public void onScanCompleted(String path, Uri uri); } /** @@ -111,13 +109,12 @@ public class MediaScannerConnection implements ServiceConnection { */ public void connect() { synchronized (this) { - if (!mConnected) { - Intent intent = new Intent(IMediaScannerService.class.getName()); - intent.setComponent( - new ComponentName("com.android.providers.media", - "com.android.providers.media.MediaScannerService")); - mContext.bindService(intent, this, Context.BIND_AUTO_CREATE); - mConnected = true; + if (mProvider == null) { + mProvider = mContext.getContentResolver() + .acquireContentProviderClient(MediaStore.AUTHORITY); + if (mClient != null) { + mClient.onMediaScannerConnected(); + } } } } @@ -127,22 +124,9 @@ public class MediaScannerConnection implements ServiceConnection { */ public void disconnect() { synchronized (this) { - if (mConnected) { - if (false) { - Log.v(TAG, "Disconnecting from Media Scanner"); - } - try { - mContext.unbindService(this); - if (mClient instanceof ClientProxy) { - mClient = null; - } - mService = null; - } catch (IllegalArgumentException ex) { - if (false) { - Log.v(TAG, "disconnect failed: " + ex); - } - } - mConnected = false; + if (mProvider != null) { + mProvider.close(); + mProvider = null; } } } @@ -152,7 +136,7 @@ public class MediaScannerConnection implements ServiceConnection { * @return true if we are connected, false otherwise */ public synchronized boolean isConnected() { - return (mService != null && mConnected); + return (mProvider != null); } /** @@ -166,107 +150,107 @@ public class MediaScannerConnection implements ServiceConnection { */ public void scanFile(String path, String mimeType) { synchronized (this) { - if (mService == null || !mConnected) { + if (mProvider == null) { throw new IllegalStateException("not connected to MediaScannerService"); } - try { - if (false) { - Log.v(TAG, "Scanning file " + path); + BackgroundThread.getExecutor().execute(() -> { + final Uri uri = scanFileQuietly(mProvider, new File(path)); + if (mClient != null) { + mClient.onScanCompleted(path, uri); } - mService.requestScanFile(path, mimeType, mListener); - } catch (RemoteException e) { - if (false) { - Log.d(TAG, "Failed to scan file " + path); + }); + } + } + + /** + * Convenience for constructing a {@link MediaScannerConnection}, calling + * {@link #connect} on it, and calling {@link #scanFile} with the given + * <var>path</var> and <var>mimeType</var> when the connection is + * established. + * @param context The caller's Context, required for establishing a connection to + * the media scanner service. + * Success or failure of the scanning operation cannot be determined until + * {@link MediaScannerConnectionClient#onScanCompleted(String, Uri)} is called. + * @param paths Array of paths to be scanned. + * @param mimeTypes Optional array of MIME types for each path. + * If mimeType is null, then the mimeType will be inferred from the file extension. + * @param callback Optional callback through which you can receive the + * scanned URI and MIME type; If null, the file will be scanned but + * you will not get a result back. + * @see #scanFile(String, String) + */ + public static void scanFile(Context context, String[] paths, String[] mimeTypes, + OnScanCompletedListener callback) { + BackgroundThread.getExecutor().execute(() -> { + try (ContentProviderClient client = context.getContentResolver() + .acquireContentProviderClient(MediaStore.AUTHORITY)) { + for (String path : paths) { + final Uri uri = scanFileQuietly(client, new File(path)); + if (callback != null) { + callback.onScanCompleted(path, uri); + } } } + }); + } + + private static Uri scanFileQuietly(ContentProviderClient client, File file) { + Uri uri = null; + try { + uri = MediaStore.scanFile(client, file); + Log.d(TAG, "Scanned " + file + " to " + uri); + } catch (Exception e) { + Log.w(TAG, "Failed to scan " + file + ": " + e); } + return uri; } + @Deprecated static class ClientProxy implements MediaScannerConnectionClient { + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) final String[] mPaths; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) final String[] mMimeTypes; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) final OnScanCompletedListener mClient; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) MediaScannerConnection mConnection; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) int mNextPath; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) ClientProxy(String[] paths, String[] mimeTypes, OnScanCompletedListener client) { mPaths = paths; mMimeTypes = mimeTypes; mClient = client; } + @Override public void onMediaScannerConnected() { - scanNextPath(); } + @Override public void onScanCompleted(String path, Uri uri) { - if (mClient != null) { - mClient.onScanCompleted(path, uri); - } - scanNextPath(); } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) void scanNextPath() { - if (mNextPath >= mPaths.length) { - mConnection.disconnect(); - mConnection = null; - return; - } - String mimeType = mMimeTypes != null ? mMimeTypes[mNextPath] : null; - mConnection.scanFile(mPaths[mNextPath], mimeType); - mNextPath++; } } /** - * Convenience for constructing a {@link MediaScannerConnection}, calling - * {@link #connect} on it, and calling {@link #scanFile} with the given - * <var>path</var> and <var>mimeType</var> when the connection is - * established. - * @param context The caller's Context, required for establishing a connection to - * the media scanner service. - * Success or failure of the scanning operation cannot be determined until - * {@link MediaScannerConnectionClient#onScanCompleted(String, Uri)} is called. - * @param paths Array of paths to be scanned. - * @param mimeTypes Optional array of MIME types for each path. - * If mimeType is null, then the mimeType will be inferred from the file extension. - * @param callback Optional callback through which you can receive the - * scanned URI and MIME type; If null, the file will be scanned but - * you will not get a result back. - * @see #scanFile(String, String) - */ - public static void scanFile(Context context, String[] paths, String[] mimeTypes, - OnScanCompletedListener callback) { - ClientProxy client = new ClientProxy(paths, mimeTypes, callback); - MediaScannerConnection connection = new MediaScannerConnection(context, client); - client.mConnection = connection; - connection.connect(); - } - - /** * Part of the ServiceConnection interface. Do not call. */ + @Override public void onServiceConnected(ComponentName className, IBinder service) { - if (false) { - Log.v(TAG, "Connected to Media Scanner"); - } - synchronized (this) { - mService = IMediaScannerService.Stub.asInterface(service); - if (mService != null && mClient != null) { - mClient.onMediaScannerConnected(); - } - } + // No longer needed } /** * Part of the ServiceConnection interface. Do not call. */ + @Override public void onServiceDisconnected(ComponentName className) { - if (false) { - Log.v(TAG, "Disconnected from Media Scanner"); - } - synchronized (this) { - mService = null; - } + // No longer needed } } diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java index 792a2ba678fd..be0d966fa075 100644 --- a/media/java/android/media/Metadata.java +++ b/media/java/android/media/Metadata.java @@ -272,6 +272,15 @@ import java.util.TimeZone; @UnsupportedAppUsage public Metadata() { } + // Have to declare protected for finalize() since it is protected + // in the base class Object. + @Override + protected void finalize() throws Throwable { + if (mParcel != null) { + mParcel.recycle(); + } + } + /** * Go over all the records, collecting metadata keys and records' * type field offset in the Parcel. These are stored in @@ -418,6 +427,10 @@ import java.util.TimeZone; parcel.setDataPosition(pin); return false; } + + if (mParcel != null) { + mParcel.recycle(); + } mParcel = parcel; return true; } diff --git a/media/lib/signer/Android.bp b/media/lib/signer/Android.bp index 44f8725ec6f5..f320397bc84b 100644 --- a/media/lib/signer/Android.bp +++ b/media/lib/signer/Android.bp @@ -18,7 +18,7 @@ java_sdk_library { name: "com.android.mediadrm.signer", srcs: ["java/**/*.java"], api_packages: ["com.android.mediadrm.signer"], - srcs_lib: "framework", + srcs_lib: "framework-minus-apex", srcs_lib_whitelist_dirs: ["media/java"], srcs_lib_whitelist_pkgs: ["android.media"], } diff --git a/packages/CarSystemUI/AndroidManifest.xml b/packages/CarSystemUI/AndroidManifest.xml index 195d4fee5162..261b9f508ccd 100644 --- a/packages/CarSystemUI/AndroidManifest.xml +++ b/packages/CarSystemUI/AndroidManifest.xml @@ -21,4 +21,8 @@ coreApp="true"> <!-- This permission is required to monitor car power state. --> <uses-permission android:name="android.car.permission.CAR_POWER" /> + <!-- This permission is required to get the trusted device list of a user. --> + <uses-permission android:name="android.car.permission.CAR_ENROLL_TRUST"/> + <!-- This permission is required to get bluetooth broadcast. --> + <uses-permission android:name="android.permission.BLUETOOTH" /> </manifest> diff --git a/packages/CarSystemUI/res/drawable/unlock_dialog_background.xml b/packages/CarSystemUI/res/drawable/unlock_dialog_background.xml new file mode 100644 index 000000000000..bec6ba7b7c4f --- /dev/null +++ b/packages/CarSystemUI/res/drawable/unlock_dialog_background.xml @@ -0,0 +1,26 @@ +<?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 + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/unlock_dialog_background_color"/> + <padding + android:bottom="@*android:dimen/car_padding_2" + android:left="@*android:dimen/car_padding_2" + android:right="@*android:dimen/car_padding_2" + android:top="@*android:dimen/car_padding_2"/> + <corners + android:radius="@dimen/unlock_dialog_radius"/> +</shape>
\ No newline at end of file diff --git a/packages/CarSystemUI/res/layout/trust_agent_unlock_dialog.xml b/packages/CarSystemUI/res/layout/trust_agent_unlock_dialog.xml new file mode 100644 index 000000000000..2d9901c30d02 --- /dev/null +++ b/packages/CarSystemUI/res/layout/trust_agent_unlock_dialog.xml @@ -0,0 +1,72 @@ +<?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 + --> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/layout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center"> + + <LinearLayout + android:layout_width="@dimen/unlock_dialog_width" + android:layout_height="wrap_content" + android:gravity="center" + android:layout_gravity="center" + android:orientation="vertical" + android:background="@drawable/unlock_dialog_background" + android:padding="@*android:dimen/car_padding_2"> + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + <ProgressBar + android:layout_gravity="center" + android:layout_width="@dimen/unlock_dialog_progress_bar_size" + android:layout_height="@dimen/unlock_dialog_progress_bar_size" /> + <ImageView + android:id="@+id/avatar" + android:layout_gravity="center" + android:layout_width="@dimen/unlock_dialog_avatar_size" + android:layout_height="@dimen/unlock_dialog_avatar_size" + android:scaleType="fitCenter"/> + </FrameLayout> + + <TextView + android:id="@+id/user_name" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/unlock_dialog_default_user_name" + android:textSize="@*android:dimen/car_body1_size" + android:textColor="@android:color/white"/> + + <TextView + android:id="@+id/unlocking_text" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_marginTop="@*android:dimen/car_padding_1" + android:text="@string/unlock_dialog_message_default" + android:textSize="@*android:dimen/car_body4_size" + android:textColor="@color/unlock_dialog_message_text_default"/> + + <Button + android:id="@+id/enter_pin_button" + android:layout_marginTop="@*android:dimen/car_padding_1" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:text="@string/unlock_dialog_button_text_pin" + style="@style/UnlockDialogButton"/> + </LinearLayout> +</FrameLayout>
\ No newline at end of file diff --git a/packages/CarSystemUI/res/values/colors_car.xml b/packages/CarSystemUI/res/values/colors_car.xml index 69ab3f3cf957..0a3f7aa92d84 100644 --- a/packages/CarSystemUI/res/values/colors_car.xml +++ b/packages/CarSystemUI/res/values/colors_car.xml @@ -26,4 +26,9 @@ <color name="car_user_switcher_add_user_background_color">@*android:color/car_dark_blue_grey_600</color> <color name="car_user_switcher_add_user_add_sign_color">@*android:color/car_body1_light</color> + <!-- colors for unlock dialog --> + <color name="unlock_dialog_background_color">#ff282a2d</color> + <color name="unlock_dialog_message_text_default">@*android:color/car_grey_400</color> + <color name="unlock_dialog_enter_pin_text_color">#ff66b5ff</color> + </resources> diff --git a/packages/CarSystemUI/res/values/dimens_car.xml b/packages/CarSystemUI/res/values/dimens_car.xml index 42a764959545..9cb09c942781 100644 --- a/packages/CarSystemUI/res/values/dimens_car.xml +++ b/packages/CarSystemUI/res/values/dimens_car.xml @@ -43,4 +43,10 @@ <!-- This must be the negative of car_user_switcher_container_height for the animation. --> <dimen name="car_user_switcher_container_anim_height">-420dp</dimen> + <!-- dimensions for the unlock dialog --> + <dimen name="unlock_dialog_width">500dp</dimen> + <dimen name="unlock_dialog_radius">16dp</dimen> + <dimen name="unlock_dialog_avatar_size">100dp</dimen> + <dimen name="unlock_dialog_progress_bar_size">140dp</dimen> + </resources> diff --git a/packages/CarSystemUI/res/values/integers_car.xml b/packages/CarSystemUI/res/values/integers_car.xml index be2cb0d8d900..862ba751aa55 100644 --- a/packages/CarSystemUI/res/values/integers_car.xml +++ b/packages/CarSystemUI/res/values/integers_car.xml @@ -31,5 +31,7 @@ <!--Percentage of the screen height, from the bottom, that a notification panel being peeked at will result in remaining closed the panel if released--> <integer name="notification_settle_close_percentage">80</integer> + <!-- The delay before the unlock dialog pops up --> + <integer name="unlock_dialog_delay_ms">3000</integer> </resources> diff --git a/packages/CarSystemUI/res/values/strings_car.xml b/packages/CarSystemUI/res/values/strings_car.xml index 83e91c57ccc3..717692e2f02f 100644 --- a/packages/CarSystemUI/res/values/strings_car.xml +++ b/packages/CarSystemUI/res/values/strings_car.xml @@ -29,4 +29,19 @@ <string name="user_add_user_message_setup">When you add a new user, that person needs to set up their space.</string> <!-- Message to inform user that the newly created user will have permissions to update apps for all other users. [CHAR LIMIT=100] --> <string name="user_add_user_message_update">Any user can update apps for all other users.</string> + <!-- Default messages displayed on the unlock dialog before unlock advertising started. [CHAR LIMIT=30]--> + <string name="unlock_dialog_message_default">Waiting\u2026</string> + <!-- Message to inform user that the IHU is looking for trusted device. [CHAR LIMIT=30] --> + <string name="unlock_dialog_message_start">Looking for trusted device\u2026</string> + + <!-- Cancel Button text for user who has PIN as security lock. [CHAR LIMIT=30] --> + <string name="unlock_dialog_button_text_pin">Enter PIN instead</string> + <!-- Cancel Button text for user who has Pattern as security lock. [CHAR LIMIT=30] --> + <string name="unlock_dialog_button_text_pattern">Enter Pattern instead</string> + <!-- Cancel Button text for user who has Password as security lock. [CHAR LIMIT=30] --> + <string name="unlock_dialog_button_text_password">Enter Password instead</string> + <!-- Default user name shows on unlock dialog --> + <string name="unlock_dialog_default_user_name">Default Name</string> + <!-- Default title for unlock dialog --> + <string name="unlock_dialog_title">Unlock Dialogue</string> </resources> diff --git a/packages/CarSystemUI/res/values/styles.xml b/packages/CarSystemUI/res/values/styles.xml index 371bebdebc86..a9423bf6f260 100644 --- a/packages/CarSystemUI/res/values/styles.xml +++ b/packages/CarSystemUI/res/values/styles.xml @@ -46,4 +46,12 @@ <item name="android:layout_width">96dp</item> <item name="android:background">@drawable/nav_button_background</item> </style> + + <style name="UnlockDialogButton"> + <item name="android:background">?android:attr/selectableItemBackground</item> + <item name="android:textAlignment">center</item> + <item name="android:textColor">@color/unlock_dialog_enter_pin_text_color</item> + <item name="android:paddingHorizontal">16dp</item> + <item name="android:textAllCaps">false</item> + </style> </resources>
\ No newline at end of file diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index b1f979708615..7ea83f56557a 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -26,12 +26,16 @@ import android.car.Car; import android.car.drivingstate.CarDrivingStateEvent; import android.car.drivingstate.CarUxRestrictionsManager; import android.car.hardware.power.CarPowerManager.CarPowerStateListener; +import android.car.trust.CarTrustAgentEnrollmentManager; import android.content.Context; import android.content.res.Configuration; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.inputmethodservice.InputMethodService; +import android.os.IBinder; import android.util.Log; +import android.view.Display; import android.view.GestureDetector; import android.view.Gravity; import android.view.MotionEvent; @@ -86,8 +90,7 @@ import java.util.Map; /** * A status bar (and navigation bar) tailored for the automotive use case. */ -public class CarStatusBar extends StatusBar implements - CarBatteryController.BatteryViewHandler { +public class CarStatusBar extends StatusBar implements CarBatteryController.BatteryViewHandler { private static final String TAG = "CarStatusBar"; // used to calculate how fast to open or close the window private static final float DEFAULT_FLING_VELOCITY = 0; @@ -168,6 +171,9 @@ public class CarStatusBar extends StatusBar implements private boolean mIsSwipingVerticallyToClose; // Whether heads-up notifications should be shown when shade is open. private boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen; + // If the nav bar should be hidden when the soft keyboard is visible. + private boolean mHideNavBarForKeyboard; + private boolean mBottomNavBarVisible; private final CarPowerStateListener mCarPowerStateListener = (int state) -> { @@ -189,6 +195,17 @@ public class CarStatusBar extends StatusBar implements // builds the nav bar mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class); mDeviceIsProvisioned = mDeviceProvisionedController.isDeviceProvisioned(); + + // Keyboard related setup, before nav bars are created. + mHideNavBarForKeyboard = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard); + mBottomNavBarVisible = false; + + // Need to initialize screen lifecycle before calling super.start - before switcher is + // created. + mScreenLifecycle = Dependency.get(ScreenLifecycle.class); + mScreenLifecycle.addObserver(mScreenObserver); + super.start(); mTaskStackListener = new TaskStackListenerImpl(); mActivityManagerWrapper = ActivityManagerWrapper.getInstance(); @@ -235,9 +252,6 @@ public class CarStatusBar extends StatusBar implements mPowerManagerHelper.connectToCarService(); mSwitchToGuestTimer = new SwitchToGuestTimer(mContext); - - mScreenLifecycle = Dependency.get(ScreenLifecycle.class); - mScreenLifecycle.addObserver(mScreenObserver); } /** @@ -719,6 +733,13 @@ public class CarStatusBar extends StatusBar implements buildNavBarContent(); attachNavBarWindows(); + // Try setting up the initial state of the nav bar if applicable. + if (result != null) { + setImeWindowStatus(Display.DEFAULT_DISPLAY, result.mImeToken, + result.mImeWindowVis, result.mImeBackDisposition, + result.mShowImeSwitcher); + } + // There has been a car customized nav bar on the default display, so just create nav bars // on external displays. mNavigationBarController.createNavigationBars(false /* includeDefaultDisplay */, result); @@ -757,22 +778,33 @@ public class CarStatusBar extends StatusBar implements } - private void attachNavBarWindows() { + /** + * We register for soft keyboard visibility events such that we can hide the navigation bar + * giving more screen space to the IME. Note: this is optional and controlled by + * {@code com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard}. + */ + @Override + public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, + boolean showImeSwitcher) { + if (!mHideNavBarForKeyboard) { + return; + } - if (mShowBottom) { - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, - PixelFormat.TRANSLUCENT); - lp.setTitle("CarNavigationBar"); - lp.windowAnimations = 0; - mWindowManager.addView(mNavigationBarWindow, lp); + if (mContext.getDisplay().getDisplayId() != displayId) { + return; } + boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0; + if (!isKeyboardVisible) { + attachBottomNavBarWindow(); + } else { + detachBottomNavBarWindow(); + } + } + + private void attachNavBarWindows() { + attachBottomNavBarWindow(); + if (mShowLeft) { int width = mContext.getResources().getDimensionPixelSize( R.dimen.car_left_navigation_bar_width); @@ -807,7 +839,49 @@ public class CarStatusBar extends StatusBar implements rightlp.gravity = Gravity.RIGHT; mWindowManager.addView(mRightNavigationBarWindow, rightlp); } + } + + /** + * Attaches the bottom nav bar window. Can be extended to modify the specific behavior of + * attaching the bottom nav bar. + */ + protected void attachBottomNavBarWindow() { + if (!mShowBottom) { + return; + } + if (mBottomNavBarVisible) { + return; + } + mBottomNavBarVisible = true; + + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, + PixelFormat.TRANSLUCENT); + lp.setTitle("CarNavigationBar"); + lp.windowAnimations = 0; + mWindowManager.addView(mNavigationBarWindow, lp); + } + + /** + * Detaches the bottom nav bar window. Can be extended to modify the specific behavior of + * detaching the bottom nav bar. + */ + protected void detachBottomNavBarWindow() { + if (!mShowBottom) { + return; + } + + if (!mBottomNavBarVisible) { + return; + } + mBottomNavBarVisible = false; + mWindowManager.removeView(mNavigationBarWindow); } private void buildBottomBar(int layout) { @@ -957,8 +1031,12 @@ public class CarStatusBar extends StatusBar implements UserSwitcherController userSwitcherController = Dependency.get(UserSwitcherController.class); if (userSwitcherController.useFullscreenUserSwitcher()) { + Car car = Car.createCar(mContext); + CarTrustAgentEnrollmentManager enrollmentManager = (CarTrustAgentEnrollmentManager) car + .getCarManager(Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE); mFullscreenUserSwitcher = new FullscreenUserSwitcher(this, - mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub), mContext); + mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub), + enrollmentManager, mContext); } else { super.createUserSwitcher(); } diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java new file mode 100644 index 000000000000..78bb1bcf24a8 --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarTrustAgentUnlockDialogHelper.java @@ -0,0 +1,240 @@ +/* + * 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.car; + +import android.app.admin.DevicePolicyManager; +import android.bluetooth.BluetoothAdapter; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.PixelFormat; +import android.os.Handler; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.internal.widget.LockPatternUtils; +import com.android.systemui.R; + +/** + * A helper class displays an unlock dialog and receives broadcast about detecting trusted device + * & unlocking state to show the appropriate message on the dialog. + */ +class CarTrustAgentUnlockDialogHelper extends BroadcastReceiver{ + private static final String TAG = CarTrustAgentUnlockDialogHelper.class.getSimpleName(); + + private final Context mContext; + private final WindowManager mWindowManager; + private final UserManager mUserManager; + private final WindowManager.LayoutParams mParams; + /** + * Not using Dialog because context passed from {@link FullscreenUserSwitcher} is not an + * activity. + */ + private final View mUnlockDialog; + private final TextView mUnlockingText; + private final Button mButton; + private final IntentFilter mFilter; + private int mUid; + private boolean mIsDialogShowing; + private OnHideListener mOnHideListener; + + CarTrustAgentUnlockDialogHelper(Context context) { + mContext = context; + mUserManager = mContext.getSystemService(UserManager.class); + mWindowManager = mContext.getSystemService(WindowManager.class); + mParams = createLayoutParams(); + mFilter = getIntentFilter(); + + mParams.packageName = mContext.getPackageName(); + mParams.setTitle(mContext.getString(R.string.unlock_dialog_title)); + + mUnlockDialog = LayoutInflater.from(mContext).inflate( + R.layout.trust_agent_unlock_dialog, null); + mUnlockDialog.setLayoutParams(mParams); + + mUnlockingText = mUnlockDialog.findViewById(R.id.unlocking_text); + mButton = mUnlockDialog.findViewById(R.id.enter_pin_button); + mButton.setOnClickListener(v -> { + hideUnlockDialog(/* notifyOnHideListener= */true); + // TODO(b/138250105) Stop unlock advertising + }); + + BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + if (bluetoothAdapter != null + && bluetoothAdapter.getLeState() == BluetoothAdapter.STATE_BLE_ON) { + mUnlockingText.setText(R.string.unlock_dialog_message_start); + } + } + + /** + * This filter is listening on: + * {@link BluetoothAdapter#ACTION_BLE_STATE_CHANGED} for starting unlock advertising; + * {@link Intent#ACTION_USER_UNLOCKED} for IHU unlocked + */ + private IntentFilter getIntentFilter() { + IntentFilter filter = new IntentFilter(); + filter.addAction(BluetoothAdapter.ACTION_BLE_STATE_CHANGED); + filter.addAction(Intent.ACTION_USER_UNLOCKED); + return filter; + } + + /** + * Show dialog for the given user + */ + void showUnlockDialog(int uid, OnHideListener listener) { + showUnlockDialogAfterDelay(uid, 0, listener); + } + + /** + * Show dialog for the given user after the certain time of delay has elapsed + * + * @param uid the user to unlock + * @param listener listener that listens to dialog hide + */ + void showUnlockDialogAfterDelay(int uid, OnHideListener listener) { + long delayMillis = mContext.getResources().getInteger(R.integer.unlock_dialog_delay_ms); + showUnlockDialogAfterDelay(uid, delayMillis, listener); + } + + /** + * Show dialog for the given user after the supplied delay has elapsed + */ + private void showUnlockDialogAfterDelay(int uid, long delayMillis, OnHideListener listener) { + setUid(uid); + mOnHideListener = listener; + if (!mIsDialogShowing) { + logd("Receiver registered"); + mContext.registerReceiverAsUser(this, UserHandle.ALL, mFilter, + /* broadcastPermission= */ null, + /* scheduler= */ null); + new Handler().postDelayed(() -> { + if (!mUserManager.isUserUnlocked(uid)) { + logd("Showed unlock dialog for user: " + uid + " after " + delayMillis + + " delay."); + mWindowManager.addView(mUnlockDialog, mParams); + } + }, delayMillis); + } + mIsDialogShowing = true; + } + + private void setUid(int uid) { + mUid = uid; + TextView userName = mUnlockDialog.findViewById(R.id.user_name); + userName.setText(mUserManager.getUserInfo(mUid).name); + ImageView avatar = mUnlockDialog.findViewById(R.id.avatar); + avatar.setImageBitmap(mUserManager.getUserIcon(mUid)); + setButtonText(); + } + + private void hideUnlockDialog(boolean notifyOnHideListener) { + if (!mIsDialogShowing) { + return; + } + mWindowManager.removeView(mUnlockDialog); + logd("Receiver unregistered"); + mContext.unregisterReceiver(this); + if (notifyOnHideListener && mOnHideListener != null) { + mOnHideListener.onHide(); + } + mIsDialogShowing = false; + } + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action == null) { + return; + } + switch (action) { + case BluetoothAdapter.ACTION_BLE_STATE_CHANGED: + logd("Received ACTION_BLE_STATE_CHANGED"); + int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1); + if (state == BluetoothAdapter.STATE_BLE_ON) { + logd("Received BLE_ON"); + mUnlockingText.setText(R.string.unlock_dialog_message_start); + } + break; + case Intent.ACTION_USER_UNLOCKED: + int uid = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); + if (uid == mUid) { + logd("IHU unlocked"); + hideUnlockDialog(/* notifyOnHideListener= */false); + } else { + Log.e(TAG, "Received ACTION_USER_UNLOCKED for unexpected uid: " + uid); + } + break; + default: + Log.e(TAG, "Encountered unexpected action when attempting to set " + + "unlock state message: " + action); + } + } + + // Set button text based on security lock type + private void setButtonText() { + LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); + int passwordQuality = lockPatternUtils.getActivePasswordQuality(mUid); + switch (passwordQuality) { + // PIN + case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: + // Pattern + case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: + mButton.setText(R.string.unlock_dialog_button_text_pattern); + break; + // Password + case DevicePolicyManager.PASSWORD_QUALITY_MANAGED: + mButton.setText(R.string.unlock_dialog_button_text_password); + break; + default: + Log.e(TAG, "Encountered unexpected security type when attempting to set " + + "button text:" + passwordQuality); + } + } + + private WindowManager.LayoutParams createLayoutParams() { + return new WindowManager.LayoutParams( + WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG, + WindowManager.LayoutParams.FLAG_FULLSCREEN + | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS + | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, + PixelFormat.TRANSLUCENT + ); + } + + private void logd(String message) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, message); + } + } + + /** + * Listener used to notify when the dialog is hidden + */ + interface OnHideListener { + void onHide(); + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java index 0a167d9acf98..7cd6adbb3952 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java @@ -18,29 +18,60 @@ package com.android.systemui.statusbar.car; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.car.trust.CarTrustAgentEnrollmentManager; +import android.car.userlib.CarUserManagerHelper; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.UserInfo; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.Log; import android.view.View; import android.view.ViewStub; import androidx.recyclerview.widget.GridLayoutManager; import com.android.systemui.R; +import com.android.systemui.statusbar.car.UserGridRecyclerView.UserRecord; /** * Manages the fullscreen user switcher. */ public class FullscreenUserSwitcher { + private static final String TAG = FullscreenUserSwitcher.class.getSimpleName(); + // Because user 0 is headless, user count for single user is 2 + private static final int NUMBER_OF_BACKGROUND_USERS = 1; private final UserGridRecyclerView mUserGridView; private final View mParent; private final int mShortAnimDuration; private final CarStatusBar mStatusBar; + private final Context mContext; + private final UserManager mUserManager; + private final CarTrustAgentEnrollmentManager mEnrollmentManager; + private CarTrustAgentUnlockDialogHelper mUnlockDialogHelper; + private UserGridRecyclerView.UserRecord mSelectedUser; + private CarUserManagerHelper mCarUserManagerHelper; + private final BroadcastReceiver mUserUnlockReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "user 0 is unlocked, SharedPreference is accessible."); + } + showDialogForInitialUser(); + mContext.unregisterReceiver(mUserUnlockReceiver); + } + }; + - public FullscreenUserSwitcher(CarStatusBar statusBar, ViewStub containerStub, Context context) { + public FullscreenUserSwitcher(CarStatusBar statusBar, ViewStub containerStub, + CarTrustAgentEnrollmentManager enrollmentManager, Context context) { mStatusBar = statusBar; mParent = containerStub.inflate(); - // Hide the user grid by default. It will only be made visible by clicking on a cancel - // button in a bouncer. - hide(); + mEnrollmentManager = enrollmentManager; + mContext = context; + View container = mParent.findViewById(R.id.container); // Initialize user grid. @@ -50,9 +81,51 @@ public class FullscreenUserSwitcher { mUserGridView.setLayoutManager(layoutManager); mUserGridView.buildAdapter(); mUserGridView.setUserSelectionListener(this::onUserSelected); + mCarUserManagerHelper = new CarUserManagerHelper(context); + mUnlockDialogHelper = new CarTrustAgentUnlockDialogHelper(mContext); + mUserManager = mContext.getSystemService(UserManager.class); mShortAnimDuration = container.getResources() .getInteger(android.R.integer.config_shortAnimTime); + IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED); + if (mUserManager.isUserUnlocked(UserHandle.USER_SYSTEM)) { + // User0 is unlocked, switched to the initial user + showDialogForInitialUser(); + } else { + // listen to USER_UNLOCKED + mContext.registerReceiverAsUser(mUserUnlockReceiver, + UserHandle.getUserHandleForUid(UserHandle.USER_SYSTEM), + filter, + /* broadcastPermission= */ null, + /* scheduler */ null); + } + } + + private void showDialogForInitialUser() { + int initialUser = mCarUserManagerHelper.getInitialUser(); + UserInfo initialUserInfo = mUserManager.getUserInfo(initialUser); + mSelectedUser = new UserRecord(initialUserInfo, + /* isStartGuestSession= */ false, + /* isAddUser= */ false, + /* isForeground= */ true); + // For single user without trusted device, hide the user switcher. + if (!hasMultipleUsers() && !hasTrustedDevice(initialUser)) { + dismissUserSwitcher(); + return; + } + // Show unlock dialog for initial user + if (hasTrustedDevice(initialUser)) { + mUnlockDialogHelper.showUnlockDialogAfterDelay(initialUser, + () -> dismissUserSwitcher()); + } + } + + /** + * Check if there is only one possible user to login in. + * In a Multi-User system there is always one background user (user 0) + */ + private boolean hasMultipleUsers() { + return mUserManager.getUserCount() > NUMBER_OF_BACKGROUND_USERS + 1; } /** @@ -77,14 +150,33 @@ public class FullscreenUserSwitcher { } /** - * Every time user clicks on an item in the switcher, we hide the switcher, either - * gradually or immediately. + * Every time user clicks on an item in the switcher, if the clicked user has no trusted device, + * we hide the switcher, either gradually or immediately. + * + * If the user has trusted device, we show an unlock dialog to notify user the unlock state. + * When the unlock dialog is dismissed by user, we hide the unlock dialog and the switcher. * - * We dismiss the entire keyguard if user clicked on the foreground user (user we're already - * logged in as). + * We dismiss the entire keyguard when we hide the switcher if user clicked on the foreground + * user (user we're already logged in as). */ private void onUserSelected(UserGridRecyclerView.UserRecord record) { - if (record.mIsForeground) { + mSelectedUser = record; + if (hasTrustedDevice(record.mInfo.id)) { + mUnlockDialogHelper.showUnlockDialog(record.mInfo.id, () -> dismissUserSwitcher()); + return; + } + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "no trusted device enrolled for uid: " + record.mInfo.id); + } + dismissUserSwitcher(); + } + + private void dismissUserSwitcher() { + if (mSelectedUser == null) { + Log.e(TAG, "Request to dismiss user switcher, but no user selected"); + return; + } + if (mSelectedUser.mIsForeground) { hide(); mStatusBar.dismissKeyguard(); return; @@ -106,4 +198,8 @@ public class FullscreenUserSwitcher { }); } + + private boolean hasTrustedDevice(int uid) { + return !mEnrollmentManager.getEnrolledDeviceInfoForUser(uid).isEmpty(); + } } diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java index 077f7ecd3e46..cf286bdbde96 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java @@ -20,6 +20,8 @@ import android.content.Context; import android.gsi.GsiProgress; import android.net.Uri; import android.os.AsyncTask; +import android.os.MemoryFile; +import android.os.ParcelFileDescriptor; import android.os.image.DynamicSystemManager; import android.util.Log; import android.webkit.URLUtil; @@ -28,11 +30,9 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.util.Arrays; import java.util.Locale; import java.util.zip.GZIPInputStream; - class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { private static final String TAG = "InstallationAsyncTask"; @@ -125,28 +125,26 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { Thread.sleep(10); } - if (mInstallationSession == null) { - throw new IOException("Failed to start installation with requested size: " - + (mSystemSize + mUserdataSize)); + throw new IOException( + "Failed to start installation with requested size: " + + (mSystemSize + mUserdataSize)); } installedSize = mUserdataSize; + MemoryFile memoryFile = new MemoryFile("dsu", READ_BUFFER_SIZE); byte[] bytes = new byte[READ_BUFFER_SIZE]; - + mInstallationSession.setAshmem( + new ParcelFileDescriptor(memoryFile.getFileDescriptor()), READ_BUFFER_SIZE); int numBytesRead; - Log.d(TAG, "Start installation loop"); while ((numBytesRead = mStream.read(bytes, 0, READ_BUFFER_SIZE)) != -1) { + memoryFile.writeBytes(bytes, 0, 0, numBytesRead); if (isCancelled()) { break; } - - byte[] writeBuffer = numBytesRead == READ_BUFFER_SIZE - ? bytes : Arrays.copyOf(bytes, numBytesRead); - - if (!mInstallationSession.write(writeBuffer)) { + if (!mInstallationSession.submitFromAshmem(numBytesRead)) { throw new IOException("Failed write() to DynamicSystem"); } @@ -157,7 +155,6 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { reportedInstalledSize = installedSize; } } - return null; } catch (Exception e) { diff --git a/packages/SettingsLib/res/values/styles_support_preference.xml b/packages/SettingsLib/res/values/styles_support_preference.xml index 5d787f85e3ab..6e611960b2c7 100644 --- a/packages/SettingsLib/res/values/styles_support_preference.xml +++ b/packages/SettingsLib/res/values/styles_support_preference.xml @@ -26,7 +26,7 @@ <item name="allowDividerAbove">true</item> </style> - <style name="PreferenceThemeOverlay.SettingsBase" parent="@style/PreferenceThemeOverlay.v14.Material"> + <style name="PreferenceThemeOverlay.SettingsBase" parent="@style/PreferenceThemeOverlay"> <item name="footerPreferenceStyle">@style/Preference.FooterPreference.SettingsBase</item> </style> diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index 3e359d216234..d3bab5f41f39 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -224,7 +224,9 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro mConnectivityManager = connectivityManager; // check if verbose logging developer option has been turned on or off - sVerboseLogging = mWifiManager != null && (mWifiManager.getVerboseLoggingLevel() > 0); + sVerboseLogging = Settings.Global.getInt( + mContext.getContentResolver(), + Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0) > 0; mFilter = filter; diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp index 1c97fc37cf50..e54b847f167d 100644 --- a/packages/SettingsProvider/Android.bp +++ b/packages/SettingsProvider/Android.bp @@ -9,7 +9,10 @@ android_app { "telephony-common", "ims-common", ], - static_libs: ["junit"], + static_libs: [ + "junit", + "SettingsLib", + ], platform_apis: true, certificate: "platform", privileged: true, @@ -21,11 +24,18 @@ android_test { // because this test is not an instrumentation test. (because the target runs in the system process.) srcs: [ "test/**/*.java", + "src/com/android/providers/settings/SettingsBackupAgent.java", "src/com/android/providers/settings/SettingsState.java", "src/com/android/providers/settings/SettingsHelper.java", ], - static_libs: ["androidx.test.rules"], - libs: ["android.test.base"], + static_libs: [ + "androidx.test.rules", + "SettingsLib", + ], + libs: [ + "android.test.base", + "android.test.mock", + ], resource_dirs: ["res"], aaptflags: [ "--auto-add-overlay", diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index 7d56868d0ce8..36e945fe30b6 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -34,14 +34,18 @@ import android.os.Build; import android.os.ParcelFileDescriptor; import android.os.UserHandle; import android.provider.Settings; -import android.provider.SettingsValidators.Validator; +import android.provider.settings.validators.Validator; import android.util.ArrayMap; import android.util.ArraySet; import android.util.BackupUtils; import android.util.Log; +import android.util.Slog; +import android.view.Display; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.widget.LockPatternUtils; +import com.android.settingslib.display.DisplayDensityUtils; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; @@ -52,11 +56,14 @@ import java.io.EOFException; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.time.DateTimeException; import java.util.Arrays; import java.util.HashSet; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.CRC32; /** @@ -78,10 +85,11 @@ public class SettingsBackupAgent extends BackupAgentHelper { private static final String KEY_SOFTAP_CONFIG = "softap_config"; private static final String KEY_NETWORK_POLICIES = "network_policies"; private static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config"; + private static final String KEY_DEVICE_SPECIFIC_CONFIG = "device_specific_config"; // Versioning of the state file. Increment this version // number any time the set of state items is altered. - private static final int STATE_VERSION = 7; + private static final int STATE_VERSION = 8; // Versioning of the Network Policies backup payload. private static final int NETWORK_POLICIES_BACKUP_VERSION = 1; @@ -99,8 +107,9 @@ public class SettingsBackupAgent extends BackupAgentHelper { private static final int STATE_SOFTAP_CONFIG = 7; private static final int STATE_NETWORK_POLICIES = 8; private static final int STATE_WIFI_NEW_CONFIG = 9; + private static final int STATE_DEVICE_CONFIG = 10; - private static final int STATE_SIZE = 10; // The current number of state items + private static final int STATE_SIZE = 11; // The current number of state items // Number of entries in the checksum array at various version numbers private static final int STATE_SIZES[] = { @@ -111,17 +120,19 @@ public class SettingsBackupAgent extends BackupAgentHelper { 7, // version 4 added STATE_LOCK_SETTINGS 8, // version 5 added STATE_SOFTAP_CONFIG 9, // version 6 added STATE_NETWORK_POLICIES - STATE_SIZE // version 7 added STATE_WIFI_NEW_CONFIG + 10, // version 7 added STATE_WIFI_NEW_CONFIG + STATE_SIZE // version 8 added STATE_DEVICE_CONFIG }; - // Versioning of the 'full backup' format - // Increment this version any time a new item is added - private static final int FULL_BACKUP_VERSION = 6; private static final int FULL_BACKUP_ADDED_GLOBAL = 2; // added the "global" entry private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry private static final int FULL_BACKUP_ADDED_SOFTAP_CONF = 4; //added the "softap_config" entry private static final int FULL_BACKUP_ADDED_NETWORK_POLICIES = 5; //added "network_policies" private static final int FULL_BACKUP_ADDED_WIFI_NEW = 6; // added "wifi_new_config" entry + private static final int FULL_BACKUP_ADDED_DEVICE_SPECIFIC = 7; // added "device specific" entry + // Versioning of the 'full backup' format + // Increment this version any time a new item is added + private static final int FULL_BACKUP_VERSION = FULL_BACKUP_ADDED_DEVICE_SPECIFIC; private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE; @@ -129,11 +140,17 @@ public class SettingsBackupAgent extends BackupAgentHelper { private static final String TAG = "SettingsBackupAgent"; - private static final String[] PROJECTION = { + @VisibleForTesting + static final String[] PROJECTION = { Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE }; + // Versioning of the 'device specific' section of a backup + // Increment this any time the format is changed or data added. + @VisibleForTesting + static final int DEVICE_SPECIFIC_VERSION = 1; + // the key to store the WIFI data under, should be sorted as last, so restore happens last. // use very late unicode character to quasi-guarantee last sort position. private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI"; @@ -161,7 +178,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { KEY_GLOBAL, })); - private SettingsHelper mSettingsHelper; + @VisibleForTesting + SettingsHelper mSettingsHelper; private WifiManager mWifiManager; @@ -190,6 +208,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { byte[] softApConfigData = getSoftAPConfiguration(); byte[] netPoliciesData = getNetworkPolicies(); byte[] wifiFullConfigData = getNewWifiConfigData(); + byte[] deviceSpecificInformation = getDeviceSpecificConfiguration(); long[] stateChecksums = readOldChecksums(oldState); @@ -215,6 +234,9 @@ public class SettingsBackupAgent extends BackupAgentHelper { stateChecksums[STATE_WIFI_NEW_CONFIG] = writeIfChanged(stateChecksums[STATE_WIFI_NEW_CONFIG], KEY_WIFI_NEW_CONFIG, wifiFullConfigData, data); + stateChecksums[STATE_DEVICE_CONFIG] = + writeIfChanged(stateChecksums[STATE_DEVICE_CONFIG], KEY_DEVICE_SPECIFIC_CONFIG, + deviceSpecificInformation, data); writeNewChecksums(stateChecksums, newState); } @@ -313,6 +335,12 @@ public class SettingsBackupAgent extends BackupAgentHelper { restoreNewWifiConfigData(restoredWifiNewConfigData); break; + case KEY_DEVICE_SPECIFIC_CONFIG: + byte[] restoredDeviceSpecificConfig = new byte[size]; + data.readEntityData(restoredDeviceSpecificConfig, 0, size); + restoreDeviceSpecificConfig(restoredDeviceSpecificConfig); + break; + default : data.skipEntityData(); @@ -591,6 +619,11 @@ public class SettingsBackupAgent extends BackupAgentHelper { private void restoreSettings(byte[] settings, int bytes, Uri contentUri, HashSet<String> movedToGlobal, Set<String> movedToSecure) { + restoreSettings(settings, 0, bytes, contentUri, movedToGlobal, movedToSecure); + } + + private void restoreSettings(byte[] settings, int pos, int bytes, Uri contentUri, + HashSet<String> movedToGlobal, Set<String> movedToSecure) { if (DEBUG) { Log.i(TAG, "restoreSettings: " + contentUri); } @@ -601,7 +634,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { Map<String, Validator> validators = null; if (contentUri.equals(Settings.Secure.CONTENT_URI)) { whitelist = ArrayUtils.concatElements(String.class, Settings.Secure.SETTINGS_TO_BACKUP, - Settings.Secure.LEGACY_RESTORE_SETTINGS); + Settings.Secure.LEGACY_RESTORE_SETTINGS, + Settings.Secure.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP); validators = Settings.Secure.VALIDATORS; } else if (contentUri.equals(Settings.System.CONTENT_URI)) { whitelist = ArrayUtils.concatElements(String.class, Settings.System.SETTINGS_TO_BACKUP, @@ -616,7 +650,6 @@ public class SettingsBackupAgent extends BackupAgentHelper { } // Restore only the white list data. - int pos = 0; final ArrayMap<String, String> cachedEntries = new ArrayMap<>(); ContentValues contentValues = new ContentValues(2); SettingsHelper settingsHelper = mSettingsHelper; @@ -940,6 +973,150 @@ public class SettingsBackupAgent extends BackupAgentHelper { } } + @VisibleForTesting + byte[] getDeviceSpecificConfiguration() throws IOException { + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + writeHeader(os); + os.write(getDeviceSpecificSettings()); + return os.toByteArray(); + } + } + + @VisibleForTesting + void writeHeader(OutputStream os) throws IOException { + os.write(toByteArray(DEVICE_SPECIFIC_VERSION)); + os.write(toByteArray(Build.MANUFACTURER)); + os.write(toByteArray(Build.PRODUCT)); + } + + private byte[] getDeviceSpecificSettings() { + try (Cursor cursor = + getContentResolver() + .query(Settings.Secure.CONTENT_URI, PROJECTION, null, null, null)) { + return extractRelevantValues( + cursor, Settings.Secure.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP); + } + } + + /** + * Restore the device specific settings. + * + * @param data The byte array holding a backed up version of another devices settings. + * @return true if the restore succeeded, false if it was stopped. + */ + @VisibleForTesting + boolean restoreDeviceSpecificConfig(byte[] data) { + // We're using an AtomicInteger to wrap the position int and allow called methods to + // modify it. + AtomicInteger pos = new AtomicInteger(0); + if (!isSourceAcceptable(data, pos)) { + return false; + } + + Integer originalDensity = getPreviousDensity(); + + int dataStart = pos.get(); + restoreSettings( + data, dataStart, data.length, Settings.Secure.CONTENT_URI, null, null); + + updateWindowManagerIfNeeded(originalDensity); + + return true; + } + + private void updateWindowManagerIfNeeded(Integer previousDensity) { + int newDensity; + try { + newDensity = getForcedDensity(); + } catch (Settings.SettingNotFoundException e) { + // If there's not density setting we can't perform a change. + return; + } + + if (previousDensity == null || previousDensity != newDensity) { + // From nothing to something is a change. + DisplayDensityUtils.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, newDensity); + } + } + + private Integer getPreviousDensity() { + try { + return getForcedDensity(); + } catch (Settings.SettingNotFoundException e) { + return null; + } + } + + private int getForcedDensity() throws Settings.SettingNotFoundException { + return Settings.Secure.getInt(getContentResolver(), Settings.Secure.DISPLAY_DENSITY_FORCED); + } + + @VisibleForTesting + boolean isSourceAcceptable(byte[] data, AtomicInteger pos) { + int version = readInt(data, pos); + if (version > DEVICE_SPECIFIC_VERSION) { + Slog.w(TAG, "Unable to restore device specific information; Backup is too new"); + return false; + } + + String sourceManufacturer = readString(data, pos); + if (!Objects.equals(Build.MANUFACTURER, sourceManufacturer)) { + Log.w( + TAG, + "Unable to restore device specific information; Manufacturer mismatch " + + "(\'" + + Build.MANUFACTURER + + "\' and \'" + + sourceManufacturer + + "\')"); + return false; + } + + String sourceProduct = readString(data, pos); + if (!Objects.equals(Build.PRODUCT, sourceProduct)) { + Log.w( + TAG, + "Unable to restore device specific information; Product mismatch (\'" + + Build.PRODUCT + + "\' and \'" + + sourceProduct + + "\')"); + return false; + } + + return true; + } + + @VisibleForTesting + static byte[] toByteArray(String value) { + if (value == null) { + return toByteArray(NULL_SIZE); + } + + byte[] stringBytes = value.getBytes(); + byte[] sizeAndString = new byte[stringBytes.length + INTEGER_BYTE_COUNT]; + writeInt(sizeAndString, 0, stringBytes.length); + writeBytes(sizeAndString, INTEGER_BYTE_COUNT, stringBytes); + return sizeAndString; + } + + @VisibleForTesting + static byte[] toByteArray(int value) { + byte[] result = new byte[INTEGER_BYTE_COUNT]; + writeInt(result, 0, value); + return result; + } + + private String readString(byte[] data, AtomicInteger pos) { + int byteCount = readInt(data, pos); + if (byteCount == NULL_SIZE) { + return null; + } + + int stringStart = pos.getAndAdd(byteCount); + return new String(data, stringStart, byteCount); + } + /** * Write an int in BigEndian into the byte array. * @param out byte array @@ -947,7 +1124,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { * @param value integer to write * @return the index after adding the size of an int (4) in bytes. */ - private int writeInt(byte[] out, int pos, int value) { + private static int writeInt(byte[] out, int pos, int value) { out[pos + 0] = (byte) ((value >> 24) & 0xFF); out[pos + 1] = (byte) ((value >> 16) & 0xFF); out[pos + 2] = (byte) ((value >> 8) & 0xFF); @@ -955,11 +1132,15 @@ public class SettingsBackupAgent extends BackupAgentHelper { return pos + INTEGER_BYTE_COUNT; } - private int writeBytes(byte[] out, int pos, byte[] value) { + private static int writeBytes(byte[] out, int pos, byte[] value) { System.arraycopy(value, 0, out, pos, value.length); return pos + value.length; } + private int readInt(byte[] in, AtomicInteger pos) { + return readInt(in, pos.getAndAdd(INTEGER_BYTE_COUNT)); + } + private int readInt(byte[] in, int pos) { int result = ((in[pos] & 0xFF) << 24) | ((in[pos + 1] & 0xFF) << 16) diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 6adb305d4165..00b2563f559b 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -18,7 +18,9 @@ package com.android.providers.settings; import android.annotation.NonNull; import android.os.UserHandle; +import android.provider.DeviceConfig; import android.provider.Settings; +import android.providers.settings.ConfigSettingsProto; import android.providers.settings.GlobalSettingsProto; import android.providers.settings.SecureSettingsProto; import android.providers.settings.SettingProto; @@ -28,24 +30,79 @@ import android.providers.settings.UserSettingsProto; import android.util.SparseBooleanArray; import android.util.proto.ProtoOutputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** @hide */ class SettingsProtoDumpUtil { + private static final Map<String, Long> NAMESPACE_TO_FIELD_MAP = createNamespaceMap(); + private SettingsProtoDumpUtil() {} + private static Map<String, Long> createNamespaceMap() { + Map<String, Long> namespaceToFieldMap = new HashMap<>(); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + ConfigSettingsProto.ACTIVITY_MANAGER_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, + ConfigSettingsProto.ACTIVITY_MANAGER_NATIVE_BOOT_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_APP_COMPAT, + ConfigSettingsProto.APP_COMPAT_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_AUTOFILL, + ConfigSettingsProto.AUTOFILL_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_CONNECTIVITY, + ConfigSettingsProto.CONNECTIVITY_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_CONTENT_CAPTURE, + ConfigSettingsProto.CONTENT_CAPTURE_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_DEX_BOOT, + ConfigSettingsProto.DEX_BOOT_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_GAME_DRIVER, + ConfigSettingsProto.GAME_DRIVER_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT, + ConfigSettingsProto.INPUT_NATIVE_BOOT_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_NETD_NATIVE, + ConfigSettingsProto.NETD_NATIVE_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_PRIVACY, + ConfigSettingsProto.PRIVACY_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_ROLLBACK, + ConfigSettingsProto.ROLLBACK_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_ROLLBACK_BOOT, + ConfigSettingsProto.ROLLBACK_BOOT_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_RUNTIME, + ConfigSettingsProto.RUNTIME_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_RUNTIME_NATIVE, + ConfigSettingsProto.RUNTIME_NATIVE_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT, + ConfigSettingsProto.RUNTIME_NATIVE_BOOT_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_STORAGE, + ConfigSettingsProto.STORAGE_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_SYSTEMUI, + ConfigSettingsProto.SYSTEMUI_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_TELEPHONY, + ConfigSettingsProto.TELEPHONY_SETTINGS); + namespaceToFieldMap.put(DeviceConfig.NAMESPACE_TEXTCLASSIFIER, + ConfigSettingsProto.TEXTCLASSIFIER_SETTINGS); + return Collections.unmodifiableMap(namespaceToFieldMap); + } + static void dumpProtoLocked(SettingsProvider.SettingsRegistry settingsRegistry, ProtoOutputStream proto) { // Config settings SettingsState configSettings = settingsRegistry.getSettingsLocked( SettingsProvider.SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM); if (configSettings != null) { - // TODO(b/113100523): dump configuration settings after they are added + dumpProtoConfigSettingsLocked( + proto, SettingsServiceDumpProto.CONFIG_SETTINGS, configSettings); } // Global settings SettingsState globalSettings = settingsRegistry.getSettingsLocked( SettingsProvider.SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM); if (globalSettings != null) { - dumpProtoGlobalSettingsLocked(proto, SettingsServiceDumpProto.GLOBAL_SETTINGS, globalSettings); + dumpProtoGlobalSettingsLocked( + proto, SettingsServiceDumpProto.GLOBAL_SETTINGS, globalSettings); } // Per-user settings @@ -1481,9 +1538,6 @@ class SettingsProtoDumpUtil { Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, GlobalSettingsProto.Wifi.NETWORKS_AVAILABLE_NOTIFICATION_ON); dumpSetting(s, p, - Settings.Global.WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON, - GlobalSettingsProto.Wifi.CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON); - dumpSetting(s, p, Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, GlobalSettingsProto.Wifi.NETWORKS_AVAILABLE_REPEAT_DELAY); dumpSetting(s, p, @@ -1550,9 +1604,6 @@ class SettingsProtoDumpUtil { Settings.Global.WIFI_P2P_DEVICE_NAME, GlobalSettingsProto.Wifi.P2P_DEVICE_NAME); dumpSetting(s, p, - Settings.Global.WIFI_REENABLE_DELAY_MS, - GlobalSettingsProto.Wifi.REENABLE_DELAY_MS); - dumpSetting(s, p, Settings.Global.WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS, GlobalSettingsProto.Wifi.EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS); dumpSetting(s, p, @@ -1599,6 +1650,33 @@ class SettingsProtoDumpUtil { // Settings.Global.INSTALL_NON_MARKET_APPS intentionally excluded since it's deprecated. } + private static void dumpProtoConfigSettingsLocked( + @NonNull ProtoOutputStream p, long fieldId, @NonNull SettingsState s) { + Map<String, List<String>> namespaceMap = new HashMap<>(); + final long token = p.start(fieldId); + s.dumpHistoricalOperations(p, ConfigSettingsProto.HISTORICAL_OPERATIONS); + for (String name : s.getSettingNamesLocked()) { + String namespace = name.substring(0, name.indexOf('/')); + if (NAMESPACE_TO_FIELD_MAP.containsKey(namespace)) { + dumpSetting(s, p, name, NAMESPACE_TO_FIELD_MAP.get(namespace)); + } else { + if (!namespaceMap.containsKey(namespace)) { + namespaceMap.put(namespace, new ArrayList<>()); + } + namespaceMap.get(namespace).add(name); + } + } + for (String namespace : namespaceMap.keySet()) { + final long namespacesToken = p.start(ConfigSettingsProto.EXTRA_NAMESPACES); + p.write(ConfigSettingsProto.NamespaceProto.NAMESPACE, namespace); + for (String name : namespaceMap.get(namespace)) { + dumpSetting(s, p, name, ConfigSettingsProto.NamespaceProto.SETTINGS); + } + p.end(namespacesToken); + } + p.end(token); + } + /** Dumps settings that use a common prefix into a repeated field. */ private static void dumpRepeatedSetting(@NonNull SettingsState settings, @NonNull ProtoOutputStream proto, String settingPrefix, long fieldId) { diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 7016d3067687..e492e28f6172 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -70,7 +70,7 @@ import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.Global; import android.provider.Settings.Secure; -import android.provider.SettingsValidators; +import android.provider.settings.validators.Validator; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -314,11 +314,6 @@ public class SettingsProvider extends ContentProvider { public boolean onCreate() { Settings.setInSystemServer(); - // fail to boot if there're any backed up settings that don't have a non-null validator - ensureAllBackedUpSystemSettingsHaveValidators(); - ensureAllBackedUpGlobalSettingsHaveValidators(); - ensureAllBackedUpSecureSettingsHaveValidators(); - synchronized (mLock) { mUserManager = UserManager.get(getContext()); mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); @@ -338,57 +333,6 @@ public class SettingsProvider extends ContentProvider { return true; } - private void ensureAllBackedUpSystemSettingsHaveValidators() { - String offenders = getOffenders(concat(Settings.System.SETTINGS_TO_BACKUP, - Settings.System.LEGACY_RESTORE_SETTINGS), Settings.System.VALIDATORS); - - failToBootIfOffendersPresent(offenders, "Settings.System"); - } - - private void ensureAllBackedUpGlobalSettingsHaveValidators() { - String offenders = getOffenders(concat(Settings.Global.SETTINGS_TO_BACKUP, - Settings.Global.LEGACY_RESTORE_SETTINGS), Settings.Global.VALIDATORS); - - failToBootIfOffendersPresent(offenders, "Settings.Global"); - } - - private void ensureAllBackedUpSecureSettingsHaveValidators() { - String offenders = getOffenders(concat(Settings.Secure.SETTINGS_TO_BACKUP, - Settings.Secure.LEGACY_RESTORE_SETTINGS), Settings.Secure.VALIDATORS); - - failToBootIfOffendersPresent(offenders, "Settings.Secure"); - } - - private void failToBootIfOffendersPresent(String offenders, String settingsType) { - if (offenders.length() > 0) { - throw new RuntimeException("All " + settingsType + " settings that are backed up" - + " have to have a non-null validator, but those don't: " + offenders); - } - } - - private String getOffenders(String[] settingsToBackup, Map<String, - SettingsValidators.Validator> validators) { - StringBuilder offenders = new StringBuilder(); - for (String setting : settingsToBackup) { - if (validators.get(setting) == null) { - offenders.append(setting).append(" "); - } - } - return offenders.toString(); - } - - private final String[] concat(String[] first, String[] second) { - if (second == null || second.length == 0) { - return first; - } - final int firstLen = first.length; - final int secondLen = second.length; - String[] both = new String[firstLen + secondLen]; - System.arraycopy(first, 0, both, 0, firstLen); - System.arraycopy(second, 0, both, firstLen, secondLen); - return both; - } - @Override public Bundle call(String method, String name, Bundle args) { final int requestingUserId = getRequestingUserId(args); @@ -1773,7 +1717,7 @@ public class SettingsProvider extends ContentProvider { } private void validateSystemSettingValue(String name, String value) { - SettingsValidators.Validator validator = Settings.System.VALIDATORS.get(name); + Validator validator = Settings.System.VALIDATORS.get(name); if (validator != null && !validator.validate(value)) { throw new IllegalArgumentException("Invalid value: " + value + " for setting: " + name); diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java new file mode 100644 index 000000000000..cf8e1a5c2b14 --- /dev/null +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java @@ -0,0 +1,272 @@ +/* + * 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.providers.settings; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import static org.junit.Assert.assertArrayEquals; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.ContextWrapper; +import android.database.Cursor; +import android.database.MatrixCursor; +import android.net.Uri; +import android.os.Build; +import android.provider.Settings; +import android.test.mock.MockContentProvider; +import android.test.mock.MockContentResolver; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.annotations.VisibleForTesting; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +/** Tests for the SettingsHelperTest */ +@RunWith(AndroidJUnit4.class) +public class SettingsBackupAgentTest extends BaseSettingsProviderTest { + + private static final String TEST_DISPLAY_DENSITY_FORCED = "123"; + private static final Map<String, String> TEST_VALUES = new HashMap<>(); + + static { + TEST_VALUES.put(Settings.Secure.DISPLAY_DENSITY_FORCED, TEST_DISPLAY_DENSITY_FORCED); + } + + private TestFriendlySettingsBackupAgent mAgentUnderTest; + private Context mContext; + + @Before + public void setUp() { + mContext = new ContextWithMockContentResolver(getContext()); + + mAgentUnderTest = new TestFriendlySettingsBackupAgent(); + mAgentUnderTest.attach(mContext); + } + + @Test + public void testRoundTripDeviceSpecificSettings() throws IOException { + TestSettingsHelper helper = new TestSettingsHelper(mContext); + mAgentUnderTest.mSettingsHelper = helper; + + byte[] settingsBackup = mAgentUnderTest.getDeviceSpecificConfiguration(); + + assertEquals("Not all values backed up.", TEST_VALUES.keySet(), helper.mReadEntries); + + mAgentUnderTest.restoreDeviceSpecificConfig(settingsBackup); + + assertEquals("Not all values were restored.", TEST_VALUES, helper.mWrittenValues); + } + + @Test + public void testGeneratedHeaderMatchesCurrentDevice() throws IOException { + mAgentUnderTest.mSettingsHelper = new TestSettingsHelper(mContext); + + byte[] header = generateUncorruptedHeader(); + + AtomicInteger pos = new AtomicInteger(0); + assertTrue( + "Generated header is not correct for device.", + mAgentUnderTest.isSourceAcceptable(header, pos)); + } + + @Test + public void testTestHeaderGeneratorIsAccurate() throws IOException { + byte[] classGeneratedHeader = generateUncorruptedHeader(); + byte[] testGeneratedHeader = generateCorruptedHeader(false, false, false); + + assertArrayEquals( + "Difference in header generation", classGeneratedHeader, testGeneratedHeader); + } + + @Test + public void testNewerHeaderVersionFailsMatch() throws IOException { + byte[] header = generateCorruptedHeader(true, false, false); + + AtomicInteger pos = new AtomicInteger(0); + assertFalse( + "Newer header does not fail match", + mAgentUnderTest.isSourceAcceptable(header, pos)); + } + + @Test + public void testWrongManufacturerFailsMatch() throws IOException { + byte[] header = generateCorruptedHeader(false, true, false); + + AtomicInteger pos = new AtomicInteger(0); + assertFalse( + "Wrong manufacturer does not fail match", + mAgentUnderTest.isSourceAcceptable(header, pos)); + } + + @Test + public void testWrongProductFailsMatch() throws IOException { + byte[] header = generateCorruptedHeader(false, false, true); + + AtomicInteger pos = new AtomicInteger(0); + assertFalse( + "Wrong product does not fail match", + mAgentUnderTest.isSourceAcceptable(header, pos)); + } + + @Test + public void checkAcceptTestFailingBlockRestore() { + mAgentUnderTest.setForcedDeviceInfoRestoreAcceptability(false); + byte[] data = new byte[0]; + + assertFalse( + "Blocking isSourceAcceptable did not stop restore", + mAgentUnderTest.restoreDeviceSpecificConfig(data)); + } + + private byte[] generateUncorruptedHeader() throws IOException { + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + mAgentUnderTest.writeHeader(os); + return os.toByteArray(); + } + } + + private byte[] generateCorruptedHeader( + boolean corruptVersion, boolean corruptManufacturer, boolean corruptProduct) + throws IOException { + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + int version = SettingsBackupAgent.DEVICE_SPECIFIC_VERSION; + if (corruptVersion) { + version++; + } + os.write(SettingsBackupAgent.toByteArray(version)); + + String manufacturer = Build.MANUFACTURER; + if (corruptManufacturer) { + manufacturer = manufacturer == null ? "X" : manufacturer + "X"; + } + os.write(SettingsBackupAgent.toByteArray(manufacturer)); + + String product = Build.PRODUCT; + if (corruptProduct) { + product = product == null ? "X" : product + "X"; + } + os.write(SettingsBackupAgent.toByteArray(product)); + + return os.toByteArray(); + } + } + + private static class TestFriendlySettingsBackupAgent extends SettingsBackupAgent { + private Boolean mForcedDeviceInfoRestoreAcceptability = null; + + void setForcedDeviceInfoRestoreAcceptability(boolean value) { + mForcedDeviceInfoRestoreAcceptability = value; + } + + @VisibleForTesting + boolean isSourceAcceptable(byte[] data, AtomicInteger pos) { + return mForcedDeviceInfoRestoreAcceptability == null + ? super.isSourceAcceptable(data, pos) + : mForcedDeviceInfoRestoreAcceptability; + } + } + + /** The TestSettingsHelper tracks which values have been backed up and/or restored. */ + private static class TestSettingsHelper extends SettingsHelper { + private Set<String> mReadEntries; + private Map<String, String> mWrittenValues; + + TestSettingsHelper(Context context) { + super(context); + mReadEntries = new HashSet<>(); + mWrittenValues = new HashMap<>(); + } + + @Override + public String onBackupValue(String key, String value) { + mReadEntries.add(key); + String readValue = TEST_VALUES.get(key); + assert readValue != null; + return readValue; + } + + @Override + public void restoreValue( + Context context, + ContentResolver cr, + ContentValues contentValues, + Uri destination, + String name, + String value, + int restoredFromSdkInt) { + mWrittenValues.put(name, value); + } + } + + /** + * ContextWrapper which allows us to return a MockContentResolver to code which uses it to + * access settings. This allows us to override the ContentProvider for the Settings URIs to + * return known values. + */ + private static class ContextWithMockContentResolver extends ContextWrapper { + private MockContentResolver mContentResolver; + + ContextWithMockContentResolver(Context targetContext) { + super(targetContext); + + mContentResolver = new MockContentResolver(); + mContentResolver.addProvider( + Settings.AUTHORITY, new DeviceSpecificInfoMockContentProvider()); + } + + @Override + public ContentResolver getContentResolver() { + return mContentResolver; + } + } + + /** ContentProvider which returns a set of known test values. */ + private static class DeviceSpecificInfoMockContentProvider extends MockContentProvider { + private static final Object[][] RESULT_ROWS = { + {Settings.Secure.DISPLAY_DENSITY_FORCED, TEST_DISPLAY_DENSITY_FORCED}, + }; + + @Override + public Cursor query( + Uri uri, + String[] projection, + String selection, + String[] selectionArgs, + String sortOrder) { + MatrixCursor result = new MatrixCursor(SettingsBackupAgent.PROJECTION); + for (Object[] resultRow : RESULT_ROWS) { + result.addRow(resultRow); + } + return result; + } + } +} diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 58e1d47e5379..8c0108dace69 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -352,10 +352,10 @@ public class BugreportProgressService extends Service { private final BugreportInfo mInfo; - BugreportCallbackImpl(String name) { + BugreportCallbackImpl(String name, @Nullable String title, @Nullable String description) { // pid not used in this workflow, so setting default = 0 mInfo = new BugreportInfo(mContext, 0 /* pid */, name, - 100 /* max progress*/); + 100 /* max progress*/, title, description); } @Override @@ -578,6 +578,8 @@ public class BugreportProgressService extends Service { } int bugreportType = intent.getIntExtra(EXTRA_BUGREPORT_TYPE, BugreportParams.BUGREPORT_MODE_INTERACTIVE); + String shareTitle = intent.getStringExtra(EXTRA_TITLE); + String shareDescription = intent.getStringExtra(EXTRA_DESCRIPTION); ParcelFileDescriptor screenshotFd = createReadWriteFile(BUGREPORT_DIR, bugreportName + ".png"); @@ -595,7 +597,8 @@ public class BugreportProgressService extends Service { + " bugreport file fd: " + bugreportFd + " screenshot file fd: " + screenshotFd); - BugreportCallbackImpl bugreportCallback = new BugreportCallbackImpl(bugreportName); + BugreportCallbackImpl bugreportCallback = new BugreportCallbackImpl(bugreportName, + shareTitle, shareDescription); try { mBugreportManager.startBugreport(bugreportFd, screenshotFd, new BugreportParams(bugreportType), executor, bugreportCallback); @@ -982,7 +985,10 @@ public class BugreportProgressService extends Service { } screenshotFile = null; } - onBugreportFinished(id, bugreportFile, screenshotFile, info.title, info.description, max); + // TODO: Since we are passing id to the function, it should be able to find the info linked + // to the id and therefore use the value of shareTitle and shareDescription. + onBugreportFinished(id, bugreportFile, screenshotFile, info.shareTitle, + info.shareDescription, max); } @@ -1844,6 +1850,14 @@ public class BugreportProgressService extends Service { String title; /** + * One-line summary of the bug; when set, will be used as the subject of the + * {@link Intent#ACTION_SEND_MULTIPLE} intent. This is the predefined title which is + * set initially when the request to take a bugreport is made. This overrides any changes + * in the title that the user makes after the bugreport starts. + */ + String shareTitle; + + /** * User-provided, detailed description of the bugreport; when set, will be added to the body * of the {@link Intent#ACTION_SEND_MULTIPLE} intent. */ @@ -1906,7 +1920,9 @@ public class BugreportProgressService extends Service { int screenshotCounter; /** - * Descriptive text that will be shown to the user in the notification message. + * Descriptive text that will be shown to the user in the notification message. This is the + * predefined description which is set initially when the request to take a bugreport is + * made. */ String shareDescription; @@ -1914,18 +1930,21 @@ 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, pid, name, max); + this(context, pid, name, max, null, null); this.id = id; } /** * Constructor for tracked bugreports - typically called upon receiving BUGREPORT_REQUESTED. */ - BugreportInfo(Context context, int pid, String name, int max) { + BugreportInfo(Context context, int pid, String name, int max, @Nullable String shareTitle, + @Nullable String shareDescription) { this.context = context; this.pid = pid; this.name = name; this.max = this.realMax = max; + this.shareTitle = shareTitle == null ? "" : shareTitle; + this.shareDescription = shareDescription == null ? "" : shareDescription; } /** @@ -2019,6 +2038,7 @@ public class BugreportProgressService extends Service { .append("\n\taddingDetailsToZip: ").append(addingDetailsToZip) .append(" addedDetailsToZip: ").append(addedDetailsToZip) .append("\n\tshareDescription: ").append(shareDescription) + .append("\n\tshareTitle: ").append(shareTitle) .toString(); } @@ -2046,6 +2066,7 @@ public class BugreportProgressService extends Service { finished = in.readInt() == 1; screenshotCounter = in.readInt(); shareDescription = in.readString(); + shareTitle = in.readString(); } @Override @@ -2071,6 +2092,7 @@ public class BugreportProgressService extends Service { dest.writeInt(finished ? 1 : 0); dest.writeInt(screenshotCounter); dest.writeString(shareDescription); + dest.writeString(shareTitle); } @Override diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index fab724267e3f..19e682b4b6a4 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1386,6 +1386,8 @@ buttons</string> <string name="screen_pinning_toast_recents_invisible">To unpin this screen, touch & hold Back and Home buttons</string> + <!-- Notify (in toast) user how to unpin screen in gesture navigation mode [CHAR LIMIT=NONE] --> + <string name="screen_pinning_toast_gesture_nav">To unpin this screen, swipe up & hold</string> <!-- Screen pinning positive response. --> <string name="screen_pinning_positive">Got it</string> <!-- Screen pinning negative response. --> 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 c732584eddfc..08996c38baf6 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 @@ -188,9 +188,8 @@ public class QuickStepContract { if ((sysuiStateFlags & SYSUI_STATE_BOUNCER_SHOWING) != 0) { return false; } - // Disable when in screen pinning, immersive, or the notifications are interactive - int disableFlags = SYSUI_STATE_SCREEN_PINNING - | SYSUI_STATE_NAV_BAR_HIDDEN + // Disable when in immersive, or the notifications are interactive + int disableFlags = SYSUI_STATE_NAV_BAR_HIDDEN | SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING; return (sysuiStateFlags & disableFlags) != 0; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index de20972347d5..8c5374a2a3fe 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -1446,6 +1446,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { protected void handleStartedGoingToSleep(int arg1) { checkIsHandlerThread(); + mLockIconPressed = false; clearBiometricRecognized(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -1481,7 +1482,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private void handleScreenTurnedOff() { checkIsHandlerThread(); - mLockIconPressed = false; mHardwareFingerprintUnavailableRetryCount = 0; mHardwareFaceUnavailableRetryCount = 0; for (int i = 0; i < mCallbacks.size(); i++) { diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 0ee9bff50bf3..59270a06dfbc 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -34,6 +34,7 @@ import com.android.keyguard.clock.ClockManager; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.appops.AppOpsController; import com.android.systemui.assist.AssistManager; +import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dock.DockManager; @@ -200,6 +201,7 @@ public class Dependency extends SystemUI { @Inject Lazy<ActivityStarter> mActivityStarter; @Inject Lazy<ActivityStarterDelegate> mActivityStarterDelegate; + @Inject Lazy<BroadcastDispatcher> mBroadcastDispatcher; @Inject Lazy<AsyncSensorManager> mAsyncSensorManager; @Inject Lazy<BluetoothController> mBluetoothController; @Inject Lazy<LocationController> mLocationController; @@ -317,6 +319,7 @@ public class Dependency extends SystemUI { mProviders.put(MAIN_HANDLER, mMainHandler::get); mProviders.put(ActivityStarter.class, mActivityStarter::get); mProviders.put(ActivityStarterDelegate.class, mActivityStarterDelegate::get); + mProviders.put(BroadcastDispatcher.class, mBroadcastDispatcher::get); mProviders.put(AsyncSensorManager.class, mAsyncSensorManager::get); @@ -496,6 +499,7 @@ public class Dependency extends SystemUI { // Make sure that the DumpController gets added to mDependencies, as they are only added // with Dependency#get. getDependency(DumpController.class); + getDependency(BroadcastDispatcher.class); // If an arg is specified, try to dump the dependency String controller = args != null && args.length > 1 diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index 311ed8a913f1..7e3b42389637 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -66,6 +66,7 @@ import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.UnlockMethodCache; import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.KeyguardMonitor; import com.android.systemui.util.AsyncSensorManager; import com.android.systemui.volume.VolumeDialogComponent; @@ -150,9 +151,9 @@ public class SystemUIFactory { LockscreenWallpaper lockscreenWallpaper, TriConsumer<ScrimState, Float, GradientColors> scrimStateListener, Consumer<Integer> scrimVisibleListener, DozeParameters dozeParameters, - AlarmManager alarmManager) { + AlarmManager alarmManager, KeyguardMonitor keyguardMonitor) { return new ScrimController(scrimBehind, scrimInFront, scrimStateListener, - scrimVisibleListener, dozeParameters, alarmManager); + scrimVisibleListener, dozeParameters, alarmManager, keyguardMonitor); } public NotificationIconAreaController createNotificationIconAreaController(Context context, diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java index bc782a7d62eb..bb3bd781df66 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java +++ b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java @@ -100,7 +100,9 @@ public class InvocationLightsView extends View int cornerRadiusBottom = DisplayUtils.getCornerRadiusBottom(context); int cornerRadiusTop = DisplayUtils.getCornerRadiusTop(context); - mViewHeight = Math.max(cornerRadiusBottom, cornerRadiusTop); + // ensure that height is non-zero even for square corners + mViewHeight = Math.max(Math.max(cornerRadiusBottom, cornerRadiusTop), + DisplayUtils.convertDpToPx(LIGHT_HEIGHT_DP, context)); final int dualToneDarkTheme = Utils.getThemeAttr(mContext, R.attr.darkIconTheme); final int dualToneLightTheme = Utils.getThemeAttr(mContext, R.attr.lightIconTheme); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialog.java new file mode 100644 index 000000000000..d4baefd64512 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialog.java @@ -0,0 +1,108 @@ +/* + * 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.biometrics; + +import android.hardware.biometrics.BiometricPrompt; +import android.os.Bundle; +import android.view.WindowManager; + +import com.android.systemui.biometrics.ui.BiometricDialogView; + +/** + * Interface for the biometric dialog UI. + */ +public interface BiometricDialog { + + // TODO: Clean up save/restore state + String[] KEYS_TO_BACKUP = { + BiometricPrompt.KEY_TITLE, + BiometricPrompt.KEY_USE_DEFAULT_TITLE, + BiometricPrompt.KEY_SUBTITLE, + BiometricPrompt.KEY_DESCRIPTION, + BiometricPrompt.KEY_POSITIVE_TEXT, + BiometricPrompt.KEY_NEGATIVE_TEXT, + BiometricPrompt.KEY_REQUIRE_CONFIRMATION, + BiometricPrompt.KEY_ALLOW_DEVICE_CREDENTIAL, + BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, + + BiometricDialogView.KEY_TRY_AGAIN_VISIBILITY, + BiometricDialogView.KEY_CONFIRM_VISIBILITY, + BiometricDialogView.KEY_CONFIRM_ENABLED, + BiometricDialogView.KEY_STATE, + BiometricDialogView.KEY_ERROR_TEXT_VISIBILITY, + BiometricDialogView.KEY_ERROR_TEXT_STRING, + BiometricDialogView.KEY_ERROR_TEXT_IS_TEMPORARY, + BiometricDialogView.KEY_ERROR_TEXT_COLOR, + }; + + /** + * Show the dialog. + * @param wm + * @param skipIntroAnimation + */ + void show(WindowManager wm, boolean skipIntroAnimation); + + /** + * Dismiss the dialog without sending a callback. + */ + void dismissWithoutCallback(boolean animate); + + /** + * Dismiss the dialog. Animate away. + */ + void dismissFromSystemServer(); + + /** + * Biometric authenticated. May be pending user confirmation, or completed. + */ + void onAuthenticationSucceeded(); + + /** + * Authentication failed (reject, timeout). Dialog stays showing. + * @param failureReason + */ + void onAuthenticationFailed(String failureReason); + + /** + * Authentication rejected, or help message received. + * @param help + */ + void onHelp(String help); + + /** + * Authentication failed. Dialog going away. + * @param error + */ + void onError(String error); + + /** + * Save the current state. + * @param outState + */ + void onSaveState(Bundle outState); + + /** + * Restore a previous state. + * @param savedState + */ + void restoreState(Bundle savedState); + + /** + * Get the client's package name + */ + String getOpPackageName(); +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java index e66a8fa96298..a8e572216315 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java @@ -16,135 +16,154 @@ package com.android.systemui.biometrics; +import android.app.ActivityManager; +import android.app.ActivityTaskManager; +import android.app.IActivityTaskManager; +import android.app.TaskStackListener; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Configuration; -import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.IBiometricServiceReceiverInternal; import android.os.Bundle; import android.os.Handler; import android.os.Looper; -import android.os.Message; import android.os.RemoteException; import android.util.Log; import android.view.WindowManager; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.SomeArgs; -import com.android.systemui.Dependency; import com.android.systemui.SystemUI; -import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.biometrics.ui.BiometricDialogView; import com.android.systemui.statusbar.CommandQueue; +import java.util.List; + /** - * Receives messages sent from AuthenticationClient and shows the appropriate biometric UI (e.g. - * BiometricDialogView). + * Receives messages sent from {@link com.android.server.biometrics.BiometricService} and shows the + * appropriate biometric UI (e.g. BiometricDialogView). */ -public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callbacks { +public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callbacks, + DialogViewCallback { private static final String TAG = "BiometricDialogImpl"; private static final boolean DEBUG = true; - private static final int MSG_SHOW_DIALOG = 1; - private static final int MSG_BIOMETRIC_AUTHENTICATED = 2; - private static final int MSG_BIOMETRIC_HELP = 3; - private static final int MSG_BIOMETRIC_ERROR = 4; - private static final int MSG_HIDE_DIALOG = 5; - private static final int MSG_BUTTON_NEGATIVE = 6; - private static final int MSG_USER_CANCELED = 7; - private static final int MSG_BUTTON_POSITIVE = 8; - private static final int MSG_TRY_AGAIN_PRESSED = 9; + private final Injector mInjector; + // TODO: These should just be saved from onSaveState private SomeArgs mCurrentDialogArgs; - private BiometricDialogView mCurrentDialog; - private WindowManager mWindowManager; - private IBiometricServiceReceiverInternal mReceiver; - private boolean mDialogShowing; - private Callback mCallback = new Callback(); - private WakefulnessLifecycle mWakefulnessLifecycle; + @VisibleForTesting + BiometricDialog mCurrentDialog; - private Handler mHandler = new Handler(Looper.getMainLooper()) { + private Handler mHandler = new Handler(Looper.getMainLooper()); + private WindowManager mWindowManager; + @VisibleForTesting + IActivityTaskManager mActivityTaskManager; + @VisibleForTesting + BiometricTaskStackListener mTaskStackListener; + @VisibleForTesting + IBiometricServiceReceiverInternal mReceiver; + + public class BiometricTaskStackListener extends TaskStackListener { @Override - public void handleMessage(Message msg) { - switch(msg.what) { - case MSG_SHOW_DIALOG: - handleShowDialog((SomeArgs) msg.obj, false /* skipAnimation */, - null /* savedState */); - break; - case MSG_BIOMETRIC_AUTHENTICATED: { - SomeArgs args = (SomeArgs) msg.obj; - handleBiometricAuthenticated((boolean) args.arg1 /* authenticated */, - (String) args.arg2 /* failureReason */); - args.recycle(); - break; - } - case MSG_BIOMETRIC_HELP: { - SomeArgs args = (SomeArgs) msg.obj; - handleBiometricHelp((String) args.arg1 /* message */); - args.recycle(); - break; + public void onTaskStackChanged() { + mHandler.post(mTaskStackChangedRunnable); + } + } + + private final Runnable mTaskStackChangedRunnable = () -> { + if (mCurrentDialog != null) { + try { + final String clientPackage = mCurrentDialog.getOpPackageName(); + Log.w(TAG, "Task stack changed, current client: " + clientPackage); + final List<ActivityManager.RunningTaskInfo> runningTasks = + mActivityTaskManager.getTasks(1); + if (!runningTasks.isEmpty()) { + final String topPackage = runningTasks.get(0).topActivity.getPackageName(); + if (!topPackage.contentEquals(clientPackage)) { + Log.w(TAG, "Evicting client due to: " + topPackage); + mCurrentDialog.dismissWithoutCallback(true /* animate */); + mCurrentDialog = null; + mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL); + mReceiver = null; + } } - case MSG_BIOMETRIC_ERROR: - handleBiometricError((String) msg.obj); - break; - case MSG_HIDE_DIALOG: - handleHideDialog((Boolean) msg.obj); - break; - case MSG_BUTTON_NEGATIVE: - handleButtonNegative(); - break; - case MSG_USER_CANCELED: - handleUserCanceled(); - break; - case MSG_BUTTON_POSITIVE: - handleButtonPositive(); - break; - case MSG_TRY_AGAIN_PRESSED: - handleTryAgainPressed(); - break; - default: - Log.w(TAG, "Unknown message: " + msg.what); - break; + } catch (RemoteException e) { + Log.e(TAG, "Remote exception", e); } } }; - private class Callback implements DialogViewCallback { - @Override - public void onUserCanceled() { - mHandler.obtainMessage(MSG_USER_CANCELED).sendToTarget(); + @Override + public void onTryAgainPressed() { + try { + mReceiver.onTryAgainPressed(); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException when handling try again", e); } + } - @Override - public void onErrorShown() { - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_HIDE_DIALOG, - false /* userCanceled */), BiometricPrompt.HIDE_DIALOG_DELAY); + @Override + public void onDismissed(@DismissedReason int reason) { + switch (reason) { + case DialogViewCallback.DISMISSED_USER_CANCELED: + sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_USER_CANCEL); + break; + + case DialogViewCallback.DISMISSED_BUTTON_NEGATIVE: + sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_NEGATIVE); + break; + + case DialogViewCallback.DISMISSED_BUTTON_POSITIVE: + sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_CONFIRMED); + break; + + case DialogViewCallback.DISMISSED_AUTHENTICATED: + sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_CONFIRM_NOT_REQUIRED); + break; + + case DialogViewCallback.DISMISSED_ERROR: + sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_ERROR); + break; + + case DialogViewCallback.DISMISSED_BY_SYSTEM_SERVER: + sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED); + break; + + default: + Log.e(TAG, "Unhandled reason: " + reason); + break; } + } - @Override - public void onNegativePressed() { - mHandler.obtainMessage(MSG_BUTTON_NEGATIVE).sendToTarget(); + private void sendResultAndCleanUp(@DismissedReason int reason) { + if (mReceiver == null) { + Log.e(TAG, "Receiver is null"); + return; } - - @Override - public void onPositivePressed() { - mHandler.obtainMessage(MSG_BUTTON_POSITIVE).sendToTarget(); + try { + mReceiver.onDialogDismissed(reason); + } catch (RemoteException e) { + Log.w(TAG, "Remote exception", e); } + onDialogDismissed(reason); + } - @Override - public void onTryAgainPressed() { - mHandler.obtainMessage(MSG_TRY_AGAIN_PRESSED).sendToTarget(); + public static class Injector { + IActivityTaskManager getActivityTaskManager() { + return ActivityTaskManager.getService(); } } - final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() { - @Override - public void onStartedGoingToSleep() { - if (mDialogShowing) { - if (DEBUG) Log.d(TAG, "User canceled due to screen off"); - mHandler.obtainMessage(MSG_USER_CANCELED).sendToTarget(); - } - } - }; + public BiometricDialogImpl() { + this(new Injector()); + } + + @VisibleForTesting + BiometricDialogImpl(Injector injector) { + mInjector = injector; + } @Override public void start() { @@ -154,30 +173,38 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba || pm.hasSystemFeature(PackageManager.FEATURE_IRIS)) { getComponent(CommandQueue.class).addCallback(this); mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); - mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class); - mWakefulnessLifecycle.addObserver(mWakefulnessObserver); + mActivityTaskManager = mInjector.getActivityTaskManager(); + + try { + mTaskStackListener = new BiometricTaskStackListener(); + mActivityTaskManager.registerTaskStackListener(mTaskStackListener); + } catch (RemoteException e) { + Log.w(TAG, "Unable to register task stack listener", e); + } } } @Override public void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver, - int type, boolean requireConfirmation, int userId) { + int type, boolean requireConfirmation, int userId, String opPackageName) { if (DEBUG) { Log.d(TAG, "showBiometricDialog, type: " + type + ", requireConfirmation: " + requireConfirmation); } - // Remove these messages as they are part of the previous client - mHandler.removeMessages(MSG_BIOMETRIC_ERROR); - mHandler.removeMessages(MSG_BIOMETRIC_HELP); - mHandler.removeMessages(MSG_BIOMETRIC_AUTHENTICATED); - mHandler.removeMessages(MSG_HIDE_DIALOG); SomeArgs args = SomeArgs.obtain(); args.arg1 = bundle; args.arg2 = receiver; args.argi1 = type; args.arg3 = requireConfirmation; args.argi2 = userId; - mHandler.obtainMessage(MSG_SHOW_DIALOG, args).sendToTarget(); + args.arg4 = opPackageName; + + boolean skipAnimation = false; + if (mCurrentDialog != null) { + Log.w(TAG, "mCurrentDialog: " + mCurrentDialog); + skipAnimation = true; + } + showDialog(args, skipAnimation, null /* savedState */); } @Override @@ -185,185 +212,111 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba if (DEBUG) Log.d(TAG, "onBiometricAuthenticated: " + authenticated + " reason: " + failureReason); - SomeArgs args = SomeArgs.obtain(); - args.arg1 = authenticated; - args.arg2 = failureReason; - mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED, args).sendToTarget(); + if (authenticated) { + mCurrentDialog.onAuthenticationSucceeded(); + } else { + mCurrentDialog.onAuthenticationFailed(failureReason); + } } @Override public void onBiometricHelp(String message) { if (DEBUG) Log.d(TAG, "onBiometricHelp: " + message); - SomeArgs args = SomeArgs.obtain(); - args.arg1 = message; - mHandler.obtainMessage(MSG_BIOMETRIC_HELP, args).sendToTarget(); + + mCurrentDialog.onHelp(message); } @Override public void onBiometricError(String error) { if (DEBUG) Log.d(TAG, "onBiometricError: " + error); - mHandler.obtainMessage(MSG_BIOMETRIC_ERROR, error).sendToTarget(); + mCurrentDialog.onError(error); } @Override public void hideBiometricDialog() { if (DEBUG) Log.d(TAG, "hideBiometricDialog"); - mHandler.obtainMessage(MSG_HIDE_DIALOG, false /* userCanceled */).sendToTarget(); + + mCurrentDialog.dismissFromSystemServer(); } - private void handleShowDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) { + private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) { mCurrentDialogArgs = args; final int type = args.argi1; + final Bundle biometricPromptBundle = (Bundle) args.arg1; + final boolean requireConfirmation = (boolean) args.arg3; + final int userId = args.argi2; + final String opPackageName = (String) args.arg4; // Create a new dialog but do not replace the current one yet. - BiometricDialogView newDialog; - if (type == BiometricAuthenticator.TYPE_FINGERPRINT) { - newDialog = new FingerprintDialogView(mContext, mCallback); - } else if (type == BiometricAuthenticator.TYPE_FACE) { - newDialog = new FaceDialogView(mContext, mCallback); - } else { + final BiometricDialog newDialog = buildDialog( + biometricPromptBundle, + requireConfirmation, + userId, + type, + opPackageName); + + if (newDialog == null) { Log.e(TAG, "Unsupported type: " + type); return; } - if (DEBUG) Log.d(TAG, "handleShowDialog, " - + " savedState: " + savedState - + " mCurrentDialog: " + mCurrentDialog - + " newDialog: " + newDialog - + " type: " + type); + if (DEBUG) { + Log.d(TAG, "showDialog, " + + " savedState: " + savedState + + " mCurrentDialog: " + mCurrentDialog + + " newDialog: " + newDialog + + " type: " + type); + } if (savedState != null) { // SavedState is only non-null if it's from onConfigurationChanged. Restore the state // even though it may be removed / re-created again newDialog.restoreState(savedState); - } else if (mCurrentDialog != null && mDialogShowing) { + } else if (mCurrentDialog != null) { // If somehow we're asked to show a dialog, the old one doesn't need to be animated // away. This can happen if the app cancels and re-starts auth during configuration // change. This is ugly because we also have to do things on onConfigurationChanged // here. - mCurrentDialog.forceRemove(); + mCurrentDialog.dismissWithoutCallback(false /* animate */); } mReceiver = (IBiometricServiceReceiverInternal) args.arg2; - newDialog.setBundle((Bundle) args.arg1); - newDialog.setRequireConfirmation((boolean) args.arg3); - newDialog.setUserId(args.argi2); - newDialog.setSkipIntro(skipAnimation); mCurrentDialog = newDialog; - mWindowManager.addView(mCurrentDialog, mCurrentDialog.getLayoutParams()); - mDialogShowing = true; - } - - private void handleBiometricAuthenticated(boolean authenticated, String failureReason) { - if (DEBUG) Log.d(TAG, "handleBiometricAuthenticated: " + authenticated); - - if (authenticated) { - mCurrentDialog.announceForAccessibility( - mContext.getResources() - .getText(mCurrentDialog.getAuthenticatedAccessibilityResourceId())); - if (mCurrentDialog.requiresConfirmation()) { - mCurrentDialog.updateState(BiometricDialogView.STATE_PENDING_CONFIRMATION); - } else { - mCurrentDialog.updateState(BiometricDialogView.STATE_AUTHENTICATED); - mHandler.postDelayed(() -> { - handleHideDialog(false /* userCanceled */); - }, mCurrentDialog.getDelayAfterAuthenticatedDurationMs()); - } - } else { - mCurrentDialog.onAuthenticationFailed(failureReason); - } - } - - private void handleBiometricHelp(String message) { - if (DEBUG) Log.d(TAG, "handleBiometricHelp: " + message); - mCurrentDialog.onHelpReceived(message); + mCurrentDialog.show(mWindowManager, skipAnimation); } - private void handleBiometricError(String error) { - if (DEBUG) Log.d(TAG, "handleBiometricError: " + error); - if (!mDialogShowing) { - if (DEBUG) Log.d(TAG, "Dialog already dismissed"); - return; - } - mCurrentDialog.onErrorReceived(error); - } - - private void handleHideDialog(boolean userCanceled) { - if (DEBUG) Log.d(TAG, "handleHideDialog, userCanceled: " + userCanceled); - if (!mDialogShowing) { - // This can happen if there's a race and we get called from both - // onAuthenticated and onError, etc. - Log.w(TAG, "Dialog already dismissed, userCanceled: " + userCanceled); - return; - } - if (userCanceled) { - try { - mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException when hiding dialog", e); - } + private void onDialogDismissed(@DismissedReason int reason) { + if (DEBUG) Log.d(TAG, "onDialogDismissed: " + reason); + if (mCurrentDialog == null) { + Log.w(TAG, "Dialog already dismissed"); } mReceiver = null; - mDialogShowing = false; - mCurrentDialog.startDismiss(); - } - - private void handleButtonNegative() { - if (mReceiver == null) { - Log.e(TAG, "Receiver is null"); - return; - } - try { - mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_NEGATIVE); - } catch (RemoteException e) { - Log.e(TAG, "Remote exception when handling negative button", e); - } - handleHideDialog(false /* userCanceled */); - } - - private void handleButtonPositive() { - if (mReceiver == null) { - Log.e(TAG, "Receiver is null"); - return; - } - try { - mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_POSITIVE); - } catch (RemoteException e) { - Log.e(TAG, "Remote exception when handling positive button", e); - } - handleHideDialog(false /* userCanceled */); - } - - private void handleUserCanceled() { - handleHideDialog(true /* userCanceled */); - } - - private void handleTryAgainPressed() { - try { - mReceiver.onTryAgainPressed(); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException when handling try again", e); - } + mCurrentDialog = null; } @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - final boolean wasShowing = mDialogShowing; // Save the state of the current dialog (buttons showing, etc) - final Bundle savedState = new Bundle(); if (mCurrentDialog != null) { + final Bundle savedState = new Bundle(); mCurrentDialog.onSaveState(savedState); - } + mCurrentDialog.dismissWithoutCallback(false /* animate */); + mCurrentDialog = null; - if (mDialogShowing) { - mCurrentDialog.forceRemove(); - mDialogShowing = false; + showDialog(mCurrentDialogArgs, true /* skipAnimation */, savedState); } + } - if (wasShowing) { - handleShowDialog(mCurrentDialogArgs, true /* skipAnimation */, savedState); - } + protected BiometricDialog buildDialog(Bundle biometricPromptBundle, + boolean requireConfirmation, int userId, int type, String opPackageName) { + return new BiometricDialogView.Builder(mContext) + .setCallback(this) + .setBiometricPromptBundle(biometricPromptBundle) + .setRequireConfirmation(requireConfirmation) + .setUserId(userId) + .setOpPackageName(opPackageName) + .build(type); } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/DialogViewCallback.java b/packages/SystemUI/src/com/android/systemui/biometrics/DialogViewCallback.java index 24fd22e2ee80..b65d1e823a9b 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/DialogViewCallback.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/DialogViewCallback.java @@ -16,36 +16,38 @@ package com.android.systemui.biometrics; +import android.annotation.IntDef; + /** * Callback interface for dialog views. These should be implemented by the controller (e.g. * FingerprintDialogImpl) and passed into their views (e.g. FingerprintDialogView). */ public interface DialogViewCallback { - /** - * Invoked when the user cancels authentication by tapping outside the prompt, etc. The dialog - * should be dismissed. - */ - void onUserCanceled(); - /** - * Invoked when an error is shown. The dialog should be dismissed after a set amount of time. - */ - void onErrorShown(); + int DISMISSED_USER_CANCELED = 1; + int DISMISSED_BUTTON_NEGATIVE = 2; + int DISMISSED_BUTTON_POSITIVE = 3; - /** - * Invoked when the negative button is pressed. The client should be notified and the dialog - * should be dismissed. - */ - void onNegativePressed(); + int DISMISSED_AUTHENTICATED = 4; + int DISMISSED_ERROR = 5; + int DISMISSED_BY_SYSTEM_SERVER = 6; + + @IntDef({DISMISSED_USER_CANCELED, + DISMISSED_BUTTON_NEGATIVE, + DISMISSED_BUTTON_POSITIVE, + DISMISSED_AUTHENTICATED, + DISMISSED_ERROR, + DISMISSED_BY_SYSTEM_SERVER}) + @interface DismissedReason {} /** - * Invoked when the positive button is pressed. The client should be notified and the dialog - * should be dismissed. + * Invoked when the dialog is dismissed + * @param reason */ - void onPositivePressed(); + void onDismissed(@DismissedReason int reason); /** - * Invoked when the "try again" button is pressed. + * Invoked when the "try again" button is clicked */ void onTryAgainPressed(); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/ui/BiometricDialogView.java index ce67577ea483..2b4dde55ef72 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/BiometricDialogView.java @@ -11,10 +11,10 @@ * 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 + * limitations under the License. */ -package com.android.systemui.biometrics; +package com.android.systemui.biometrics.ui; import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE; @@ -23,6 +23,7 @@ import android.content.Context; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; +import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricPrompt; import android.os.Binder; import android.os.Bundle; @@ -46,25 +47,30 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.biometrics.BiometricDialog; +import com.android.systemui.biometrics.DialogViewCallback; +import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.util.leak.RotationUtils; /** * Abstract base class. Shows a dialog for BiometricPrompt. */ -public abstract class BiometricDialogView extends LinearLayout { +public abstract class BiometricDialogView extends LinearLayout implements BiometricDialog { private static final String TAG = "BiometricDialogView"; - private static final String KEY_TRY_AGAIN_VISIBILITY = "key_try_again_visibility"; - private static final String KEY_CONFIRM_VISIBILITY = "key_confirm_visibility"; - private static final String KEY_CONFIRM_ENABLED = "key_confirm_enabled"; - private static final String KEY_STATE = "key_state"; - private static final String KEY_ERROR_TEXT_VISIBILITY = "key_error_text_visibility"; - private static final String KEY_ERROR_TEXT_STRING = "key_error_text_string"; - private static final String KEY_ERROR_TEXT_IS_TEMPORARY = "key_error_text_is_temporary"; - private static final String KEY_ERROR_TEXT_COLOR = "key_error_text_color"; + public static final String KEY_TRY_AGAIN_VISIBILITY = "key_try_again_visibility"; + public static final String KEY_CONFIRM_VISIBILITY = "key_confirm_visibility"; + public static final String KEY_CONFIRM_ENABLED = "key_confirm_enabled"; + public static final String KEY_STATE = "key_state"; + public static final String KEY_ERROR_TEXT_VISIBILITY = "key_error_text_visibility"; + public static final String KEY_ERROR_TEXT_STRING = "key_error_text_string"; + public static final String KEY_ERROR_TEXT_IS_TEMPORARY = "key_error_text_is_temporary"; + public static final String KEY_ERROR_TEXT_COLOR = "key_error_text_color"; private static final int ANIMATION_DURATION_SHOW = 250; // ms private static final int ANIMATION_DURATION_AWAY = 350; // ms @@ -77,6 +83,8 @@ public abstract class BiometricDialogView extends LinearLayout { protected static final int STATE_PENDING_CONFIRMATION = 3; protected static final int STATE_AUTHENTICATED = 4; + @VisibleForTesting + final WakefulnessLifecycle mWakefulnessLifecycle; private final AccessibilityManager mAccessibilityManager; private final IBinder mWindowToken = new Binder(); private final Interpolator mLinearOutSlowIn; @@ -90,22 +98,30 @@ public abstract class BiometricDialogView extends LinearLayout { protected final ViewGroup mLayout; protected final LinearLayout mDialog; - protected final TextView mTitleText; - protected final TextView mSubtitleText; - protected final TextView mDescriptionText; - protected final ImageView mBiometricIcon; - protected final TextView mErrorText; - protected final Button mPositiveButton; - protected final Button mNegativeButton; - protected final Button mTryAgainButton; + @VisibleForTesting + final TextView mTitleText; + @VisibleForTesting + final TextView mSubtitleText; + @VisibleForTesting + final TextView mDescriptionText; + @VisibleForTesting + final ImageView mBiometricIcon; + @VisibleForTesting + final TextView mErrorText; + @VisibleForTesting + final Button mPositiveButton; + @VisibleForTesting + final Button mNegativeButton; + @VisibleForTesting + final Button mTryAgainButton; protected final int mTextColor; private Bundle mBundle; private Bundle mRestoredState; + private String mOpPackageName; private int mState = STATE_IDLE; - private boolean mAnimatingAway; private boolean mWasForceRemoved; private boolean mSkipIntro; protected boolean mRequireConfirmation; @@ -141,6 +157,15 @@ public abstract class BiometricDialogView extends LinearLayout { } }; + @VisibleForTesting + final WakefulnessLifecycle.Observer mWakefulnessObserver = + new WakefulnessLifecycle.Observer() { + @Override + public void onStartedGoingToSleep() { + animateAway(DialogViewCallback.DISMISSED_USER_CANCELED); + } + }; + protected Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { @@ -155,8 +180,80 @@ public abstract class BiometricDialogView extends LinearLayout { } }; - public BiometricDialogView(Context context, DialogViewCallback callback) { + /** + * Builds the dialog with specified parameters. + */ + public static class Builder { + public static final int TYPE_FINGERPRINT = BiometricAuthenticator.TYPE_FINGERPRINT; + public static final int TYPE_FACE = BiometricAuthenticator.TYPE_FACE; + + private Context mContext; + private DialogViewCallback mCallback; + private Bundle mBundle; + private boolean mRequireConfirmation; + private int mUserId; + private String mOpPackageName; + + public Builder(Context context) { + mContext = context; + } + + public Builder setCallback(DialogViewCallback callback) { + mCallback = callback; + return this; + } + + public Builder setBiometricPromptBundle(Bundle bundle) { + mBundle = bundle; + return this; + } + + public Builder setRequireConfirmation(boolean requireConfirmation) { + mRequireConfirmation = requireConfirmation; + return this; + } + + public Builder setUserId(int userId) { + mUserId = userId; + return this; + } + + public Builder setOpPackageName(String opPackageName) { + mOpPackageName = opPackageName; + return this; + } + + public BiometricDialogView build(int type) { + return build(type, new Injector()); + } + + public BiometricDialogView build(int type, Injector injector) { + BiometricDialogView dialog; + if (type == TYPE_FINGERPRINT) { + dialog = new FingerprintDialogView(mContext, mCallback, injector); + } else if (type == TYPE_FACE) { + dialog = new FaceDialogView(mContext, mCallback, injector); + } else { + return null; + } + dialog.setBundle(mBundle); + dialog.setRequireConfirmation(mRequireConfirmation); + dialog.setUserId(mUserId); + dialog.setOpPackageName(mOpPackageName); + return dialog; + } + } + + public static class Injector { + public WakefulnessLifecycle getWakefulnessLifecycle() { + return Dependency.get(WakefulnessLifecycle.class); + } + } + + protected BiometricDialogView(Context context, DialogViewCallback callback, Injector injector) { super(context); + mWakefulnessLifecycle = injector.getWakefulnessLifecycle(); + mCallback = callback; mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN; mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); @@ -178,19 +275,13 @@ public abstract class BiometricDialogView extends LinearLayout { addView(mLayout); mLayout.setOnKeyListener(new View.OnKeyListener() { - boolean downPressed = false; @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode != KeyEvent.KEYCODE_BACK) { return false; } - if (event.getAction() == KeyEvent.ACTION_DOWN && downPressed == false) { - downPressed = true; - } else if (event.getAction() == KeyEvent.ACTION_DOWN) { - downPressed = false; - } else if (event.getAction() == KeyEvent.ACTION_UP && downPressed == true) { - downPressed = false; - mCallback.onUserCanceled(); + if (event.getAction() == KeyEvent.ACTION_UP) { + animateAway(DialogViewCallback.DISMISSED_USER_CANCELED); } return true; } @@ -219,16 +310,16 @@ public abstract class BiometricDialogView extends LinearLayout { mNegativeButton.setOnClickListener((View v) -> { if (mState == STATE_PENDING_CONFIRMATION || mState == STATE_AUTHENTICATED) { - mCallback.onUserCanceled(); + animateAway(DialogViewCallback.DISMISSED_USER_CANCELED); } else { - mCallback.onNegativePressed(); + animateAway(DialogViewCallback.DISMISSED_BUTTON_NEGATIVE); } }); mPositiveButton.setOnClickListener((View v) -> { updateState(STATE_AUTHENTICATED); mHandler.postDelayed(() -> { - mCallback.onPositivePressed(); + animateAway(DialogViewCallback.DISMISSED_BUTTON_POSITIVE); }, getDelayAfterAuthenticatedDurationMs()); }); @@ -248,21 +339,12 @@ public abstract class BiometricDialogView extends LinearLayout { mLayout.requestFocus(); } - public void onSaveState(Bundle bundle) { - bundle.putInt(KEY_TRY_AGAIN_VISIBILITY, mTryAgainButton.getVisibility()); - bundle.putInt(KEY_CONFIRM_VISIBILITY, mPositiveButton.getVisibility()); - bundle.putBoolean(KEY_CONFIRM_ENABLED, mPositiveButton.isEnabled()); - bundle.putInt(KEY_STATE, mState); - bundle.putInt(KEY_ERROR_TEXT_VISIBILITY, mErrorText.getVisibility()); - bundle.putCharSequence(KEY_ERROR_TEXT_STRING, mErrorText.getText()); - bundle.putBoolean(KEY_ERROR_TEXT_IS_TEMPORARY, mHandler.hasMessages(MSG_RESET_MESSAGE)); - bundle.putInt(KEY_ERROR_TEXT_COLOR, mErrorText.getCurrentTextColor()); - } - @Override public void onAttachedToWindow() { super.onAttachedToWindow(); + mWakefulnessLifecycle.addObserver(mWakefulnessObserver); + final ImageView backgroundView = mLayout.findViewById(R.id.background); if (mUserManager.isManagedProfile(mUserId)) { @@ -278,6 +360,7 @@ public abstract class BiometricDialogView extends LinearLayout { } mNegativeButton.setVisibility(View.VISIBLE); + mNegativeButton.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT)); if (RotationUtils.getRotation(mContext) != RotationUtils.ROTATION_NONE) { mDialog.getLayoutParams().width = (int) mDialogWidth; @@ -285,7 +368,6 @@ public abstract class BiometricDialogView extends LinearLayout { if (mRestoredState == null) { updateState(STATE_AUTHENTICATING); - mNegativeButton.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT)); final int hint = getHintStringResourceId(); if (hint != 0) { mErrorText.setText(hint); @@ -346,34 +428,49 @@ public abstract class BiometricDialogView extends LinearLayout { mSkipIntro = false; } + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + mWakefulnessLifecycle.removeObserver(mWakefulnessObserver); + } + private void setDismissesDialog(View v) { v.setClickable(true); v.setOnClickListener(v1 -> { if (mState != STATE_AUTHENTICATED && shouldGrayAreaDismissDialog()) { - mCallback.onUserCanceled(); + animateAway(DialogViewCallback.DISMISSED_USER_CANCELED); } }); } - public void startDismiss() { + private void animateAway(@DialogViewCallback.DismissedReason int reason) { + animateAway(true /* sendReason */, reason); + } + + /** + * Animate the dialog away + * @param reason one of the {@link DialogViewCallback} codes + */ + private void animateAway(boolean sendReason, @DialogViewCallback.DismissedReason int reason) { if (!mCompletedAnimatingIn) { Log.w(TAG, "startDismiss(): waiting for onDialogAnimatedIn"); mPendingDismissDialog = true; return; } - mAnimatingAway = true; - // This is where final cleanup should occur. final Runnable endActionRunnable = new Runnable() { @Override public void run() { mWindowManager.removeView(BiometricDialogView.this); - mAnimatingAway = false; // Set the icons / text back to normal state handleResetMessage(); showTryAgainButton(false /* show */); updateState(STATE_IDLE); + if (sendReason) { + mCallback.onDismissed(reason); + } } }; @@ -398,47 +495,30 @@ public abstract class BiometricDialogView extends LinearLayout { } /** - * Force remove the window, cancelling any animation that's happening. This should only be - * called if we want to quickly show the dialog again (e.g. on rotation). Calling this method - * will cause the dialog to show without an animation the next time it's attached. - */ - public void forceRemove() { - mLayout.animate().cancel(); - mDialog.animate().cancel(); - mWindowManager.removeView(BiometricDialogView.this); - mAnimatingAway = false; - mWasForceRemoved = true; - } - - /** * Skip the intro animation */ - public void setSkipIntro(boolean skip) { + private void setSkipIntro(boolean skip) { mSkipIntro = skip; } - public boolean isAnimatingAway() { - return mAnimatingAway; - } - - public void setBundle(Bundle bundle) { + private void setBundle(Bundle bundle) { mBundle = bundle; } - public void setRequireConfirmation(boolean requireConfirmation) { + private void setRequireConfirmation(boolean requireConfirmation) { mRequireConfirmation = requireConfirmation; } - public boolean requiresConfirmation() { + protected boolean requiresConfirmation() { return mRequireConfirmation; } - public void setUserId(int userId) { + private void setUserId(int userId) { mUserId = userId; } - public ViewGroup getLayout() { - return mLayout; + private void setOpPackageName(String opPackageName) { + mOpPackageName = opPackageName; } // Shows an error/help message @@ -452,17 +532,63 @@ public abstract class BiometricDialogView extends LinearLayout { BiometricPrompt.HIDE_DIALOG_DELAY); } + @Override + public void show(WindowManager wm, boolean skipIntroAnimation) { + setSkipIntro(skipIntroAnimation); + wm.addView(this, getLayoutParams(mWindowToken)); + } + /** - * Transient help message (acquire) is received, dialog stays showing. Sensor stays in - * "authenticating" state. - * @param message + * Force remove the window, cancelling any animation that's happening. This should only be + * called if we want to quickly show the dialog again (e.g. on rotation). Calling this method + * will cause the dialog to show without an animation the next time it's attached. */ - public void onHelpReceived(String message) { + @Override + public void dismissWithoutCallback(boolean animate) { + if (animate) { + animateAway(false /* sendReason */, 0 /* reason */); + } else { + mLayout.animate().cancel(); + mDialog.animate().cancel(); + mWindowManager.removeView(BiometricDialogView.this); + mWasForceRemoved = true; + } + } + + @Override + public void dismissFromSystemServer() { + animateAway(DialogViewCallback.DISMISSED_BY_SYSTEM_SERVER); + } + + @Override + public void onAuthenticationSucceeded() { + announceForAccessibility(getResources().getText(getAuthenticatedAccessibilityResourceId())); + + if (requiresConfirmation()) { + updateState(STATE_PENDING_CONFIRMATION); + } else { + mHandler.postDelayed(() -> { + animateAway(DialogViewCallback.DISMISSED_AUTHENTICATED); + }, getDelayAfterAuthenticatedDurationMs()); + + updateState(STATE_AUTHENTICATED); + } + } + + + @Override + public void onAuthenticationFailed(String message) { updateState(STATE_ERROR); showTemporaryMessage(message); } - public void onAuthenticationFailed(String message) { + /** + * Transient help message (acquire) is received, dialog stays showing. Sensor stays in + * "authenticating" state. + * @param message + */ + @Override + public void onHelp(String message) { updateState(STATE_ERROR); showTemporaryMessage(message); } @@ -471,14 +597,61 @@ public abstract class BiometricDialogView extends LinearLayout { * Hard error is received, dialog will be dismissed soon. * @param error */ - public void onErrorReceived(String error) { + @Override + public void onError(String error) { updateState(STATE_ERROR); showTemporaryMessage(error); showTryAgainButton(false /* show */); - mCallback.onErrorShown(); // TODO: Split between fp and face + + mHandler.postDelayed(() -> { + animateAway(DialogViewCallback.DISMISSED_ERROR); + }, BiometricPrompt.HIDE_DIALOG_DELAY); + } + + + @Override + public void onSaveState(Bundle bundle) { + bundle.putInt(KEY_TRY_AGAIN_VISIBILITY, mTryAgainButton.getVisibility()); + bundle.putInt(KEY_CONFIRM_VISIBILITY, mPositiveButton.getVisibility()); + bundle.putBoolean(KEY_CONFIRM_ENABLED, mPositiveButton.isEnabled()); + bundle.putInt(KEY_STATE, mState); + bundle.putInt(KEY_ERROR_TEXT_VISIBILITY, mErrorText.getVisibility()); + bundle.putCharSequence(KEY_ERROR_TEXT_STRING, mErrorText.getText()); + bundle.putBoolean(KEY_ERROR_TEXT_IS_TEMPORARY, mHandler.hasMessages(MSG_RESET_MESSAGE)); + bundle.putInt(KEY_ERROR_TEXT_COLOR, mErrorText.getCurrentTextColor()); + } + + @Override + public void restoreState(Bundle bundle) { + mRestoredState = bundle; + final int tryAgainVisibility = bundle.getInt(KEY_TRY_AGAIN_VISIBILITY); + mTryAgainButton.setVisibility(tryAgainVisibility); + final int confirmVisibility = bundle.getInt(KEY_CONFIRM_VISIBILITY); + mPositiveButton.setVisibility(confirmVisibility); + final boolean confirmEnabled = bundle.getBoolean(KEY_CONFIRM_ENABLED); + mPositiveButton.setEnabled(confirmEnabled); + mState = bundle.getInt(KEY_STATE); + mErrorText.setText(bundle.getCharSequence(KEY_ERROR_TEXT_STRING)); + mErrorText.setContentDescription(bundle.getCharSequence(KEY_ERROR_TEXT_STRING)); + final int errorTextVisibility = bundle.getInt(KEY_ERROR_TEXT_VISIBILITY); + mErrorText.setVisibility(errorTextVisibility); + if (errorTextVisibility == View.INVISIBLE || tryAgainVisibility == View.INVISIBLE + || confirmVisibility == View.INVISIBLE) { + announceAccessibilityEvent(); + } + mErrorText.setTextColor(bundle.getInt(KEY_ERROR_TEXT_COLOR)); + if (bundle.getBoolean(KEY_ERROR_TEXT_IS_TEMPORARY)) { + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RESET_MESSAGE), + BiometricPrompt.HIDE_DIALOG_DELAY); + } } - public void updateState(int newState) { + @Override + public String getOpPackageName() { + return mOpPackageName; + } + + protected void updateState(int newState) { if (newState == STATE_PENDING_CONFIRMATION) { mHandler.removeMessages(MSG_RESET_MESSAGE); mErrorText.setTextColor(mTextColor); @@ -505,48 +678,24 @@ public abstract class BiometricDialogView extends LinearLayout { mState = newState; } - public void showTryAgainButton(boolean show) { + protected void showTryAgainButton(boolean show) { } - public void onDialogAnimatedIn() { + protected void onDialogAnimatedIn() { mCompletedAnimatingIn = true; if (mPendingDismissDialog) { Log.d(TAG, "onDialogAnimatedIn(): mPendingDismissDialog=true, dismissing now"); - startDismiss(); + animateAway(false /* sendReason */, 0); mPendingDismissDialog = false; } } - public void restoreState(Bundle bundle) { - mRestoredState = bundle; - final int tryAgainVisibility = bundle.getInt(KEY_TRY_AGAIN_VISIBILITY); - mTryAgainButton.setVisibility(tryAgainVisibility); - final int confirmVisibility = bundle.getInt(KEY_CONFIRM_VISIBILITY); - mPositiveButton.setVisibility(confirmVisibility); - final boolean confirmEnabled = bundle.getBoolean(KEY_CONFIRM_ENABLED); - mPositiveButton.setEnabled(confirmEnabled); - mState = bundle.getInt(KEY_STATE); - mErrorText.setText(bundle.getCharSequence(KEY_ERROR_TEXT_STRING)); - mErrorText.setContentDescription(bundle.getCharSequence(KEY_ERROR_TEXT_STRING)); - final int errorTextVisibility = bundle.getInt(KEY_ERROR_TEXT_VISIBILITY); - mErrorText.setVisibility(errorTextVisibility); - if (errorTextVisibility == View.INVISIBLE || tryAgainVisibility == View.INVISIBLE - || confirmVisibility == View.INVISIBLE) { - announceAccessibilityEvent(); - } - mErrorText.setTextColor(bundle.getInt(KEY_ERROR_TEXT_COLOR)); - if (bundle.getBoolean(KEY_ERROR_TEXT_IS_TEMPORARY)) { - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RESET_MESSAGE), - BiometricPrompt.HIDE_DIALOG_DELAY); - } - } - - protected int getState() { - return mState; - } - - public WindowManager.LayoutParams getLayoutParams() { + /** + * @param windowToken token for the window + * @return + */ + public static WindowManager.LayoutParams getLayoutParams(IBinder windowToken) { final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, @@ -555,7 +704,7 @@ public abstract class BiometricDialogView extends LinearLayout { PixelFormat.TRANSLUCENT); lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; lp.setTitle("BiometricDialogView"); - lp.token = mWindowToken; + lp.token = windowToken; return lp; } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/ui/FaceDialogView.java index ae6cb5ce23d3..bd8714812ab4 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/FaceDialogView.java @@ -11,10 +11,10 @@ * 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 + * limitations under the License. */ -package com.android.systemui.biometrics; +package com.android.systemui.biometrics.ui; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -33,7 +33,9 @@ import android.util.Log; import android.view.View; import android.view.ViewOutlineProvider; +import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; +import com.android.systemui.biometrics.DialogViewCallback; /** * This class loads the view for the system-provided dialog. The view consists of: @@ -52,7 +54,8 @@ public class FaceDialogView extends BiometricDialogView { private static final int TEXT_ANIMATE_DISTANCE = 32; // dp private static final int SIZE_UNKNOWN = 0; - private static final int SIZE_SMALL = 1; + @VisibleForTesting + static final int SIZE_SMALL = 1; private static final int SIZE_GROWING = 2; private static final int SIZE_BIG = 3; @@ -152,13 +155,13 @@ public class FaceDialogView extends BiometricDialogView { announceAccessibilityEvent(); }; - public FaceDialogView(Context context, - DialogViewCallback callback) { - super(context, callback); + protected FaceDialogView(Context context, DialogViewCallback callback, Injector injector) { + super(context, callback, injector); mIconController = new IconController(); } - private void updateSize(int newSize) { + @VisibleForTesting + void updateSize(int newSize) { final float padding = dpToPixels(IMPLICIT_Y_PADDING); final float iconSmallPositionY = mDialog.getHeight() - mBiometricIcon.getHeight() - padding; @@ -339,8 +342,8 @@ public class FaceDialogView extends BiometricDialogView { } @Override - public void onErrorReceived(String error) { - super.onErrorReceived(error); + public void onError(String error) { + super.onError(error); // All error messages will cause the dialog to go from small -> big. Error messages // are messages such as lockout, auth failed, etc. if (mSize == SIZE_SMALL) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/ui/FingerprintDialogView.java index 183933eb395c..e597080f89fd 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/FingerprintDialogView.java @@ -11,10 +11,10 @@ * 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 + * limitations under the License. */ -package com.android.systemui.biometrics; +package com.android.systemui.biometrics.ui; import android.content.Context; import android.graphics.drawable.AnimatedVectorDrawable; @@ -22,6 +22,7 @@ import android.graphics.drawable.Drawable; import android.util.Log; import com.android.systemui.R; +import com.android.systemui.biometrics.DialogViewCallback; /** * This class loads the view for the system-provided dialog. The view consists of: @@ -32,9 +33,9 @@ public class FingerprintDialogView extends BiometricDialogView { private static final String TAG = "FingerprintDialogView"; - public FingerprintDialogView(Context context, - DialogViewCallback callback) { - super(context, callback); + protected FingerprintDialogView(Context context, DialogViewCallback callback, + Injector injector) { + super(context, callback, injector); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt new file mode 100644 index 000000000000..f0e8c16e650a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt @@ -0,0 +1,156 @@ +/* + * 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.broadcast + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.IntentFilter +import android.os.Handler +import android.os.Looper +import android.os.Message +import android.os.UserHandle +import android.util.Log +import android.util.SparseArray +import com.android.internal.annotations.VisibleForTesting +import com.android.systemui.Dependency.BG_LOOPER_NAME +import com.android.systemui.Dependency.MAIN_HANDLER_NAME +import com.android.systemui.Dumpable +import java.io.FileDescriptor +import java.io.PrintWriter +import javax.inject.Inject +import javax.inject.Named +import javax.inject.Singleton + +data class ReceiverData( + val receiver: BroadcastReceiver, + val filter: IntentFilter, + val handler: Handler, + val user: UserHandle +) + +private const val MSG_ADD_RECEIVER = 0 +private const val MSG_REMOVE_RECEIVER = 1 +private const val MSG_REMOVE_RECEIVER_FOR_USER = 2 +private const val TAG = "BroadcastDispatcher" +private const val DEBUG = false + +/** + * SystemUI master Broadcast Dispatcher. + * + * This class allows [BroadcastReceiver] to register and centralizes registrations to [Context] + * from SystemUI. That way the number of calls to [BroadcastReceiver.onReceive] can be reduced for + * a given broadcast. + * + * Use only for IntentFilters with actions and optionally categories. It does not support, + * permissions, schemes or data types. Cannot be used for getting sticky broadcasts. + */ +@Singleton +open class BroadcastDispatcher @Inject constructor ( + private val context: Context, + @Named(MAIN_HANDLER_NAME) private val mainHandler: Handler, + @Named(BG_LOOPER_NAME) private val bgLooper: Looper +) : Dumpable { + + // Only modify in BG thread + private val receiversByUser = SparseArray<UserBroadcastDispatcher>(20) + + /** + * Register a receiver for broadcast with the dispatcher + * + * @param receiver A receiver to dispatch the [Intent] + * @param filter A filter to determine what broadcasts should be dispatched to this receiver. + * It will only take into account actions and categories for filtering. + * @param handler A handler to dispatch [BroadcastReceiver.onReceive]. By default, it is the + * main handler. + * @param user A user handle to determine which broadcast should be dispatched to this receiver. + * By default, it is the current user. + */ + @JvmOverloads + fun registerReceiver( + receiver: BroadcastReceiver, + filter: IntentFilter, + handler: Handler = mainHandler, + user: UserHandle = context.user + ) { + this.handler.obtainMessage(MSG_ADD_RECEIVER, ReceiverData(receiver, filter, handler, user)) + .sendToTarget() + } + + /** + * Unregister receiver for all users. + * <br> + * This will remove every registration of [receiver], not those done just with [UserHandle.ALL]. + * + * @param receiver The receiver to unregister. It will be unregistered for all users. + */ + fun unregisterReceiver(receiver: BroadcastReceiver) { + handler.obtainMessage(MSG_REMOVE_RECEIVER, receiver).sendToTarget() + } + + /** + * Unregister receiver for a particular user. + * + * @param receiver The receiver to unregister. It will be unregistered for all users. + * @param user The user associated to the registered [receiver]. It can be [UserHandle.ALL]. + */ + fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) { + handler.obtainMessage(MSG_REMOVE_RECEIVER_FOR_USER, user.identifier, 0, receiver) + .sendToTarget() + } + + @VisibleForTesting + protected open fun createUBRForUser(userId: Int) = + UserBroadcastDispatcher(context, userId, mainHandler, bgLooper) + + override fun dump(fd: FileDescriptor?, pw: PrintWriter?, args: Array<out String>?) { + pw?.println("Broadcast dispatcher:") + for (index in 0 until receiversByUser.size()) { + pw?.println(" User ${receiversByUser.keyAt(index)}") + receiversByUser.valueAt(index).dump(fd, pw, args) + } + } + + private val handler = object : Handler(bgLooper) { + override fun handleMessage(msg: Message) { + when (msg.what) { + MSG_ADD_RECEIVER -> { + val data = msg.obj as ReceiverData + val userId = data.user.identifier + if (userId < UserHandle.USER_ALL) { + if (DEBUG) Log.w(TAG, "Register receiver for invalid user: $userId") + return + } + val uBR = receiversByUser.get(userId, createUBRForUser(userId)) + receiversByUser.put(userId, uBR) + uBR.registerReceiver(data) + } + + MSG_REMOVE_RECEIVER -> { + for (it in 0 until receiversByUser.size()) { + receiversByUser.valueAt(it).unregisterReceiver(msg.obj as BroadcastReceiver) + } + } + + MSG_REMOVE_RECEIVER_FOR_USER -> { + receiversByUser.get(msg.arg1)?.unregisterReceiver(msg.obj as BroadcastReceiver) + } + + else -> super.handleMessage(msg) + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt new file mode 100644 index 000000000000..d44b63e813e6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt @@ -0,0 +1,179 @@ +/* + * 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.broadcast + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.os.Handler +import android.os.Looper +import android.os.Message +import android.os.UserHandle +import android.util.ArrayMap +import android.util.ArraySet +import android.util.Log +import com.android.systemui.Dumpable +import java.io.FileDescriptor +import java.io.PrintWriter +import java.util.concurrent.atomic.AtomicBoolean + +private const val MSG_REGISTER_RECEIVER = 0 +private const val MSG_UNREGISTER_RECEIVER = 1 +private const val TAG = "UniversalReceiver" +private const val DEBUG = false + +/** + * Broadcast dispatcher for a given user registration [userId]. + * + * Created by [BroadcastDispatcher] as needed by users. The value of [userId] can be + * [UserHandle.USER_ALL]. + */ +class UserBroadcastDispatcher( + private val context: Context, + private val userId: Int, + private val mainHandler: Handler, + private val bgLooper: Looper +) : BroadcastReceiver(), Dumpable { + + private val bgHandler = object : Handler(bgLooper) { + override fun handleMessage(msg: Message) { + when (msg.what) { + MSG_REGISTER_RECEIVER -> handleRegisterReceiver(msg.obj as ReceiverData) + MSG_UNREGISTER_RECEIVER -> handleUnregisterReceiver(msg.obj as BroadcastReceiver) + else -> Unit + } + } + } + + private val registered = AtomicBoolean(false) + + internal fun isRegistered() = registered.get() + + private val registerReceiver = Runnable { + val categories = mutableSetOf<String>() + receiverToReceiverData.values.flatten().forEach { + it.filter.categoriesIterator()?.asSequence()?.let { + categories.addAll(it) + } + } + val intentFilter = IntentFilter().apply { + actionsToReceivers.keys.forEach { addAction(it) } + categories.forEach { addCategory(it) } + } + + if (registered.get()) { + context.unregisterReceiver(this) + registered.set(false) + } + // Short interval without receiver, this can be problematic + if (intentFilter.countActions() > 0 && !registered.get()) { + context.registerReceiverAsUser( + this, + UserHandle.of(userId), + intentFilter, + null, + bgHandler) + registered.set(true) + } + } + + // Only modify in BG thread + private val actionsToReceivers = ArrayMap<String, MutableSet<ReceiverData>>() + private val receiverToReceiverData = ArrayMap<BroadcastReceiver, MutableSet<ReceiverData>>() + + override fun onReceive(context: Context, intent: Intent) { + bgHandler.post(HandleBroadcastRunnable(actionsToReceivers, context, intent)) + } + + /** + * Register a [ReceiverData] for this user. + */ + fun registerReceiver(receiverData: ReceiverData) { + bgHandler.obtainMessage(MSG_REGISTER_RECEIVER, receiverData).sendToTarget() + } + + /** + * Unregister a given [BroadcastReceiver] for this user. + */ + fun unregisterReceiver(receiver: BroadcastReceiver) { + bgHandler.obtainMessage(MSG_UNREGISTER_RECEIVER, receiver).sendToTarget() + } + + private fun handleRegisterReceiver(receiverData: ReceiverData) { + if (DEBUG) Log.w(TAG, "Register receiver: ${receiverData.receiver}") + receiverToReceiverData.getOrPut(receiverData.receiver, { ArraySet() }).add(receiverData) + var changed = false + // Index the BroadcastReceiver by all its actions, that way it's easier to dispatch given + // a received intent. + receiverData.filter.actionsIterator().forEach { + actionsToReceivers.getOrPut(it) { + changed = true + ArraySet() + }.add(receiverData) + } + if (changed) { + mainHandler.post(registerReceiver) + } + } + + private fun handleUnregisterReceiver(receiver: BroadcastReceiver) { + if (DEBUG) Log.w(TAG, "Unregister receiver: $receiver") + val actions = receiverToReceiverData.getOrElse(receiver) { return } + .flatMap { it.filter.actionsIterator().asSequence().asIterable() }.toSet() + receiverToReceiverData.get(receiver)?.clear() + var changed = false + actions.forEach { action -> + actionsToReceivers.get(action)?.removeIf { it.receiver == receiver } + if (actionsToReceivers.get(action)?.isEmpty() ?: false) { + changed = true + actionsToReceivers.remove(action) + } + } + if (changed) { + mainHandler.post(registerReceiver) + } + } + + override fun dump(fd: FileDescriptor?, pw: PrintWriter?, args: Array<out String>?) { + pw?.println(" Registered=${registered.get()}") + actionsToReceivers.forEach { (action, list) -> + pw?.println(" $action:") + list.forEach { pw?.println(" ${it.receiver}") } + } + } + + private class HandleBroadcastRunnable( + val actionsToReceivers: Map<String, Set<ReceiverData>>, + val context: Context, + val intent: Intent + ) : Runnable { + override fun run() { + if (DEBUG) Log.w(TAG, "Dispatching $intent") + actionsToReceivers.get(intent.action) + ?.filter { + it.filter.hasAction(intent.action) && + it.filter.matchCategories(intent.categories) == null } + ?.forEach { + it.handler.post { + if (DEBUG) Log.w(TAG, "Dispatching to ${it.receiver}") + it.receiver.onReceive(context, intent) + } + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java index 128cc614fd08..ee79e6b973de 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java @@ -26,6 +26,7 @@ import android.provider.DeviceConfig; import android.view.MotionEvent; import com.android.internal.annotations.VisibleForTesting; +import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.Dependency; import com.android.systemui.classifier.brightline.BrightLineFalsingManager; import com.android.systemui.classifier.brightline.FalsingDataProvider; @@ -102,7 +103,8 @@ public class FalsingManagerProxy implements FalsingManager { } else { mInternalFalsingManager = new BrightLineFalsingManager( new FalsingDataProvider(context.getResources().getDisplayMetrics()), - Dependency.get(AsyncSensorManager.class) + Dependency.get(AsyncSensorManager.class), + KeyguardUpdateMonitor.getInstance(context) ); } 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 ce82bbfb1512..9e0b7025ddf8 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java @@ -23,11 +23,14 @@ import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; +import android.hardware.biometrics.BiometricSourceType; import android.net.Uri; import android.util.Log; import android.view.MotionEvent; import com.android.internal.logging.MetricsLogger; +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.classifier.Classifier; import com.android.systemui.plugins.FalsingManager; @@ -47,11 +50,13 @@ public class BrightLineFalsingManager implements FalsingManager { private final SensorManager mSensorManager; private final FalsingDataProvider mDataProvider; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private boolean mSessionStarted; private MetricsLogger mMetricsLogger; private int mIsFalseTouchCalls; private boolean mShowingAod; private boolean mScreenOn; + private boolean mJustUnlockedWithFace; private final ExecutorService mBackgroundExecutor = Executors.newSingleThreadExecutor(); @@ -68,10 +73,27 @@ public class BrightLineFalsingManager implements FalsingManager { } }; - public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider, - SensorManager sensorManager) { + private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback = + new KeyguardUpdateMonitorCallback() { + @Override + public void onBiometricAuthenticated(int userId, + BiometricSourceType biometricSourceType) { + if (userId == KeyguardUpdateMonitor.getCurrentUser() + && biometricSourceType == BiometricSourceType.FACE) { + mJustUnlockedWithFace = true; + } + } + }; + + public BrightLineFalsingManager( + FalsingDataProvider falsingDataProvider, + SensorManager sensorManager, + KeyguardUpdateMonitor keyguardUpdateMonitor) { + mKeyguardUpdateMonitor = keyguardUpdateMonitor; mDataProvider = falsingDataProvider; mSensorManager = sensorManager; + mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback); + mMetricsLogger = new MetricsLogger(); mClassifiers = new ArrayList<>(); DistanceClassifier distanceClassifier = new DistanceClassifier(mDataProvider); @@ -110,6 +132,7 @@ public class BrightLineFalsingManager implements FalsingManager { if (!mSessionStarted && !mShowingAod && mScreenOn) { logDebug("Starting Session"); mSessionStarted = true; + mJustUnlockedWithFace = false; registerSensors(); mClassifiers.forEach(FalsingClassifier::onSessionStarted); } @@ -141,7 +164,7 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public boolean isFalseTouch() { - boolean r = mClassifiers.stream().anyMatch(falsingClassifier -> { + boolean r = !mJustUnlockedWithFace && mClassifiers.stream().anyMatch(falsingClassifier -> { boolean result = falsingClassifier.isFalseTouch(); if (result) { logInfo(falsingClassifier.getClass().getName() + ": true"); @@ -335,6 +358,7 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public void cleanup() { unregisterSensors(); + mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback); } static void logDebug(String msg) { diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java index c58b7db451b0..82ae30ac4bdf 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java @@ -39,8 +39,8 @@ class ZigZagClassifier extends FalsingClassifier { // most swipes will follow somewhat of a 'C' or 'S' shape, we allow more deviance along the // `SECONDARY` axis. private static final float MAX_X_PRIMARY_DEVIANCE = .05f; - private static final float MAX_Y_PRIMARY_DEVIANCE = .05f; - private static final float MAX_X_SECONDARY_DEVIANCE = .3f; + private static final float MAX_Y_PRIMARY_DEVIANCE = .1f; + private static final float MAX_X_SECONDARY_DEVIANCE = .6f; private static final float MAX_Y_SECONDARY_DEVIANCE = .3f; private final float mMaxXPrimaryDeviance; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java b/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java index e6a9e47be71c..e5a54b816ec6 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java @@ -25,7 +25,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; */ public class DozeAuthRemover implements DozeMachine.Part { - KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; public DozeAuthRemover(Context context) { mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(context); diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java index 1bc7e635f9ed..86d4a48d3d59 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java @@ -30,6 +30,7 @@ import com.android.systemui.R; import com.android.systemui.SystemUIApplication; import com.android.systemui.dock.DockManager; import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.util.AsyncSensorManager; @@ -47,6 +48,7 @@ public class DozeFactory { SensorManager sensorManager = Dependency.get(AsyncSensorManager.class); AlarmManager alarmManager = context.getSystemService(AlarmManager.class); DockManager dockManager = Dependency.get(DockManager.class); + WakefulnessLifecycle wakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class); DozeHost host = getHost(dozeService); AmbientDisplayConfiguration config = new AmbientDisplayConfiguration(context); @@ -61,7 +63,8 @@ public class DozeFactory { wrappedService = DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(wrappedService, params); - DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock); + DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock, + wakefulnessLifecycle); machine.setParts(new DozeMachine.Part[]{ new DozePauser(handler, machine, alarmManager, params.getPolicy()), new DozeFalsingManagerAdapter(falsingManager), diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java index 8bf2256a4f80..93a51cc20db2 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java @@ -24,6 +24,8 @@ import android.util.Log; import android.view.Display; import com.android.internal.util.Preconditions; +import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.util.Assert; import com.android.systemui.util.wakelock.WakeLock; @@ -118,6 +120,7 @@ public class DozeMachine { private final Service mDozeService; private final WakeLock mWakeLock; private final AmbientDisplayConfiguration mConfig; + private final WakefulnessLifecycle mWakefulnessLifecycle; private Part[] mParts; private final ArrayList<State> mQueuedRequests = new ArrayList<>(); @@ -126,9 +129,10 @@ public class DozeMachine { private boolean mWakeLockHeldForCurrentState = false; public DozeMachine(Service service, AmbientDisplayConfiguration config, - WakeLock wakeLock) { + WakeLock wakeLock, WakefulnessLifecycle wakefulnessLifecycle) { mDozeService = service; mConfig = config; + mWakefulnessLifecycle = wakefulnessLifecycle; mWakeLock = wakeLock; } @@ -334,9 +338,18 @@ public class DozeMachine { switch (state) { case INITIALIZED: case DOZE_PULSE_DONE: - transitionTo(mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) - ? DozeMachine.State.DOZE_AOD : DozeMachine.State.DOZE, - DozeLog.PULSE_REASON_NONE); + final State nextState; + @Wakefulness int wakefulness = mWakefulnessLifecycle.getWakefulness(); + if (wakefulness == WakefulnessLifecycle.WAKEFULNESS_AWAKE + || wakefulness == WakefulnessLifecycle.WAKEFULNESS_WAKING) { + nextState = State.FINISH; + } else if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) { + nextState = State.DOZE_AOD; + } else { + nextState = State.DOZE; + } + + transitionTo(nextState, DozeLog.PULSE_REASON_NONE); break; default: break; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index f79bb3ae5b90..026a62528c8d 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -288,6 +288,7 @@ public class DozeSensors { final AlarmTimeout mCooldownTimer; final AlwaysOnDisplayPolicy mPolicy; final Sensor mSensor; + final boolean mUsingBrightnessSensor; public ProxSensor(AlwaysOnDisplayPolicy policy) { mPolicy = policy; @@ -298,6 +299,7 @@ public class DozeSensors { // if available. Sensor sensor = DozeSensors.findSensorWithType(mSensorManager, mContext.getString(R.string.doze_brightness_sensor_type)); + mUsingBrightnessSensor = sensor != null; if (sensor == null) { sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); } @@ -327,8 +329,7 @@ public class DozeSensors { return; } if (register) { - mRegistered = mSensorManager.registerListener(this, - mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY), + mRegistered = mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_NORMAL, mHandler); } else { mSensorManager.unregisterListener(this); @@ -341,7 +342,13 @@ public class DozeSensors { public void onSensorChanged(android.hardware.SensorEvent event) { if (DEBUG) Log.d(TAG, "onSensorChanged " + event); - mCurrentlyFar = event.values[0] >= event.sensor.getMaximumRange(); + if (mUsingBrightnessSensor) { + // The custom brightness sensor is gated by the proximity sensor and will return 0 + // whenever prox is covered. + mCurrentlyFar = event.values[0] > 0; + } else { + mCurrentlyFar = event.values[0] >= event.sensor.getMaximumRange(); + } mProxCallback.accept(mCurrentlyFar); long now = SystemClock.elapsedRealtime(); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java b/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java index 52a0214c492c..d17f2f621ec8 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java @@ -16,12 +16,15 @@ package com.android.systemui.keyguard; +import android.annotation.IntDef; import android.os.Trace; import com.android.systemui.Dumpable; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import javax.inject.Inject; import javax.inject.Singleton; @@ -33,6 +36,15 @@ import javax.inject.Singleton; public class WakefulnessLifecycle extends Lifecycle<WakefulnessLifecycle.Observer> implements Dumpable { + @IntDef(prefix = { "WAKEFULNESS_" }, value = { + WAKEFULNESS_ASLEEP, + WAKEFULNESS_WAKING, + WAKEFULNESS_AWAKE, + WAKEFULNESS_GOING_TO_SLEEP, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Wakefulness {} + public static final int WAKEFULNESS_ASLEEP = 0; public static final int WAKEFULNESS_WAKING = 1; public static final int WAKEFULNESS_AWAKE = 2; @@ -44,7 +56,7 @@ public class WakefulnessLifecycle extends Lifecycle<WakefulnessLifecycle.Observe public WakefulnessLifecycle() { } - public int getWakefulness() { + public @Wakefulness int getWakefulness() { return mWakefulness; } @@ -86,7 +98,7 @@ public class WakefulnessLifecycle extends Lifecycle<WakefulnessLifecycle.Observe pw.println(" mWakefulness=" + mWakefulness); } - private void setWakefulness(int wakefulness) { + private void setWakefulness(@Wakefulness int wakefulness) { mWakefulness = wakefulness; Trace.traceCounter(Trace.TRACE_TAG_APP, "wakefulness", wakefulness); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index 991d9fa549ac..0403a0505b00 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -248,7 +248,9 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { int numPages = Math.max(nTiles / mPages.get(0).maxTiles(), 1); // Add one more not full page if needed - numPages += (nTiles % mPages.get(0).maxTiles() == 0 ? 0 : 1); + if (nTiles > numPages * mPages.get(0).maxTiles()) { + numPages++; + } final int NP = mPages.size(); for (int i = 0; i < NP; i++) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java index c209b315b197..83b000dca83b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java @@ -296,10 +296,13 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene mY = y - containerLocation[1]; } - private final Callback mKeyguardCallback = () -> { - if (!isAttachedToWindow()) return; - if (Dependency.get(KeyguardMonitor.class).isShowing() && !mOpening) { - hide(); + private final Callback mKeyguardCallback = new Callback() { + @Override + public void onKeyguardShowingChanged() { + if (!isAttachedToWindow()) return; + if (Dependency.get(KeyguardMonitor.class).isShowing() && !mOpening) { + hide(); + } } }; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index 001e09406e3a..16a39750a9bd 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -73,6 +73,7 @@ public class HotspotTile extends QSTileImpl<BooleanState> { if (listening) { refreshState(); } + mHotspotController.handleSetListening(listening); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java index 822a6669bd5c..0383dee4f9c3 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java @@ -27,32 +27,29 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; +import android.graphics.Point; import android.graphics.drawable.Icon; import android.hardware.display.DisplayManager; import android.hardware.display.VirtualDisplay; import android.media.MediaRecorder; -import android.media.ThumbnailUtils; import android.media.projection.MediaProjection; import android.media.projection.MediaProjectionManager; import android.net.Uri; -import android.os.Environment; import android.os.IBinder; import android.provider.MediaStore; import android.provider.Settings; import android.util.DisplayMetrics; import android.util.Log; +import android.util.Size; import android.view.Surface; import android.widget.Toast; -import androidx.core.content.FileProvider; - 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; import java.util.Date; @@ -79,12 +76,10 @@ public class RecordingService extends Service { private static final String ACTION_DELETE = "com.android.systemui.screenrecord.DELETE"; private static final int TOTAL_NUM_TRACKS = 1; - private static final String RECORD_DIR = "Captures"; // TODO: use a translatable string private static final int VIDEO_BIT_RATE = 6000000; private static final int VIDEO_FRAME_RATE = 30; private static final int AUDIO_BIT_RATE = 16; private static final int AUDIO_SAMPLE_RATE = 44100; - private static final String FILE_PROVIDER = "com.android.systemui.fileprovider"; private MediaProjectionManager mMediaProjectionManager; private MediaProjection mMediaProjection; @@ -120,11 +115,11 @@ public class RecordingService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { - Log.d(TAG, "RecordingService is starting"); if (intent == null) { return Service.START_NOT_STICKY; } String action = intent.getAction(); + Log.d(TAG, "onStartCommand " + action); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); @@ -160,41 +155,7 @@ public class RecordingService extends Service { case ACTION_STOP: stopRecording(); - - String fileName = new SimpleDateFormat("'screen-'yyyyMMdd-HHmmss'.mp4'") - .format(new Date()); - - 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); - - // 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(); - Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG) - .show(); - } + saveRecording(notificationManager); break; case ACTION_PAUSE: @@ -208,8 +169,7 @@ public class RecordingService extends Service { break; case ACTION_SHARE: - File shareFile = new File(intent.getStringExtra(EXTRA_PATH)); - Uri shareUri = FileProvider.getUriForFile(this, FILE_PROVIDER, shareFile); + Uri shareUri = Uri.parse(intent.getStringExtra(EXTRA_PATH)); Intent shareIntent = new Intent(Intent.ACTION_SEND) .setType("video/mp4") @@ -229,20 +189,18 @@ public class RecordingService extends Service { // Close quick shade sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); - File file = new File(intent.getStringExtra(EXTRA_PATH)); - if (file.delete()) { - Toast.makeText( - this, - R.string.screenrecord_delete_description, - Toast.LENGTH_LONG).show(); + ContentResolver resolver = getContentResolver(); + Uri uri = Uri.parse(intent.getStringExtra(EXTRA_PATH)); + resolver.delete(uri, null, null); - // Remove notification - notificationManager.cancel(NOTIFICATION_ID); - } else { - Log.e(TAG, "Error deleting screen recording!"); - Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG) - .show(); - } + Toast.makeText( + this, + R.string.screenrecord_delete_description, + Toast.LENGTH_LONG).show(); + + // Remove notification + notificationManager.cancel(NOTIFICATION_ID); + Log.d(TAG, "Deleted recording " + uri); break; } return Service.START_STICKY; @@ -313,6 +271,7 @@ public class RecordingService extends Service { mMediaRecorder.start(); } catch (IOException e) { + Log.e(TAG, "Error starting screen recording: " + e.getMessage()); e.printStackTrace(); throw new RuntimeException(e); } @@ -370,9 +329,7 @@ public class RecordingService extends Service { notificationManager.notify(NOTIFICATION_ID, mRecordingNotificationBuilder.build()); } - private Notification createSaveNotification(Uri uri, Path path) { - Log.d(TAG, "Screen recording saved to " + uri.toString() + ", " + path.toString()); - + private Notification createSaveNotification(Uri uri) { Intent viewIntent = new Intent(Intent.ACTION_VIEW) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION) .setDataAndType(uri, "video/mp4"); @@ -411,8 +368,15 @@ public class RecordingService extends Service { .setAutoCancel(true); // Add thumbnail if available - Bitmap thumbnailBitmap = ThumbnailUtils.createVideoThumbnail(path.toString(), - MediaStore.Video.Thumbnails.MINI_KIND); + Bitmap thumbnailBitmap = null; + try { + ContentResolver resolver = getContentResolver(); + Size size = Point.convert(MediaStore.ThumbnailConstants.MINI_SIZE); + thumbnailBitmap = resolver.loadThumbnail(uri, size, null); + } catch (IOException e) { + Log.e(TAG, "Error creating thumbnail: " + e.getMessage()); + e.printStackTrace(); + } if (thumbnailBitmap != null) { Notification.BigPictureStyle pictureStyle = new Notification.BigPictureStyle() .bigPicture(thumbnailBitmap) @@ -434,6 +398,38 @@ public class RecordingService extends Service { stopSelf(); } + private void saveRecording(NotificationManager notificationManager) { + String fileName = new SimpleDateFormat("'screen-'yyyyMMdd-HHmmss'.mp4'") + .format(new Date()); + + 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); + + try { + // Add to the mediastore + OutputStream os = resolver.openOutputStream(itemUri, "w"); + Files.copy(mTempFile.toPath(), os); + os.close(); + + Notification notification = createSaveNotification(itemUri); + notificationManager.notify(NOTIFICATION_ID, notification); + + mTempFile.delete(); + } catch (IOException e) { + Log.e(TAG, "Error saving screen recording: " + e.getMessage()); + Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG) + .show(); + } + } + private void setTapsVisible(boolean turnOn) { int value = turnOn ? 1 : 0; Settings.System.putInt(getApplicationContext().getContentResolver(), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index fa0fe136b8eb..134d4b87a159 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -271,7 +271,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< default void onRotationProposal(int rotation, boolean isValid) { } default void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver, - int type, boolean requireConfirmation, int userId) { } + int type, boolean requireConfirmation, int userId, String opPackageName) { } default void onBiometricAuthenticated(boolean authenticated, String failureReason) { } default void onBiometricHelp(String message) { } default void onBiometricError(String error) { } @@ -741,7 +741,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< @Override public void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver, - int type, boolean requireConfirmation, int userId) { + int type, boolean requireConfirmation, int userId, String opPackageName) { synchronized (mLock) { SomeArgs args = SomeArgs.obtain(); args.arg1 = bundle; @@ -749,6 +749,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< args.argi1 = type; args.arg3 = requireConfirmation; args.argi2 = userId; + args.arg4 = opPackageName; mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args) .sendToTarget(); } @@ -1036,7 +1037,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< (IBiometricServiceReceiverInternal) someArgs.arg2, someArgs.argi1 /* type */, (boolean) someArgs.arg3 /* requireConfirmation */, - someArgs.argi2 /* userId */); + someArgs.argi2 /* userId */, + (String) someArgs.arg4 /* opPackageName */); } someArgs.recycle(); break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt index 48d6de964b08..276afa7a3a94 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt @@ -41,7 +41,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll import com.android.systemui.statusbar.phone.HeadsUpManagerPhone import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.phone.ShadeController -import com.android.systemui.statusbar.policy.HeadsUpManager import javax.inject.Inject import javax.inject.Singleton @@ -52,11 +51,13 @@ import kotlin.math.max */ @Singleton class PulseExpansionHandler @Inject -constructor(context: Context, - private val wakeUpCoordinator: NotificationWakeUpCoordinator, - private val bypassController: KeyguardBypassController, - private val headsUpManager: HeadsUpManagerPhone, - private val roundnessManager: NotificationRoundnessManager) : Gefingerpoken { +constructor( + context: Context, + private val wakeUpCoordinator: NotificationWakeUpCoordinator, + private val bypassController: KeyguardBypassController, + private val headsUpManager: HeadsUpManagerPhone, + private val roundnessManager: NotificationRoundnessManager +) : Gefingerpoken { companion object { private val RUBBERBAND_FACTOR_STATIC = 0.25f private val SPRING_BACK_ANIMATION_LENGTH_MS = 375 @@ -124,8 +125,8 @@ constructor(context: Context, } private fun maybeStartExpansion(event: MotionEvent): Boolean { - if (!wakeUpCoordinator.canShowPulsingHuns || qsExpanded - || bouncerShowing) { + if (!wakeUpCoordinator.canShowPulsingHuns || qsExpanded || + bouncerShowing) { return false } if (velocityTracker == null) { @@ -160,18 +161,18 @@ constructor(context: Context, } MotionEvent.ACTION_UP -> { - recycleVelocityTracker(); + recycleVelocityTracker() } MotionEvent.ACTION_CANCEL -> { - recycleVelocityTracker(); + recycleVelocityTracker() } } return false } private fun recycleVelocityTracker() { - velocityTracker?.recycle(); + velocityTracker?.recycle() velocityTracker = null } @@ -216,7 +217,7 @@ constructor(context: Context, "com.android.systemui:PULSEDRAG") } shadeController.goToLockedShade(mStartingChild) - leavingLockscreen = true; + leavingLockscreen = true isExpanding = false if (mStartingChild is ExpandableNotificationRow) { val row = mStartingChild as ExpandableNotificationRow? @@ -227,7 +228,7 @@ constructor(context: Context, private fun updateExpansionHeight(height: Float) { var expansionHeight = max(height, 0.0f) if (!mReachedWakeUpHeight && height > mWakeUpHeight) { - mReachedWakeUpHeight = true; + mReachedWakeUpHeight = true } if (mStartingChild != null) { val child = mStartingChild!! @@ -317,9 +318,11 @@ constructor(context: Context, } else null } - fun setUp(stackScroller: NotificationStackScrollLayout, - expansionCallback: ExpansionCallback, - shadeController: ShadeController) { + fun setUp( + stackScroller: NotificationStackScrollLayout, + expansionCallback: ExpansionCallback, + shadeController: ShadeController + ) { this.expansionCallback = expansionCallback this.shadeController = shadeController this.stackScroller = stackScroller diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java index 6a7477945cdd..3314e67857e2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java @@ -34,6 +34,7 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.util.Log; import android.util.MathUtils; +import android.util.StatsLog; import android.view.Gravity; import android.view.IPinnedStackController; import android.view.IPinnedStackListener; @@ -107,7 +108,11 @@ public class EdgeBackGestureHandler implements DisplayListener { public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion, Region unrestrictedOrNull) { if (displayId == mDisplayId) { - mMainExecutor.execute(() -> mExcludeRegion.set(systemGestureExclusion)); + mMainExecutor.execute(() -> { + mExcludeRegion.set(systemGestureExclusion); + mUnrestrictedExcludeRegion.set(unrestrictedOrNull != null + ? unrestrictedOrNull : systemGestureExclusion); + }); } } }; @@ -121,6 +126,8 @@ public class EdgeBackGestureHandler implements DisplayListener { private final Executor mMainExecutor; private final Region mExcludeRegion = new Region(); + private final Region mUnrestrictedExcludeRegion = new Region(); + // The edge width where touch down is allowed private int mEdgeWidth; // The slop to distinguish between horizontal and vertical motion @@ -139,6 +146,7 @@ public class EdgeBackGestureHandler implements DisplayListener { private final PointF mDownPoint = new PointF(); private boolean mThresholdCrossed = false; private boolean mAllowGesture = false; + private boolean mInRejectedExclusion = false; private boolean mIsOnLeftEdge; private int mImeHeight = 0; @@ -297,6 +305,7 @@ public class EdgeBackGestureHandler implements DisplayListener { return mSamplingRect; } }); + mRegionSamplingHelper.setWindowVisible(true); } } @@ -318,6 +327,12 @@ public class EdgeBackGestureHandler implements DisplayListener { if (isInExcludedRegion) { mOverviewProxyService.notifyBackAction(false /* completed */, -1, -1, false /* isButton */, !mIsOnLeftEdge); + StatsLog.write(StatsLog.BACK_GESTURE_REPORTED_REPORTED, + StatsLog.BACK_GESTURE__TYPE__INCOMPLETE_EXCLUDED, y, + mIsOnLeftEdge ? StatsLog.BACK_GESTURE__X_LOCATION__LEFT : + StatsLog.BACK_GESTURE__X_LOCATION__RIGHT); + } else { + mInRejectedExclusion = mUnrestrictedExcludeRegion.contains(x, y); } return !isInExcludedRegion; } @@ -325,6 +340,7 @@ public class EdgeBackGestureHandler implements DisplayListener { private void cancelGesture(MotionEvent ev) { // Send action cancel to reset all the touch events mAllowGesture = false; + mInRejectedExclusion = false; MotionEvent cancelEv = MotionEvent.obtain(ev); cancelEv.setAction(MotionEvent.ACTION_CANCEL); mEdgePanel.handleTouch(cancelEv); @@ -338,6 +354,7 @@ public class EdgeBackGestureHandler implements DisplayListener { // either the bouncer is showing or the notification panel is hidden int stateFlags = mOverviewProxyService.getSystemUiStateFlags(); mIsOnLeftEdge = ev.getX() <= mEdgeWidth + mLeftInset; + mInRejectedExclusion = false; mAllowGesture = !QuickStepContract.isBackGestureDisabled(stateFlags) && isWithinTouchRegion((int) ev.getX(), (int) ev.getY()); if (mAllowGesture) { @@ -392,6 +409,14 @@ public class EdgeBackGestureHandler implements DisplayListener { } mOverviewProxyService.notifyBackAction(performAction, (int) mDownPoint.x, (int) mDownPoint.y, false /* isButton */, !mIsOnLeftEdge); + int backtype = performAction ? (mInRejectedExclusion + ? StatsLog.BACK_GESTURE__TYPE__COMPLETED_REJECTED : + StatsLog.BACK_GESTURE__TYPE__COMPLETED) : + StatsLog.BACK_GESTURE__TYPE__INCOMPLETE; + StatsLog.write(StatsLog.BACK_GESTURE_REPORTED_REPORTED, backtype, + (int) mDownPoint.y, mIsOnLeftEdge + ? StatsLog.BACK_GESTURE__X_LOCATION__LEFT : + StatsLog.BACK_GESTURE__X_LOCATION__RIGHT); } if (isUp || action == MotionEvent.ACTION_CANCEL) { mRegionSamplingHelper.stop(); @@ -463,7 +488,9 @@ public class EdgeBackGestureHandler implements DisplayListener { pw.println("EdgeBackGestureHandler:"); pw.println(" mIsEnabled=" + mIsEnabled); pw.println(" mAllowGesture=" + mAllowGesture); + pw.println(" mInRejectedExclusion" + mInRejectedExclusion); pw.println(" mExcludeRegion=" + mExcludeRegion); + pw.println(" mUnrestrictedExcludeRegion=" + mUnrestrictedExcludeRegion); pw.println(" mImeHeight=" + mImeHeight); pw.println(" mIsAttached=" + mIsAttached); pw.println(" mEdgeWidth=" + mEdgeWidth); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java deleted file mode 100644 index 8bb8ca2550e3..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java +++ /dev/null @@ -1,210 +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. - */ - -package com.android.systemui.statusbar.phone; - -import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Point; -import android.graphics.Rect; -import android.os.Handler; -import android.view.CompositionSamplingListener; -import android.view.View; - -import com.android.systemui.R; -import com.android.systemui.shared.system.QuickStepContract; - -import java.io.PrintWriter; - -/** - * Updates the nav bar tint based on the color of the content behind the nav bar. - */ -public class NavBarTintController implements View.OnAttachStateChangeListener, - View.OnLayoutChangeListener { - - public static final int MIN_COLOR_ADAPT_TRANSITION_TIME = 400; - public static final int DEFAULT_COLOR_ADAPT_TRANSITION_TIME = 1700; - - private final Handler mHandler = new Handler(); - private final NavigationBarView mNavigationBarView; - private final LightBarTransitionsController mLightBarController; - private int mNavBarMode = NAV_BAR_MODE_3BUTTON; - private boolean mWindowVisible; - - private final CompositionSamplingListener mSamplingListener; - private final Runnable mUpdateSamplingListener = this::updateSamplingListener; - private final Rect mSamplingBounds = new Rect(); - private boolean mSamplingEnabled = false; - private boolean mSamplingListenerRegistered = false; - - private float mLastMedianLuma; - private float mCurrentMedianLuma; - private boolean mUpdateOnNextDraw; - - private final int mNavBarHeight; - private final int mNavColorSampleMargin; - - // Passing the threshold of this luminance value will make the button black otherwise white - private final float mLuminanceThreshold; - private final float mLuminanceChangeThreshold; - - public NavBarTintController(NavigationBarView navigationBarView, - LightBarTransitionsController lightBarController) { - mSamplingListener = new CompositionSamplingListener( - navigationBarView.getContext().getMainExecutor()) { - @Override - public void onSampleCollected(float medianLuma) { - updateTint(medianLuma); - } - }; - mNavigationBarView = navigationBarView; - mNavigationBarView.addOnAttachStateChangeListener(this); - mNavigationBarView.addOnLayoutChangeListener(this); - mLightBarController = lightBarController; - - final Resources res = navigationBarView.getResources(); - mNavBarHeight = res.getDimensionPixelSize(R.dimen.navigation_bar_height); - mNavColorSampleMargin = - res.getDimensionPixelSize(R.dimen.navigation_handle_sample_horizontal_margin); - mLuminanceThreshold = res.getFloat(R.dimen.navigation_luminance_threshold); - mLuminanceChangeThreshold = res.getFloat(R.dimen.navigation_luminance_change_threshold); - } - - void onDraw() { - if (mUpdateOnNextDraw) { - mUpdateOnNextDraw = false; - requestUpdateSamplingListener(); - } - } - - void start() { - if (!isEnabled(mNavigationBarView.getContext(), mNavBarMode)) { - return; - } - mSamplingEnabled = true; - // Defer calling updateSamplingListener since we may have just reinflated prior to this - requestUpdateSamplingListener(); - } - - void stop() { - mSamplingEnabled = false; - requestUpdateSamplingListener(); - } - - @Override - public void onViewAttachedToWindow(View view) { - requestUpdateSamplingListener(); - } - - @Override - public void onViewDetachedFromWindow(View view) { - // Defer calling updateSamplingListener the attach info has not yet been reset - requestUpdateSamplingListener(); - } - - @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, - int oldLeft, int oldTop, int oldRight, int oldBottom) { - mSamplingBounds.setEmpty(); - // TODO: Extend this to 2/3 button layout as well - View view = mNavigationBarView.getHomeHandle().getCurrentView(); - if (view != null) { - int[] pos = new int[2]; - view.getLocationOnScreen(pos); - Point displaySize = new Point(); - view.getContext().getDisplay().getRealSize(displaySize); - final Rect samplingBounds = new Rect(pos[0] - mNavColorSampleMargin, - displaySize.y - mNavBarHeight, pos[0] + view.getWidth() + mNavColorSampleMargin, - displaySize.y); - if (!samplingBounds.equals(mSamplingBounds)) { - mSamplingBounds.set(samplingBounds); - requestUpdateSamplingListener(); - } - } - } - - private void requestUpdateSamplingListener() { - mHandler.removeCallbacks(mUpdateSamplingListener); - mHandler.post(mUpdateSamplingListener); - } - - private void updateSamplingListener() { - if (mSamplingListenerRegistered) { - mSamplingListenerRegistered = false; - CompositionSamplingListener.unregister(mSamplingListener); - } - if (mSamplingEnabled && mWindowVisible && !mSamplingBounds.isEmpty() - && mNavigationBarView.isAttachedToWindow()) { - if (!mNavigationBarView.getViewRootImpl().getSurfaceControl().isValid()) { - // The view may still be attached, but the surface backing the window can be - // destroyed, so wait until the next draw to update the listener again - mUpdateOnNextDraw = true; - return; - } - mSamplingListenerRegistered = true; - CompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY, - mNavigationBarView.getViewRootImpl().getSurfaceControl(), - mSamplingBounds); - } - } - - private void updateTint(float medianLuma) { - mLastMedianLuma = medianLuma; - - // If the difference between the new luma and the current luma is larger than threshold - // then apply the current luma, this is to prevent small changes causing colors to flicker - if (Math.abs(mCurrentMedianLuma - mLastMedianLuma) > mLuminanceChangeThreshold) { - if (medianLuma > mLuminanceThreshold) { - // Black - mLightBarController.setIconsDark(true /* dark */, true /* animate */); - } else { - // White - mLightBarController.setIconsDark(false /* dark */, true /* animate */); - } - mCurrentMedianLuma = medianLuma; - } - } - - public void setWindowVisible(boolean visible) { - mWindowVisible = visible; - requestUpdateSamplingListener(); - } - - public void onNavigationModeChanged(int mode) { - mNavBarMode = mode; - } - - void dump(PrintWriter pw) { - pw.println("NavBarTintController:"); - pw.println(" navBar isAttached: " + mNavigationBarView.isAttachedToWindow()); - pw.println(" navBar isScValid: " + (mNavigationBarView.isAttachedToWindow() - ? mNavigationBarView.getViewRootImpl().getSurfaceControl().isValid() - : "false")); - pw.println(" mSamplingListenerRegistered: " + mSamplingListenerRegistered); - pw.println(" mSamplingBounds: " + mSamplingBounds); - pw.println(" mLastMedianLuma: " + mLastMedianLuma); - pw.println(" mCurrentMedianLuma: " + mCurrentMedianLuma); - pw.println(" mWindowVisible: " + mWindowVisible); - } - - public static boolean isEnabled(Context context, int navBarMode) { - return context.getDisplayId() == DEFAULT_DISPLAY - && QuickStepContract.isGesturalMode(navBarMode); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index e9731c521308..5d3f3ac52395 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -1063,16 +1063,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback if (Intent.ACTION_SCREEN_OFF.equals(action) || Intent.ACTION_SCREEN_ON.equals(action)) { notifyNavigationBarScreenOn(); - - if (Intent.ACTION_SCREEN_ON.equals(action)) { - // Enabled and screen is on, start it again if enabled - if (NavBarTintController.isEnabled(getContext(), mNavBarMode)) { - mNavigationBarView.getTintController().start(); - } - } else { - // Screen off disable it - mNavigationBarView.getTintController().stop(); - } + mNavigationBarView.onScreenStateChanged(Intent.ACTION_SCREEN_ON.equals(action)); } if (Intent.ACTION_USER_SWITCHED.equals(action)) { // The accessibility settings may be different for the new user diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java index 23cc0fc51ec0..3b590315a5ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java @@ -18,8 +18,7 @@ package com.android.systemui.statusbar.phone; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; -import static com.android.systemui.statusbar.phone.NavBarTintController.DEFAULT_COLOR_ADAPT_TRANSITION_TIME; -import static com.android.systemui.statusbar.phone.NavBarTintController.MIN_COLOR_ADAPT_TRANSITION_TIME; +import static com.android.systemui.util.Utils.isGesturalModeOnDefaultDisplay; import android.content.Context; import android.graphics.Rect; @@ -42,6 +41,9 @@ import java.util.List; public final class NavigationBarTransitions extends BarTransitions implements LightBarTransitionsController.DarkIntensityApplier { + public static final int MIN_COLOR_ADAPT_TRANSITION_TIME = 400; + public static final int DEFAULT_COLOR_ADAPT_TRANSITION_TIME = 1700; + /** * Notified when the color of nav bar elements changes. */ @@ -124,7 +126,7 @@ public final class NavigationBarTransitions extends BarTransitions implements @Override public void setAutoDim(boolean autoDim) { // Ensure we aren't in gestural nav if we are triggering auto dim - if (autoDim && NavBarTintController.isEnabled(mView.getContext(), mNavBarMode)) return; + if (autoDim && isGesturalModeOnDefaultDisplay(mView.getContext(), mNavBarMode)) return; if (mAutoDim == autoDim) return; mAutoDim = autoDim; applyLightsOut(true, false); @@ -201,7 +203,7 @@ public final class NavigationBarTransitions extends BarTransitions implements @Override public int getTintAnimationDuration() { - if (NavBarTintController.isEnabled(mView.getContext(), mNavBarMode)) { + if (isGesturalModeOnDefaultDisplay(mView.getContext(), mNavBarMode)) { return Math.max(DEFAULT_COLOR_ADAPT_TRANSITION_TIME, MIN_COLOR_ADAPT_TRANSITION_TIME); } return LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION; 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 f689a3eadf58..3485f233222c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.phone; -import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; +import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; 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; @@ -26,6 +26,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_S 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; +import static com.android.systemui.util.Utils.isGesturalModeOnDefaultDisplay; import android.animation.LayoutTransition; import android.animation.LayoutTransition.TransitionListener; @@ -89,6 +90,8 @@ public class NavigationBarView extends FrameLayout implements final static boolean SLIPPERY_WHEN_DISABLED = true; final static boolean ALTERNATE_CAR_MODE_UI = false; + private final RegionSamplingHelper mRegionSamplingHelper; + private final int mNavColorSampleMargin; View mCurrentView = null; private View mVertical; @@ -101,7 +104,7 @@ public class NavigationBarView extends FrameLayout implements boolean mLongClickableAccessibilityButton; int mDisabledFlags = 0; int mNavigationIconHints = 0; - private int mNavBarMode = NAV_BAR_MODE_3BUTTON; + private int mNavBarMode; private Rect mHomeButtonBounds = new Rect(); private Rect mBackButtonBounds = new Rect(); @@ -143,14 +146,13 @@ public class NavigationBarView extends FrameLayout implements private FloatingRotationButton mFloatingRotationButton; private RotationButtonController mRotationButtonController; - private NavBarTintController mTintController; - /** * Helper that is responsible for showing the right toast when a disallowed activity operation * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in * fully locked mode we only show that unlocking is blocked. */ private ScreenPinningNotify mScreenPinningNotify; + private Rect mSamplingBounds = new Rect(); private class NavTransitionListener implements TransitionListener { private boolean mBackTransitioning; @@ -305,12 +307,30 @@ public class NavigationBarView extends FrameLayout implements mButtonDispatchers.put(R.id.menu_container, mContextualButtonGroup); mDeadZone = new DeadZone(this); - mEdgeBackGestureHandler = new EdgeBackGestureHandler(context, mOverviewProxyService); - mTintController = new NavBarTintController(this, getLightTransitionsController()); - } + mNavColorSampleMargin = + getResources() + .getDimensionPixelSize(R.dimen.navigation_handle_sample_horizontal_margin); - public NavBarTintController getTintController() { - return mTintController; + mEdgeBackGestureHandler = new EdgeBackGestureHandler(context, mOverviewProxyService); + mRegionSamplingHelper = new RegionSamplingHelper(this, + new RegionSamplingHelper.SamplingCallback() { + @Override + public void onRegionDarknessChanged(boolean isRegionDark) { + getLightTransitionsController().setIconsDark(!isRegionDark , + true /* animate */); + } + + @Override + public Rect getSampledRegion(View sampledView) { + updateSamplingRect(); + return mSamplingBounds; + } + + @Override + public boolean isSamplingEnabled() { + return isGesturalModeOnDefaultDisplay(getContext(), mNavBarMode); + } + }); } public NavigationBarTransitions getBarTransitions() { @@ -326,12 +346,6 @@ public class NavigationBarView extends FrameLayout implements updatePanelSystemUiStateFlags(); } - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - mTintController.onDraw(); - } - public void setOnVerticalChangedListener(OnVerticalChangedListener onVerticalChangedListener) { mOnVerticalChangedListener = onVerticalChangedListener; notifyVerticalChangedListener(mIsVertical); @@ -352,10 +366,10 @@ public class NavigationBarView extends FrameLayout implements if (newMode == MODE_OPAQUE) { // If the nav bar background is opaque, stop auto tinting since we know the icons are // showing over a dark background - mTintController.stop(); + mRegionSamplingHelper.stop(); getLightTransitionsController().setIconsDark(false /* dark */, true /* animate */); } else { - mTintController.start(); + mRegionSamplingHelper.start(mSamplingBounds); } } @@ -535,8 +549,19 @@ public class NavigationBarView extends FrameLayout implements return KeyButtonDrawable.create(mContext, icon, hasShadow); } + /** To be called when screen lock/unlock state changes */ + public void onScreenStateChanged(boolean isScreenOn) { + if (isScreenOn) { + if (isGesturalModeOnDefaultDisplay(getContext(), mNavBarMode)) { + mRegionSamplingHelper.start(mSamplingBounds); + } + } else { + mRegionSamplingHelper.stop(); + } + } + public void setWindowVisible(boolean visible) { - mTintController.setWindowVisible(visible); + mRegionSamplingHelper.setWindowVisible(visible); mRotationButtonController.onNavigationBarWindowVisibilityChange(visible); } @@ -799,13 +824,7 @@ public class NavigationBarView extends FrameLayout implements mRecentsOnboarding.onNavigationModeChanged(mNavBarMode); getRotateSuggestionButton().onNavigationModeChanged(mNavBarMode); - // Color adaption is tied with showing home handle, only avaliable if visible - mTintController.onNavigationModeChanged(mNavBarMode); - if (isGesturalMode(mNavBarMode)) { - mTintController.start(); - } else { - mTintController.stop(); - } + mRegionSamplingHelper.start(mSamplingBounds); } public void setAccessibilityButtonState(final boolean visible, final boolean longClickable) { @@ -836,6 +855,24 @@ public class NavigationBarView extends FrameLayout implements super.onDraw(canvas); } + private void updateSamplingRect() { + mSamplingBounds.setEmpty(); + // TODO: Extend this to 2/3 button layout as well + View view = getHomeHandle().getCurrentView(); + + if (view != null) { + int[] pos = new int[2]; + view.getLocationOnScreen(pos); + Point displaySize = new Point(); + view.getContext().getDisplay().getRealSize(displaySize); + final Rect samplingBounds = new Rect(pos[0] - mNavColorSampleMargin, + displaySize.y - getNavBarHeight(), + pos[0] + view.getWidth() + mNavColorSampleMargin, + displaySize.y); + mSamplingBounds.set(samplingBounds); + } + } + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); @@ -920,7 +957,8 @@ public class NavigationBarView extends FrameLayout implements } public void showPinningEscapeToast() { - mScreenPinningNotify.showEscapeToast(isRecentsButtonVisible()); + mScreenPinningNotify.showEscapeToast( + mNavBarMode == NAV_BAR_MODE_GESTURAL, isRecentsButtonVisible()); } public boolean isVertical() { @@ -984,6 +1022,14 @@ public class NavigationBarView extends FrameLayout implements super.onMeasure(widthMeasureSpec, heightMeasureSpec); } + private int getNavBarHeight() { + return mIsVertical + ? getResources().getDimensionPixelSize( + com.android.internal.R.dimen.navigation_bar_height_landscape) + : getResources().getDimensionPixelSize( + com.android.internal.R.dimen.navigation_bar_height); + } + private void notifyVerticalChangedListener(boolean newVertical) { if (mOnVerticalChangedListener != null) { mOnVerticalChangedListener.onVerticalChanged(newVertical); @@ -1130,7 +1176,7 @@ public class NavigationBarView extends FrameLayout implements mContextualButtonGroup.dump(pw); mRecentsOnboarding.dump(pw); - mTintController.dump(pw); + mRegionSamplingHelper.dump(pw); mEdgeBackGestureHandler.dump(pw); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java index 9988c85361bb..5d8044f37c38 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.phone; -import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; +import static android.view.Display.DEFAULT_DISPLAY; import android.annotation.IntDef; import android.content.ComponentCallbacks; @@ -29,8 +29,6 @@ import android.net.Uri; import android.os.Handler; import android.provider.Settings; -import com.android.systemui.shared.system.QuickStepContract; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -120,8 +118,7 @@ public class NavigationPrototypeController extends ContentObserver implements Co } else if (path.endsWith(HIDE_HOME_BUTTON_SETTING)) { mListener.onHomeButtonVisibilityChanged(!hideHomeButton()); } else if (path.endsWith(NAV_COLOR_ADAPT_ENABLE_SETTING)) { - mListener.onColorAdaptChanged( - NavBarTintController.isEnabled(mContext, NAV_BAR_MODE_GESTURAL)); + mListener.onColorAdaptChanged(mContext.getDisplayId() == DEFAULT_DISPLAY); } else if (path.endsWith(SHOW_HOME_HANDLE_SETTING)) { mListener.onHomeHandleVisiblilityChanged(showHomeHandle()); } else if (path.endsWith(ENABLE_ASSISTANT_GESTURE)) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RegionSamplingHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RegionSamplingHelper.java index 8026f654414c..c1ff572bb210 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RegionSamplingHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RegionSamplingHelper.java @@ -29,6 +29,8 @@ import android.view.ViewTreeObserver; import com.android.systemui.R; +import java.io.PrintWriter; + /** * A helper class to sample regions on the screen and inspect its luminosity. */ @@ -62,6 +64,7 @@ public class RegionSamplingHelper implements View.OnAttachStateChangeListener, private final float mLuminanceThreshold; private final float mLuminanceChangeThreshold; private boolean mFirstSamplingAfterStart; + private boolean mWindowVisible; private SurfaceControl mRegisteredStopLayer = null; private ViewTreeObserver.OnDrawListener mUpdateOnDraw = new ViewTreeObserver.OnDrawListener() { @Override @@ -148,7 +151,9 @@ public class RegionSamplingHelper implements View.OnAttachStateChangeListener, } private void updateSamplingListener() { - boolean isSamplingEnabled = mSamplingEnabled && !mSamplingRequestBounds.isEmpty() + boolean isSamplingEnabled = mSamplingEnabled + && !mSamplingRequestBounds.isEmpty() + && mWindowVisible && (mSampledView.isAttachedToWindow() || mFirstSamplingAfterStart); if (isSamplingEnabled) { ViewRootImpl viewRootImpl = mSampledView.getViewRootImpl(); @@ -216,6 +221,24 @@ public class RegionSamplingHelper implements View.OnAttachStateChangeListener, } } + void setWindowVisible(boolean visible) { + mWindowVisible = visible; + updateSamplingListener(); + } + + void dump(PrintWriter pw) { + pw.println("RegionSamplingHelper:"); + pw.println(" sampleView isAttached: " + mSampledView.isAttachedToWindow()); + pw.println(" sampleView isScValid: " + (mSampledView.isAttachedToWindow() + ? mSampledView.getViewRootImpl().getSurfaceControl().isValid() + : "false")); + pw.println(" mSamplingListenerRegistered: " + mSamplingListenerRegistered); + pw.println(" mSamplingRequestBounds: " + mSamplingRequestBounds); + pw.println(" mLastMedianLuma: " + mLastMedianLuma); + pw.println(" mCurrentMedianLuma: " + mCurrentMedianLuma); + pw.println(" mWindowVisible: " + mWindowVisible); + } + public interface SamplingCallback { /** * Called when the darkness of the sampled region changes diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenPinningNotify.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenPinningNotify.java index f8731b4980d9..071e00d08d67 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenPinningNotify.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenPinningNotify.java @@ -51,7 +51,7 @@ public class ScreenPinningNotify { } /** Show a toast that describes the gesture the user should use to escape pinned mode. */ - public void showEscapeToast(boolean isRecentsButtonVisible) { + public void showEscapeToast(boolean isGestureNavEnabled, boolean isRecentsButtonVisible) { long showToastTime = SystemClock.elapsedRealtime(); if ((showToastTime - mLastShowToastTime) < SHOW_TOAST_MINIMUM_INTERVAL) { Slog.i(TAG, "Ignore toast since it is requested in very short interval."); @@ -60,9 +60,11 @@ public class ScreenPinningNotify { if (mLastToast != null) { mLastToast.cancel(); } - mLastToast = makeAllUserToastAndShow(isRecentsButtonVisible - ? R.string.screen_pinning_toast - : R.string.screen_pinning_toast_recents_invisible); + mLastToast = makeAllUserToastAndShow(isGestureNavEnabled + ? R.string.screen_pinning_toast_gesture_nav + : isRecentsButtonVisible + ? R.string.screen_pinning_toast + : R.string.screen_pinning_toast_recents_invisible); mLastShowToastTime = showToastTime; } 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 b12bf5c39970..a7262cfcfefb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -47,6 +47,7 @@ import com.android.systemui.R; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.statusbar.ScrimView; import com.android.systemui.statusbar.notification.stack.ViewState; +import com.android.systemui.statusbar.policy.KeyguardMonitor; import com.android.systemui.util.AlarmTimeout; import com.android.systemui.util.wakelock.DelayedWakeLock; import com.android.systemui.util.wakelock.WakeLock; @@ -177,7 +178,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront, TriConsumer<ScrimState, Float, GradientColors> scrimStateListener, Consumer<Integer> scrimVisibleListener, DozeParameters dozeParameters, - AlarmManager alarmManager) { + AlarmManager alarmManager, KeyguardMonitor keyguardMonitor) { mScrimBehind = scrimBehind; mScrimInFront = scrimInFront; mScrimStateListener = scrimStateListener; @@ -197,6 +198,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo // to make sure that text on top of it is legible. mScrimBehindAlpha = mScrimBehindAlphaResValue; mDozeParameters = dozeParameters; + keyguardMonitor.addCallback(new KeyguardMonitor.Callback() { + @Override + public void onKeyguardFadingAwayChanged() { + setKeyguardFadingAway(keyguardMonitor.isKeyguardFadingAway(), + keyguardMonitor.getKeyguardFadingAwayDuration()); + } + }); mColorExtractor = Dependency.get(SysuiColorExtractor.class); mColorExtractor.addOnColorsChangedListener(this); @@ -948,9 +956,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo } } - public void setUnlockIsFading(boolean unlockFading) { + private void setKeyguardFadingAway(boolean fadingAway, long duration) { for (ScrimState state : ScrimState.values()) { - state.setUnlockIsFading(unlockFading); + state.setKeyguardFadingAway(fadingAway, duration); } } 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 b45914b2e83d..9fdd3b88e9d0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -156,8 +156,8 @@ public enum ScrimState { public void prepare(ScrimState previousState) { mCurrentBehindAlpha = 0; mCurrentInFrontAlpha = 0; - mAnimationDuration = mUnlockIsFading - ? KeyguardBypassController.BYPASS_PANEL_FADE_DURATION + mAnimationDuration = mKeyguardFadingAway + ? mKeyguardFadingAwayDuration : StatusBar.FADE_KEYGUARD_DURATION; mAnimateChange = !mLaunchingAffordanceWithPreview; @@ -209,7 +209,8 @@ public enum ScrimState { boolean mHasBackdrop; boolean mLaunchingAffordanceWithPreview; boolean mWakeLockScreenSensorActive; - boolean mUnlockIsFading; + boolean mKeyguardFadingAway; + long mKeyguardFadingAwayDuration; ScrimState(int index) { mIndex = index; @@ -298,7 +299,8 @@ public enum ScrimState { mWakeLockScreenSensorActive = active; } - public void setUnlockIsFading(boolean unlockIsFading) { - mUnlockIsFading = unlockIsFading; + public void setKeyguardFadingAway(boolean fadingAway, long duration) { + mKeyguardFadingAway = fadingAway; + mKeyguardFadingAwayDuration = duration; } }
\ No newline at end of file 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 90aba879f510..f158ca1eaf5b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -948,7 +948,8 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarWindow.onScrimVisibilityChanged(scrimsVisible); } }, DozeParameters.getInstance(mContext), - mContext.getSystemService(AlarmManager.class)); + mContext.getSystemService(AlarmManager.class), + mKeyguardMonitor); mNotificationPanel.initDependencies(this, mGroupManager, mNotificationShelf, mHeadsUpManager, mNotificationIconAreaController, mScrimController); mDozeScrimController = new DozeScrimController(DozeParameters.getInstance(context)); @@ -3874,7 +3875,6 @@ public class StatusBar extends SystemUI implements DemoMode, public void notifyBiometricAuthModeChanged() { updateDozing(); - mScrimController.setUnlockIsFading(mBiometricUnlockController.isUnlockFading()); updateScrimController(); mStatusBarWindow.onBiometricAuthModeChanged(mBiometricUnlockController.isWakeAndUnlock(), mBiometricUnlockController.isBiometricUnlock()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java index 830b50e35490..8b06a9fa05a1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java @@ -20,6 +20,8 @@ import com.android.systemui.Dumpable; import com.android.systemui.statusbar.policy.HotspotController.Callback; public interface HotspotController extends CallbackController<Callback>, Dumpable { + void handleSetListening(boolean listening); + boolean isHotspotEnabled(); boolean isHotspotTransient(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java index db2be0e78e9a..1c6d12f15e4c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java @@ -51,6 +51,7 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof private int mHotspotState; private int mNumConnectedDevices; private boolean mWaitingForTerminalState; + private boolean mListening; /** */ @@ -105,14 +106,18 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof if (DEBUG) Log.d(TAG, "addCallback " + callback); mCallbacks.add(callback); if (mWifiManager != null) { - if (mCallbacks.size() == 1) { - mWifiManager.registerSoftApCallback(this, mMainHandler); - } else { - // mWifiManager#registerSoftApCallback triggers a call to onNumClientsChanged - // on the Main Handler. In order to always update the callback on added, we - // make this call when adding callbacks after the first. - mMainHandler.post(() -> - callback.onHotspotChanged(isHotspotEnabled(), mNumConnectedDevices)); + if (mListening) { + if (mCallbacks.size() == 1) { + mWifiManager.registerSoftApCallback(this, mMainHandler); + } else { + // mWifiManager#registerSoftApCallback triggers a call to + // onNumClientsChanged on the Main Handler. In order to always update the + // callback on added, we make this call when adding callbacks after the + // first. + mMainHandler.post(() -> + callback.onHotspotChanged(isHotspotEnabled(), + mNumConnectedDevices)); + } } } } @@ -124,13 +129,24 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof if (DEBUG) Log.d(TAG, "removeCallback " + callback); synchronized (mCallbacks) { mCallbacks.remove(callback); - if (mCallbacks.isEmpty() && mWifiManager != null) { + if (mCallbacks.isEmpty() && mWifiManager != null && mListening) { mWifiManager.unregisterSoftApCallback(this); } } } @Override + public void handleSetListening(boolean listening) { + // Wait for the first |handleSetListening(true))| to register softap callbacks (for lazy + // registration of the softap callbacks). + if (mListening || !listening) return; + mListening = true; + if (mCallbacks.size() >= 1) { + mWifiManager.registerSoftApCallback(this, mMainHandler); + } + } + + @Override public boolean isHotspotEnabled() { return mHotspotState == WifiManager.WIFI_AP_STATE_ENABLED; } 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 070136ec94c1..e1ef809a883c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java @@ -76,7 +76,7 @@ public interface KeyguardMonitor extends CallbackController<Callback> { } interface Callback { - void onKeyguardShowingChanged(); + default void onKeyguardShowingChanged() {} default void onKeyguardFadingAwayChanged() {} } } 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 8829be4ee0f8..87ed14a9eeec 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java @@ -142,10 +142,10 @@ public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback } public void notifyKeyguardFadingAway(long delay, long fadeoutDuration, boolean isBypassFading) { - setKeyguardFadingAway(true); mKeyguardFadingAwayDelay = delay; mKeyguardFadingAwayDuration = fadeoutDuration; mBypassFadingAnimation = isBypassFading; + setKeyguardFadingAway(true); } private void setKeyguardFadingAway(boolean keyguardFadingAway) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index 45627631efe1..7acf4fd27ced 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -216,10 +216,14 @@ public class MobileSignalController extends SignalController< MobileIconGroup hGroup = TelephonyIcons.THREE_G; MobileIconGroup hPlusGroup = TelephonyIcons.THREE_G; - if (mConfig.hspaDataDistinguishable) { + if (mConfig.show4gFor3g) { + hGroup = TelephonyIcons.FOUR_G; + hPlusGroup = TelephonyIcons.FOUR_G; + } else if (mConfig.hspaDataDistinguishable) { hGroup = TelephonyIcons.H; hPlusGroup = TelephonyIcons.H_PLUS; } + mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup); mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup); mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup); @@ -533,8 +537,14 @@ public class MobileSignalController extends SignalController< return mConfig.nr5GIconMap.get(Config.NR_CONNECTED); } } else if (nrState == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED) { - if (mConfig.nr5GIconMap.containsKey(Config.NR_NOT_RESTRICTED)) { - return mConfig.nr5GIconMap.get(Config.NR_NOT_RESTRICTED); + if (mCurrentState.activityDormant) { + if (mConfig.nr5GIconMap.containsKey(Config.NR_NOT_RESTRICTED_RRC_IDLE)) { + return mConfig.nr5GIconMap.get(Config.NR_NOT_RESTRICTED_RRC_IDLE); + } + } else { + if (mConfig.nr5GIconMap.containsKey(Config.NR_NOT_RESTRICTED_RRC_CON)) { + return mConfig.nr5GIconMap.get(Config.NR_NOT_RESTRICTED_RRC_CON); + } } } else if (nrState == NetworkRegistrationInfo.NR_STATE_RESTRICTED) { if (mConfig.nr5GIconMap.containsKey(Config.NR_RESTRICTED)) { @@ -555,6 +565,8 @@ public class MobileSignalController extends SignalController< || activity == TelephonyManager.DATA_ACTIVITY_IN; mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT || activity == TelephonyManager.DATA_ACTIVITY_OUT; + mCurrentState.activityDormant = activity == TelephonyManager.DATA_ACTIVITY_DORMANT; + notifyListenersIfNecessary(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index d545dc8f7428..292571e1d9b2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -312,6 +312,7 @@ public class NetworkControllerImpl extends BroadcastReceiver filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(ConnectivityManager.INET_CONDITION_ACTION); filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); + filter.addAction(Intent.ACTION_BOOT_COMPLETED); filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); mContext.registerReceiver(this, filter, null, mReceiverHandler); mListening = true; @@ -513,6 +514,9 @@ public class NetworkControllerImpl extends BroadcastReceiver recalculateEmergency(); } break; + case Intent.ACTION_BOOT_COMPLETED: + mWifiSignalController.handleBootCompleted(); + break; case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED: mConfig = Config.readConfig(mContext); mReceiverHandler.post(this::handleConfigurationChanged); @@ -1108,12 +1112,14 @@ public class NetworkControllerImpl extends BroadcastReceiver static class Config { static final int NR_CONNECTED_MMWAVE = 1; static final int NR_CONNECTED = 2; - static final int NR_NOT_RESTRICTED = 3; - static final int NR_RESTRICTED = 4; + static final int NR_NOT_RESTRICTED_RRC_IDLE = 3; + static final int NR_NOT_RESTRICTED_RRC_CON = 4; + static final int NR_RESTRICTED = 5; Map<Integer, MobileIconGroup> nr5GIconMap = new HashMap<>(); boolean showAtLeast3G = false; + boolean show4gFor3g = false; boolean alwaysShowCdmaRssi = false; boolean show4gForLte = false; boolean hideLtePlus = false; @@ -1128,10 +1134,11 @@ public class NetworkControllerImpl extends BroadcastReceiver */ private static final Map<String, Integer> NR_STATUS_STRING_TO_INDEX; static { - NR_STATUS_STRING_TO_INDEX = new HashMap<>(4); + NR_STATUS_STRING_TO_INDEX = new HashMap<>(5); NR_STATUS_STRING_TO_INDEX.put("connected_mmwave", NR_CONNECTED_MMWAVE); NR_STATUS_STRING_TO_INDEX.put("connected", NR_CONNECTED); - NR_STATUS_STRING_TO_INDEX.put("not_restricted", NR_NOT_RESTRICTED); + NR_STATUS_STRING_TO_INDEX.put("not_restricted_rrc_idle", NR_NOT_RESTRICTED_RRC_IDLE); + NR_STATUS_STRING_TO_INDEX.put("not_restricted_rrc_con", NR_NOT_RESTRICTED_RRC_CON); NR_STATUS_STRING_TO_INDEX.put("restricted", NR_RESTRICTED); } @@ -1158,6 +1165,8 @@ public class NetworkControllerImpl extends BroadcastReceiver CarrierConfigManager.KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL); config.show4gForLte = b.getBoolean( CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL); + config.show4gFor3g = b.getBoolean( + CarrierConfigManager.KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL); config.hideLtePlus = b.getBoolean( CarrierConfigManager.KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL); config.patternOfCarrierSpecificDataIcon = b.getString( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java index 9ec30d43ac75..abe3f2c18891 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java @@ -258,6 +258,7 @@ public abstract class SignalController<T extends SignalController.State, boolean enabled; boolean activityIn; boolean activityOut; + public boolean activityDormant; int level; IconGroup iconGroup; int inetCondition; @@ -274,6 +275,7 @@ public abstract class SignalController<T extends SignalController.State, inetCondition = state.inetCondition; activityIn = state.activityIn; activityOut = state.activityOut; + activityDormant = state.activityDormant; rssi = state.rssi; time = state.time; } @@ -297,6 +299,7 @@ public abstract class SignalController<T extends SignalController.State, .append("iconGroup=").append(iconGroup).append(',') .append("activityIn=").append(activityIn).append(',') .append("activityOut=").append(activityOut).append(',') + .append("activityDormant=").append(activityDormant).append(',') .append("rssi=").append(rssi).append(',') .append("lastModified=").append(DateFormat.format("MM-dd HH:mm:ss", time)); } @@ -314,6 +317,7 @@ public abstract class SignalController<T extends SignalController.State, && other.iconGroup == iconGroup && other.activityIn == activityIn && other.activityOut == activityOut + && other.activityDormant == activityDormant && other.rssi == rssi; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java index 6f63544d3cfa..a441f660ecb7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java @@ -38,6 +38,7 @@ import java.util.Objects; public class WifiSignalController extends SignalController<WifiSignalController.WifiState, SignalController.IconGroup> { private final boolean mHasMobileData; + private final WifiManager mWifiManager; private final WifiStatusTracker mWifiTracker; public WifiSignalController(Context context, boolean hasMobileData, @@ -49,13 +50,11 @@ public class WifiSignalController extends context.getSystemService(NetworkScoreManager.class); ConnectivityManager connectivityManager = context.getSystemService(ConnectivityManager.class); + mWifiManager = wifiManager; mWifiTracker = new WifiStatusTracker(mContext, wifiManager, networkScoreManager, connectivityManager, this::handleStatusUpdated); mWifiTracker.setListening(true); mHasMobileData = hasMobileData; - if (wifiManager != null) { - wifiManager.registerTrafficStateCallback(new WifiTrafficStateCallback(), null); - } // WiFi only has one state. mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup( "Wi-Fi Icons", @@ -128,6 +127,10 @@ public class WifiSignalController extends notifyListenersIfNecessary(); } + public void handleBootCompleted() { + mWifiManager.registerTrafficStateCallback(new WifiTrafficStateCallback(), null); + } + /** * Handler to receive the data activity on wifi. */ diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java index 1102bb7e690e..92a8d8482e87 100644 --- a/packages/SystemUI/src/com/android/systemui/util/Utils.java +++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java @@ -14,12 +14,16 @@ package com.android.systemui.util; +import static android.view.Display.DEFAULT_DISPLAY; + import android.Manifest; +import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.view.View; import com.android.systemui.SysUiServiceProvider; +import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.CommandQueue; import java.util.List; @@ -110,4 +114,14 @@ public class Utils { return pm.queryIntentActivities(homeIntent, 0).isEmpty(); } + /** + * Returns {@code true} if the navMode is that of + * {@link android.view.WindowManagerPolicyConstants#NAV_BAR_MODE_GESTURAL} AND + * the context is that of the default display + */ + public static boolean isGesturalModeOnDefaultDisplay(Context context, int navMode) { + return context.getDisplayId() == DEFAULT_DISPLAY + && QuickStepContract.isGesturalMode(navMode); + } + } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDialogImplTest.java new file mode 100644 index 000000000000..8f2f8b1c0e63 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDialogImplTest.java @@ -0,0 +1,329 @@ +/* + * 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.biometrics; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNull; +import static junit.framework.TestCase.assertNotNull; + +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.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.ActivityManager; +import android.app.IActivityTaskManager; +import android.content.ComponentName; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.hardware.biometrics.BiometricPrompt; +import android.hardware.biometrics.IBiometricServiceReceiverInternal; +import android.os.Bundle; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableContext; +import android.testing.TestableLooper.RunWithLooper; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.phone.StatusBar; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +@SmallTest +public class BiometricDialogImplTest extends SysuiTestCase { + + @Mock + private PackageManager mPackageManager; + @Mock + private IBiometricServiceReceiverInternal mReceiver; + @Mock + private BiometricDialog mDialog1; + @Mock + private BiometricDialog mDialog2; + + private TestableBiometricDialogImpl mBiometricDialogImpl; + + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + TestableContext context = spy(mContext); + + mContext.putComponent(StatusBar.class, mock(StatusBar.class)); + mContext.putComponent(CommandQueue.class, mock(CommandQueue.class)); + + when(context.getPackageManager()).thenReturn(mPackageManager); + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) + .thenReturn(true); + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) + .thenReturn(true); + + when(mDialog1.getOpPackageName()).thenReturn("Dialog1"); + when(mDialog2.getOpPackageName()).thenReturn("Dialog2"); + + mBiometricDialogImpl = new TestableBiometricDialogImpl(new MockInjector()); + mBiometricDialogImpl.mContext = context; + mBiometricDialogImpl.mComponents = mContext.getComponents(); + + mBiometricDialogImpl.start(); + } + + // Callback tests + + @Test + public void testSendsReasonUserCanceled_whenDismissedByUserCancel() throws Exception { + showDialog(BiometricPrompt.TYPE_FACE); + mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_USER_CANCELED); + verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL); + } + + @Test + public void testSendsReasonNegative_whenDismissedByButtonNegative() throws Exception { + showDialog(BiometricPrompt.TYPE_FACE); + mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_BUTTON_NEGATIVE); + verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_NEGATIVE); + } + + @Test + public void testSendsReasonConfirmed_whenDismissedByButtonPositive() throws Exception { + showDialog(BiometricPrompt.TYPE_FACE); + mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_BUTTON_POSITIVE); + verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_CONFIRMED); + } + + @Test + public void testSendsReasonConfirmNotRequired_whenDismissedByAuthenticated() throws Exception { + showDialog(BiometricPrompt.TYPE_FACE); + mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_AUTHENTICATED); + verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_CONFIRM_NOT_REQUIRED); + } + + @Test + public void testSendsReasonError_whenDismissedByError() throws Exception { + showDialog(BiometricPrompt.TYPE_FACE); + mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_ERROR); + verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_ERROR); + } + + @Test + public void testSendsReasonDismissedBySystemServer_whenDismissedByServer() throws Exception { + showDialog(BiometricPrompt.TYPE_FACE); + mBiometricDialogImpl.onDismissed(DialogViewCallback.DISMISSED_BY_SYSTEM_SERVER); + verify(mReceiver).onDialogDismissed(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED); + } + + // Statusbar tests + + @Test + public void testShowInvoked_whenSystemRequested() + throws Exception { + showDialog(BiometricPrompt.TYPE_FACE); + verify(mDialog1).show(any(), eq(false) /* skipIntro */); + } + + @Test + public void testOnAuthenticationSucceededInvoked_whenSystemRequested() throws Exception { + showDialog(BiometricPrompt.TYPE_FACE); + mBiometricDialogImpl.onBiometricAuthenticated(true, null /* failureReason */); + verify(mDialog1).onAuthenticationSucceeded(); + } + + @Test + public void testOnAuthenticationFailedInvoked_whenSystemRequested() throws Exception { + showDialog(BiometricPrompt.TYPE_FACE); + final String failureReason = "failure reason"; + mBiometricDialogImpl.onBiometricAuthenticated(false, failureReason); + + ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); + verify(mDialog1).onAuthenticationFailed(captor.capture()); + + assertEquals(captor.getValue(), failureReason); + } + + @Test + public void testOnHelpInvoked_whenSystemRequested() throws Exception { + showDialog(BiometricPrompt.TYPE_FACE); + final String helpMessage = "help"; + mBiometricDialogImpl.onBiometricHelp(helpMessage); + + ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); + verify(mDialog1).onHelp(captor.capture()); + + assertEquals(captor.getValue(), helpMessage); + } + + @Test + public void testOnErrorInvoked_whenSystemRequested() throws Exception { + showDialog(BiometricPrompt.TYPE_FACE); + final String errMessage = "error message"; + mBiometricDialogImpl.onBiometricError(errMessage); + + ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); + verify(mDialog1).onError(captor.capture()); + + assertEquals(captor.getValue(), errMessage); + } + + @Test + public void testDismissWithoutCallbackInvoked_whenSystemRequested() throws Exception { + showDialog(BiometricPrompt.TYPE_FACE); + mBiometricDialogImpl.hideBiometricDialog(); + verify(mDialog1).dismissFromSystemServer(); + } + + @Test + public void testClientNotified_whenDismissedBySystemServer() throws Exception { + showDialog(BiometricPrompt.TYPE_FACE); + mBiometricDialogImpl.hideBiometricDialog(); + verify(mDialog1).dismissFromSystemServer(); + + assertNotNull(mBiometricDialogImpl.mCurrentDialog); + assertNotNull(mBiometricDialogImpl.mReceiver); + } + + // Corner case tests + + @Test + public void testShowNewDialog_beforeOldDialogDismissed_SkipsAnimations() throws Exception { + showDialog(BiometricPrompt.TYPE_FACE); + verify(mDialog1).show(any(), eq(false) /* skipIntro */); + + showDialog(BiometricPrompt.TYPE_FACE); + + // First dialog should be dismissed without animation + verify(mDialog1).dismissWithoutCallback(eq(false) /* animate */); + + // Second dialog should be shown without animation + verify(mDialog2).show(any(), eq(true)) /* skipIntro */; + } + + @Test + public void testConfigurationPersists_whenOnConfigurationChanged() throws Exception { + showDialog(BiometricPrompt.TYPE_FACE); + verify(mDialog1).show(any(), eq(false) /* skipIntro */); + + mBiometricDialogImpl.onConfigurationChanged(new Configuration()); + + ArgumentCaptor<Bundle> captor = ArgumentCaptor.forClass(Bundle.class); + verify(mDialog1).onSaveState(captor.capture()); + + // Old dialog doesn't animate + verify(mDialog1).dismissWithoutCallback(eq(false /* animate */)); + + // Saved state is restored into new dialog + ArgumentCaptor<Bundle> captor2 = ArgumentCaptor.forClass(Bundle.class); + verify(mDialog2).restoreState(captor2.capture()); + + // Dialog for new configuration skips intro + verify(mDialog2).show(any(), eq(true) /* skipIntro */); + + // TODO: This should check all values we want to save/restore + assertEquals(captor.getValue(), captor2.getValue()); + } + + @Test + public void testClientNotified_whenTaskStackChangesDuringAuthentication() throws Exception { + showDialog(BiometricPrompt.TYPE_FACE); + + List<ActivityManager.RunningTaskInfo> tasks = new ArrayList<>(); + ActivityManager.RunningTaskInfo taskInfo = mock(ActivityManager.RunningTaskInfo.class); + taskInfo.topActivity = mock(ComponentName.class); + when(taskInfo.topActivity.getPackageName()).thenReturn("other_package"); + tasks.add(taskInfo); + when(mBiometricDialogImpl.mActivityTaskManager.getTasks(anyInt())).thenReturn(tasks); + + mBiometricDialogImpl.mTaskStackListener.onTaskStackChanged(); + waitForIdleSync(); + + assertNull(mBiometricDialogImpl.mCurrentDialog); + assertNull(mBiometricDialogImpl.mReceiver); + verify(mDialog1).dismissWithoutCallback(true /* animate */); + verify(mReceiver).onDialogDismissed(eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL)); + } + + // Helpers + + private void showDialog(int type) { + mBiometricDialogImpl.showBiometricDialog(createTestDialogBundle(), + mReceiver /* receiver */, + type, + true /* requireConfirmation */, + 0 /* userId */, + "testPackage"); + } + + private Bundle createTestDialogBundle() { + Bundle bundle = new Bundle(); + + bundle.putCharSequence(BiometricPrompt.KEY_TITLE, "Title"); + bundle.putCharSequence(BiometricPrompt.KEY_SUBTITLE, "Subtitle"); + bundle.putCharSequence(BiometricPrompt.KEY_DESCRIPTION, "Description"); + bundle.putCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT, "Negative Button"); + + // RequireConfirmation is a hint to BiometricService. This can be forced to be required + // by user settings, and should be tested in BiometricService. + bundle.putBoolean(BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true); + + return bundle; + } + + private final class TestableBiometricDialogImpl extends BiometricDialogImpl { + private int mBuildCount = 0; + + public TestableBiometricDialogImpl(Injector injector) { + super(injector); + } + + @Override + protected BiometricDialog buildDialog(Bundle biometricPromptBundle, + boolean requireConfirmation, int userId, int type, String opPackageName) { + BiometricDialog dialog; + if (mBuildCount == 0) { + dialog = mDialog1; + } else if (mBuildCount == 1) { + dialog = mDialog2; + } else { + dialog = null; + } + mBuildCount++; + return dialog; + } + } + + private final class MockInjector extends BiometricDialogImpl.Injector { + @Override + IActivityTaskManager getActivityTaskManager() { + return mock(IActivityTaskManager.class); + } + } +} + diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/BiometricDialogViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/BiometricDialogViewTest.java new file mode 100644 index 000000000000..bbdd837bb446 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/BiometricDialogViewTest.java @@ -0,0 +1,204 @@ +/* + * 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.biometrics.ui; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotSame; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.Mockito.spy; + +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.hardware.biometrics.BiometricPrompt; +import android.os.Bundle; +import android.os.UserManager; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableContext; +import android.testing.TestableLooper.RunWithLooper; +import android.view.View; +import android.view.WindowManager; +import android.view.accessibility.AccessibilityManager; + +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.biometrics.DialogViewCallback; +import com.android.systemui.keyguard.WakefulnessLifecycle; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +@SmallTest +public class BiometricDialogViewTest extends SysuiTestCase { + + FaceDialogView mFaceDialogView; + + private static final String TITLE = "Title"; + private static final String SUBTITLE = "Subtitle"; + private static final String DESCRIPTION = "Description"; + private static final String NEGATIVE_BUTTON = "Negative Button"; + + private static final String TEST_HELP = "Help"; + + TestableContext mTestableContext; + @Mock + private DialogViewCallback mCallback; + @Mock + private UserManager mUserManager; + @Mock + private DevicePolicyManager mDpm; + + private static class Injector extends BiometricDialogView.Injector { + @Override + public WakefulnessLifecycle getWakefulnessLifecycle() { + final WakefulnessLifecycle lifecycle = new WakefulnessLifecycle(); + lifecycle.dispatchFinishedWakingUp(); + return lifecycle; + } + } + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mTestableContext = spy(mContext); + mTestableContext.addMockSystemService(UserManager.class, mUserManager); + mTestableContext.addMockSystemService(DevicePolicyManager.class, mDpm); + } + + @Test + public void testContentStates_confirmationRequired_authenticated() { + mFaceDialogView = buildFaceDialogView(mTestableContext, mCallback, + true /* requireConfirmation */); + mFaceDialogView.onAttachedToWindow(); + + // When starting authentication + assertEquals(View.VISIBLE, mFaceDialogView.mTitleText.getVisibility()); + assertEquals(View.VISIBLE, mFaceDialogView.mSubtitleText.getVisibility()); + assertEquals(View.VISIBLE, mFaceDialogView.mDescriptionText.getVisibility()); + assertEquals(View.INVISIBLE, mFaceDialogView.mErrorText.getVisibility()); + assertEquals(View.VISIBLE, mFaceDialogView.mPositiveButton.getVisibility()); + assertEquals(View.VISIBLE, mFaceDialogView.mNegativeButton.getVisibility()); + assertEquals(View.GONE, mFaceDialogView.mTryAgainButton.getVisibility()); + + // Contents are as expected + assertTrue(TITLE.contentEquals(mFaceDialogView.mTitleText.getText())); + assertTrue(SUBTITLE.contentEquals(mFaceDialogView.mSubtitleText.getText())); + assertTrue(DESCRIPTION.contentEquals(mFaceDialogView.mDescriptionText.getText())); + assertTrue(mFaceDialogView.mPositiveButton.getText().toString() + .contentEquals(mContext.getString(R.string.biometric_dialog_confirm))); + assertTrue(NEGATIVE_BUTTON.contentEquals(mFaceDialogView.mNegativeButton.getText())); + assertTrue(mFaceDialogView.mTryAgainButton.getText().toString() + .contentEquals(mContext.getString(R.string.biometric_dialog_try_again))); + + // When help message is received + mFaceDialogView.onHelp(TEST_HELP); + assertEquals(mFaceDialogView.mErrorText.getVisibility(), View.VISIBLE); + assertTrue(TEST_HELP.contentEquals(mFaceDialogView.mErrorText.getText())); + + // When authenticated, confirm button comes out + mFaceDialogView.onAuthenticationSucceeded(); + assertEquals(View.VISIBLE, mFaceDialogView.mPositiveButton.getVisibility()); + assertEquals(true, mFaceDialogView.mPositiveButton.isEnabled()); + } + + @Test + public void testContentStates_confirmationNotRequired_authenticated() { + mFaceDialogView = buildFaceDialogView(mTestableContext, mCallback, + false /* requireConfirmation */); + mFaceDialogView.onAttachedToWindow(); + mFaceDialogView.updateSize(FaceDialogView.SIZE_SMALL); + + assertEquals(View.INVISIBLE, mFaceDialogView.mTitleText.getVisibility()); + assertNotSame(View.VISIBLE, mFaceDialogView.mSubtitleText.getVisibility()); + assertNotSame(View.VISIBLE, mFaceDialogView.mDescriptionText.getVisibility()); + assertEquals(View.INVISIBLE, mFaceDialogView.mErrorText.getVisibility()); + assertEquals(View.GONE, mFaceDialogView.mPositiveButton.getVisibility()); + assertEquals(View.GONE, mFaceDialogView.mTryAgainButton.getVisibility()); + assertEquals(View.GONE, mFaceDialogView.mTryAgainButton.getVisibility()); + } + + @Test + public void testContentStates_confirmationNotRequired_help() { + mFaceDialogView = buildFaceDialogView(mTestableContext, mCallback, + false /* requireConfirmation */); + mFaceDialogView.onAttachedToWindow(); + + mFaceDialogView.onHelp(TEST_HELP); + assertEquals(mFaceDialogView.mErrorText.getVisibility(), View.VISIBLE); + assertTrue(TEST_HELP.contentEquals(mFaceDialogView.mErrorText.getText())); + } + + @Test + public void testBack_sendsUserCanceled() { + // TODO: Need robolectric framework to wait for handler to complete + } + + @Test + public void testScreenOff_sendsUserCanceled() { + // TODO: Need robolectric framework to wait for handler to complete + } + + @Test + public void testRestoreState_contentStatesCorrect() { + mFaceDialogView = buildFaceDialogView(mTestableContext, mCallback, + false /* requireConfirmation */); + mFaceDialogView.onAttachedToWindow(); + mFaceDialogView.onAuthenticationFailed(TEST_HELP); + + final Bundle bundle = new Bundle(); + mFaceDialogView.onSaveState(bundle); + + mFaceDialogView = buildFaceDialogView(mTestableContext, mCallback, + false /* requireConfirmation */); + mFaceDialogView.restoreState(bundle); + mFaceDialogView.onAttachedToWindow(); + + assertEquals(View.VISIBLE, mFaceDialogView.mTryAgainButton.getVisibility()); + } + + private FaceDialogView buildFaceDialogView(Context context, DialogViewCallback callback, + boolean requireConfirmation) { + return (FaceDialogView) new BiometricDialogView.Builder(context) + .setCallback(callback) + .setBiometricPromptBundle(createTestDialogBundle()) + .setRequireConfirmation(requireConfirmation) + .setUserId(0) + .setOpPackageName("test_package") + .build(BiometricDialogView.Builder.TYPE_FACE, new Injector()); + } + + private Bundle createTestDialogBundle() { + Bundle bundle = new Bundle(); + + bundle.putCharSequence(BiometricPrompt.KEY_TITLE, TITLE); + bundle.putCharSequence(BiometricPrompt.KEY_SUBTITLE, SUBTITLE); + bundle.putCharSequence(BiometricPrompt.KEY_DESCRIPTION, DESCRIPTION); + bundle.putCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT, NEGATIVE_BUTTON); + + // RequireConfirmation is a hint to BiometricService. This can be forced to be required + // by user settings, and should be tested in BiometricService. + bundle.putBoolean(BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true); + + return bundle; + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt new file mode 100644 index 000000000000..2bff5488937d --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt @@ -0,0 +1,142 @@ +/* + * 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.broadcast + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.IntentFilter +import android.os.Handler +import android.os.Looper +import android.os.UserHandle +import android.test.suitebuilder.annotation.SmallTest +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import com.android.systemui.SysuiTestCase +import junit.framework.Assert.assertSame +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +@SmallTest +class BroadcastDispatcherTest : SysuiTestCase() { + + companion object { + val user0 = UserHandle.of(0) + val user1 = UserHandle.of(1) + + fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture() + } + + @Mock + private lateinit var mockContext: Context + @Mock + private lateinit var mockUBRUser0: UserBroadcastDispatcher + @Mock + private lateinit var mockUBRUser1: UserBroadcastDispatcher + @Mock + private lateinit var broadcastReceiver: BroadcastReceiver + @Mock + private lateinit var broadcastReceiverOther: BroadcastReceiver + @Mock + private lateinit var intentFilter: IntentFilter + @Mock + private lateinit var intentFilterOther: IntentFilter + @Mock + private lateinit var mockHandler: Handler + + @Captor + private lateinit var argumentCaptor: ArgumentCaptor<ReceiverData> + + private lateinit var testableLooper: TestableLooper + private lateinit var broadcastDispatcher: BroadcastDispatcher + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + testableLooper = TestableLooper.get(this) + + broadcastDispatcher = TestBroadcastDispatcher( + mockContext, + Handler(testableLooper.looper), + testableLooper.looper, + mapOf(0 to mockUBRUser0, 1 to mockUBRUser1)) + } + + @Test + fun testAddingReceiverToCorrectUBR() { + broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler, user0) + broadcastDispatcher.registerReceiver( + broadcastReceiverOther, intentFilterOther, mockHandler, user1) + + testableLooper.processAllMessages() + + verify(mockUBRUser0).registerReceiver(capture(argumentCaptor)) + + assertSame(broadcastReceiver, argumentCaptor.value.receiver) + assertSame(intentFilter, argumentCaptor.value.filter) + + verify(mockUBRUser1).registerReceiver(capture(argumentCaptor)) + assertSame(broadcastReceiverOther, argumentCaptor.value.receiver) + assertSame(intentFilterOther, argumentCaptor.value.filter) + } + + @Test + fun testRemovingReceiversRemovesFromAllUBR() { + broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler, user0) + broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler, user1) + + broadcastDispatcher.unregisterReceiver(broadcastReceiver) + + testableLooper.processAllMessages() + + verify(mockUBRUser0).unregisterReceiver(broadcastReceiver) + verify(mockUBRUser1).unregisterReceiver(broadcastReceiver) + } + + @Test + fun testRemoveReceiverFromUser() { + broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler, user0) + broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler, user1) + + broadcastDispatcher.unregisterReceiverForUser(broadcastReceiver, user0) + + testableLooper.processAllMessages() + + verify(mockUBRUser0).unregisterReceiver(broadcastReceiver) + verify(mockUBRUser1, never()).unregisterReceiver(broadcastReceiver) + } + + private class TestBroadcastDispatcher( + context: Context, + mainHandler: Handler, + bgLooper: Looper, + var mockUBRMap: Map<Int, UserBroadcastDispatcher> + ) : BroadcastDispatcher(context, mainHandler, bgLooper) { + override fun createUBRForUser(userId: Int): UserBroadcastDispatcher { + return mockUBRMap.getOrDefault(userId, mock(UserBroadcastDispatcher::class.java)) + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt new file mode 100644 index 000000000000..011c2cd57588 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt @@ -0,0 +1,230 @@ +/* + * 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.broadcast + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.os.Handler +import android.os.UserHandle +import android.test.suitebuilder.annotation.SmallTest +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import com.android.systemui.SysuiTestCase +import junit.framework.Assert.assertEquals +import junit.framework.Assert.assertFalse +import junit.framework.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.eq +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.anyString +import org.mockito.Mockito.atLeastOnce +import org.mockito.Mockito.never +import org.mockito.Mockito.reset +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +@SmallTest +class UserBroadcastDispatcherTest : SysuiTestCase() { + + companion object { + private const val ACTION_1 = "com.android.systemui.tests.ACTION_1" + private const val ACTION_2 = "com.android.systemui.tests.ACTION_2" + private const val CATEGORY_1 = "com.android.systemui.tests.CATEGORY_1" + private const val CATEGORY_2 = "com.android.systemui.tests.CATEGORY_2" + private const val USER_ID = 0 + private val USER_HANDLE = UserHandle.of(USER_ID) + + fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture() + } + + @Mock + private lateinit var broadcastReceiver: BroadcastReceiver + @Mock + private lateinit var broadcastReceiverOther: BroadcastReceiver + @Mock + private lateinit var mockContext: Context + @Mock + private lateinit var mockHandler: Handler + + @Captor + private lateinit var argumentCaptor: ArgumentCaptor<IntentFilter> + + private lateinit var testableLooper: TestableLooper + private lateinit var universalBroadcastReceiver: UserBroadcastDispatcher + private lateinit var intentFilter: IntentFilter + private lateinit var intentFilterOther: IntentFilter + private lateinit var handler: Handler + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + testableLooper = TestableLooper.get(this) + handler = Handler(testableLooper.looper) + + universalBroadcastReceiver = UserBroadcastDispatcher( + mockContext, USER_ID, handler, testableLooper.looper) + } + + @Test + fun testNotRegisteredOnStart() { + testableLooper.processAllMessages() + verify(mockContext, never()).registerReceiver(any(), any()) + verify(mockContext, never()).registerReceiver(any(), any(), anyInt()) + verify(mockContext, never()).registerReceiver(any(), any(), anyString(), any()) + verify(mockContext, never()).registerReceiver(any(), any(), anyString(), any(), anyInt()) + verify(mockContext, never()).registerReceiverAsUser(any(), any(), any(), anyString(), any()) + } + + @Test + fun testSingleReceiverRegistered() { + intentFilter = IntentFilter(ACTION_1) + + universalBroadcastReceiver.registerReceiver( + ReceiverData(broadcastReceiver, intentFilter, mockHandler, USER_HANDLE)) + testableLooper.processAllMessages() + + assertTrue(universalBroadcastReceiver.isRegistered()) + verify(mockContext).registerReceiverAsUser( + any(), + eq(USER_HANDLE), + capture(argumentCaptor), + any(), + any()) + assertEquals(1, argumentCaptor.value.countActions()) + assertTrue(argumentCaptor.value.hasAction(ACTION_1)) + assertEquals(0, argumentCaptor.value.countCategories()) + } + + @Test + fun testSingleReceiverUnregistered() { + intentFilter = IntentFilter(ACTION_1) + + universalBroadcastReceiver.registerReceiver( + ReceiverData(broadcastReceiver, intentFilter, mockHandler, USER_HANDLE)) + testableLooper.processAllMessages() + reset(mockContext) + + assertTrue(universalBroadcastReceiver.isRegistered()) + + universalBroadcastReceiver.unregisterReceiver(broadcastReceiver) + testableLooper.processAllMessages() + + verify(mockContext, atLeastOnce()).unregisterReceiver(any()) + verify(mockContext, never()).registerReceiverAsUser(any(), any(), any(), any(), any()) + assertFalse(universalBroadcastReceiver.isRegistered()) + } + + @Test + fun testFilterHasAllActionsAndCategories_twoReceivers() { + intentFilter = IntentFilter(ACTION_1) + intentFilterOther = IntentFilter(ACTION_2).apply { + addCategory(CATEGORY_1) + addCategory(CATEGORY_2) + } + + universalBroadcastReceiver.registerReceiver( + ReceiverData(broadcastReceiver, intentFilter, mockHandler, USER_HANDLE)) + universalBroadcastReceiver.registerReceiver( + ReceiverData(broadcastReceiverOther, intentFilterOther, mockHandler, USER_HANDLE)) + + testableLooper.processAllMessages() + assertTrue(universalBroadcastReceiver.isRegistered()) + + verify(mockContext, times(2)).registerReceiverAsUser( + any(), + eq(USER_HANDLE), + capture(argumentCaptor), + any(), + any()) + + val lastFilter = argumentCaptor.value + + assertTrue(lastFilter.hasAction(ACTION_1)) + assertTrue(lastFilter.hasAction(ACTION_2)) + assertTrue(lastFilter.hasCategory(CATEGORY_1)) + assertTrue(lastFilter.hasCategory(CATEGORY_1)) + } + + @Test + fun testDispatchToCorrectReceiver() { + intentFilter = IntentFilter(ACTION_1) + intentFilterOther = IntentFilter(ACTION_2) + + universalBroadcastReceiver.registerReceiver( + ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE)) + universalBroadcastReceiver.registerReceiver( + ReceiverData(broadcastReceiverOther, intentFilterOther, handler, USER_HANDLE)) + + val intent = Intent(ACTION_2) + + universalBroadcastReceiver.onReceive(mockContext, intent) + testableLooper.processAllMessages() + + verify(broadcastReceiver, never()).onReceive(any(), any()) + verify(broadcastReceiverOther).onReceive(mockContext, intent) + } + + @Test + fun testDispatchToCorrectReceiver_differentFiltersSameReceiver() { + intentFilter = IntentFilter(ACTION_1) + intentFilterOther = IntentFilter(ACTION_2) + + universalBroadcastReceiver.registerReceiver( + ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE)) + universalBroadcastReceiver.registerReceiver( + ReceiverData(broadcastReceiver, intentFilterOther, handler, USER_HANDLE)) + + val intent = Intent(ACTION_2) + + universalBroadcastReceiver.onReceive(mockContext, intent) + testableLooper.processAllMessages() + + verify(broadcastReceiver).onReceive(mockContext, intent) + } + + @Test + fun testDispatchIntentWithoutCategories() { + intentFilter = IntentFilter(ACTION_1) + intentFilter.addCategory(CATEGORY_1) + intentFilterOther = IntentFilter(ACTION_1) + intentFilterOther.addCategory(CATEGORY_2) + + universalBroadcastReceiver.registerReceiver( + ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE)) + universalBroadcastReceiver.registerReceiver( + ReceiverData(broadcastReceiverOther, intentFilterOther, handler, USER_HANDLE)) + + val intent = Intent(ACTION_1) + + universalBroadcastReceiver.onReceive(mockContext, intent) + testableLooper.processAllMessages() + + verify(broadcastReceiver).onReceive(mockContext, intent) + verify(broadcastReceiverOther).onReceive(mockContext, intent) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java index 25a1a75b0cbf..fb4c1ec11faa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java @@ -133,8 +133,8 @@ public class ZigZagClassifierTest extends ClassifierTest { // This test looks just like testPass_horizontalZigZagVerticalStraight but with // a shorter y range, making it look more crooked. appendMoveEvent(0, 0); - appendMoveEvent(5, 10); - appendMoveEvent(-5, 20); + appendMoveEvent(6, 10); + appendMoveEvent(-6, 20); assertThat(mClassifier.isFalseTouch(), is(true)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java index 6dfb19ea075a..1e18e51bc079 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java @@ -45,11 +45,14 @@ import android.testing.UiThreadTest; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.util.wakelock.WakeLockFake; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidTestingRunner.class) @@ -58,6 +61,8 @@ public class DozeMachineTest extends SysuiTestCase { DozeMachine mMachine; + @Mock + private WakefulnessLifecycle mWakefulnessLifecycle; private DozeServiceFake mServiceFake; private WakeLockFake mWakeLockFake; private AmbientDisplayConfiguration mConfigMock; @@ -65,12 +70,13 @@ public class DozeMachineTest extends SysuiTestCase { @Before public void setUp() { + MockitoAnnotations.initMocks(this); mServiceFake = new DozeServiceFake(); mWakeLockFake = new WakeLockFake(); mConfigMock = mock(AmbientDisplayConfiguration.class); mPartMock = mock(DozeMachine.Part.class); - mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake); + mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake, mWakefulnessLifecycle); mMachine.setParts(new DozeMachine.Part[]{mPartMock}); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java index 1e1f21568377..b252a0d95f94 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java @@ -365,4 +365,45 @@ public class CommandQueueTest extends SysuiTestCase { waitForIdleSync(); verify(mCallbacks).onRecentsAnimationStateChanged(eq(true)); } + + @Test + public void testShowBiometricDialog() { + Bundle bundle = new Bundle(); + String packageName = "test"; + mCommandQueue.showBiometricDialog(bundle, null /* receiver */, 1, true, 3, packageName); + waitForIdleSync(); + verify(mCallbacks).showBiometricDialog(eq(bundle), eq(null), eq(1), eq(true), eq(3), + eq(packageName)); + } + + @Test + public void testOnBiometricAuthenticated() { + String failureReason = "test_failure_reason"; + mCommandQueue.onBiometricAuthenticated(true /* authenticated */, failureReason); + waitForIdleSync(); + verify(mCallbacks).onBiometricAuthenticated(eq(true), eq(failureReason)); + } + + @Test + public void testOnBiometricHelp() { + String helpMessage = "test_help_message"; + mCommandQueue.onBiometricHelp(helpMessage); + waitForIdleSync(); + verify(mCallbacks).onBiometricHelp(eq(helpMessage)); + } + + @Test + public void testOnBiometricError() { + String errorMessage = "test_error_message"; + mCommandQueue.onBiometricError(errorMessage); + waitForIdleSync(); + verify(mCallbacks).onBiometricError(eq(errorMessage)); + } + + @Test + public void testHideBiometricDialog() { + mCommandQueue.hideBiometricDialog(); + waitForIdleSync(); + verify(mCallbacks).hideBiometricDialog(); + } } 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 0dbf30881ffe..97ad47ec3f0c 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 @@ -47,6 +47,7 @@ import com.android.internal.colorextraction.ColorExtractor.GradientColors; import com.android.internal.util.function.TriConsumer; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.ScrimView; +import com.android.systemui.statusbar.policy.KeyguardMonitor; import com.android.systemui.util.wakelock.WakeLock; import com.android.systemui.utils.os.FakeHandler; @@ -96,7 +97,8 @@ public class ScrimControllerTest extends SysuiTestCase { mScrimBehindAlpha = scrimBehindAlpha; mScrimInFrontColor = scrimInFrontColor; }, - visible -> mScrimVisibility = visible, mDozeParamenters, mAlarmManager); + visible -> mScrimVisibility = visible, mDozeParamenters, mAlarmManager, + mock(KeyguardMonitor.class)); mScrimController.setHasBackdrop(false); mScrimController.setWallpaperSupportsAmbientMode(false); mScrimController.transitionTo(ScrimState.KEYGUARD); @@ -681,9 +683,9 @@ public class ScrimControllerTest extends SysuiTestCase { SynchronousScrimController(ScrimView scrimBehind, ScrimView scrimInFront, TriConsumer<ScrimState, Float, GradientColors> scrimStateListener, Consumer<Integer> scrimVisibleListener, DozeParameters dozeParameters, - AlarmManager alarmManager) { + AlarmManager alarmManager, KeyguardMonitor keyguardMonitor) { super(scrimBehind, scrimInFront, scrimStateListener, scrimVisibleListener, - dozeParameters, alarmManager); + dozeParameters, alarmManager, keyguardMonitor); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java index 3e4c4d6a7a8a..556ed5c30496 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java @@ -73,6 +73,7 @@ public class HotspotControllerImplTest extends SysuiTestCase { any(Handler.class)); mController = new HotspotControllerImpl(mContext, new Handler(mLooper.getLooper())); + mController.handleSetListening(true); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index 9ae9ceb2629f..e691b7dec0d9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -228,6 +228,18 @@ public class NetworkControllerBaseTest extends SysuiTestCase { NetworkControllerImpl.Config.add5GIconMapping("connected:5g", mConfig); } + public void setupNr5GIconConfigurationForNotRestrictedRrcCon() { + NetworkControllerImpl.Config.add5GIconMapping("connected_mmwave:5g_plus", mConfig); + NetworkControllerImpl.Config.add5GIconMapping("connected:5g_plus", mConfig); + NetworkControllerImpl.Config.add5GIconMapping("not_restricted_rrc_con:5g", mConfig); + } + + public void setupNr5GIconConfigurationForNotRestrictedRrcIdle() { + NetworkControllerImpl.Config.add5GIconMapping("connected_mmwave:5g_plus", mConfig); + NetworkControllerImpl.Config.add5GIconMapping("connected:5g_plus", mConfig); + NetworkControllerImpl.Config.add5GIconMapping("not_restricted_rrc_idle:5g", mConfig); + } + public void setConnectivityViaBroadcast( int networkType, boolean validated, boolean isConnected) { setConnectivityCommon(networkType, validated, isConnected); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java index 5128675e2723..f0394da6f479 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java @@ -175,6 +175,35 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { } @Test + public void testNr5GIcon_NrNotRestrictedRrcCon_show5GIcon() { + setupNr5GIconConfigurationForNotRestrictedRrcCon(); + setupDefaultSignal(); + updateDataConnectionState(TelephonyManager.DATA_CONNECTED, + TelephonyManager.NETWORK_TYPE_LTE); + updateDataActivity(TelephonyManager.DATA_ACTIVITY_INOUT); + ServiceState ss = Mockito.mock(ServiceState.class); + doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(ss).getNrState(); + mPhoneStateListener.onServiceStateChanged(ss); + + verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, TelephonyIcons.ICON_5G, + true, DEFAULT_QS_SIGNAL_STRENGTH, TelephonyIcons.ICON_5G, true, true); + } + + @Test + public void testNr5GIcon_NrNotRestrictedRrcIdle_show5GIcon() { + setupNr5GIconConfigurationForNotRestrictedRrcIdle(); + setupDefaultSignal(); + updateDataConnectionState(TelephonyManager.DATA_CONNECTED, + TelephonyManager.NETWORK_TYPE_LTE); + updateDataActivity(TelephonyManager.DATA_ACTIVITY_DORMANT); + ServiceState ss = Mockito.mock(ServiceState.class); + doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(ss).getNrState(); + mPhoneStateListener.onServiceStateChanged(ss); + + verifyDataIndicators(TelephonyIcons.ICON_5G); + } + + @Test public void testNr5GIcon_NrConnectedWithoutMMWave_show5GIcon() { setupDefaultNr5GIconConfiguration(); setupDefaultSignal(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java index 016160aea433..c9681ac558f9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java @@ -26,6 +26,10 @@ public class FakeHotspotController extends BaseLeakChecker<Callback> implements } @Override + public void handleSetListening(boolean listening) { + } + + @Override public boolean isHotspotEnabled() { return false; } diff --git a/services/Android.bp b/services/Android.bp index b08d1a8095db..54157d0b7eb1 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -35,6 +35,7 @@ java_library { "services.usage", "services.usb", "services.voiceinteraction", + "services.wifi", "android.hidl.base-V1.0-java", ], diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 6b88f5a9a6d7..5e9c08b4d480 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -348,13 +348,13 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } } - protected abstract boolean isCalledForCurrentUserLocked(); + protected abstract boolean hasRightsToCurrentUserLocked(); @Override public List<AccessibilityWindowInfo> getWindows() { ensureWindowsAvailableTimed(); synchronized (mLock) { - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return null; } final boolean permissionGranted = @@ -387,7 +387,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ public AccessibilityWindowInfo getWindow(int windowId) { ensureWindowsAvailableTimed(); synchronized (mLock) { - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return null; } final boolean permissionGranted = @@ -420,7 +420,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ MagnificationSpec spec; synchronized (mLock) { mUsesAccessibilityCache = true; - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return null; } resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); @@ -481,7 +481,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ MagnificationSpec spec; synchronized (mLock) { mUsesAccessibilityCache = true; - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return null; } resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); @@ -542,7 +542,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ MagnificationSpec spec; synchronized (mLock) { mUsesAccessibilityCache = true; - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return null; } resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); @@ -602,7 +602,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ Region partialInteractiveRegion = Region.obtain(); MagnificationSpec spec; synchronized (mLock) { - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return null; } resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked( @@ -663,7 +663,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ Region partialInteractiveRegion = Region.obtain(); MagnificationSpec spec; synchronized (mLock) { - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return null; } resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); @@ -728,7 +728,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ throws RemoteException { final int resolvedWindowId; synchronized (mLock) { - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return false; } resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); @@ -748,7 +748,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ @Override public boolean performGlobalAction(int action) { synchronized (mLock) { - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return false; } } @@ -771,7 +771,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ @Override public float getMagnificationScale(int displayId) { synchronized (mLock) { - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return 1.0f; } } @@ -787,7 +787,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ public Region getMagnificationRegion(int displayId) { synchronized (mLock) { final Region region = Region.obtain(); - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return region; } MagnificationController magnificationController = @@ -810,7 +810,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ @Override public float getMagnificationCenterX(int displayId) { synchronized (mLock) { - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return 0.0f; } MagnificationController magnificationController = @@ -832,7 +832,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ @Override public float getMagnificationCenterY(int displayId) { synchronized (mLock) { - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return 0.0f; } MagnificationController magnificationController = @@ -864,7 +864,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ @Override public boolean resetMagnification(int displayId, boolean animate) { synchronized (mLock) { - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return false; } if (!mSecurityPolicy.canControlMagnification(this)) { @@ -886,7 +886,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ public boolean setMagnificationScaleAndCenter(int displayId, float scale, float centerX, float centerY, boolean animate) { synchronized (mLock) { - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return false; } if (!mSecurityPolicy.canControlMagnification(this)) { @@ -1186,8 +1186,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ mInvocationHandler.notifySoftKeyboardShowModeChangedLocked(showState); } - public void notifyAccessibilityButtonClickedLocked() { - mInvocationHandler.notifyAccessibilityButtonClickedLocked(); + public void notifyAccessibilityButtonClickedLocked(int displayId) { + mInvocationHandler.notifyAccessibilityButtonClickedLocked(displayId); } public void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) { @@ -1226,11 +1226,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } } - private void notifyAccessibilityButtonClickedInternal() { + private void notifyAccessibilityButtonClickedInternal(int displayId) { final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); if (listener != null) { try { - listener.onAccessibilityButtonClicked(); + listener.onAccessibilityButtonClicked(displayId); } catch (RemoteException re) { Slog.e(LOG_TAG, "Error sending accessibility button click to " + mService, re); } @@ -1484,7 +1484,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } break; case MSG_ON_ACCESSIBILITY_BUTTON_CLICKED: { - notifyAccessibilityButtonClickedInternal(); + final int displayId = (int) message.arg1; + notifyAccessibilityButtonClickedInternal(displayId); } break; case MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED: { @@ -1546,8 +1547,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ mIsSoftKeyboardCallbackEnabled = enabled; } - public void notifyAccessibilityButtonClickedLocked() { - final Message msg = obtainMessage(MSG_ON_ACCESSIBILITY_BUTTON_CLICKED); + public void notifyAccessibilityButtonClickedLocked(int displayId) { + final Message msg = obtainMessage(MSG_ON_ACCESSIBILITY_BUTTON_CLICKED, displayId, 0); msg.sendToTarget(); } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index 18b6f90f921f..c733d3bee6b6 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -29,8 +29,8 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.accessibility.AccessibilityEvent; -import com.android.server.accessibility.gestures.TouchExplorer; import com.android.server.LocalServices; +import com.android.server.accessibility.gestures.TouchExplorer; import com.android.server.policy.WindowManagerPolicy; import java.util.ArrayList; diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index b5b3cd2fe530..893e4e49020b 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -1085,9 +1085,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { final AccessibilityServiceConnection service = state.mBoundServices.get(i); if (service.mRequestAccessibilityButton) { - // TODO(b/120762691): Need to notify each accessibility service if - // accessibility button is clicked per display. - service.notifyAccessibilityButtonClickedLocked(); + service.notifyAccessibilityButtonClickedLocked(displayId); return; } } @@ -1109,9 +1107,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub final AccessibilityServiceConnection service = state.mBoundServices.get(i); if (service.mRequestAccessibilityButton && (service.mComponentName.equals( state.mServiceAssignedToAccessibilityButton))) { - // TODO(b/120762691): Need to notify each accessibility service if - // accessibility button is clicked per display. - service.notifyAccessibilityButtonClickedLocked(); + service.notifyAccessibilityButtonClickedLocked(displayId); return; } } @@ -2535,10 +2531,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub // to create event handler per display. The events should be handled by the // display which is overlaid by it. final Display display = displays[i]; - if (display.getType() == Display.TYPE_OVERLAY) { - continue; + if (isValidDisplay(display)) { + mDisplaysList.add(display); } - mDisplaysList.add(display); } } } @@ -2546,7 +2541,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub @Override public void onDisplayAdded(int displayId) { final Display display = mDisplayManager.getDisplay(displayId); - if (display == null || display.getType() == Display.TYPE_OVERLAY) { + if (!isValidDisplay(display)) { return; } @@ -2597,6 +2592,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub public void onDisplayChanged(int displayId) { /* do nothing */ } + + private boolean isValidDisplay(@Nullable Display display) { + if (display == null || display.getType() == Display.TYPE_OVERLAY) { + return false; + } + // Private virtual displays are created by the ap and is not allowed to access by other + // aps. We assume we could ignore them. + if ((display.getType() == Display.TYPE_VIRTUAL + && (display.getFlags() & Display.FLAG_PRIVATE) != 0)) { + return false; + } + return true; + } } /** Represents an {@link AccessibilityManager} */ diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java index 315d6fa287f2..b88b24e21c2a 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java @@ -468,7 +468,7 @@ public class AccessibilitySecurityPolicy { } } - private boolean hasPermission(String permission) { + boolean hasPermission(String permission) { return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED; } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java index 02f7821bd0d5..d7f61e5371d5 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java @@ -18,6 +18,7 @@ package com.android.server.accessibility; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; +import android.Manifest; import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.IAccessibilityServiceClient; import android.content.ComponentName; @@ -27,6 +28,7 @@ import android.content.pm.ParceledListSlice; import android.os.Binder; import android.os.Handler; import android.os.IBinder; +import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; @@ -211,19 +213,31 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect } @Override - protected boolean isCalledForCurrentUserLocked() { + protected boolean hasRightsToCurrentUserLocked() { // We treat calls from a profile as if made by its parent as profiles // share the accessibility state of the parent. The call below // performs the current profile parent resolution. - final int resolvedUserId = mSecurityPolicy - .resolveCallingUserIdEnforcingPermissionsLocked(UserHandle.USER_CURRENT); - return resolvedUserId == mSystemSupport.getCurrentUserIdLocked(); + final int callingUid = Binder.getCallingUid(); + if (callingUid == Process.ROOT_UID + || callingUid == Process.SYSTEM_UID + || callingUid == Process.SHELL_UID) { + return true; + } + if (mSecurityPolicy.resolveProfileParentLocked(UserHandle.getUserId(callingUid)) + == mSystemSupport.getCurrentUserIdLocked()) { + return true; + } + if (mSecurityPolicy.hasPermission(Manifest.permission.INTERACT_ACROSS_USERS) + || mSecurityPolicy.hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) { + return true; + } + return false; } @Override public boolean setSoftKeyboardShowMode(int showMode) { synchronized (mLock) { - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return false; } final UserState userState = mUserStateWeakReference.get(); @@ -241,7 +255,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect @Override public boolean isAccessibilityButtonAvailable() { synchronized (mLock) { - if (!isCalledForCurrentUserLocked()) { + if (!hasRightsToCurrentUserLocked()) { return false; } UserState userState = mUserStateWeakReference.get(); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java index 9687098b6f3f..c9efe36b2014 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java @@ -872,8 +872,8 @@ public class AccessibilityWindowManager { RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection( windowId, connection, packageName, resolvedUid, resolvedUserId); wrapper.linkToDeath(); - getInteractionConnectionsForUserLocked(userId).put(windowId, wrapper); - getWindowTokensForUserLocked(userId).put(windowId, windowToken.asBinder()); + getInteractionConnectionsForUserLocked(resolvedUserId).put(windowId, wrapper); + getWindowTokensForUserLocked(resolvedUserId).put(windowId, windowToken.asBinder()); if (DEBUG) { Slog.i(LOG_TAG, "Added user connection for pid:" + Binder.getCallingPid() + " with windowId: " + windowId diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java index 2698b72fdb36..79d975dac2b2 100644 --- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java +++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java @@ -66,6 +66,7 @@ class UiAutomationManager { mUiAutomationServiceOwner.unlinkToDeath(this, 0); mUiAutomationServiceOwner = null; destroyUiAutomationService(); + Slog.v(LOG_TAG, "UiAutomation service owner died"); } }; @@ -263,7 +264,7 @@ class UiAutomationManager { } @Override - protected boolean isCalledForCurrentUserLocked() { + protected boolean hasRightsToCurrentUserLocked() { // Allow UiAutomation to work for any user return true; } diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index 10c32ee87c13..d8b7e3a25e04 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -27,8 +27,6 @@ import android.os.Handler; import android.util.Slog; import android.view.InputDevice; import android.view.MotionEvent; -import android.view.MotionEvent.PointerCoords; -import android.view.MotionEvent.PointerProperties; import android.view.ViewConfiguration; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -129,15 +127,6 @@ public class TouchExplorer extends BaseEventStreamTransformation // Context in which this explorer operates. private final Context mContext; - // The long pressing pointer id if coordinate remapping is needed. - private int mLongPressingPointerId = -1; - - // The long pressing pointer X if coordinate remapping is needed. - private int mLongPressingPointerDeltaX; - - // The long pressing pointer Y if coordinate remapping is needed. - private int mLongPressingPointerDeltaY; - /** * Creates a new instance. @@ -231,10 +220,6 @@ public class TouchExplorer extends BaseEventStreamTransformation mGestureDetector.clear(); // Go to initial state. mState.clear(); - // Clear the long pressing pointer remap data. - mLongPressingPointerId = -1; - mLongPressingPointerDeltaX = 0; - mLongPressingPointerDeltaY = 0; mAms.onTouchInteractionEnd(); } @@ -705,17 +690,6 @@ public class TouchExplorer extends BaseEventStreamTransformation return; } case MotionEvent.ACTION_UP: { - // Offset the event if we are doing a long press as the - // target is not necessarily under the user's finger. - if (mLongPressingPointerId >= 0) { - event = offsetEvent(event, - mLongPressingPointerDeltaX, - - mLongPressingPointerDeltaY); - // Clear the long press state. - mLongPressingPointerId = -1; - mLongPressingPointerDeltaX = 0; - mLongPressingPointerDeltaY = 0; - } - // Deliver the event. sendMotionEvent(event, event.getAction(), ALL_POINTER_ID_BITS, policyFlags); @@ -865,18 +839,6 @@ public class TouchExplorer extends BaseEventStreamTransformation } else { event.setDownTime(mInjectedPointerTracker.getLastInjectedDownEventTime()); } - - // If the user is long pressing but the long pressing pointer - // was not exactly over the accessibility focused item we need - // to remap the location of that pointer so the user does not - // have to explicitly touch explore something to be able to - // long press it, or even worse to avoid the user long pressing - // on the wrong item since click and long press behave differently. - if (mLongPressingPointerId >= 0) { - event = offsetEvent(event, - mLongPressingPointerDeltaX, - - mLongPressingPointerDeltaY); - } - if (DEBUG) { Slog.d(LOG_TAG, "Injecting event: " + event + ", policyFlags=0x" + Integer.toHexString(policyFlags)); @@ -897,39 +859,6 @@ public class TouchExplorer extends BaseEventStreamTransformation } /** - * Offsets all pointers in the given event by adding the specified X and Y - * offsets. - * - * @param event The event to offset. - * @param offsetX The X offset. - * @param offsetY The Y offset. - * @return An event with the offset pointers or the original event if both - * offsets are zero. - */ - private MotionEvent offsetEvent(MotionEvent event, int offsetX, int offsetY) { - if (offsetX == 0 && offsetY == 0) { - return event; - } - final int remappedIndex = event.findPointerIndex(mLongPressingPointerId); - final int pointerCount = event.getPointerCount(); - PointerProperties[] props = PointerProperties.createArray(pointerCount); - PointerCoords[] coords = PointerCoords.createArray(pointerCount); - for (int i = 0; i < pointerCount; i++) { - event.getPointerProperties(i, props[i]); - event.getPointerCoords(i, coords[i]); - if (i == remappedIndex) { - coords[i].x += offsetX; - coords[i].y += offsetY; - } - } - return MotionEvent.obtain(event.getDownTime(), - event.getEventTime(), event.getAction(), event.getPointerCount(), - props, coords, event.getMetaState(), event.getButtonState(), - 1.0f, 1.0f, event.getDeviceId(), event.getEdgeFlags(), - event.getSource(), event.getDisplayId(), event.getFlags()); - } - - /** * Computes the action for an injected event based on a masked action * and a pointer index. * @@ -1189,9 +1118,6 @@ public class TouchExplorer extends BaseEventStreamTransformation + ", mDetermineUserIntentTimeout: " + mDetermineUserIntentTimeout + ", mDoubleTapSlop: " + mDoubleTapSlop + ", mDraggingPointerId: " + mDraggingPointerId - + ", mLongPressingPointerId: " + mLongPressingPointerId - + ", mLongPressingPointerDeltaX: " + mLongPressingPointerDeltaX - + ", mLongPressingPointerDeltaY: " + mLongPressingPointerDeltaY + ", mTempPoint: " + mTempPoint + " }"; } diff --git a/services/art-profile-boot b/services/art-profile-boot index 23d709099cc0..e09424bc261c 100644 --- a/services/art-profile-boot +++ b/services/art-profile-boot @@ -1,326 +1,760 @@ -Lcom/android/server/SystemServer;->run()V -Lcom/android/server/SystemServer;->main([Ljava/lang/String;)V -Lcom/android/server/SystemServer;->startBootstrapServices()V -Lcom/android/server/pm/PackageManagerService;->main(Landroid/content/Context;Lcom/android/server/pm/Installer;ZZ)Lcom/android/server/pm/PackageManagerService; -Lcom/android/server/pm/PackageManagerService;-><init>(Landroid/content/Context;Lcom/android/server/pm/Installer;ZZ)V -Lcom/android/server/pm/Settings;->readLPw(Ljava/util/List;)Z -Lcom/android/server/pm/Settings;->readPackageLPw(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/appop/AppOpsService;->readUidOps(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/appop/AppOpsService;->readOp(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/appop/AppOpsService$UidState;Ljava/lang/String;Z)V +Lcom/android/server/appop/AppOpsService$UidState;->evalForegroundOps(Landroid/util/SparseArray;)V +Lcom/android/server/appop/AppOpsService;->readUid(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)V +Lcom/android/server/appop/AppOpsService$Op;->updateProxyState(JILjava/lang/String;)V +Lcom/android/server/appop/AppOpsService$Op;->accessed(JILjava/lang/String;II)V +Lcom/android/server/pm/permission/PermissionSettings;->readPermissions(Landroid/util/ArrayMap;Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/pm/permission/BasePermission;-><init>(Ljava/lang/String;Ljava/lang/String;I)V +Lcom/android/server/pm/permission/BasePermission;->readInt(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Ljava/lang/String;I)I +Lcom/android/server/pm/permission/BasePermission;->readLPw(Ljava/util/Map;Lorg/xmlpull/v1/XmlPullParser;)Z +Lcom/android/server/pm/permission/PermissionsState$PermissionData;->isInstallPermission()Z +Lcom/android/server/pm/permission/BasePermission;->getName()Ljava/lang/String; +Lcom/android/server/pm/permission/PermissionsState$PermissionState;->access$100(Lcom/android/server/pm/permission/PermissionsState$PermissionState;)I +Lcom/android/server/pm/permission/PermissionsState;->enforceValidUserId(I)V +Lcom/android/server/pm/permission/PermissionsState;->hasPermission(Ljava/lang/String;I)Z +Lcom/android/server/pm/permission/PermissionsState$PermissionData;->isGranted(I)Z +Lcom/android/server/pm/permission/BasePermission;->computeGids(I)[I +Lcom/android/server/pm/permission/PermissionsState;->appendInts([I[I)[I +Lcom/android/server/pm/permission/PermissionsState;->computeGids(I)[I +Lcom/android/server/pm/permission/PermissionsState$PermissionState;->access$000(Lcom/android/server/pm/permission/PermissionsState$PermissionState;)Z +Lcom/android/server/pm/permission/PermissionsState$PermissionData;->computeGids(I)[I Lcom/android/server/pm/Settings;->readInstallPermissionsLPr(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/pm/permission/PermissionsState;)V -Lcom/android/server/pm/permission/PermissionsState;->grantPermission(Lcom/android/server/pm/permission/BasePermission;I)I +Lcom/android/server/pm/permission/PermissionsState$PermissionData;->isCompatibleUserId(I)Z +Lcom/android/server/pm/permission/PermissionsState$PermissionData;->isDefault()Z +Lcom/android/server/pm/permission/PermissionSettings;->getPermissionLocked(Ljava/lang/String;)Lcom/android/server/pm/permission/BasePermission; +Lcom/android/server/pm/permission/PermissionSettings;->getPermission(Ljava/lang/String;)Lcom/android/server/pm/permission/BasePermission; Lcom/android/server/pm/permission/PermissionsState;->grantInstallPermission(Lcom/android/server/pm/permission/BasePermission;)I -Lcom/android/server/-$$Lambda$YWiwiKm_Qgqb55C6tTuq_n2JzdY;->run()V -Lcom/android/server/pm/PackageSignatures;->readXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/util/ArrayList;)V -Lcom/android/server/pm/permission/PermissionsState;->computeGids(I)[I -Lcom/android/server/am/-$$Lambda$BatteryExternalStatsWorker$ddVY5lmqswnSjXppAxPTOHbuzzQ;->run()V -Lcom/android/server/SystemServiceManager;->startService(Lcom/android/server/SystemService;)V -Lcom/android/server/SystemServiceManager;->startService(Ljava/lang/Class;)Lcom/android/server/SystemService; -Lcom/android/server/SystemServiceManager;->startService(Ljava/lang/String;)Lcom/android/server/SystemService; -Lcom/android/server/pm/permission/PermissionsState;->hasPermission(Ljava/lang/String;I)Z -Lcom/android/server/pm/permission/PermissionsState;->hasPermissionRequiringReview(I)Z -Lcom/android/server/am/ActivityManagerService$Lifecycle;-><init>(Landroid/content/Context;)V -Lcom/android/server/am/ActivityManagerService;-><init>(Landroid/content/Context;Lcom/android/server/wm/ActivityTaskManagerService;)V -Lcom/android/server/pm/Settings;->readSharedUserLPw(Lorg/xmlpull/v1/XmlPullParser;)V -Lcom/android/server/pm/permission/PermissionsState;->updatePermissionFlags(Lcom/android/server/pm/permission/BasePermission;III)Z +Lcom/android/server/pm/permission/PermissionsState;->grantPermission(Lcom/android/server/pm/permission/BasePermission;I)I Lcom/android/server/pm/permission/PermissionsState;->ensurePermissionData(Lcom/android/server/pm/permission/BasePermission;)Lcom/android/server/pm/permission/PermissionsState$PermissionData; -Lcom/android/server/am/BatteryExternalStatsWorker$1;->run()V -Lcom/android/server/am/BatteryExternalStatsWorker;->updateExternalStatsLocked(Ljava/lang/String;IZZZ)V +Lcom/android/server/pm/permission/PermissionsState$PermissionData;-><init>(Lcom/android/server/pm/permission/BasePermission;)V Lcom/android/server/pm/permission/PermissionsState$PermissionData;->grant(I)Z -Lcom/android/server/am/BatteryExternalStatsWorker$2;->run()V -Lcom/android/server/pm/permission/PermissionSettings;->getPermission(Ljava/lang/String;)Lcom/android/server/pm/permission/BasePermission; -Lcom/android/server/pm/permission/PermissionSettings;->getPermissionLocked(Ljava/lang/String;)Lcom/android/server/pm/permission/BasePermission; -Lcom/android/server/pm/permission/PermissionSettings;->getPermissionTreeLocked(Ljava/lang/String;)Lcom/android/server/pm/permission/BasePermission; -Lcom/android/server/pm/Settings;->readDisabledSysPackageLPw(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/pm/permission/PermissionsState$PermissionState;-><init>(Ljava/lang/String;)V +Lcom/android/server/pm/permission/PermissionsState$PermissionState;->access$002(Lcom/android/server/pm/permission/PermissionsState$PermissionState;Z)Z +Lcom/android/server/pm/permission/PermissionsState;->updatePermissionFlags(Lcom/android/server/pm/permission/BasePermission;III)Z +Lcom/android/server/pm/permission/PermissionsState$PermissionData;->getFlags(I)I Lcom/android/server/pm/permission/PermissionsState$PermissionData;->updateFlags(III)Z +Lcom/android/server/pm/permission/PermissionsState$PermissionData;->isInstallPermissionKey(I)Z +Lcom/android/server/pm/permission/PermissionsState$PermissionState;->access$102(Lcom/android/server/pm/permission/PermissionsState$PermissionState;I)I +Lcom/android/server/pm/permission/PermissionsState$PermissionState;->isDefault()Z +Lcom/android/server/pm/Settings;->readPackageLPw(Lorg/xmlpull/v1/XmlPullParser;)V Lcom/android/server/pm/PackageSignatures;->readCertsListXml(Lorg/xmlpull/v1/XmlPullParser;Ljava/util/ArrayList;Ljava/util/ArrayList;IZLandroid/content/pm/PackageParser$SigningDetails$Builder;)I -Lcom/android/server/pm/permission/PermissionsState$PermissionData;-><init>(Lcom/android/server/pm/permission/PermissionsState$PermissionData;)V -Lcom/android/server/pm/permission/PermissionSettings;->readPermissions(Landroid/util/ArrayMap;Lorg/xmlpull/v1/XmlPullParser;)V -Lcom/android/server/pm/permission/PermissionSettings;->readPermissions(Lorg/xmlpull/v1/XmlPullParser;)V -Lcom/android/server/pm/Settings$RuntimePermissionPersistence;->readStateForUserSyncLPr(I)V -Lcom/android/server/pm/Settings$RuntimePermissionPersistence;->parseRuntimePermissionsLPr(Lorg/xmlpull/v1/XmlPullParser;I)V -Lcom/android/server/pm/Settings$RuntimePermissionPersistence;->parsePermissionsLPr(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/pm/permission/PermissionsState;I)V -Lcom/android/server/pm/permission/BasePermission;->readLPw(Ljava/util/Map;Lorg/xmlpull/v1/XmlPullParser;)Z -Lcom/android/server/pm/Settings;->writeKernelMappingLPr()V -Lcom/android/server/pm/Settings;->writeKernelMappingLPr(Lcom/android/server/pm/PackageSetting;)V -Lcom/android/server/pm/Settings;->writeKernelMappingLPr(Ljava/lang/String;I[I)V -Lcom/android/server/pm/Settings;->readPackageRestrictionsLPr(I)V -Lcom/android/server/am/ActivityManagerService$Injector;->getAppOpsService(Ljava/io/File;Landroid/os/Handler;)Lcom/android/server/appop/AppOpsService; -Lcom/android/server/appop/AppOpsService;-><init>(Ljava/io/File;Landroid/os/Handler;)V -Lcom/android/server/appop/AppOpsService;->readState()V -Lcom/android/server/am/ProcessStatsService;-><init>(Lcom/android/server/am/ActivityManagerService;Ljava/io/File;)V -Lcom/android/server/pm/PackageManagerService;->scanDirTracedLI(Ljava/io/File;IIJ)V -Lcom/android/server/pm/PackageManagerService;->scanDirLI(Ljava/io/File;IIJ)V -Lcom/android/server/pm/PackageManagerService;->addForInitLI(Landroid/content/pm/PackageParser$Package;IIJLandroid/os/UserHandle;)Landroid/content/pm/PackageParser$Package; -Lcom/android/server/pm/PackageManagerService;->scanPackageChildLI(Landroid/content/pm/PackageParser$Package;IIJLandroid/os/UserHandle;)Landroid/content/pm/PackageParser$Package; -Lcom/android/server/pm/KeySetManagerService;->readKeySetsLPw(Lorg/xmlpull/v1/XmlPullParser;Landroid/util/ArrayMap;)V -Lcom/android/server/pm/ParallelPackageParser;->lambda$submit$0$ParallelPackageParser(Ljava/io/File;I)V -Lcom/android/server/pm/-$$Lambda$ParallelPackageParser$FTtinPrp068lVeI7K6bC1tNE3iM;->run()V -Lcom/android/server/pm/ParallelPackageParser;->parsePackage(Landroid/content/pm/PackageParser;Ljava/io/File;I)Landroid/content/pm/PackageParser$Package; -Lcom/android/server/appop/AppOpsService;->readPackage(Lorg/xmlpull/v1/XmlPullParser;)V -Lcom/android/server/pm/Settings;->addPackageLPw(Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IJIILjava/lang/String;Ljava/util/List;[Ljava/lang/String;[J)Lcom/android/server/pm/PackageSetting; -Lcom/android/server/appop/AppOpsService;->readUid(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;)V -Lcom/android/server/appop/AppOpsService;->readUidOps(Lorg/xmlpull/v1/XmlPullParser;)V -Lcom/android/server/pm/PackageSetting;-><init>(Lcom/android/server/pm/PackageSetting;)V +Lcom/android/server/pm/Settings;->registerExistingAppIdLPw(ILcom/android/server/pm/SettingBase;Ljava/lang/Object;)Z +Lcom/android/server/pm/Settings;->readLPw(Ljava/util/List;)Z +Lcom/android/server/pm/SettingBase;-><init>(II)V +Lcom/android/server/pm/SettingBase;->setFlags(I)V +Lcom/android/server/pm/SettingBase;->setPrivateFlags(I)V +Lcom/android/server/pm/permission/PermissionsState;-><init>()V +Lcom/android/server/pm/PackageSignatures;-><init>()V Lcom/android/server/pm/PackageSetting;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JIILjava/lang/String;Ljava/util/List;I[Ljava/lang/String;[J)V -Lcom/android/server/pm/SELinuxMMAC;->readInstallPolicy()Z -Lcom/android/server/pm/KeySetManagerService;->readKeysLPw(Lorg/xmlpull/v1/XmlPullParser;)V -Lcom/android/server/pm/Settings;->writeIntToFile(Ljava/io/File;I)V Lcom/android/server/pm/PackageSettingBase;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JIILjava/lang/String;Ljava/util/List;[Ljava/lang/String;[J)V -Lcom/android/server/appop/AppOpsService;->readOp(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/appop/AppOpsService$UidState;Ljava/lang/String;Z)V -Lcom/android/server/pm/SELinuxMMAC;->readSignerOrThrow(Lorg/xmlpull/v1/XmlPullParser;)Lcom/android/server/pm/Policy; -Lcom/android/server/pm/Settings;->readComponentsLPr(Lorg/xmlpull/v1/XmlPullParser;)Landroid/util/ArraySet; -Lcom/android/server/pm/KeySetManagerService;->readPublicKeyLPw(Lorg/xmlpull/v1/XmlPullParser;)V -Lcom/android/server/pm/PackageManagerService;->scanPackageNewLI(Landroid/content/pm/PackageParser$Package;IIJLandroid/os/UserHandle;)Lcom/android/server/pm/PackageManagerService$ScanResult; -Lcom/android/server/pm/permission/PermissionsState;->grantRuntimePermission(Lcom/android/server/pm/permission/BasePermission;I)I -Lcom/android/server/pm/Policy$PolicyBuilder;->addSignature(Ljava/lang/String;)Lcom/android/server/pm/Policy$PolicyBuilder; -Lcom/android/server/display/DisplayManagerService;-><init>(Landroid/content/Context;)V -Lcom/android/server/display/DisplayManagerService;-><init>(Landroid/content/Context;Lcom/android/server/display/DisplayManagerService$Injector;)V -Lcom/android/server/am/ActivityManagerService;->start()V -Lcom/android/server/am/ActivityManagerService;->startAssociationLocked(ILjava/lang/String;IIJLandroid/content/ComponentName;Ljava/lang/String;)Lcom/android/server/am/ActivityManagerService$Association; -Lcom/android/server/am/ActivityManagerService;->startIsolatedProcess(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Runnable;)Z -Lcom/android/server/am/ActivityManagerService;->startObservingNativeCrashes()V -Lcom/android/server/am/ActivityManagerService;->startPersistentApps(I)V -Lcom/android/server/am/ActivityManagerService;->startProcessLocked(Ljava/lang/String;Landroid/content/pm/ApplicationInfo;ZILjava/lang/String;Landroid/content/ComponentName;ZZZ)Lcom/android/server/am/ProcessRecord; -Lcom/android/server/am/ActivityManagerService;->startService(Landroid/app/IApplicationThread;Landroid/content/Intent;Ljava/lang/String;ZLjava/lang/String;I)Landroid/content/ComponentName; -PLcom/android/server/am/ActivityManagerService;->startUserInBackgroundWithListener(ILandroid/os/IProgressListener;)Z -Lcom/android/server/am/ActivityManagerService$Lifecycle;->onStart()V -Lcom/android/server/pm/PackageManagerService;->scanPackageOnlyLI(Lcom/android/server/pm/PackageManagerService$ScanRequest;ZJ)Lcom/android/server/pm/PackageManagerService$ScanResult; -Lcom/android/server/pm/PackageSettingBase;->modifyUserState(I)Landroid/content/pm/PackageUserState; -Lcom/android/server/pm/PackageSettingBase;->modifyUserStateComponents(IZZ)Landroid/content/pm/PackageUserState; -Lcom/android/server/pm/Settings;->readDomainVerificationLPw(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/pm/PackageSettingBase;)V -Lcom/android/server/pm/PackageSettingBase;->setEnabled(IILjava/lang/String;)V -Lcom/android/server/am/BatteryStatsService;-><init>(Landroid/content/Context;Ljava/io/File;Landroid/os/Handler;)V -Lcom/android/server/pm/PackageManagerService;->commitReconciledScanResultLocked(Lcom/android/server/pm/PackageManagerService$ReconciledPackage;)V -Lcom/android/server/pm/KeySetManagerService;->readKeySetListLPw(Lorg/xmlpull/v1/XmlPullParser;)V -Lcom/android/server/appop/AppOpsService$Op;->accessed(JILjava/lang/String;II)V -Lcom/android/server/wm/ActivityTaskManagerService;->initialize(Lcom/android/server/firewall/IntentFirewall;Lcom/android/server/am/PendingIntentController;Landroid/os/Looper;)V -Lcom/android/server/pm/SettingBase;-><init>(II)V -Lcom/android/server/pm/PackageManagerService;->locationIsPrivileged(Ljava/lang/String;)Z -Lcom/android/server/power/PowerManagerService;-><init>(Landroid/content/Context;)V -Lcom/android/server/power/PowerManagerService;-><init>(Landroid/content/Context;Lcom/android/server/power/PowerManagerService$Injector;)V -Lcom/android/server/pm/permission/PermissionsState;->enforceValidUserId(I)V -Lcom/android/server/Watchdog;->getInstance()Lcom/android/server/Watchdog; -Lcom/android/server/Watchdog;-><init>()V -Lcom/android/server/pm/PackageManagerService;->commitPackageSettings(Landroid/content/pm/PackageParser$Package;Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/PackageSetting;IZLcom/android/server/pm/PackageManagerService$ReconciledPackage;)V -Lcom/android/server/pm/PackageSetting;->getPermissionsState()Lcom/android/server/pm/permission/PermissionsState; -Lcom/android/server/pm/Settings;->registerExistingAppIdLPw(ILcom/android/server/pm/SettingBase;Ljava/lang/Object;)Z -Lcom/android/server/pm/permission/PermissionManagerService;->create(Landroid/content/Context;Lcom/android/server/pm/permission/DefaultPermissionGrantPolicy$DefaultPermissionGrantedCallback;Ljava/lang/Object;)Lcom/android/server/pm/permission/PermissionManagerServiceInternal; -Lcom/android/server/pm/Settings;->addSharedUserLPw(Ljava/lang/String;III)Lcom/android/server/pm/SharedUserSetting; -Lcom/android/server/pm/PackageSettingBase;->init(Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V -Lcom/android/server/appop/AppOpsService$Op;->updateProxyState(JILjava/lang/String;)V -Lcom/android/server/display/DisplayManagerService$DisplayAdapterListener;->onDisplayDeviceEvent(Lcom/android/server/display/DisplayDevice;I)V -Lcom/android/server/wm/ActivityTaskManagerService;->onActivityManagerInternalAdded()V -Lcom/android/server/SystemService;->publishBinderService(Ljava/lang/String;Landroid/os/IBinder;)V -Lcom/android/server/am/ActivityManagerService;->initPowerManagement()V -Lcom/android/server/wm/ActivityTaskManagerService$Lifecycle;-><init>(Landroid/content/Context;)V -Lcom/android/server/display/DisplayManagerService;->onStart()V -Lcom/android/server/pm/Settings;->readPreferredActivitiesLPw(Lorg/xmlpull/v1/XmlPullParser;I)V Lcom/android/server/pm/PackageKeySetData;-><init>()V -Lcom/android/server/display/DisplayManagerService;->registerDefaultDisplayAdapters()V -Lcom/android/server/display/LocalDisplayAdapter;->registerLocked()V -Lcom/android/server/ServiceThread;->run()V -Lcom/android/server/display/DisplayModeDirector;-><init>(Landroid/content/Context;Landroid/os/Handler;)V -Lcom/android/server/pm/Settings;->addPackageSettingLPw(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/SharedUserSetting;)V -Lcom/android/server/pm/permission/PermissionManagerService;-><init>(Landroid/content/Context;Lcom/android/server/pm/permission/DefaultPermissionGrantPolicy$DefaultPermissionGrantedCallback;Ljava/lang/Object;)V -Lcom/android/server/appop/AppOpsService;->getUidStateLocked(IZ)Lcom/android/server/appop/AppOpsService$UidState; -Lcom/android/server/am/BatteryStatsService;->fillRailDataStats(Lcom/android/internal/os/RailStats;)V -Lcom/android/server/pm/SELinuxMMAC;->getSeInfo(Landroid/content/pm/PackageParser$Package;ZII)Ljava/lang/String; -Lcom/android/server/pm/PackageManagerService;->collectCertificatesLI(Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$Package;ZZ)V -Lcom/android/server/pm/PackageManagerService;->reconcilePackagesLocked(Lcom/android/server/pm/PackageManagerService$ReconcileRequest;Lcom/android/server/pm/KeySetManagerService;)Ljava/util/Map; -Lcom/android/server/pm/permission/BasePermission;->readInt(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;Ljava/lang/String;I)I -Lcom/android/server/pm/UserManagerService;-><init>(Landroid/content/Context;Lcom/android/server/pm/PackageManagerService;Lcom/android/server/pm/UserDataPreparer;Ljava/lang/Object;)V -Lcom/android/server/pm/UserManagerService;-><init>(Landroid/content/Context;Lcom/android/server/pm/PackageManagerService;Lcom/android/server/pm/UserDataPreparer;Ljava/lang/Object;Ljava/io/File;)V -Lcom/android/server/display/LocalDisplayAdapter;->tryConnectDisplayLocked(J)V -Lcom/android/server/pm/PreferredActivity;-><init>(Landroid/content/IntentFilter;I[Landroid/content/ComponentName;Landroid/content/ComponentName;Z)V -Lcom/android/server/pm/PackageManagerService;->preparePackageParserCache()Ljava/io/File; -Lcom/android/server/pm/Policy$PolicyBuilder;->build()Lcom/android/server/pm/Policy; -Lcom/android/server/LockGuard;->installLock(Ljava/lang/Object;I)Ljava/lang/Object; -Lcom/android/server/LockGuard;->installLock(Ljava/lang/Object;IZ)Ljava/lang/Object; -Lcom/android/server/SystemServiceManager;->startBootPhase(I)V -Lcom/android/server/display/PersistentDataStore;->load()V -Lcom/android/server/display/PersistentDataStore;->loadDisplaysFromXml(Lorg/xmlpull/v1/XmlPullParser;)V -Lcom/android/server/display/PersistentDataStore;->loadFromXml(Lorg/xmlpull/v1/XmlPullParser;)V -Lcom/android/server/display/PersistentDataStore;->loadRememberedWifiDisplaysFromXml(Lorg/xmlpull/v1/XmlPullParser;)V -Lcom/android/server/wm/AppWarnings;-><init>(Lcom/android/server/wm/ActivityTaskManagerService;Landroid/content/Context;Landroid/os/Handler;Landroid/os/Handler;Ljava/io/File;)V -Lcom/android/server/pm/PreferredComponent;-><init>(Lcom/android/server/pm/PreferredComponent$Callbacks;I[Landroid/content/ComponentName;Landroid/content/ComponentName;Z)V -Lcom/android/server/pm/PreferredComponent;-><init>(Lcom/android/server/pm/PreferredComponent$Callbacks;Lorg/xmlpull/v1/XmlPullParser;)V -Lcom/android/server/display/DisplayManagerService;->handleDisplayDeviceAdded(Lcom/android/server/display/DisplayDevice;)V -Lcom/android/server/display/DisplayManagerService;->handleDisplayDeviceAddedLocked(Lcom/android/server/display/DisplayDevice;)V -Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice;->getDisplayDeviceInfoLocked()Lcom/android/server/display/DisplayDeviceInfo; -Lcom/android/server/pm/PackageSettingBase;->setUserState(IJIZZZZIZLjava/lang/String;Landroid/content/pm/SuspendDialogInfo;Landroid/os/PersistableBundle;Landroid/os/PersistableBundle;ZZLjava/lang/String;Landroid/util/ArraySet;Landroid/util/ArraySet;IIILjava/lang/String;)V -Lcom/android/server/pm/Installer;->onStart()V -Lcom/android/server/pm/Installer;->connect()V -Lcom/android/server/lights/LightsService$LightImpl;-><init>(Lcom/android/server/lights/LightsService;Landroid/content/Context;I)V -Lcom/android/server/pm/PackageManagerService;->addBuiltInSharedLibraryLocked(Ljava/lang/String;Ljava/lang/String;)Z -Lcom/android/server/LockGuard;->findOrCreateLockInfo(Ljava/lang/Object;)Lcom/android/server/LockGuard$LockInfo; -Lcom/android/server/lights/LightsService;-><init>(Landroid/content/Context;)V -Lcom/android/server/pm/Policy;->getMatchedSeInfo(Landroid/content/pm/PackageParser$Package;)Ljava/lang/String; -Lcom/android/server/ServiceThread;-><init>(Ljava/lang/String;IZ)V -Lcom/android/server/wm/ActivityTaskManagerService;->createStackSupervisor()Lcom/android/server/wm/ActivityStackSupervisor; -Lcom/android/server/Watchdog;->addMonitor(Lcom/android/server/Watchdog$Monitor;)V -Lcom/android/server/wm/ActivityStackSupervisor;->initPowerManagement()V -Lcom/android/server/wm/ActivityTaskManagerService;->onInitPowerManagement()V -Lcom/android/server/pm/KeySetManagerService;->addScannedPackageLPw(Landroid/content/pm/PackageParser$Package;)V -Lcom/android/server/am/BatteryStatsService;->initPowerManagement()V -Lcom/android/server/wm/ActivityTaskManagerService;-><init>(Landroid/content/Context;)V -Lcom/android/server/am/ProcessList;-><init>()V -Lcom/android/server/pm/PackageManagerService;->commitSharedLibraryInfoLocked(Landroid/content/pm/SharedLibraryInfo;)V -Lcom/android/server/pm/PackageManagerServiceUtils;->getLastModifiedTime(Landroid/content/pm/PackageParser$Package;)J -Lcom/android/server/am/ProcessStatsService;->updateFile()V -Lcom/android/server/pm/Policy$PolicyBuilder;->setGlobalSeinfoOrThrow(Ljava/lang/String;)Lcom/android/server/pm/Policy$PolicyBuilder; -Lcom/android/server/wm/AppWarnings;->readConfigFromFileAmsThread()V -Lcom/android/server/am/BatteryStatsService;->fillLowPowerStats(Lcom/android/internal/os/RpmStats;)V -Lcom/android/server/display/DisplayManagerService;->handleDisplayDeviceChanged(Lcom/android/server/display/DisplayDevice;)V -Lcom/android/server/firewall/IntentFirewall;-><init>(Lcom/android/server/firewall/IntentFirewall$AMSInterface;Landroid/os/Handler;)V +Lcom/android/server/pm/PackageSettingBase;->init(Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V +Lcom/android/server/pm/KeySetManagerService;->readKeySetListLPw(Lorg/xmlpull/v1/XmlPullParser;)V +Lcom/android/server/pm/PackageSettingBase;->modifyUserState(I)Landroid/content/pm/PackageUserState; +Lcom/android/server/pm/Settings;->readComponentsLPr(Lorg/xmlpull/v1/XmlPullParser;)Landroid/util/ArraySet; +Lcom/android/server/pm/Settings;->readPackageRestrictionsLPr(I)V +Lcom/android/server/pm/Settings$RuntimePermissionPersistence;->parsePermissionsLPr(Lorg/xmlpull/v1/XmlPullParser;Lcom/android/server/pm/permission/PermissionsState;I)V +Lcom/android/server/pm/SettingBase;->getPermissionsState()Lcom/android/server/pm/permission/PermissionsState; +Lcom/android/server/pm/Settings;->writeKernelMappingLPr()V Lcom/android/server/pm/PackageSettingBase;->getNotInstalledUserIds()[I -Lcom/android/server/appop/AppOpsService$UidState;->evalForegroundOps(Landroid/util/SparseArray;)V -Lcom/android/server/SystemServerInitThreadPool;->submit(Ljava/lang/Runnable;Ljava/lang/String;)Ljava/util/concurrent/Future; -Lcom/android/server/pm/KeySetManagerService;->addSigningKeySetToPackageLPw(Lcom/android/server/pm/PackageSetting;Landroid/util/ArraySet;)V -Lcom/android/server/pm/ComponentResolver;->addAllComponents(Landroid/content/pm/PackageParser$Package;Z)V -Lcom/android/server/appop/AppOpsService;->publish(Landroid/content/Context;)V -Lcom/android/server/power/PowerManagerService;->onStart()V -Lcom/android/server/os/DeviceIdentifiersPolicyService;->onStart()V -Lcom/android/server/uri/UriGrantsManagerService$Lifecycle;-><init>(Landroid/content/Context;)V -Lcom/android/server/pm/PackageManagerService;->applyPolicy(Landroid/content/pm/PackageParser$Package;IILandroid/content/pm/PackageParser$Package;)V -Lcom/android/server/pm/KeySetManagerService;->addRefCountsFromSavedPackagesLPw(Landroid/util/ArrayMap;)V -Lcom/android/server/am/OomAdjuster;-><init>(Lcom/android/server/am/ActivityManagerService;Lcom/android/server/am/ProcessList;Lcom/android/server/am/ActiveUids;)V -Lcom/android/server/am/ProcessList;->init(Lcom/android/server/am/ActivityManagerService;Lcom/android/server/am/ActiveUids;)V -Lcom/android/server/pm/PackageManagerService$ScanRequest;-><init>(Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/SharedUserSetting;Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Ljava/lang/String;IIZLandroid/os/UserHandle;)V -Lcom/android/server/pm/Settings;->writeUserRestrictionsLPw(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;)V -PLcom/android/server/pm/permission/PermissionsState;-><init>(Lcom/android/server/pm/permission/PermissionsState;)V -Lcom/android/server/pm/UserManagerService;->readUserListLP()V -Lcom/android/server/RescueParty;->isUsbActive()Z -Lcom/android/server/RescueParty;->isDisabled()Z -Lcom/android/server/pm/SharedUserSetting;->addPackage(Lcom/android/server/pm/PackageSetting;)V -Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice;-><init>(Lcom/android/server/display/LocalDisplayAdapter;Landroid/os/IBinder;J[Landroid/view/SurfaceControl$PhysicalDisplayInfo;I[I[IIZ)V -Lcom/android/server/am/BatteryStatsService$WakeupReasonThread;->run()V +Lcom/android/server/pm/PackageManagerService;-><init>(Lcom/android/server/pm/PackageManagerService$Injector;ZZ)V +Lcom/android/server/pm/AppsFilter;->addPackage(Landroid/content/pm/PackageParser$Package;Ljava/util/Map;)V +Lcom/android/server/pm/AppsFilter;->canQuery(Landroid/content/pm/PackageParser$Package;Landroid/content/pm/PackageParser$Package;)Z +Lcom/android/server/pm/SELinuxMMAC;->getSeInfo(Landroid/content/pm/PackageParser$Package;ZI)Ljava/lang/String; +Lcom/android/server/pm/Policy;->getMatchedSeInfo(Landroid/content/pm/PackageParser$Package;)Ljava/lang/String; +Lcom/android/server/pm/PackageSettingBase;->readUserState(I)Landroid/content/pm/PackageUserState; +Lcom/android/server/pm/permission/PermissionsState;->copyFrom(Lcom/android/server/pm/permission/PermissionsState;)V +Lcom/android/server/pm/permission/PermissionsState$PermissionData;-><init>(Lcom/android/server/pm/permission/PermissionsState$PermissionData;)V +Lcom/android/server/pm/permission/PermissionsState$PermissionState;-><init>(Lcom/android/server/pm/permission/PermissionsState$PermissionState;)V +Lcom/android/server/pm/permission/BasePermission;->findPermissionTree(Ljava/util/Collection;Ljava/lang/String;)Lcom/android/server/pm/permission/BasePermission; +Lcom/android/server/pm/permission/PermissionManagerService;->addAllPermissions(Landroid/content/pm/PackageParser$Package;Z)V +Lcom/android/server/pm/permission/PermissionSettings;->putPermissionLocked(Ljava/lang/String;Lcom/android/server/pm/permission/BasePermission;)V +Lcom/android/server/pm/permission/PermissionSettings;->getAllPermissionTreesLocked()Ljava/util/Collection; +Lcom/android/server/pm/permission/BasePermission;->createOrUpdate(Lcom/android/server/pm/permission/BasePermission;Landroid/content/pm/PackageParser$Permission;Landroid/content/pm/PackageParser$Package;Ljava/util/Collection;Z)Lcom/android/server/pm/permission/BasePermission; +Lcom/android/server/pm/PackageManagerService;->commitPackageSettings(Landroid/content/pm/PackageParser$Package;Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/PackageSetting;IZLcom/android/server/pm/PackageManagerService$ReconciledPackage;)V +Lcom/android/server/IntentResolver;->register_intent_filter(Landroid/content/IntentFilter;Ljava/util/Iterator;Landroid/util/ArrayMap;Ljava/lang/String;)I +Lcom/android/server/pm/PackageManagerService;->fixProcessName(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; +Lcom/android/server/pm/PackageManagerService;->isPackageRenamed(Landroid/content/pm/PackageParser$Package;Ljava/lang/String;)Z Lcom/android/server/pm/PackageSettingBase;->doCopy(Lcom/android/server/pm/PackageSettingBase;)V -Lcom/android/server/SystemServerInitThreadPool;->get()Lcom/android/server/SystemServerInitThreadPool; -Lcom/android/server/pm/PreferredActivity;->onReadTag(Ljava/lang/String;Lorg/xmlpull/v1/XmlPullParser;)Z -Lcom/android/server/FgThread;->getHandler()Landroid/os/Handler; -Lcom/android/server/FgThread;->ensureThreadLocked()V -Lcom/android/server/IntentResolver;->addFilter(Landroid/content/IntentFilter;)V +Lcom/android/server/pm/PackageSettingBase;->setTimeStamp(J)V +Lcom/android/server/pm/PackageManagerService;->scanDirLI(Ljava/io/File;IIJ)V +Lcom/android/server/pm/PackageManagerService$PackageParserCallback;->getStaticOverlayPackages(Ljava/util/Collection;Ljava/lang/String;)Ljava/util/List; +Lcom/android/server/pm/ComponentResolver$ActivityIntentResolver;->addActivity(Landroid/content/pm/PackageParser$Activity;Ljava/lang/String;Ljava/util/List;)V Lcom/android/server/IntentResolver;->addFilter(Landroid/util/ArrayMap;Ljava/lang/String;Landroid/content/IntentFilter;)V -Lcom/android/server/pm/PackageManagerService;->assertPackageIsValid(Landroid/content/pm/PackageParser$Package;II)V -Lcom/android/server/pm/PackageManagerService;->getSettingsVersionForPackage(Landroid/content/pm/PackageParser$Package;)Lcom/android/server/pm/Settings$VersionInfo; -Lcom/android/server/pm/KeySetManagerService;->getPublicKeysFromKeySetLPr(J)Landroid/util/ArraySet; +Lcom/android/server/pm/PackageManagerService;->applyPolicy(Landroid/content/pm/PackageParser$Package;IILandroid/content/pm/PackageParser$Package;)V Lcom/android/server/pm/ComponentResolver;->addActivitiesLocked(Landroid/content/pm/PackageParser$Package;Ljava/util/List;Z)V -Lcom/android/server/pm/PackageManagerServiceCompilerMapping;->checkProperties()V +Lcom/android/server/pm/ComponentResolver$ActivityIntentResolver;->access$600(Lcom/android/server/pm/ComponentResolver$ActivityIntentResolver;Landroid/content/pm/PackageParser$Activity;Ljava/lang/String;Ljava/util/List;)V +Lcom/android/server/pm/Settings;->getDisabledSystemPkgLPr(Ljava/lang/String;)Lcom/android/server/pm/PackageSetting; +Lcom/android/server/IntentResolver;->register_mime_types(Landroid/content/IntentFilter;Ljava/lang/String;)I +Lcom/android/server/pm/Settings;->getPackageLPr(Ljava/lang/String;)Lcom/android/server/pm/PackageSetting; +Lcom/android/server/pm/SettingBase;->doCopy(Lcom/android/server/pm/SettingBase;)V +Lcom/android/server/pm/PackageManagerService;->reconcilePackagesLocked(Lcom/android/server/pm/PackageManagerService$ReconcileRequest;Lcom/android/server/pm/KeySetManagerService;)Ljava/util/Map; +Lcom/android/server/pm/ComponentResolver$ActivityIntentResolver;->newArray(I)[Landroid/content/IntentFilter; +Lcom/android/server/pm/ComponentResolver$ActivityIntentResolver;->newArray(I)[Landroid/content/pm/PackageParser$ActivityIntentInfo; +Lcom/android/server/IntentResolver;->addFilter(Landroid/content/IntentFilter;)V Lcom/android/server/pm/Settings;->getSettingLPr(I)Lcom/android/server/pm/SettingBase; -Lcom/android/server/uri/UriGrantsManagerService;-><init>(Landroid/content/Context;)V -Lcom/android/server/pm/Settings;-><init>(Ljava/io/File;Lcom/android/server/pm/permission/PermissionSettings;Ljava/lang/Object;)V -Lcom/android/server/uri/UriGrantsManagerService$Lifecycle;->onStart()V -Lcom/android/server/wm/ActivityTaskManagerService$Lifecycle;->onStart()V -Lcom/android/server/pm/PackageSetting;->updateFrom(Lcom/android/server/pm/PackageSetting;)V -Lcom/android/server/display/DisplayModeDirector$SettingsObserver;-><init>(Lcom/android/server/display/DisplayModeDirector;Landroid/content/Context;Landroid/os/Handler;)V -Lcom/android/server/power/batterysaver/BatterySaverController;-><init>(Ljava/lang/Object;Landroid/content/Context;Landroid/os/Looper;Lcom/android/server/power/batterysaver/BatterySaverPolicy;Lcom/android/server/power/batterysaver/BatterySavingStats;)V -Lcom/android/server/wm/ActivityStackSupervisor;-><init>(Lcom/android/server/wm/ActivityTaskManagerService;Landroid/os/Looper;)V -Lcom/android/server/PackageWatchdog;-><init>(Landroid/content/Context;)V -Lcom/android/server/PackageWatchdog;->getInstance(Landroid/content/Context;)Lcom/android/server/PackageWatchdog; -Lcom/android/server/pm/Settings;->getAllUsers(Lcom/android/server/pm/UserManagerService;)Ljava/util/List; -Lcom/android/server/Watchdog;->addThread(Landroid/os/Handler;)V -Lcom/android/server/Watchdog;->addThread(Landroid/os/Handler;J)V -Lcom/android/server/wm/RecentTasks;-><init>(Lcom/android/server/wm/ActivityTaskManagerService;Lcom/android/server/wm/ActivityStackSupervisor;)V -Lcom/android/server/pm/PackageSettingBase;->updateFrom(Lcom/android/server/pm/PackageSettingBase;)Lcom/android/server/pm/PackageSettingBase; +Lcom/android/server/pm/ComponentResolver;->addAllComponents(Landroid/content/pm/PackageParser$Package;Z)V +Lcom/android/server/pm/ComponentResolver;->addServicesLocked(Landroid/content/pm/PackageParser$Package;Z)V Lcom/android/server/pm/UserManagerService;->getUsers(Z)Ljava/util/List; -Lcom/android/server/firewall/IntentFirewall;->readRulesDir(Ljava/io/File;)V -Lcom/android/server/wm/TaskChangeNotificationController;-><init>(Ljava/lang/Object;Lcom/android/server/wm/ActivityStackSupervisor;Landroid/os/Handler;)V -Lcom/android/server/am/BatteryExternalStatsWorker;->awaitControllerInfo(Landroid/os/SynchronousResultReceiver;)Landroid/os/Parcelable; -Lcom/android/server/display/DisplayManagerService;->addLogicalDisplayLocked(Lcom/android/server/display/DisplayDevice;)Lcom/android/server/display/LogicalDisplay; -Lcom/android/server/display/DisplayManagerService;->updateLogicalDisplaysLocked()Z -Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice;->updatePhysicalDisplayInfoLocked([Landroid/view/SurfaceControl$PhysicalDisplayInfo;I[I[II)Z -Lcom/android/server/display/DisplayDeviceInfo;->toString()Ljava/lang/String; -Lcom/android/server/UiThread;->run()V -Lcom/android/server/pm/PackageKeySetData;->setProperSigningKeySet(J)V -Lcom/android/server/UiThread;->ensureThreadLocked()V -Lcom/android/server/UiThread;->getHandler()Landroid/os/Handler; -Lcom/android/server/pm/Settings;->getPackageLPr(Ljava/lang/String;)Lcom/android/server/pm/PackageSetting; -Lcom/android/server/IoThread;->ensureThreadLocked()V -Lcom/android/server/IoThread;->getHandler()Landroid/os/Handler; Lcom/android/server/pm/Settings;->getInternalVersion()Lcom/android/server/pm/Settings$VersionInfo; -Lcom/android/server/appop/AppOpsService$Op;->running(JJII)V -Lcom/android/server/appop/AppOpsService$Op;->updateAccessTimeAndDuration(JJII)V -Lcom/android/server/appop/AppOpsService$Op;->rejected(JILjava/lang/String;II)V -Lcom/android/server/DisplayThread;->ensureThreadLocked()V -Lcom/android/server/DisplayThread;->getHandler()Landroid/os/Handler; -Lcom/android/server/am/UserController;-><init>(Lcom/android/server/am/UserController$Injector;)V -Lcom/android/server/AnimationThread;->ensureThreadLocked()V -Lcom/android/server/AnimationThread;->getHandler()Landroid/os/Handler; -Lcom/android/server/wm/SurfaceAnimationThread;->ensureThreadLocked()V -Lcom/android/server/wm/SurfaceAnimationThread;->getHandler()Landroid/os/Handler; -Lcom/android/server/wm/ActivityStackSupervisor;->initialize()V -Lcom/android/server/pm/PackageSettingBase;->readUserState(I)Landroid/content/pm/PackageUserState; +Lcom/android/server/pm/Settings;->getRenamedPackageLPr(Ljava/lang/String;)Ljava/lang/String; +Lcom/android/server/pm/PackageManagerService;->getRealPackageName(Landroid/content/pm/PackageParser$Package;Ljava/lang/String;)Ljava/lang/String; +Lcom/android/server/pm/PackageManagerService;->getOriginalPackageLocked(Landroid/content/pm/PackageParser$Package;Ljava/lang/String;)Lcom/android/server/pm/PackageSetting; +Lcom/android/server/pm/PackageSetting;-><init>(Lcom/android/server/pm/PackageSetting;)V +Lcom/android/server/pm/PackageSettingBase;-><init>(Lcom/android/server/pm/PackageSettingBase;Ljava/lang/String;)V +Lcom/android/server/pm/SettingBase;-><init>(Lcom/android/server/pm/SettingBase;)V +Lcom/android/server/pm/PackageSetting;->doCopy(Lcom/android/server/pm/PackageSetting;)V +Lcom/android/server/pm/PackageManagerService;->isSystemApp(Landroid/content/pm/PackageParser$Package;)Z +Lcom/android/server/pm/PackageManagerServiceUtils;->getLastModifiedTime(Landroid/content/pm/PackageParser$Package;)J +Lcom/android/server/pm/PackageManagerService;->getSettingsVersionForPackage(Landroid/content/pm/PackageParser$Package;)Lcom/android/server/pm/Settings$VersionInfo; +Lcom/android/server/pm/PackageManagerService;->isExternal(Landroid/content/pm/PackageParser$Package;)Z +Lcom/android/server/pm/PackageManagerService;->isCompatSignatureUpdateNeeded(Lcom/android/server/pm/Settings$VersionInfo;)Z +Lcom/android/server/pm/PackageManagerService;->isRecoverSignatureUpdateNeeded(Lcom/android/server/pm/Settings$VersionInfo;)Z +Lcom/android/server/pm/PackageSettingBase;->updateFrom(Lcom/android/server/pm/PackageSettingBase;)Lcom/android/server/pm/PackageSettingBase; +Lcom/android/server/pm/UserManagerService;->getInstance()Lcom/android/server/pm/UserManagerService; +Lcom/android/server/pm/Settings;->writeUserRestrictionsLPw(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;)V +Lcom/android/server/pm/KeySetManagerService;->getPublicKeysFromKeySetLPr(J)Landroid/util/ArraySet; +Lcom/android/server/pm/PackageSettingBase;->getInstantApp(I)Z +Lcom/android/server/pm/ComponentResolver;->addReceiversLocked(Landroid/content/pm/PackageParser$Package;Z)V +Lcom/android/server/pm/ComponentResolver;->addProvidersLocked(Landroid/content/pm/PackageParser$Package;Z)V +Lcom/android/server/pm/ComponentResolver$ServiceIntentResolver;->addService(Landroid/content/pm/PackageParser$Service;)V +Lcom/android/server/pm/PackageManagerService$PackageManagerInternalImpl;->getDisabledSystemPackage(Ljava/lang/String;)Landroid/content/pm/PackageParser$Package; +Lcom/android/server/pm/ComponentResolver;->adjustPriority(Ljava/util/List;Landroid/content/pm/PackageParser$ActivityIntentInfo;Ljava/lang/String;)V +Lcom/android/server/pm/ComponentResolver;->isProtectedAction(Landroid/content/pm/PackageParser$ActivityIntentInfo;)Z +Lcom/android/server/pm/Settings;->addPackageSettingLPw(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/SharedUserSetting;)V +Lcom/android/server/pm/PackageInstallerService;->isStageName(Ljava/lang/String;)Z +Lcom/android/server/pm/ParallelPackageParser;->submit(Ljava/io/File;I)V +Lcom/android/server/pm/-$$Lambda$ParallelPackageParser$FTtinPrp068lVeI7K6bC1tNE3iM;-><init>(Lcom/android/server/pm/ParallelPackageParser;Ljava/io/File;I)V +Lcom/android/server/IntentResolver;->filterEquals(Landroid/content/IntentFilter;Landroid/content/IntentFilter;)Z +Lcom/android/server/IntentResolver;->collectFilters([Landroid/content/IntentFilter;Landroid/content/IntentFilter;)Ljava/util/ArrayList; +Lcom/android/server/pm/-$$Lambda$ParallelPackageParser$FTtinPrp068lVeI7K6bC1tNE3iM;->run()V +Lcom/android/server/pm/ParallelPackageParser;->lambda$submit$0$ParallelPackageParser(Ljava/io/File;I)V +Lcom/android/server/pm/ParallelPackageParser$ParseResult;-><init>()V +Lcom/android/server/pm/ParallelPackageParser;->parsePackage(Landroid/content/pm/PackageParser;Ljava/io/File;I)Landroid/content/pm/PackageParser$Package; +Lcom/android/server/pm/PackageManagerService$PackageParserCallback;->getOverlayApks(Ljava/lang/String;)[Ljava/lang/String; +Lcom/android/server/pm/PackageManagerService$ParallelPackageParserCallback;->getStaticOverlayPaths(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String; +Lcom/android/server/IntentResolver;->findFilters(Landroid/content/IntentFilter;)Ljava/util/ArrayList; +Lcom/android/server/pm/ComponentResolver;->findMatchingActivity(Ljava/util/List;Landroid/content/pm/ActivityInfo;)Landroid/content/pm/PackageParser$Activity; +Lcom/android/server/pm/ComponentResolver$ProviderIntentResolver;->addProvider(Landroid/content/pm/PackageParser$Provider;)V +Lcom/android/server/pm/PackageManagerService$Injector$Singleton;->get(Lcom/android/server/pm/PackageManagerService$Injector;Lcom/android/server/pm/PackageManagerService;)Ljava/lang/Object; +Lcom/android/server/pm/ParallelPackageParser;->take()Lcom/android/server/pm/ParallelPackageParser$ParseResult; +Lcom/android/server/pm/PackageManagerService;->scanPackageOnlyLI(Lcom/android/server/pm/PackageManagerService$ScanRequest;Lcom/android/server/pm/PackageManagerService$Injector;ZJ)Lcom/android/server/pm/PackageManagerService$ScanResult; +Lcom/android/server/pm/PackageManagerService$Injector;->getUserManagerService()Lcom/android/server/pm/UserManagerService; +Lcom/android/server/pm/ComponentResolver;->getIntentListSubset(Ljava/util/List;Lcom/android/server/pm/ComponentResolver$IterGenerator;Ljava/util/Iterator;)V +Lcom/android/server/pm/PackageManagerService;->scanPackageChildLI(Landroid/content/pm/PackageParser$Package;IIJLandroid/os/UserHandle;)Landroid/content/pm/PackageParser$Package; +Lcom/android/server/pm/PackageManagerService;->addForInitLI(Landroid/content/pm/PackageParser$Package;IIJLandroid/os/UserHandle;)Landroid/content/pm/PackageParser$Package; Lcom/android/server/pm/PackageManagerServiceUtils;->getCompressedFiles(Ljava/lang/String;)[Ljava/io/File; -Lcom/android/server/pm/Settings;->insertPackageSettingLPw(Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$Package;)V -Lcom/android/server/pm/ComponentResolver$ActivityIntentResolver;->addActivity(Landroid/content/pm/PackageParser$Activity;Ljava/lang/String;Ljava/util/List;)V -Lcom/android/server/pm/Installer;->invalidateMounts()V -Lcom/android/server/power/PowerManagerService$NativeWrapper;->nativeInit(Lcom/android/server/power/PowerManagerService;)V -Lcom/android/server/power/ThermalManagerService;->onStart()V -Lcom/android/server/am/OomAdjProfiler;-><init>()V -Lcom/android/server/pm/PackageManagerService;->maybeClearProfilesForUpgradesLI(Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$Package;)V -Lcom/android/server/am/ActivityManagerConstants;-><init>(Lcom/android/server/am/ActivityManagerService;Landroid/os/Handler;)V -Lcom/android/server/IntentResolver;-><init>()V +Lcom/android/server/pm/PackageManagerService$ScanRequest;-><init>(Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/SharedUserSetting;Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Ljava/lang/String;IIZLandroid/os/UserHandle;)V +Lcom/android/server/pm/PackageManagerService$Injector;->getAbiHelper()Lcom/android/server/pm/PackageAbiHelper; +Lcom/android/server/pm/PackageManagerService$Injector;->getUserManagerInternal()Landroid/os/UserManagerInternal; +Lcom/android/server/pm/UserManagerService;->getInternalForInjectorOnly()Landroid/os/UserManagerInternal; Lcom/android/server/pm/Settings;->updatePackageSetting(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/SharedUserSetting;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IILjava/util/List;Lcom/android/server/pm/UserManagerService;[Ljava/lang/String;[J)V -Lcom/android/server/PackageWatchdog;->loadFromFile()V -Lcom/android/server/power/batterysaver/BatterySaverPolicy;-><init>(Ljava/lang/Object;Landroid/content/Context;Lcom/android/server/power/batterysaver/BatterySavingStats;)V -Lcom/android/server/power/AttentionDetector;-><init>(Ljava/lang/Runnable;Ljava/lang/Object;)V -Lcom/android/server/pm/dex/DexManager;-><init>(Landroid/content/Context;Landroid/content/pm/IPackageManager;Lcom/android/server/pm/PackageDexOptimizer;Lcom/android/server/pm/Installer;Ljava/lang/Object;)V -Lcom/android/server/appop/AppOpsService$Op;-><init>(Lcom/android/server/appop/AppOpsService$UidState;Ljava/lang/String;I)V -Lcom/android/server/pm/UserManagerService;->readUserLP(I)Lcom/android/server/pm/UserManagerService$UserData; -Lcom/android/server/pm/UserManagerService;->readUserLP(ILjava/io/InputStream;)Lcom/android/server/pm/UserManagerService$UserData; -Lcom/android/server/pm/UserRestrictionsUtils;->readRestrictions(Lorg/xmlpull/v1/XmlPullParser;)Landroid/os/Bundle; -Lcom/android/server/pm/UserRestrictionsUtils;->readRestrictions(Lorg/xmlpull/v1/XmlPullParser;Landroid/os/Bundle;)V -Lcom/android/server/pm/PackageManagerService;->adjustScanFlags(ILcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Landroid/os/UserHandle;Landroid/content/pm/PackageParser$Package;)I -Lcom/android/server/pm/SettingBase;->setFlags(I)V -Lcom/android/server/display/LogicalDisplay;->updateLocked(Ljava/util/List;)V -Lcom/android/server/Watchdog$HandlerChecker;->run()V -Lcom/android/server/Watchdog;->run()V -Lcom/android/server/display/DisplayAdapter$1;->run()V -Lcom/android/server/display/DisplayManagerService$DisplayManagerHandler;->handleMessage(Landroid/os/Message;)V -Lcom/android/server/pm/PackageManagerServiceCompilerMapping;->getAndCheckValidity(I)Ljava/lang/String; -Lcom/android/server/pm/ParallelPackageParser;->take()Lcom/android/server/pm/ParallelPackageParser$ParseResult; -Lcom/android/server/pm/KeySetManagerService;->assertScannedPackageValid(Landroid/content/pm/PackageParser$Package;)V -Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice$1;->run()V -Lcom/android/server/pm/PackageManagerServiceUtils;->verifySignatures(Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageSetting;Landroid/content/pm/PackageParser$SigningDetails;ZZ)Z -Lcom/android/server/pm/PackageManagerService;->getSharedLibLatestVersionSetting(Lcom/android/server/pm/PackageManagerService$ScanResult;)Lcom/android/server/pm/PackageSetting; -Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice$1;->setDisplayBrightness(I)V -Lcom/android/server/pm/PackageManagerService;->getLatestSharedLibraVersionLPr(Landroid/content/pm/PackageParser$Package;)Landroid/content/pm/SharedLibraryInfo; -Lcom/android/server/pm/PackageManagerServiceCompilerMapping;->getSystemPropertyName(I)Ljava/lang/String; -Lcom/android/server/lights/LightsService$LightImpl;->setLightLocked(IIIII)V -Lcom/android/server/lights/LightsService$LightImpl;->setBrightness(I)V -Lcom/android/server/lights/LightsService$LightImpl;->setBrightness(II)V -Lcom/android/server/Watchdog$HandlerChecker;->scheduleCheckLocked()V -Lcom/android/server/pm/permission/PermissionsState;->copyFrom(Lcom/android/server/pm/permission/PermissionsState;)V -Lcom/android/server/pm/permission/PermissionManagerService$PermissionManagerServiceInternalImpl;->addAllPermissionGroups(Landroid/content/pm/PackageParser$Package;Z)V -Lcom/android/server/RecoverySystemService;->onStart()V -Lcom/android/server/display/DisplayManagerService;->onBootPhase(I)V -Lcom/android/server/am/ProcessList;->updateOomLevels(IIZ)V -Lcom/android/server/am/OomAdjProfiler;->batteryPowerChanged(Z)V +Lcom/android/server/pm/PackageManagerService;->setInstantAppForUser(Lcom/android/server/pm/PackageManagerService$Injector;Lcom/android/server/pm/PackageSetting;IZZ)V +Lcom/android/server/pm/PackageManagerServiceUtils;->deriveAbiOverride(Ljava/lang/String;Lcom/android/server/pm/PackageSetting;)Ljava/lang/String; +Lcom/android/server/pm/PackageAbiHelperImpl;->getNativeLibraryPaths(Landroid/content/pm/PackageParser$Package;Ljava/io/File;)Lcom/android/server/pm/PackageAbiHelper$NativeLibraryPaths; +Lcom/android/server/pm/PackageAbiHelper$Abis;-><init>(Landroid/content/pm/PackageParser$Package;)V +Lcom/android/server/pm/PackageAbiHelper$Abis;-><init>(Ljava/lang/String;Ljava/lang/String;)V +Lcom/android/server/pm/PackageAbiHelperImpl;->getNativeLibraryPaths(Lcom/android/server/pm/PackageAbiHelper$Abis;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;ZZ)Lcom/android/server/pm/PackageAbiHelper$NativeLibraryPaths; +Lcom/android/server/pm/InstructionSets;->getPrimaryInstructionSet(Lcom/android/server/pm/PackageAbiHelper$Abis;)Ljava/lang/String; +Lcom/android/server/pm/PackageAbiHelper$NativeLibraryPaths;-><init>(Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V +Lcom/android/server/pm/PackageAbiHelper$NativeLibraryPaths;->applyTo(Landroid/content/pm/PackageParser$Package;)V +Lcom/android/server/pm/PackageManagerService$ScanResult;-><init>(Lcom/android/server/pm/PackageManagerService$ScanRequest;ZLcom/android/server/pm/PackageSetting;Ljava/util/List;ZLandroid/content/pm/SharedLibraryInfo;Ljava/util/List;)V +Lcom/android/server/pm/PackageSetting;->updateFrom(Lcom/android/server/pm/PackageSetting;)V +Lcom/android/server/pm/SettingBase;->copyFrom(Lcom/android/server/pm/SettingBase;)V +Lcom/android/server/pm/ComponentResolver$ActivityIntentResolver;->allowFilterResult(Landroid/content/pm/PackageParser$ActivityIntentInfo;Ljava/util/List;)Z +Lcom/android/server/pm/PackageManagerService;->executeSharedLibrariesUpdateLPr(Landroid/content/pm/PackageParser$Package;Landroid/content/pm/PackageParser$Package;Ljava/util/ArrayList;)V +Lcom/android/server/pm/PackageManagerService;->collectSharedLibraryInfos(Ljava/util/List;[J[[Ljava/lang/String;Ljava/lang/String;ZILjava/util/ArrayList;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)Ljava/util/ArrayList; +Lcom/android/server/pm/PackageManagerService;->getSharedLibraryInfo(Ljava/lang/String;JLjava/util/Map;Ljava/util/Map;)Landroid/content/pm/SharedLibraryInfo; +Lcom/android/server/pm/PackageManagerService;->addSharedLibraryLPr(Landroid/content/pm/PackageParser$Package;Ljava/util/Set;Landroid/content/pm/SharedLibraryInfo;Landroid/content/pm/PackageParser$Package;)V +Lcom/android/server/pm/PackageUsage;->readToken(Ljava/io/InputStream;Ljava/lang/StringBuffer;C)Ljava/lang/String; +Lcom/android/server/pm/PackageUsage;->readVersion1LP(Ljava/util/Map;Ljava/io/InputStream;Ljava/lang/StringBuffer;)V +Lcom/android/server/pm/PackageUsage;->parseAsLong(Ljava/lang/String;)J +Lcom/android/server/pm/CompilerStats;->read(Ljava/io/Reader;)Z +Lcom/android/server/pm/permission/BasePermission;->getSourcePackageSetting()Lcom/android/server/pm/PackageSettingBase; +Lcom/android/server/pm/permission/PermissionManagerService;->updatePermissionSourcePackage(Ljava/lang/String;Landroid/content/pm/PackageParser$Package;)Z +Lcom/android/server/pm/permission/BasePermission;->isDynamic()Z +Lcom/android/server/pm/permission/PermissionManagerService;->cacheBackgroundToForegoundPermissionMapping()V +Lcom/android/server/pm/PackageManagerService$PackageManagerInternalImpl;->getKnownPackageName(II)Ljava/lang/String; +Lcom/android/server/pm/PackageSetting;->isSystem()Z +Lcom/android/server/pm/permission/PermissionsState;->hasInstallPermission(Ljava/lang/String;)Z +Lcom/android/server/pm/permission/PermissionsState;->getPermissions(I)Ljava/util/Set; +Lcom/android/server/pm/permission/PermissionManagerService;->revokePermissionsNoLongerImplicitLocked(Lcom/android/server/pm/permission/PermissionsState;Landroid/content/pm/PackageParser$Package;[I)[I +Lcom/android/server/pm/PackageSetting;->getPermissionsState()Lcom/android/server/pm/permission/PermissionsState; +Lcom/android/server/pm/permission/PermissionsState;->grantRuntimePermission(Lcom/android/server/pm/permission/BasePermission;I)I +Lcom/android/server/pm/permission/PermissionManagerService;->restorePermissionState(Landroid/content/pm/PackageParser$Package;ZLjava/lang/String;Lcom/android/server/pm/permission/PermissionManagerServiceInternal$PermissionCallback;)V +Lcom/android/server/pm/permission/PermissionsState;->getPermissionState(Ljava/lang/String;I)Lcom/android/server/pm/permission/PermissionsState$PermissionState; +Lcom/android/server/pm/permission/PermissionsState$PermissionData;->getPermissionState(I)Lcom/android/server/pm/permission/PermissionsState$PermissionState; +Lcom/android/server/pm/PackageSettingBase;->getPermissionsState()Lcom/android/server/pm/permission/PermissionsState; +Lcom/android/server/pm/permission/PermissionsState;->getRuntimePermissionState(Ljava/lang/String;I)Lcom/android/server/pm/permission/PermissionsState$PermissionState; +Lcom/android/server/pm/permission/PermissionsState;->hasRequestedPermission(Ljava/lang/String;)Z +Lcom/android/server/pm/permission/BasePermission;->isRuntimeOnly()Z +Lcom/android/server/pm/permission/BasePermission;->isAppOp()Z +Lcom/android/server/pm/permission/BasePermission;->isNormal()Z +Lcom/android/server/pm/permission/PermissionManagerService;->setInitialGrantForNewImplicitPermissionsLocked(Lcom/android/server/pm/permission/PermissionsState;Lcom/android/server/pm/permission/PermissionsState;Landroid/content/pm/PackageParser$Package;Landroid/util/ArraySet;[I)[I +Lcom/android/server/pm/UserManagerService;->getUserIds()[I +Lcom/android/server/pm/permission/PermissionsState$PermissionState;->getFlags()I +Lcom/android/server/pm/permission/BasePermission;->isRuntime()Z +Lcom/android/server/pm/permission/PermissionsState;->hasRuntimePermission(Ljava/lang/String;I)Z +Lcom/android/server/pm/PackageSettingBase;->getSigningDetails()Landroid/content/pm/PackageParser$SigningDetails; +Lcom/android/server/pm/permission/BasePermission;->isVendorPrivileged()Z +Lcom/android/server/pm/permission/BasePermission;->isSignature()Z +Lcom/android/server/pm/permission/PermissionManagerService;->grantSignaturePermission(Ljava/lang/String;Landroid/content/pm/PackageParser$Package;Lcom/android/server/pm/permission/BasePermission;Lcom/android/server/pm/permission/PermissionsState;)Z +Lcom/android/server/pm/permission/BasePermission;->isOEM()Z +Lcom/android/server/pm/permission/BasePermission;->isPrivileged()Z +Lcom/android/server/pm/permission/BasePermission;->getSourcePackageName()Ljava/lang/String; +Lcom/android/server/pm/PackageManagerService$PackageManagerInternalImpl;->getPackage(Ljava/lang/String;)Landroid/content/pm/PackageParser$Package; +Lcom/android/server/pm/PackageManagerService;->access$5700(Lcom/android/server/pm/PackageManagerService;Ljava/lang/String;J)Ljava/lang/String; +Lcom/android/server/pm/PackageManagerService;->resolveInternalPackageNameLPr(Ljava/lang/String;J)Ljava/lang/String; +Lcom/android/server/pm/permission/PermissionsState;->getPermissionFlags(Ljava/lang/String;I)I +Lcom/android/server/pm/permission/PermissionsState;->getInstallPermissionState(Ljava/lang/String;)Lcom/android/server/pm/permission/PermissionsState$PermissionState; +Lcom/android/server/pm/permission/PermissionManagerService;->hasPrivappWhitelistEntry(Ljava/lang/String;Landroid/content/pm/PackageParser$Package;)Z +Lcom/android/server/pm/permission/BasePermission;->isHardRestricted()Z +Lcom/android/server/pm/permission/BasePermission;->isSoftRestricted()Z +Lcom/android/server/pm/permission/PermissionsState$PermissionState;->isGranted()Z +Lcom/android/server/pm/PackageManagerService;->reconcileAppsDataLI(Ljava/lang/String;IIZZ)Ljava/util/List; +Lcom/android/server/pm/permission/BasePermission;->writeLPr(Lorg/xmlpull/v1/XmlSerializer;)V +Lcom/android/server/pm/permission/PermissionSettings;->writePermissions(Lorg/xmlpull/v1/XmlSerializer;)V +Lcom/android/server/pm/permission/PermissionsState;->getPermissionStatesInternal(I)Ljava/util/List; +Lcom/android/server/pm/Settings;->writePermissionsLPr(Lorg/xmlpull/v1/XmlSerializer;Ljava/util/List;)V +Lcom/android/server/pm/permission/PermissionsState$PermissionState;->getName()Ljava/lang/String; +Lcom/android/server/pm/PackageKeySetData;->getProperSigningKeySet()J +Lcom/android/server/pm/PackageSignatures;->writeCertsListXml(Lorg/xmlpull/v1/XmlSerializer;Ljava/util/ArrayList;[Landroid/content/pm/Signature;Z)V +Lcom/android/server/pm/Settings;->writeLPr()V +Lcom/android/server/pm/Settings;->writeUsesStaticLibLPw(Lorg/xmlpull/v1/XmlSerializer;[Ljava/lang/String;[J)V +Lcom/android/server/pm/Settings;->writeChildPackagesLPw(Lorg/xmlpull/v1/XmlSerializer;Ljava/util/List;)V +Lcom/android/server/pm/permission/PermissionsState;->getInstallPermissionStates()Ljava/util/List; +Lcom/android/server/pm/KeySetManagerService$PublicKeyHandle;->getKey()Ljava/security/PublicKey; +Lcom/android/server/pm/Settings;->writeKernelMappingLPr(Ljava/lang/String;I[I)V +Lcom/android/server/pm/Settings;->writeIntToFile(Ljava/io/File;I)V +Lcom/android/server/pm/Settings;->writeKernelMappingLPr(Lcom/android/server/pm/PackageSetting;)V +Lcom/android/server/pm/Settings;->writePackageListLPrInternal(I)V +Lcom/android/server/pm/permission/PermissionsState;->computeGids([I)[I +Lcom/android/server/pm/Settings;->writePackageRestrictionsLPr(I)V +Lcom/android/server/IntentResolver;->buildResolveList(Landroid/content/Intent;Landroid/util/FastImmutableArraySet;ZZLjava/lang/String;Ljava/lang/String;[Landroid/content/IntentFilter;Ljava/util/List;I)V +Lcom/android/server/pm/ComponentResolver$ActivityIntentResolver;->allowFilterResult(Landroid/content/IntentFilter;Ljava/util/List;)Z +Lcom/android/server/pm/ComponentResolver$ActivityIntentResolver;->queryIntentForPackage(Landroid/content/Intent;Ljava/lang/String;ILjava/util/List;I)Ljava/util/List; +Lcom/android/server/pm/ComponentResolver$ActivityIntentResolver;->isPackageForFilter(Ljava/lang/String;Landroid/content/IntentFilter;)Z +Lcom/android/server/pm/ComponentResolver$ActivityIntentResolver;->isPackageForFilter(Ljava/lang/String;Landroid/content/pm/PackageParser$ActivityIntentInfo;)Z +Lcom/android/server/pm/PackageSettingBase;->getInstalled(I)Z +Lcom/android/server/pm/PackageManagerService;->getInstantAppPackageName(I)Ljava/lang/String; +Lcom/android/server/pm/PackageManagerService;->shouldFilterApplicationLocked(Lcom/android/server/pm/PackageSetting;II)Z +Lcom/android/server/pm/PackageManagerService;->shouldFilterApplicationLocked(Lcom/android/server/pm/PackageSetting;ILandroid/content/ComponentName;II)Z +Lcom/android/server/pm/PackageManagerService;->isCallerSameApp(Ljava/lang/String;I)Z +Lcom/android/server/pm/AppsFilter;->shouldFilterApplication(ILcom/android/server/pm/SettingBase;Lcom/android/server/pm/PackageSetting;I)Z +Lcom/android/server/pm/UserManagerService$LocalService;->exists(I)Z +Lcom/android/server/pm/UserManagerService;->access$2900(Lcom/android/server/pm/UserManagerService;I)Landroid/content/pm/UserInfo; +Lcom/android/server/pm/UserManagerService;->getUserInfoNoChecks(I)Landroid/content/pm/UserInfo; +Lcom/android/server/pm/UserManagerService;->exists(I)Z +Lcom/android/server/pm/dex/DexManager;->putIfAbsent(Ljava/util/Map;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +Lcom/android/server/pm/dex/DexManager;->cachePackageCodeLocation(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;I)V +Lcom/android/server/pm/dex/DexManager$PackageCodeLocations;->mergeAppDataDirs(Ljava/lang/String;I)V +Lcom/android/server/pm/dex/DexManager;->access$300(Ljava/util/Map;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +Lcom/android/server/pm/dex/DexManager$PackageCodeLocations;->updateCodeLocation(Ljava/lang/String;[Ljava/lang/String;)V +Lcom/android/server/appop/AppOpsService$Op;->access$100(Lcom/android/server/appop/AppOpsService$Op;)I +Lcom/android/server/pm/PackageManagerService;->generatePackageInfo(Lcom/android/server/pm/PackageSetting;II)Landroid/content/pm/PackageInfo; +Lcom/android/server/pm/PackageManagerService;->resolveExternalPackageNameLPr(Landroid/content/pm/PackageParser$Package;)Ljava/lang/String; +Lcom/android/server/pm/Settings$RuntimePermissionPersistence;->writePermissionsSync(I)V +Lcom/android/server/pm/Settings$RuntimePermissionPersistence;->writePermissions(Lorg/xmlpull/v1/XmlSerializer;Ljava/util/List;)V +Lcom/android/server/om/OverlayManagerSettings$SettingsItem;->access$1600(Lcom/android/server/om/OverlayManagerSettings$SettingsItem;)I +Lcom/android/server/pm/PackageManagerService;->filterSharedLibPackageLPr(Lcom/android/server/pm/PackageSetting;III)Z +Lcom/android/server/om/OverlayManagerSettings;->select(Ljava/lang/String;I)I +Lcom/android/server/om/OverlayManagerSettings$SettingsItem;->access$1100(Lcom/android/server/om/OverlayManagerSettings$SettingsItem;)Ljava/lang/String; +Lcom/android/server/pm/PackageManagerServiceUtils;->compareSignatures([Landroid/content/pm/Signature;[Landroid/content/pm/Signature;)I +Lcom/android/server/om/-$$Lambda$OverlayManagerSettings$Fjt465P6G89HQZERZFsOEjMbtXI;->test(Ljava/lang/Object;)Z +Lcom/android/server/om/OverlayManagerSettings;->lambda$selectWhereUser$10(ILcom/android/server/om/OverlayManagerSettings$SettingsItem;)Z +Lcom/android/server/om/OverlayManagerSettings$SettingsItem;->access$1000(Lcom/android/server/om/OverlayManagerSettings$SettingsItem;)Ljava/lang/String; +Lcom/android/server/om/OverlayManagerSettings$SettingsItem;->getTargetPackageName()Ljava/lang/String; +Lcom/android/server/om/-$$Lambda$OverlayManagerSettings$L_Sj43p2Txm_KH-wT0lseBTVzh8;->test(Ljava/lang/Object;)Z +Lcom/android/server/om/OverlayManagerSettings;->lambda$selectWhereTarget$11(Ljava/lang/String;Lcom/android/server/om/OverlayManagerSettings$SettingsItem;)Z +Lcom/android/server/om/OverlayManagerService;->updateOverlayPaths(ILjava/util/List;)V +Lcom/android/server/usage/UsageStatsProto;->loadUsageStats(Landroid/util/proto/ProtoInputStream;JLcom/android/server/usage/IntervalStats;Ljava/util/List;)V +Lcom/android/server/usage/UsageStatsProto;->read(Ljava/io/InputStream;Lcom/android/server/usage/IntervalStats;)V +Lcom/android/server/usage/UsageStatsProto;->readStringPool(Landroid/util/proto/ProtoInputStream;)Ljava/util/List; +Lcom/android/server/usage/IntervalStats;->getOrCreateUsageStats(Ljava/lang/String;)Landroid/app/usage/UsageStats; +Lcom/android/server/usage/IntervalStats;->getCachedStringRef(Ljava/lang/String;)Ljava/lang/String; +Lcom/android/server/pm/ComponentResolver$ProviderIntentResolver;->access$400(Lcom/android/server/pm/ComponentResolver$ProviderIntentResolver;)Landroid/util/ArrayMap; +Lcom/android/server/pm/ComponentResolver;->queryProviders(Ljava/lang/String;Ljava/lang/String;III)Ljava/util/List; +Lcom/android/server/pm/PackageManagerService;->getInstalledPackages(II)Landroid/content/pm/ParceledListSlice; +Lcom/android/server/content/ContentService$ObserverNode;->addObserverLocked(Landroid/net/Uri;ILandroid/database/IContentObserver;ZLjava/lang/Object;III)V +Lcom/android/server/am/ActivityManagerService;->registerReceiver(Landroid/app/IApplicationThread;Ljava/lang/String;Landroid/content/IIntentReceiver;Landroid/content/IntentFilter;Ljava/lang/String;II)Landroid/content/Intent; +Lcom/android/server/appop/AppOpsService;->evalAllForegroundOpsLocked()V +Lcom/android/server/DropBoxManagerService$EntryFile;->compareTo(Ljava/lang/Object;)I +Lcom/android/server/DropBoxManagerService$EntryFile;->compareTo(Lcom/android/server/DropBoxManagerService$EntryFile;)I +Lcom/android/server/DropBoxManagerService$EntryFile;->hasFile()Z +Lcom/android/server/DropBoxManagerService;->init()V +Lcom/android/server/DropBoxManagerService$EntryFile;-><init>(Ljava/io/File;I)V +Lcom/android/server/DropBoxManagerService;->enrollEntry(Lcom/android/server/DropBoxManagerService$EntryFile;)V +Lcom/android/server/ThreadPriorityBooster;->boost()V +Lcom/android/server/ThreadPriorityBooster;->reset()V +Lcom/android/server/wm/DisplayPolicy;->hasNavigationBar()Z +Lcom/android/server/wm/DisplayPolicy;->navigationBarPosition(III)I +Lcom/android/server/wm/DisplayPolicy;->navigationBarCanMove()Z +Lcom/android/server/PersistentDataBlockService;->computeDigestLocked([B)[B +Lcom/android/server/am/ActivityManagerService;->boostPriorityForLockedSection()V +Lcom/android/server/am/ActivityManagerService;->resetPriorityAfterLockedSection()V +Lcom/android/server/PinnerService;->clamp(III)I +Lcom/android/server/am/ActivityManagerService;->checkComponentPermission(Ljava/lang/String;IIIZ)I +Lcom/android/server/notification/PreferencesHelper;->readXml(Lorg/xmlpull/v1/XmlPullParser;ZI)V +Lcom/android/server/pm/PackageManagerService;->updateFlags(II)I +Lcom/android/server/pm/UserManagerService;->access$2800(Lcom/android/server/pm/UserManagerService;)Landroid/util/SparseIntArray; +Lcom/android/server/pm/ComponentResolver$ServiceIntentResolver;->queryIntentForPackage(Landroid/content/Intent;Ljava/lang/String;ILjava/util/List;I)Ljava/util/List; +Lcom/android/server/IntentResolver;->queryIntentFromList(Landroid/content/Intent;Ljava/lang/String;ZLjava/util/ArrayList;I)Ljava/util/List; +Lcom/android/server/pm/ComponentResolver$ServiceIntentResolver;->allowFilterResult(Landroid/content/pm/PackageParser$ServiceIntentInfo;Ljava/util/List;)Z +Lcom/android/server/pm/ComponentResolver$ServiceIntentResolver;->allowFilterResult(Landroid/content/IntentFilter;Ljava/util/List;)Z +Lcom/android/server/pm/ComponentResolver$ServiceIntentResolver;->isPackageForFilter(Ljava/lang/String;Landroid/content/IntentFilter;)Z +Lcom/android/server/pm/ComponentResolver$ServiceIntentResolver;->isPackageForFilter(Ljava/lang/String;Landroid/content/pm/PackageParser$ServiceIntentInfo;)Z +Lcom/android/server/notification/PreferencesHelper;->writeXml(Lorg/xmlpull/v1/XmlSerializer;ZI)V +Lcom/android/server/am/UserController;->handleIncomingUser(IIIZILjava/lang/String;Ljava/lang/String;)I +Lcom/android/server/am/UserController;->unsafeConvertIncomingUser(I)I +Lcom/android/server/audio/AudioService$VolumeStreamState;->hasValidSettingsName()Z +Lcom/android/server/audio/AudioService$VolumeStreamState;->readSettings()V +Lcom/android/server/am/ActivityManagerService;->handleIncomingUser(IIIZZLjava/lang/String;Ljava/lang/String;)I +Lcom/android/server/am/UserController;->getCurrentUserId()I +Lcom/android/server/am/UserController;->ensureNotSpecialUser(I)V +Lcom/android/server/audio/AudioService;->access$2800(Lcom/android/server/audio/AudioService;)Landroid/content/ContentResolver; +Lcom/android/server/audio/AudioService$VolumeStreamState;->getSettingNameForDevice(I)Ljava/lang/String; +Lcom/android/server/pm/permission/PermissionManagerService$PermissionManagerServiceInternalImpl;->enforceCrossUserPermission(IIZZLjava/lang/String;)V +Lcom/android/server/pm/permission/PermissionManagerService;->access$1900(Lcom/android/server/pm/permission/PermissionManagerService;IIZZZLjava/lang/String;)V +Lcom/android/server/pm/permission/PermissionManagerService;->enforceCrossUserPermission(IIZZZLjava/lang/String;)V +Lcom/android/server/pm/UserManagerService;->userWithName(Landroid/content/pm/UserInfo;)Landroid/content/pm/UserInfo; +Lcom/android/server/pm/UserManagerService;->checkManageOrCreateUsersPermission(Ljava/lang/String;)V +Lcom/android/server/pm/UserManagerService;->hasManageOrCreateUsersPermission()Z Lcom/android/server/pm/UserManagerService;->hasManageUsersOrPermission(Ljava/lang/String;)Z -Lcom/android/server/am/OomAdjProfiler;->scheduleSystemServerCpuTimeUpdate()V -Lcom/android/server/pm/PackageManagerService$ReconcileRequest;-><init>(Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Lcom/android/server/pm/PackageManagerService$1;)V -Lcom/android/server/pm/PackageManagerService$ReconcileRequest;-><init>(Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;)V -Lcom/android/server/wm/ConfigurationContainer;->onConfigurationChanged(Landroid/content/res/Configuration;)V -Lcom/android/server/wm/RootActivityContainer;-><init>(Lcom/android/server/wm/ActivityTaskManagerService;)V -Lcom/android/server/wm/ActivityTaskManagerService;->createRecentTasks()Lcom/android/server/wm/RecentTasks; -Lcom/android/server/am/OomAdjuster;->updateOomAdjLocked()V -Lcom/android/server/am/OomAdjuster;->updateOomAdjLocked(Lcom/android/server/am/ProcessRecord;Z)Z -Lcom/android/server/am/ActivityManagerService;->updateOomAdjLocked()V -Lcom/android/server/am/ActivityManagerService;->updateOomAdjLocked(Lcom/android/server/am/ProcessRecord;Z)Z -Lcom/android/server/pm/Settings;->getRenamedPackageLPr(Ljava/lang/String;)Ljava/lang/String; -Lcom/android/server/am/OomAdjProfiler;->updateSystemServerCpuTime(ZZ)V -Lcom/android/server/pm/UserManagerService;->getInstance()Lcom/android/server/pm/UserManagerService; -Lcom/android/server/pm/permission/PermissionManagerService$PermissionManagerServiceInternalImpl;->addAllPermissions(Landroid/content/pm/PackageParser$Package;Z)V -Lcom/android/server/power/PowerManagerService$Injector;->createBatterySaverPolicy(Ljava/lang/Object;Landroid/content/Context;Lcom/android/server/power/batterysaver/BatterySavingStats;)Lcom/android/server/power/batterysaver/BatterySaverPolicy; -Lcom/android/server/power/ThermalManagerService;-><init>(Landroid/content/Context;)V -Lcom/android/server/power/ThermalManagerService;-><init>(Landroid/content/Context;Lcom/android/server/power/ThermalManagerService$ThermalHalWrapper;)V -Lcom/android/server/display/PersistentDataStore$Injector;->openRead()Ljava/io/InputStream; -Lcom/android/server/pm/PackageManagerService$ReconciledPackage;-><init>(Lcom/android/server/pm/PackageManagerService$InstallArgs;Lcom/android/server/pm/PackageSetting;Lcom/android/server/pm/PackageManagerService$PackageInstalledInfo;Lcom/android/server/pm/PackageManagerService$PrepareResult;Lcom/android/server/pm/PackageManagerService$ScanResult;Lcom/android/server/pm/PackageManagerService$DeletePackageAction;Ljava/util/List;Landroid/content/pm/PackageParser$SigningDetails;ZZLcom/android/server/pm/PackageManagerService$1;)V -Lcom/android/server/pm/ComponentResolver;-><init>(Lcom/android/server/pm/UserManagerService;Landroid/content/pm/PackageManagerInternal;Ljava/lang/Object;)V -Lcom/android/server/wm/LaunchParamsController;->registerDefaultModifiers(Lcom/android/server/wm/ActivityStackSupervisor;)V -Lcom/android/server/Watchdog$OpenFdMonitor;->create()Lcom/android/server/Watchdog$OpenFdMonitor; +Lcom/android/server/utils/TimingsTraceAndSlog;->traceBegin(Ljava/lang/String;)V +Lcom/android/server/utils/TimingsTraceAndSlog;->logDuration(Ljava/lang/String;J)V +Lcom/android/server/pm/PackageManagerService;->addPackageHoldingPermissions(Ljava/util/ArrayList;Lcom/android/server/pm/PackageSetting;[Ljava/lang/String;[ZII)V +Lcom/android/server/pm/PackageManagerService;->updateFlagsForPackage(IILjava/lang/Object;)I +Lcom/android/server/am/ActivityManagerService;->checkPermission(Ljava/lang/String;II)I +Lcom/android/server/pm/UserManagerService;->isUserUnlockingOrUnlocked(I)Z +Lcom/android/server/pm/UserManagerService;->checkManageOrInteractPermIfCallerInOtherProfileGroup(ILjava/lang/String;)V +Lcom/android/server/pm/UserManagerService$LocalService;->isUserUnlockingOrUnlocked(I)Z +Lcom/android/server/pm/PackageManagerService;->updateFlagsForComponent(IILjava/lang/Object;)I Lcom/android/server/SystemServiceManager;->warnIfTooLong(JLcom/android/server/SystemService;Ljava/lang/String;)V -Lcom/android/server/am/UserController$Injector;->getLockPatternUtils()Lcom/android/internal/widget/LockPatternUtils; -Lcom/android/server/am/PendingIntentController;-><init>(Landroid/os/Looper;Lcom/android/server/am/UserController;)V -Lcom/android/server/am/BroadcastQueue;-><init>(Lcom/android/server/am/ActivityManagerService;Landroid/os/Handler;Ljava/lang/String;Lcom/android/server/am/BroadcastConstants;Z)V -Lcom/android/server/display/LocalDisplayAdapter$LocalDisplayDevice$1;->setDisplayState(I)V -Lcom/android/server/am/BatteryStatsService$WakeupReasonThread;->waitWakeup()Ljava/lang/String; +Lcom/android/server/PinnerService;->pinFileRanges(Ljava/lang/String;ILcom/android/server/PinnerService$PinRangeSource;)Lcom/android/server/PinnerService$PinnedFile; +Lcom/android/server/PinnerService$PinRangeSourceStream;->read(Lcom/android/server/PinnerService$PinRange;)Z +Lcom/android/server/am/ReceiverList;->containsFilter(Landroid/content/IntentFilter;)Z +Lcom/android/server/pm/Settings;->isEnabledAndMatchLPr(Landroid/content/pm/ComponentInfo;II)Z +Lcom/android/server/pm/permission/PermissionManagerService;->access$2100(Lcom/android/server/pm/permission/PermissionManagerService;)Lcom/android/server/pm/permission/PermissionSettings; +Lcom/android/server/pm/permission/PermissionManagerService$PermissionManagerServiceInternalImpl;->getAllPermissionWithProtectionLevel(I)Ljava/util/ArrayList; +Lcom/android/server/pm/PackageManagerService;->forEachPackage(Ljava/util/function/Consumer;)V +Lcom/android/server/pm/permission/PermissionManagerService;->access$200(Lcom/android/server/pm/permission/PermissionManagerService;)Landroid/content/pm/PackageManagerInternal; +Lcom/android/server/pm/permission/-$$Lambda$PermissionManagerService$7fYYDxKgBF9e9QlxmWAdwL0CsDs;->accept(Ljava/lang/Object;)V +Lcom/android/server/pm/permission/PermissionManagerService;->lambda$updatePermissions$10$PermissionManagerService(Landroid/content/pm/PackageParser$Package;ZLjava/lang/String;Ljava/lang/String;Lcom/android/server/pm/permission/PermissionManagerServiceInternal$PermissionCallback;Landroid/content/pm/PackageParser$Package;)V +Lcom/android/server/pm/permission/PermissionManagerService;->getVolumeUuidForPackage(Landroid/content/pm/PackageParser$Package;)Ljava/lang/String; +Lcom/android/server/pm/permission/PermissionsState;->setGlobalGids([I)V +Lcom/android/server/pm/permission/PermissionManagerService;->checkIfLegacyStorageOpsNeedToBeUpdated(Landroid/content/pm/PackageParser$Package;Z[I)[I +Lcom/android/server/pm/permission/PermissionManagerService$1;->onPermissionUpdated([IZ)V +Lcom/android/server/pm/PackageManagerService$PackageManagerInternalImpl;->writePermissionSettings([IZ)V +Lcom/android/server/pm/PackageSetting;->isPrivileged()Z +Lcom/android/server/pm/permission/BasePermission;->isPre23()Z +Lcom/android/server/pm/permission/BasePermission;->isInstaller()Z +Lcom/android/server/usage/AppIdleHistory;->getLongValue(Lorg/xmlpull/v1/XmlPullParser;Ljava/lang/String;J)J +Lcom/android/server/pm/PackageManagerService;->reconcileApps(Ljava/lang/String;)V +Lcom/android/server/usage/AppIdleHistory;->readAppIdleTimes(ILandroid/util/ArrayMap;)V +Lcom/android/server/SystemServiceManager;->startBootPhase(Lcom/android/server/utils/TimingsTraceAndSlog;I)V +Lcom/android/server/pm/PackageManagerService$PackageManagerInternalImpl;->getPackageList(Landroid/content/pm/PackageManagerInternal$PackageListObserver;)Landroid/content/pm/PackageList; +Lcom/android/server/pm/PackageManagerService;->getPackagesForUid(I)[Ljava/lang/String; +Lcom/android/server/wm/ConfigurationContainer;->getConfiguration()Landroid/content/res/Configuration; +Lcom/android/server/am/ActivityManagerService;->enforceNotIsolatedCaller(Ljava/lang/String;)V +Lcom/android/server/am/ActivityManagerService;->getRecordForAppLocked(Landroid/app/IApplicationThread;)Lcom/android/server/am/ProcessRecord; +Lcom/android/server/am/ProcessList;->getLRURecordForAppLocked(Landroid/app/IApplicationThread;)Lcom/android/server/am/ProcessRecord; +Lcom/android/server/am/ActivityManagerService;->isInstantApp(Lcom/android/server/am/ProcessRecord;Ljava/lang/String;I)Z +Lcom/android/server/inputmethod/InputMethodUtils$InputMethodSettings;->getEnabledInputMethodSubtypeListLocked(Landroid/view/inputmethod/InputMethodInfo;)Ljava/util/List; +Lcom/android/server/inputmethod/InputMethodSubtypeSwitchingController$InputMethodAndSubtypeList;->getSortedInputMethodAndSubtypeList(ZZ)Ljava/util/List; +Lcom/android/server/policy/PermissionPolicyService;->getSwitchOp(Ljava/lang/String;)I +Lcom/android/server/policy/PermissionPolicyService;->access$500(Ljava/lang/String;)I +Lcom/android/server/policy/PermissionPolicyService$PermissionToOpSynchroniser;->addPackage(Ljava/lang/String;)V +Lcom/android/server/pm/PackageManagerService$PackageManagerInternalImpl;->getInstantAppPackageName(I)Ljava/lang/String; +Lcom/android/server/pm/PackageManagerService;->access$5500(Lcom/android/server/pm/PackageManagerService;I)Ljava/lang/String; +Lcom/android/server/pm/permission/PermissionManagerService;->getPermissionInfo(Ljava/lang/String;Ljava/lang/String;I)Landroid/content/pm/PermissionInfo; +Lcom/android/server/pm/permission/BasePermission;->getProtectionLevel()I +Lcom/android/server/pm/permission/PermissionManagerService;->adjustPermissionProtectionFlagsLocked(ILjava/lang/String;I)I +Lcom/android/server/pm/permission/BasePermission;->generatePermissionInfo(II)Landroid/content/pm/PermissionInfo; +Lcom/android/server/policy/PermissionPolicyService$PermissionToOpSynchroniser;->addOpIfRestricted(Landroid/content/pm/PermissionInfo;Landroid/content/pm/PackageInfo;)V +Lcom/android/server/policy/PermissionPolicyService$PermissionToOpSynchroniser;->addOpIfFgPermissions(Landroid/content/pm/PermissionInfo;Landroid/content/pm/PackageInfo;)V +Lcom/android/server/pm/PackageManagerService$PackageManagerInternalImpl;->filterAppAccess(Landroid/content/pm/PackageParser$Package;II)Z +Lcom/android/server/pm/PackageManagerService;->access$5600(Lcom/android/server/pm/PackageManagerService;Lcom/android/server/pm/PackageSetting;II)Z +Lcom/android/server/wm/ActivityTaskManagerService;->getRecentTasks()Lcom/android/server/wm/RecentTasks; +Lcom/android/server/pm/PackageManagerService;->isRecentsAccessingChildProfiles(II)Z +Lcom/android/server/pm/PackageManagerService$Injector;->getActivityTaskManagerInternal()Lcom/android/server/wm/ActivityTaskManagerInternal; +Lcom/android/server/wm/ActivityTaskManagerService$LocalService;->isCallerRecents(I)Z +Lcom/android/server/wm/RecentTasks;->isCallerRecents(I)Z +Lcom/android/server/pm/PackageManagerService;->getApplicationInfoInternal(Ljava/lang/String;III)Landroid/content/pm/ApplicationInfo; +Lcom/android/server/pm/PackageManagerService;->updateFlagsForApplication(IILjava/lang/Object;)I +Lcom/android/server/pm/PackageManagerService;->getApplicationInfo(Ljava/lang/String;II)Landroid/content/pm/ApplicationInfo; +Lcom/android/server/pm/PackageManagerService;->getPackageInfo(Ljava/lang/String;II)Landroid/content/pm/PackageInfo; +Lcom/android/server/pm/PackageManagerService;->getPackageInfoInternal(Ljava/lang/String;JIII)Landroid/content/pm/PackageInfo; +Lcom/android/server/policy/SoftRestrictedPermissionPolicy;->getMinimumTargetSDK(Landroid/content/Context;Landroid/content/pm/ApplicationInfo;Landroid/os/UserHandle;)I +Lcom/android/server/pm/permission/PermissionManagerService;->getPermissionFlags(Ljava/lang/String;Ljava/lang/String;I)I +Lcom/android/server/pm/permission/PermissionManagerService;->getPermissionFlagsInternal(Ljava/lang/String;Ljava/lang/String;II)I +Lcom/android/server/pm/permission/PermissionManagerService;->enforceGrantRevokeGetRuntimePermissionPermissions(Ljava/lang/String;)V +Lcom/android/server/policy/PermissionPolicyService$PermissionToOpSynchroniser$OpToChange;-><init>(Lcom/android/server/policy/PermissionPolicyService$PermissionToOpSynchroniser;ILjava/lang/String;I)V +Lcom/android/server/appop/AppOpsService;->getUidStateLocked(IZ)Lcom/android/server/appop/AppOpsService$UidState; +Lcom/android/server/appop/AppOpsService;->verifyIncomingUid(I)V +Lcom/android/server/appop/AppOpsService;->verifyIncomingOp(I)V +Lcom/android/server/pm/UserManagerService;->hasManagedProfile(I)Z +Lcom/android/server/appop/AppOpsService;->verifyAndGetIsPrivileged(ILjava/lang/String;)Z +Lcom/android/server/appop/AppOpsService;->resolvePackageName(ILjava/lang/String;)Ljava/lang/String; +Lcom/android/server/appop/AppOpsService;->isOpRestrictedLocked(IILjava/lang/String;Z)Z +Lcom/android/server/policy/PermissionPolicyService$PermissionToOpSynchroniser;->syncPackages()V +Lcom/android/server/appop/AppOpsService;->checkOperationInternal(IILjava/lang/String;Z)I +Lcom/android/server/appop/AppOpsService;->checkOperationImpl(IILjava/lang/String;Z)I +Lcom/android/server/appop/AppOpsService;->checkOperationUnchecked(IILjava/lang/String;Z)I +Lcom/android/server/pm/permission/BasePermission;->isVerifier()Z +Lcom/android/server/pm/permission/BasePermission;->isPreInstalled()Z +Lcom/android/server/policy/PermissionPolicyService;->isStarted(I)Z +Lcom/android/server/policy/PermissionPolicyService$Internal;->isInitialized(I)Z +Lcom/android/server/policy/PermissionPolicyService;->access$100(Lcom/android/server/policy/PermissionPolicyService;I)Z +Lcom/android/server/usage/AppStandbyController;->getIdleUidsForUser(I)[I +Lcom/android/server/pm/PackageManagerService;->getInstalledApplicationsListInternal(III)Ljava/util/List; +Lcom/android/server/am/ProcessRecord;->getCurProcState()I +Lcom/android/server/connectivity/PermissionMonitor;->hasPermission(Landroid/content/pm/PackageInfo;Ljava/lang/String;)Z +Lcom/android/server/connectivity/PermissionMonitor;->getNetdPermissionMask([Ljava/lang/String;[I)I +Lcom/android/server/usage/AppStandbyController;->isAppIdleFiltered(Ljava/lang/String;IIJ)Z +Lcom/android/server/usage/AppStandbyController;->isAppSpecial(Ljava/lang/String;II)Z +Lcom/android/server/pm/PackageManagerService$PackageManagerInternalImpl;->getPackage(I)Landroid/content/pm/PackageParser$Package; +Lcom/android/server/usage/AppStandbyController$Injector;->isPowerSaveWhitelistExceptIdleApp(Ljava/lang/String;)Z +Lcom/android/server/DeviceIdleController$BinderService;->isPowerSaveWhitelistExceptIdleApp(Ljava/lang/String;)Z +Lcom/android/server/DeviceIdleController;->isPowerSaveWhitelistExceptIdleAppInternal(Ljava/lang/String;)Z +Lcom/android/server/usage/AppIdleHistory;->getUserHistory(I)Landroid/util/ArrayMap; +Lcom/android/server/usage/AppIdleHistory;->getPackageHistory(Landroid/util/ArrayMap;Ljava/lang/String;JZ)Lcom/android/server/usage/AppIdleHistory$AppUsageHistory; +Lcom/android/server/net/NetworkPolicyManagerService;->updateRulesForAllAppsUL(I)V +Lcom/android/server/pm/permission/PermissionManagerService;->checkUidPermission(Ljava/lang/String;I)I +Lcom/android/server/pm/permission/PermissionManagerService;->checkUidPermissionImpl(Ljava/lang/String;I)I +Lcom/android/server/pm/permission/PermissionManagerService;->checkUidPermissionInternal(Ljava/lang/String;Landroid/content/pm/PackageParser$Package;II)I +Lcom/android/server/pm/PackageManagerService;->checkUidPermission(Ljava/lang/String;I)I +Lcom/android/server/net/NetworkPolicyManagerService;->hasInternetPermissions(I)Z +Lcom/android/server/pm/permission/PermissionManagerService;->isImpliedPermissionGranted(Lcom/android/server/pm/permission/PermissionsState;Ljava/lang/String;I)Z +Lcom/android/server/pm/PackageManagerService;->resolveContentProvider(Ljava/lang/String;II)Landroid/content/pm/ProviderInfo; +Lcom/android/server/pm/PackageManagerService;->resolveContentProviderInternal(Ljava/lang/String;II)Landroid/content/pm/ProviderInfo; +Lcom/android/server/pm/ComponentResolver;->queryProvider(Ljava/lang/String;II)Landroid/content/pm/ProviderInfo; +Lcom/android/server/am/OomAdjuster;->updateOomAdjLocked(Ljava/lang/String;)V +Lcom/android/server/am/BroadcastFilter;-><init>(Landroid/content/IntentFilter;Lcom/android/server/am/ReceiverList;Ljava/lang/String;Ljava/lang/String;IIZZ)V +Lcom/android/server/am/ActivityManagerService$PidMap;->get(I)Lcom/android/server/am/ProcessRecord; +Lcom/android/server/am/UidRecord;->getCurProcState()I +Lcom/android/server/am/ActivityManagerService;->checkContentProviderPermissionLocked(Landroid/content/pm/ProviderInfo;Lcom/android/server/am/ProcessRecord;IZ)Ljava/lang/String; +Lcom/android/server/am/ActiveUids;->valueAt(I)Lcom/android/server/am/UidRecord; +Lcom/android/server/NetworkManagementService;->getFirewallChainState(I)Z +Lcom/android/server/pm/ComponentResolver;->access$800()Lcom/android/server/pm/UserManagerService; +Lcom/android/server/content/ContentService;->handleIncomingUser(Landroid/net/Uri;IIIZI)I +Lcom/android/server/am/ActivityManagerService$LocalService;->checkContentProviderAccess(Ljava/lang/String;I)Ljava/lang/String; +Lcom/android/server/am/ActivityManagerService;->checkContentProviderAccess(Ljava/lang/String;I)Ljava/lang/String; +Lcom/android/server/content/ContentService;->registerContentObserver(Landroid/net/Uri;ZLandroid/database/IContentObserver;II)V +Lcom/android/server/content/ContentService$ObserverNode;->addObserverLocked(Landroid/net/Uri;Landroid/database/IContentObserver;ZLjava/lang/Object;III)V +Lcom/android/server/content/ContentService$ObserverNode$ObserverEntry;-><init>(Lcom/android/server/content/ContentService$ObserverNode;Landroid/database/IContentObserver;ZLjava/lang/Object;IIILandroid/net/Uri;)V +Lcom/android/server/content/ContentService;->access$300()Lcom/android/internal/os/BinderDeathDispatcher; +Lcom/android/server/am/ProcessRecord;->setCurRawAdj(I)V +Lcom/android/server/wm/WindowProcessController;->setPerceptible(Z)V +Lcom/android/server/am/OomAdjuster;->computeOomAdjLocked(Lcom/android/server/am/ProcessRecord;ILcom/android/server/am/ProcessRecord;ZJZ)Z +Lcom/android/server/am/UidRecord;->setCurProcState(I)V +Lcom/android/server/am/ProcessRecord;->setCurRawProcState(I)V +Lcom/android/server/location/GnssConfiguration;->loadPropertiesFromCarrierConfig()V +Lcom/android/server/LockGuard;->guard(I)V +Lcom/android/server/role/RoleManagerService;->lambda$computeComponentStateHash$2(Ljava/io/ByteArrayOutputStream;Landroid/content/pm/PackageManagerInternal;ILandroid/content/pm/PackageParser$Package;)V +Lcom/android/server/wm/ActivityStack;->topRunningActivityLocked(Z)Lcom/android/server/wm/ActivityRecord; +Lcom/android/server/pm/UserManagerService;->getUserInfoLU(I)Landroid/content/pm/UserInfo; +Lcom/android/server/wm/RootActivityContainer;->getActivityDisplay(I)Lcom/android/server/wm/ActivityDisplay; +Lcom/android/server/wm/ActivityStack;->getDisplay()Lcom/android/server/wm/ActivityDisplay; +Lcom/android/server/wm/ConfigurationContainer;->getActivityType()I +Lcom/android/server/wm/ActivityStack;->topRunningActivityLocked()Lcom/android/server/wm/ActivityRecord; +Lcom/android/server/wm/WindowContainer;->forAllWindows(Lcom/android/internal/util/ToBooleanFunction;Z)Z +Lcom/android/server/wm/WindowContainer;->getDisplayContent()Lcom/android/server/wm/DisplayContent; +Lcom/android/server/am/ActivityManagerService$4;->allowFilterResult(Lcom/android/server/am/BroadcastFilter;Ljava/util/List;)Z +Lcom/android/server/am/ProcessRecord;->getWindowProcessController()Lcom/android/server/wm/WindowProcessController; +Lcom/android/server/usage/AppStandbyController;->isActiveDeviceAdmin(Ljava/lang/String;I)Z +Lcom/android/server/usage/AppStandbyController;->isActiveNetworkScorer(Ljava/lang/String;)Z +Lcom/android/server/usage/AppStandbyController$Injector;->getActiveNetworkScorer()Ljava/lang/String; +Lcom/android/server/NetworkScoreService;->getActiveScorerPackage()Ljava/lang/String; +Lcom/android/server/NetworkScoreService;->enforceSystemOrHasScoreNetworks()V +Lcom/android/server/usage/AppStandbyController$Injector;->isBoundWidgetPackage(Landroid/appwidget/AppWidgetManager;Ljava/lang/String;I)Z +Lcom/android/server/appwidget/AppWidgetServiceImpl;->isBoundWidgetPackage(Ljava/lang/String;I)Z +Lcom/android/server/usage/AppStandbyController;->isDeviceProvisioningPackage(Ljava/lang/String;)Z +Lcom/android/server/usage/AppStandbyController;->isCarrierApp(Ljava/lang/String;)Z +Lcom/android/server/usage/AppIdleHistory;->getThresholdIndex(Ljava/lang/String;IJ[J[J)I +Lcom/android/server/usage/AppIdleHistory;->getElapsedTime(J)J +Lcom/android/server/usage/AppIdleHistory;->isIdle(Ljava/lang/String;IJ)Z +Lcom/android/server/net/NetworkPolicyManagerService;->isUidValidForBlacklistRules(I)Z +Lcom/android/server/net/NetworkPolicyManagerService;->updateRulesForPowerRestrictionsUL(IIZ)I +Lcom/android/server/net/NetworkPolicyManagerService;->updateRulesForPowerRestrictionsULInner(IIZ)I +Lcom/android/server/net/NetworkPolicyManagerService;->updateRulesForPowerRestrictionsUL(I)V +Lcom/android/server/usage/AppStandbyController;->isAppIdleUnfiltered(Ljava/lang/String;IJ)Z +Lcom/android/server/usage/AppStandbyController;->informListeners(Ljava/lang/String;IIIZ)V +Lcom/android/server/am/ActivityManagerService;->dispatchUidsChangedForObserver(Landroid/app/IUidObserver;Lcom/android/server/am/ActivityManagerService$UidObserverRegistration;I)V +Lcom/android/server/pm/PackageManagerService;->getPackageUid(Ljava/lang/String;II)I +Lcom/android/server/am/ProcessRecord;->getCurRawAdj()I +Lcom/android/server/am/ProcessRecord;->getReportedProcState()I +Lcom/android/server/usage/UserUsageStatsService;->reportEvent(Landroid/app/usage/UsageEvents$Event;)V +Lcom/android/server/usage/IntervalStats;->update(Ljava/lang/String;Ljava/lang/String;JII)V +Lcom/android/server/BinderCallsStatsService$AuthorizedWorkSourceProvider;->resolveWorkSourceUid(I)I +Lcom/android/server/BinderCallsStatsService$AuthorizedWorkSourceProvider;->getCallingUid()I +Lcom/android/server/wm/WindowContainer;->getParent()Lcom/android/server/wm/WindowContainer; +Lcom/android/server/wm/WindowContainer;->scheduleAnimation()V +Lcom/android/server/wm/ConfigurationContainer;->getBounds()Landroid/graphics/Rect; +Lcom/android/server/wm/DisplayContent;->forAllWindows(Lcom/android/internal/util/ToBooleanFunction;Z)Z +Lcom/android/server/wm/WindowContainer;->getPendingTransaction()Landroid/view/SurfaceControl$Transaction; +Lcom/android/server/wm/DisplayContent;->skipTraverseChild(Lcom/android/server/wm/WindowContainer;)Z +Lcom/android/server/am/ActivityManagerService;->incrementProcStateSeqAndNotifyAppsLocked()V +Lcom/android/server/wm/WindowManagerService;->boostPriorityForLockedSection()V +Lcom/android/server/wm/WindowManagerThreadPriorityBooster;->boost()V +Lcom/android/server/wm/WindowManagerService;->resetPriorityAfterLockedSection()V +Lcom/android/server/wm/WindowManagerThreadPriorityBooster;->reset()V +Lcom/android/server/IntentResolver;->filterResults(Ljava/util/List;)V +Lcom/android/server/IntentResolver;->getFastIntentCategories(Landroid/content/Intent;)Landroid/util/FastImmutableArraySet; +Lcom/android/server/am/ProcessRecord;->getCurrentSchedulingGroup()I +Lcom/android/server/content/ContentService$ObserverNode;->collectObserversLocked(Landroid/net/Uri;ILandroid/database/IContentObserver;ZIILjava/util/ArrayList;)V +Lcom/android/server/display/LogicalDisplay;->getDisplayInfoLocked()Landroid/view/DisplayInfo; +Lcom/android/server/am/UidRecord;->reset()V +Lcom/android/server/am/ActivityManagerService;->isReceivingBroadcastLocked(Lcom/android/server/am/ProcessRecord;Landroid/util/ArraySet;)Z +Lcom/android/server/am/ProcessRecord;->hasForegroundServices()Z +Lcom/android/server/wm/WindowContainer;->prepareSurfaces()V +Lcom/android/server/am/ReceiverList;-><init>(Lcom/android/server/am/ActivityManagerService;Lcom/android/server/am/ProcessRecord;IIILandroid/content/IIntentReceiver;)V +Lcom/android/server/am/ReceiverList;->hashCode()I +Lcom/android/server/display/DisplayManagerService;->access$1600(Lcom/android/server/display/DisplayManagerService;II)Landroid/view/DisplayInfo; +Lcom/android/server/display/DisplayManagerService;->getDisplayInfoInternal(II)Landroid/view/DisplayInfo; +Lcom/android/server/display/DisplayManagerService$BinderService;->getDisplayInfo(I)Landroid/view/DisplayInfo; +Lcom/android/server/am/ActivityManagerService$Injector;->isNetworkRestrictedForUid(I)Z +Lcom/android/server/am/ActivityManagerService$Injector;->ensureHasNetworkManagementInternal()Z +Lcom/android/server/NetworkManagementService$LocalService;->isNetworkRestrictedForUid(I)Z +Lcom/android/server/NetworkManagementService;->access$1400(Lcom/android/server/NetworkManagementService;I)Z +Lcom/android/server/NetworkManagementService;->isNetworkRestrictedInternal(I)Z +Lcom/android/server/wm/ConfigurationContainer;->getWindowingMode()I +Lcom/android/server/wm/WindowContainer;->isSelfOrChildAnimating()Z +Lcom/android/server/am/ProcessRecord;->setCurrentSchedulingGroup(I)V +Lcom/android/server/wm/WindowProcessController;->setCurrentSchedulingGroup(I)V +Lcom/android/server/IntentResolver;->queryIntent(Landroid/content/Intent;Ljava/lang/String;ZI)Ljava/util/List; +Lcom/android/server/am/ProcessRecord;->hasForegroundActivities()Z +Lcom/android/server/wm/WindowState;->getDisplayContent()Lcom/android/server/wm/DisplayContent; +Lcom/android/server/pm/ComponentResolver;->access$900()Landroid/content/pm/PackageManagerInternal; +Lcom/android/server/wm/SurfaceAnimator;->hasLeash()Z +Lcom/android/server/wm/WindowContainer;->checkCompleteDeferredRemoval()Z +Lcom/android/server/wm/WindowContainer;->isSelfAnimating()Z +Lcom/android/server/wm/SurfaceAnimator;->isAnimating()Z +Lcom/android/server/wm/DisplayContent;->getDisplayId()I +Lcom/android/server/am/ProcessRecord;->setHasForegroundActivities(Z)V +Lcom/android/server/wm/WindowProcessController;->setHasForegroundActivities(Z)V +Lcom/android/server/am/ProcessRecord;->setCurProcState(I)V +Lcom/android/server/wm/WindowProcessController;->setCurrentProcState(I)V +Lcom/android/server/am/ActivityManagerService;->updateLowMemStateLocked(III)Z +Lcom/android/server/wm/ConfigurationContainer;->getWindowConfiguration()Landroid/app/WindowConfiguration; +Lcom/android/server/am/OomAdjuster;->applyOomAdjLocked(Lcom/android/server/am/ProcessRecord;ZJJ)Z +Lcom/android/server/am/AppCompactor;->useCompaction()Z +Lcom/android/server/am/ProcessList;->procStatesDifferForMem(II)Z +Lcom/android/server/am/ActivityManagerService;->dispatchUidsChanged()V +Lcom/android/server/audio/AudioService$VolumeStreamState;->setIndex(IILjava/lang/String;)Z +Lcom/android/server/audio/AudioService;->access$3000(Lcom/android/server/audio/AudioService;)[Lcom/android/server/audio/AudioService$VolumeStreamState; +Lcom/android/server/content/ContentService$ObserverNode;->removeObserverLocked(Landroid/database/IContentObserver;)Z +Lcom/android/server/wm/DisplayContent$TaskStackContainers;->forAllExitingAppTokenWindows(Lcom/android/internal/util/ToBooleanFunction;Z)Z +Lcom/android/server/wm/WindowState;->getTask()Lcom/android/server/wm/Task; +Lcom/android/server/appop/AppOpsService;->getOpLocked(IILjava/lang/String;ZZ)Lcom/android/server/appop/AppOpsService$Op; +Lcom/android/server/appop/AppOpsService;->getOpsRawNoVerifyLocked(ILjava/lang/String;ZZ)Lcom/android/server/appop/AppOpsService$Ops; +Lcom/android/server/wm/AppWindowToken;->getTask()Lcom/android/server/wm/Task; +Lcom/android/server/wm/WindowContainer;->checkAppWindowsReadyToShow()V +Lcom/android/server/SystemService;->getContext()Landroid/content/Context; +Lcom/android/server/am/ProcessRecord;->getInteractionEventTime()J +Lcom/android/server/power/PowerManagerService;->findWakeLockIndexLocked(Landroid/os/IBinder;)I +Lcom/android/server/power/PowerManagerService;->updateWakeLockSummaryLocked(I)V +Lcom/android/server/pm/PackageManagerService$PackageManagerInternalImpl;->isEnabledAndMatches(Landroid/content/pm/ComponentInfo;II)Z +Lcom/android/server/wm/ConfigurationContainer;->onConfigurationChanged(Landroid/content/res/Configuration;)V +Lcom/android/server/policy/SoftRestrictedPermissionPolicy;->forPermission(Landroid/content/Context;Landroid/content/pm/ApplicationInfo;Landroid/os/UserHandle;Ljava/lang/String;)Lcom/android/server/policy/SoftRestrictedPermissionPolicy; +Lcom/android/server/appop/AppOpsService;->checkOperationRaw(IILjava/lang/String;)I +Lcom/android/server/appop/AppOpsService;->getOpLocked(Lcom/android/server/appop/AppOpsService$Ops;IZ)Lcom/android/server/appop/AppOpsService$Op; +Lcom/android/server/policy/PermissionPolicyService$PermissionToOpSynchroniser;->setUidModeIfMode(IIIILjava/lang/String;)Z +Lcom/android/server/policy/PermissionPolicyService$PermissionToOpSynchroniser;->setUidModeAllowedIfDefault(IILjava/lang/String;)Z +Lcom/android/server/pm/PackageManagerService;->getPackagesForSharedUserIdLocked(Ljava/lang/String;I)[Ljava/lang/String; +Lcom/android/server/policy/PermissionPolicyService;->synchronizePackagePermissionsAndAppOpsForUser(Ljava/lang/String;I)V +Lcom/android/server/am/ActivityManagerService;->getPackageManagerInternalLocked()Landroid/content/pm/PackageManagerInternal; +Lcom/android/server/power/PowerManagerService;->getWakeLockSummaryFlags(Lcom/android/server/power/PowerManagerService$WakeLock;)I +Lcom/android/server/TelephonyRegistry;->add(Landroid/os/IBinder;)Lcom/android/server/TelephonyRegistry$Record; +Lcom/android/server/am/ServiceRecord;->getConnections()Landroid/util/ArrayMap; +Lcom/android/server/am/ProcessRecord;->hasTopUi()Z +Lcom/android/server/wm/WindowProcessController;->hasVisibleActivities()Z +Lcom/android/server/am/ActivityManagerService;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z +Lcom/android/server/am/ProcessRecord;->hasPendingUiClean()Z +Lcom/android/server/am/UserController;->getStartedUserState(I)Lcom/android/server/am/UserState; +Lcom/android/server/wm/ConfigurationContainer;->inSplitScreenPrimaryWindowingMode()Z +Lcom/android/server/wm/ActivityDisplay;->getFocusedStack()Lcom/android/server/wm/ActivityStack; +Lcom/android/server/pm/dex/DexManager$PackageCodeLocations;->searchDex(Ljava/lang/String;I)I +Lcom/android/server/pm/dex/DexManager;->getDexPackage(Landroid/content/pm/ApplicationInfo;Ljava/lang/String;I)Lcom/android/server/pm/dex/DexManager$DexSearchResult; +Lcom/android/server/pm/PackageManagerService;->updateFlagsForResolve(IILandroid/content/Intent;IZZ)I +Lcom/android/server/wm/WindowState;->getParentWindow()Lcom/android/server/wm/WindowState; +Lcom/android/server/TelephonyRegistry$Record;->matchPhoneStateListenerEvent(I)Z +Lcom/android/server/wm/WindowState;->forAllWindows(Lcom/android/internal/util/ToBooleanFunction;Z)Z +Lcom/android/server/wm/WindowState;->applyInOrderWithImeWindows(Lcom/android/internal/util/ToBooleanFunction;Z)Z +Lcom/android/server/wm/WindowState;->applyImeWindowsIfNeeded(Lcom/android/internal/util/ToBooleanFunction;Z)Z +Lcom/android/server/wm/WindowState;->isInputMethodTarget()Z +Lcom/android/server/wm/WindowContainer;->getChildCount()I +Lcom/android/server/am/ProcessRecord;->getActiveInstrumentation()Lcom/android/server/am/ActiveInstrumentation; +Lcom/android/server/am/ProcessRecord;->modifyRawOomAdj(I)I +Lcom/android/server/wm/WindowAnimator;->scheduleAnimation()V +Lcom/android/server/wm/WindowContainer$ForAllWindowsConsumerWrapper;->apply(Ljava/lang/Object;)Z +Lcom/android/server/wm/WindowContainer$ForAllWindowsConsumerWrapper;->apply(Lcom/android/server/wm/WindowState;)Z +Lcom/android/server/wm/RootWindowContainer;->getDisplayContent(I)Lcom/android/server/wm/DisplayContent; +Lcom/android/server/wm/ActivityTaskManagerService$LocalService;->getTopProcessState()I +Lcom/android/server/wm/ActivityTaskManagerService$LocalService;->isHeavyWeightProcess(Lcom/android/server/wm/WindowProcessController;)Z +Lcom/android/server/wm/WindowProcessController;->isHomeProcess()Z +Lcom/android/server/wm/WindowProcessController;->isPreviousProcess()Z +Lcom/android/server/pm/PackageManagerService;->updateFlagsForResolve(IILandroid/content/Intent;IZ)I +Lcom/android/server/am/BroadcastQueue;->processNextBroadcastLocked(ZZ)V +Lcom/android/server/am/ActivityManagerService;->ensureAllowedAssociations()V +Lcom/android/server/am/ActivityManagerService;->validateAssociationAllowedLocked(Ljava/lang/String;ILjava/lang/String;I)Z +Lcom/android/server/StorageManagerService;->isUserKeyUnlocked(I)Z +Lcom/android/server/am/ProcessRecord;->hasOverlayUi()Z +Lcom/android/server/am/ContentProviderRecord;->hasExternalProcessHandles()Z +Lcom/android/server/am/UserController;->isUserRunning(II)Z +Lcom/android/server/wm/RootActivityContainer;->isFocusable(Lcom/android/server/wm/ConfigurationContainer;Z)Z +Lcom/android/server/wm/WindowProcessController;->hasActivities()Z +Lcom/android/server/wm/WindowState;->getAttrs()Landroid/view/WindowManager$LayoutParams; +Lcom/android/server/am/ProcessRecord$PackageList;->containsKey(Ljava/lang/Object;)Z +Lcom/android/server/wm/ActivityDisplay;->getChildCount()I +Lcom/android/server/TelephonyRegistry;->notifyDataConnectionForSubscriber(IIIZLjava/lang/String;Ljava/lang/String;Landroid/net/LinkProperties;Landroid/net/NetworkCapabilities;IZ)V +Lcom/android/server/am/OomAdjuster;->shouldSkipDueToCycle(Lcom/android/server/am/ProcessRecord;Lcom/android/server/am/ProcessRecord;IIZ)Z +Lcom/android/server/am/ProcessRecord;->getCurRawProcState()I +Lcom/android/server/am/ConnectionRecord;->trackProcState(IIJ)V +Lcom/android/server/wm/ActivityStack;->getResumedActivity()Lcom/android/server/wm/ActivityRecord; +Lcom/android/server/wm/ActivityStackSupervisor;->isCurrentProfileLocked(I)Z +Lcom/android/server/wm/ActivityRecord;->okToShowLocked()Z +Lcom/android/server/am/ActivityManagerService$LocalService;->isUserRunning(II)Z +Lcom/android/server/am/ProcessRecord;->hasRecentTasks()Z +Lcom/android/server/wm/WindowProcessController;->hasRecentTasks()Z +Lcom/android/server/am/ConnectionRecord;->hasFlag(I)Z +Lcom/android/server/am/ActiveServices;->updateServiceClientActivitiesLocked(Lcom/android/server/am/ProcessRecord;Lcom/android/server/am/ConnectionRecord;Z)Z +Lcom/android/server/pm/PackageManagerService$PackageManagerInternalImpl;->isPermissionsReviewRequired(Ljava/lang/String;I)Z +Lcom/android/server/pm/PackageManagerService;->access$5900(Lcom/android/server/pm/PackageManagerService;)Lcom/android/server/pm/permission/PermissionManagerServiceInternal; +Lcom/android/server/pm/permission/PermissionManagerService$PermissionManagerServiceInternalImpl;->isPermissionsReviewRequired(Landroid/content/pm/PackageParser$Package;I)Z +Lcom/android/server/pm/permission/PermissionManagerService;->access$600(Lcom/android/server/pm/permission/PermissionManagerService;Landroid/content/pm/PackageParser$Package;I)Z +Lcom/android/server/pm/permission/PermissionManagerService;->isPermissionsReviewRequired(Landroid/content/pm/PackageParser$Package;I)Z +Lcom/android/server/am/ProcessRecord;->updateBoundClientUids()V +Lcom/android/server/firewall/IntentFirewall;->checkIntent(Lcom/android/server/firewall/IntentFirewall$FirewallIntentResolver;Landroid/content/ComponentName;ILandroid/content/Intent;IILjava/lang/String;I)Z +Lcom/android/server/firewall/IntentFirewall$FirewallIntentResolver;->queryByComponent(Landroid/content/ComponentName;Ljava/util/List;)V +Lcom/android/server/pm/permission/PermissionManagerService;->checkPermission(Ljava/lang/String;Ljava/lang/String;I)I +Lcom/android/server/pm/permission/PermissionManagerService;->checkPermissionImpl(Ljava/lang/String;Ljava/lang/String;I)I +Lcom/android/server/pm/permission/PermissionManagerService;->checkPermissionInternal(Ljava/lang/String;Ljava/lang/String;II)I +Lcom/android/server/am/ActivityManagerService;->checkTime(JLjava/lang/String;)V +Lcom/android/server/wm/ActivityDisplay;->getChildAt(I)Lcom/android/server/wm/ActivityStack; +Lcom/android/server/power/PowerManagerService;->access$3700(Lcom/android/server/power/PowerManagerService;)Landroid/content/Context; +Lcom/android/server/appop/AppOpsService;->checkPackage(ILjava/lang/String;)I +Lcom/android/server/am/BroadcastQueue;->deliverToRegisteredReceiverLocked(Lcom/android/server/am/BroadcastRecord;Lcom/android/server/am/BroadcastFilter;ZI)V +Lcom/android/server/am/ProcessList;->checkSlow(JLjava/lang/String;)V +Lcom/android/server/pm/ComponentResolver$ActivityIntentResolver;->isFilterStopped(Landroid/content/IntentFilter;I)Z +Lcom/android/server/pm/ComponentResolver$ActivityIntentResolver;->isFilterStopped(Landroid/content/pm/PackageParser$ActivityIntentInfo;I)Z +Lcom/android/server/wm/ConfigurationContainer;->inPinnedWindowingMode()Z +Lcom/android/server/am/ActiveUids;->size()I +Lcom/android/server/wm/TaskRecord;->topRunningActivityLocked()Lcom/android/server/wm/ActivityRecord; +Lcom/android/server/firewall/IntentFirewall$FirewallIntentResolver;->sortResults(Ljava/util/List;)V +Lcom/android/server/pm/PackageManagerService;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z +Lcom/android/server/wm/WindowContainer;->isAnimating()Z +Lcom/android/server/wm/WindowContainer;->getDisplayedBounds()Landroid/graphics/Rect; +Lcom/android/server/wm/WindowManagerService;->scheduleAnimationLocked()V +Lcom/android/server/wm/Dimmer;->resetDimStates()V +Lcom/android/server/wm/Dimmer;->updateDims(Landroid/view/SurfaceControl$Transaction;Landroid/graphics/Rect;)Z +Lcom/android/server/wm/WindowState;->wouldBeVisibleIfPolicyIgnored()Z +Lcom/android/server/firewall/IntentFirewall;->checkBroadcast(Landroid/content/Intent;IILjava/lang/String;I)Z +Lcom/android/server/am/BroadcastQueue;->requestStartTargetPermissionsReviewIfNeededLocked(Lcom/android/server/am/BroadcastRecord;Ljava/lang/String;I)Z +Lcom/android/server/wm/WindowState;->isParentWindowHidden()Z +Lcom/android/server/wm/WindowStateAnimator;->hasSurface()Z +Lcom/android/server/wm/WindowContainer;->getDimmer()Lcom/android/server/wm/Dimmer; +Lcom/android/server/power/batterysaver/BatterySaverPolicy;->getCurrentPolicyLocked()Lcom/android/server/power/batterysaver/BatterySaverPolicy$Policy; +Lcom/android/server/power/batterysaver/BatterySaverPolicy;->getBatterySaverPolicy(I)Landroid/os/PowerSaveState; +Lcom/android/server/power/Notifier;->getBatteryStatsWakeLockMonitorType(I)I +Lcom/android/server/display/DisplayManagerService;->access$600(Lcom/android/server/display/DisplayManagerService;)Lcom/android/server/display/DisplayManagerService$SyncRoot; +Lcom/android/server/power/PowerManagerService;->updatePowerStateLocked()V +Lcom/android/server/am/BatteryStatsService;->enforceCallingPermission()V +Lcom/android/server/power/PowerManagerService;->isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()Z +Lcom/android/server/wm/WindowState;->isVisible()Z +Lcom/android/server/power/PowerManagerService;->updateIsPoweredLocked(I)V +Lcom/android/server/power/PowerManagerService;->updateStayOnLocked(I)V +Lcom/android/server/power/PowerManagerService;->updateScreenBrightnessBoostLocked(I)V +Lcom/android/server/power/PowerManagerService;->updateUserActivitySummaryLocked(JI)V +Lcom/android/server/power/PowerManagerService;->updateWakefulnessLocked(I)Z +Lcom/android/server/power/PowerManagerService;->updateProfilesLocked(J)V +Lcom/android/server/power/PowerManagerService;->updateDisplayPowerStateLocked(I)Z +Lcom/android/server/power/PowerManagerService;->updateDreamLocked(IZ)V +Lcom/android/server/power/PowerManagerService;->finishWakefulnessChangeIfNeededLocked()V +Lcom/android/server/power/PowerManagerService;->updateSuspendBlockerLocked()V +Lcom/android/server/power/PowerManagerService;->needDisplaySuspendBlockerLocked()Z +Lcom/android/server/power/PowerManagerService;->setHalAutoSuspendModeLocked(Z)V +Lcom/android/server/power/PowerManagerService;->setHalInteractiveModeLocked(Z)V +Lcom/android/server/display/DisplayManagerService;->access$3900(Lcom/android/server/display/DisplayManagerService;)Lcom/android/server/display/DisplayPowerController; +Lcom/android/server/power/PowerManagerService;->scheduleSandmanLocked()V +Lcom/android/server/appop/AppOpsService;->scheduleWriteLocked()V +Lcom/android/server/power/PowerManagerService;->getDesiredScreenPolicyLocked()I +Lcom/android/server/power/PowerManagerService;->shouldUseProximitySensorLocked()Z +Lcom/android/server/power/PowerManagerService;->shouldBoostScreenBrightness()Z +Lcom/android/server/power/PowerManagerService;->updatePowerRequestFromBatterySaverPolicy(Landroid/hardware/display/DisplayManagerInternal$DisplayPowerRequest;)V +Lcom/android/server/display/DisplayManagerService$LocalService;->requestPowerState(Landroid/hardware/display/DisplayManagerInternal$DisplayPowerRequest;Z)Z +Lcom/android/server/display/DisplayPowerController;->requestPowerState(Landroid/hardware/display/DisplayManagerInternal$DisplayPowerRequest;Z)Z +Lcom/android/server/power/PowerManagerService$PowerManagerHandler;->handleMessage(Landroid/os/Message;)V +Lcom/android/server/power/PowerManagerService;->access$3100(Lcom/android/server/power/PowerManagerService;)V +Lcom/android/server/power/PowerManagerService;->handleSandman()V +Lcom/android/server/dreams/DreamManagerService$LocalService;->isDreaming()Z +Lcom/android/server/dreams/DreamManagerService;->access$1400(Lcom/android/server/dreams/DreamManagerService;)Z +Lcom/android/server/dreams/DreamManagerService;->isDreamingInternal()Z +Lcom/android/server/power/PowerManagerService;->getSleepTimeoutLocked()J +Lcom/android/server/power/PowerManagerService;->getScreenOffTimeoutLocked(J)J +Lcom/android/server/power/PowerManagerService;->getScreenDimDurationLocked(J)J +Lcom/android/server/power/PowerManagerService;->getNextProfileTimeoutLocked(J)J +Lcom/android/server/power/PowerManagerService;->adjustWakeLockSummaryLocked(I)I +Lcom/android/server/power/PowerManagerService;->isItBedTimeYetLocked()Z +Lcom/android/server/wm/WindowContainer;->assignChildLayers(Landroid/view/SurfaceControl$Transaction;)V +Lcom/android/server/wm/WindowState;->isDrawnLw()Z +Lcom/android/server/wm/DisplayContent;->getDisplayPolicy()Lcom/android/server/wm/DisplayPolicy; +Lcom/android/server/wm/WindowState;->isVisibleByPolicy()Z +Lcom/android/server/wm/WindowState;->inSizeCompatMode()Z +Lcom/android/server/wm/DisplayContent$TaskStackContainers;->forAllWindows(Lcom/android/internal/util/ToBooleanFunction;Z)Z +Lcom/android/server/am/BroadcastQueue;->maybeAddAllowBackgroundActivityStartsToken(Lcom/android/server/am/ProcessRecord;Lcom/android/server/am/BroadcastRecord;)V +Lcom/android/server/wm/ConfigurationContainer;->inFreeformWindowingMode()Z +Lcom/android/server/wm/RootActivityContainer;->getTopResumedActivity()Lcom/android/server/wm/ActivityRecord; +Lcom/android/server/wm/WindowState;->isChildWindow()Z +Lcom/android/server/pm/PackageManagerService;->applyPostResolutionFilter(Ljava/util/List;Ljava/lang/String;ZIZILandroid/content/Intent;)Ljava/util/List; +Lcom/android/server/locksettings/LockSettingsService;->checkReadPermission(Ljava/lang/String;I)V +Lcom/android/server/wm/ConfigurationContainer;->getBounds(Landroid/graphics/Rect;)V +Lcom/android/server/wm/WindowState;->getFrameLw()Landroid/graphics/Rect; +Lcom/android/server/wm/WindowState;->isDisplayedLw()Z +Lcom/android/server/wm/TaskStack;->getStackOutset()I +Lcom/android/server/wm/WindowState;->getDisplayId()I +Lcom/android/server/wm/WindowState;->getOrientationChanging()Z +Lcom/android/server/wm/WindowContainer;->forAllWindows(Ljava/util/function/Consumer;Z)V +Lcom/android/server/wm/WindowContainer;->obtainConsumerWrapper(Ljava/util/function/Consumer;)Lcom/android/server/wm/WindowContainer$ForAllWindowsConsumerWrapper; +Lcom/android/server/wm/WindowContainer$ForAllWindowsConsumerWrapper;->setConsumer(Ljava/util/function/Consumer;)V +Lcom/android/server/wm/WindowContainer$ForAllWindowsConsumerWrapper;->release()V +Lcom/android/server/wm/WindowContainer;->access$100(Lcom/android/server/wm/WindowContainer;)Landroid/util/Pools$SynchronizedPool; +Lcom/android/server/wm/WindowState;->updateSurfacePosition()V +Lcom/android/server/wm/WindowState;->updateSurfacePosition(Landroid/view/SurfaceControl$Transaction;)V +Lcom/android/server/appop/AppOpsService$UidState;->evalMode(II)I +Lcom/android/server/power/PowerManagerService;->access$3300(Landroid/os/WorkSource;)Landroid/os/WorkSource; +Lcom/android/server/power/PowerManagerService;->copyWorkSource(Landroid/os/WorkSource;)Landroid/os/WorkSource; +Lcom/android/server/power/Notifier;->onWakeLockAcquired(ILjava/lang/String;Ljava/lang/String;IILandroid/os/WorkSource;Ljava/lang/String;)V +Lcom/android/server/power/PowerManagerService;->restartNofifyLongTimerLocked(Lcom/android/server/power/PowerManagerService$WakeLock;)V +Lcom/android/server/am/ProcessRecord;->isCrashing()Z +Lcom/android/server/wm/WindowToken;->isHidden()Z +Lcom/android/server/wm/AppWindowToken;->forAllWindows(Lcom/android/internal/util/ToBooleanFunction;Z)Z +Lcom/android/server/wm/AppWindowToken;->forAllWindowsUnchecked(Lcom/android/internal/util/ToBooleanFunction;Z)Z +Lcom/android/server/wm/WindowState;->transformFrameToSurfacePosition(IILandroid/graphics/Point;)V +Lcom/android/server/wm/WindowState;->getStack()Lcom/android/server/wm/TaskStack; +Lcom/android/server/wm/WindowState;->transformSurfaceInsetsPosition(Landroid/graphics/Point;Landroid/graphics/Rect;)V +Lcom/android/server/wm/WindowState;->prepareSurfaces()V +Lcom/android/server/wm/WindowState;->applyDims(Lcom/android/server/wm/Dimmer;)V +Lcom/android/server/wm/WindowStateAnimator;->prepareSurfaceLocked(Z)V +Lcom/android/server/wm/RootWindowContainer;->performSurfacePlacementNoTrace(Z)V +Lcom/android/server/wm/WindowState;->isVisibleLw()Z +Lcom/android/server/wm/WindowSurfaceController;->hasSurface()Z +Lcom/android/server/wm/WindowManagerService;->getDefaultDisplayContentLocked()Lcom/android/server/wm/DisplayContent; +Lcom/android/server/wm/RootWindowContainer;->scheduleAnimation()V +Lcom/android/server/wm/WindowContainer;->getWindow(Ljava/util/function/Predicate;)Lcom/android/server/wm/WindowState; +Lcom/android/server/wm/WindowContainer;->needsZBoost()Z +Lcom/android/server/wm/WindowState;->isOnScreen()Z +Lcom/android/server/wm/utils/InsetUtils;->insetsBetweenFrames(Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;)V +Lcom/android/server/wm/PolicyControl;->getWindowFlags(Lcom/android/server/wm/WindowState;Landroid/view/WindowManager$LayoutParams;)I +Lcom/android/server/wm/WindowContainer;->getChildAt(I)Lcom/android/server/wm/WindowContainer; +Lcom/android/server/wm/InsetsStateController;->onPostLayout()V +Lcom/android/server/wm/WindowFrames;->setContentChanged(Z)V +Lcom/android/server/wm/DisplayContent$NonAppWindowContainers;->prepareSurfaces()V +Lcom/android/server/wm/DisplayContent;->getHomeStack()Lcom/android/server/wm/TaskStack; +Lcom/android/server/wm/DisplayContent$TaskStackContainers;->getHomeStack()Lcom/android/server/wm/TaskStack; +Lcom/android/server/wm/DisplayContent$NonAppWindowContainers;->getDimmer()Lcom/android/server/wm/Dimmer; +Lcom/android/server/wm/RootActivityContainer;->getTopDisplayFocusedStack()Lcom/android/server/wm/ActivityStack; +Lcom/android/server/wm/WindowState;->resetContentChanged()V +Lcom/android/server/wm/WindowState;->isDragResizeChanged()Z +Lcom/android/server/wm/WindowState;->computeDragResizing()Z +Lcom/android/server/wm/WindowState;->isVisibleOrAdding()Z diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index b4ee0b1abbd7..4579a3d5cf9f 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -301,6 +301,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState + "mForAugmentedAutofillOnly: %s", mForAugmentedAutofillOnly); return; } + if (mCurrentViewId == null) { + Slog.w(TAG, "No current view id - session might have finished"); + return; + } + final AssistStructure structure = resultData.getParcelable(ASSIST_KEY_STRUCTURE); if (structure == null) { Slog.e(TAG, "No assist structure - app might have crashed providing it"); @@ -887,7 +892,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mMetricsLogger.write(log); if (intentSender != null) { if (sDebug) Slog.d(TAG, "Starting intent sender on save()"); - startIntentSender(intentSender); + startIntentSenderAndFinishSession(intentSender); } // Nothing left to do... @@ -1101,24 +1106,32 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // AutoFillUiCallback @Override - public void startIntentSender(IntentSender intentSender) { + public void startIntentSenderAndFinishSession(IntentSender intentSender) { + startIntentSender(intentSender, null); + } + + // AutoFillUiCallback + @Override + public void startIntentSender(IntentSender intentSender, Intent intent) { synchronized (mLock) { if (mDestroyed) { Slog.w(TAG, "Call to Session#startIntentSender() rejected - session: " + id + " destroyed"); return; } - removeSelfLocked(); + if (intent == null) { + removeSelfLocked(); + } } mHandler.sendMessage(obtainMessage( Session::doStartIntentSender, - this, intentSender)); + this, intentSender, intent)); } - private void doStartIntentSender(IntentSender intentSender) { + private void doStartIntentSender(IntentSender intentSender, Intent intent) { try { synchronized (mLock) { - mClient.startIntentSender(intentSender, null); + mClient.startIntentSender(intentSender, intent); } } catch (RemoteException e) { Slog.e(TAG, "Error launching auth intent", e); @@ -1863,7 +1876,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mHandler.sendMessage(obtainMessage(Session::logSaveShown, this)); final IAutoFillManagerClient client = getClient(); - mPendingSaveUi = new PendingUi(mActivityToken, id, client); + mPendingSaveUi = new PendingUi(new Binder(), id, client); final CharSequence serviceLabel; final Drawable serviceIcon; diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java index fe86ab3a3f26..0b2e2bf9de1c 100644 --- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java +++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.IntentSender; import android.graphics.drawable.Drawable; import android.metrics.LogMaker; @@ -82,7 +83,8 @@ public final class AutoFillUI { void requestShowFillUi(AutofillId id, int width, int height, IAutofillWindowPresenter presenter); void requestHideFillUi(AutofillId id); - void startIntentSender(IntentSender intentSender); + void startIntentSenderAndFinishSession(IntentSender intentSender); + void startIntentSender(IntentSender intentSender, Intent intent); void dispatchUnhandledKey(AutofillId id, KeyEvent keyEvent); } @@ -253,7 +255,7 @@ public final class AutoFillUI { @Override public void startIntentSender(IntentSender intentSender) { if (mCallback != null) { - mCallback.startIntentSender(intentSender); + mCallback.startIntentSenderAndFinishSession(intentSender); } } @@ -338,6 +340,13 @@ public final class AutoFillUI { } mMetricsLogger.write(log); } + + @Override + public void startIntentSender(IntentSender intentSender, Intent intent) { + if (mCallback != null) { + mCallback.startIntentSender(intentSender, intent); + } + } }, mUiModeMgr.isNightMode(), isUpdate, compatMode); }); } 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 e2cdddb932d7..8e200196050c 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -32,7 +32,6 @@ import android.graphics.drawable.Drawable; import android.metrics.LogMaker; import android.os.Handler; import android.os.IBinder; -import android.os.RemoteException; import android.service.autofill.BatchUpdates; import android.service.autofill.CustomDescription; import android.service.autofill.InternalOnClickAction; @@ -83,6 +82,7 @@ final class SaveUi { void onSave(); void onCancel(IntentSender listener); void onDestroy(); + void startIntentSender(IntentSender intentSender, Intent intent); } /** @@ -129,6 +129,15 @@ final class SaveUi { mDone = true; mRealListener.onDestroy(); } + + @Override + public void startIntentSender(IntentSender intentSender, Intent intent) { + if (sDebug) Slog.d(TAG, "OneTimeListener.startIntentSender(): " + mDone); + if (mDone) { + return; + } + mRealListener.startIntentSender(intentSender, intent); + } } private final Handler mHandler = UiThread.getHandler(); @@ -168,8 +177,8 @@ final class SaveUi { context = new ContextThemeWrapper(context, mThemeId) { @Override public void startActivity(Intent intent) { - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - super.startActivity(intent); + PendingIntent p = PendingIntent.getActivity(this, 0, intent, 0); + mListener.startIntentSender(p.getIntentSender(), intent); } }; final LayoutInflater inflater = LayoutInflater.from(context); @@ -329,21 +338,13 @@ final class SaveUi { if (sVerbose) Slog.v(TAG, "Intercepting custom description intent"); final IBinder token = mPendingUi.getToken(); intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token); - try { - mPendingUi.client.startIntentSender(pendingIntent.getIntentSender(), - intent); - mPendingUi.setState(PendingUi.STATE_PENDING); - if (sDebug) Slog.d(TAG, "hiding UI until restored with token " + token); - hide(); - log.setType(MetricsEvent.TYPE_OPEN); - mMetricsLogger.write(log); - return true; - } catch (RemoteException e) { - Slog.w(TAG, "error triggering pending intent: " + intent); - log.setType(MetricsEvent.TYPE_FAILURE); - mMetricsLogger.write(log); - return false; - } + mListener.startIntentSender(pendingIntent.getIntentSender(), intent); + mPendingUi.setState(PendingUi.STATE_PENDING); + if (sDebug) Slog.d(TAG, "hiding UI until restored with token " + token); + hide(); + log.setType(MetricsEvent.TYPE_OPEN); + mMetricsLogger.write(log); + return true; }; try { diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index dc0bdb325f24..222a6f210448 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2014 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. @@ -18,11 +18,15 @@ package com.android.server.backup; import static com.android.internal.util.Preconditions.checkNotNull; +import static java.util.Collections.emptySet; + import android.Manifest; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; +import android.app.admin.DevicePolicyManager; import android.app.backup.BackupManager; +import android.app.backup.IBackupManager; import android.app.backup.IBackupManagerMonitor; import android.app.backup.IBackupObserver; import android.app.backup.IFullBackupRestoreObserver; @@ -31,24 +35,37 @@ import android.app.backup.ISelectBackupTransportCallback; import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobService; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.os.Binder; +import android.os.FileUtils; +import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.Process; +import android.os.RemoteException; +import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.util.Slog; import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; +import com.android.server.SystemConfig; import com.android.server.SystemService; +import com.android.server.backup.utils.RandomAccessFileUtils; +import java.io.File; import java.io.FileDescriptor; +import java.io.IOException; import java.io.PrintWriter; import java.util.Set; @@ -58,8 +75,20 @@ import java.util.Set; * <p>This class is responsible for handling user-aware operations and acts as a delegator, routing * incoming calls to the appropriate per-user {@link UserBackupManagerService} to handle the * corresponding backup/restore operation. + * + * <p>It also determines whether the backup service is available. It can be disabled in the + * following two ways: + * + * <ul> + * <li>Temporary - call {@link #setBackupServiceActive(int, boolean)}, or + * <li>Permanent - set the system property {@link #BACKUP_DISABLE_PROPERTY} to true. + * </ul> + * + * Temporary disabling is controlled by {@link #setBackupServiceActive(int, boolean)} through + * privileged callers (currently {@link DevicePolicyManager}). If called on {@link + * UserHandle#USER_SYSTEM}, backup is disabled for all users. */ -public class BackupManagerService { +public class BackupManagerService extends IBackupManager.Stub { public static final String TAG = "BackupManagerService"; public static final boolean DEBUG = true; public static final boolean MORE_DEBUG = false; @@ -68,50 +97,249 @@ public class BackupManagerService { @VisibleForTesting static final String DUMP_RUNNING_USERS_MESSAGE = "Backup Manager is running for users:"; + /** + * Name of file that disables the backup service. If this file exists, then backup is disabled + * for all users. + */ + private static final String BACKUP_SUPPRESS_FILENAME = "backup-suppress"; + + /** + * Name of file for non-system users that enables the backup service for the user. Backup is + * disabled by default in non-system users. + */ + private static final String BACKUP_ACTIVATED_FILENAME = "backup-activated"; + + /** + * Name of file for non-system users that remembers whether backup was explicitly activated or + * deactivated with a call to setBackupServiceActive. + */ + private static final String REMEMBER_ACTIVATED_FILENAME = "backup-remember-activated"; + + // Product-level suppression of backup/restore. + private static final String BACKUP_DISABLE_PROPERTY = "ro.backup.disable"; + + private static final String BACKUP_THREAD = "backup"; + + static BackupManagerService sInstance; + + static BackupManagerService getInstance() { + return checkNotNull(sInstance); + } + private final Context mContext; - private final Trampoline mTrampoline; + private final UserManager mUserManager; + + private final boolean mGlobalDisable; + // Lock to write backup suppress files. + // TODD(b/121198006): remove this object and synchronized all methods on "this". + private final Object mStateLock = new Object(); + + private final Handler mHandler; + private final Set<ComponentName> mTransportWhitelist; - // Keeps track of all unlocked users registered with this service. Indexed by user id. - private final SparseArray<UserBackupManagerService> mServiceUsers = new SparseArray<>(); + /** Keeps track of all unlocked users registered with this service. Indexed by user id. */ + private final SparseArray<UserBackupManagerService> mUserServices; - /** Instantiate a new instance of {@link BackupManagerService}. */ - public BackupManagerService(Context context, Trampoline trampoline) { - mContext = checkNotNull(context); - mTrampoline = checkNotNull(trampoline); + private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) { + int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); + if (userId > 0) { // for only non system users + mHandler.post(() -> onRemovedNonSystemUser(userId)); + } + } + } + }; + + public BackupManagerService(Context context) { + this(context, new SparseArray<>()); + } + + @VisibleForTesting + BackupManagerService(Context context, SparseArray<UserBackupManagerService> userServices) { + mContext = context; + mGlobalDisable = isBackupDisabled(); + HandlerThread handlerThread = + new HandlerThread(BACKUP_THREAD, Process.THREAD_PRIORITY_BACKGROUND); + handlerThread.start(); + mHandler = new Handler(handlerThread.getLooper()); + mUserManager = UserManager.get(context); + mUserServices = userServices; + Set<ComponentName> transportWhitelist = + SystemConfig.getInstance().getBackupTransportWhitelist(); + mTransportWhitelist = (transportWhitelist == null) ? emptySet() : transportWhitelist; + mContext.registerReceiver( + mUserRemovedReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED)); + } + + // TODO: Remove this when we implement DI by injecting in the construtor. + @VisibleForTesting + Handler getBackupHandler() { + return mHandler; + } + + protected boolean isBackupDisabled() { + return SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false); + } + + protected int binderGetCallingUserId() { + return Binder.getCallingUserHandle().getIdentifier(); + } + + protected int binderGetCallingUid() { + return Binder.getCallingUid(); + } + + /** Stored in the system user's directory. */ + protected File getSuppressFileForSystemUser() { + return new File(UserBackupManagerFiles.getBaseStateDir(UserHandle.USER_SYSTEM), + BACKUP_SUPPRESS_FILENAME); + } + + /** Stored in the system user's directory and the file is indexed by the user it refers to. */ + protected File getRememberActivatedFileForNonSystemUser(int userId) { + return UserBackupManagerFiles.getStateFileInSystemDir(REMEMBER_ACTIVATED_FILENAME, userId); + } + + /** Stored in the system user's directory and the file is indexed by the user it refers to. */ + protected File getActivatedFileForNonSystemUser(int userId) { + return UserBackupManagerFiles.getStateFileInSystemDir(BACKUP_ACTIVATED_FILENAME, userId); } /** - * If {@code userId} is different from the calling user id, then the caller must hold the - * android.permission.INTERACT_ACROSS_USERS_FULL permission. - * - * @param userId User id on which the backup operation is being requested. - * @param message A message to include in the exception if it is thrown. + * Remove backup state for non system {@code userId} when the user is removed from the device. + * For non system users, backup state is stored in both the user's own dir and the system dir. + * When the user is removed, the user's own dir gets removed by the OS. This method ensures that + * the part of the user backup state which is in the system dir also gets removed. */ - private void enforceCallingPermissionOnUserId(@UserIdInt int userId, String message) { - if (Binder.getCallingUserHandle().getIdentifier() != userId) { - mContext.enforceCallingOrSelfPermission( - Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); + private void onRemovedNonSystemUser(int userId) { + Slog.i(TAG, "Removing state for non system user " + userId); + File dir = UserBackupManagerFiles.getStateDirInSystemDir(userId); + if (!FileUtils.deleteContentsAndDir(dir)) { + Slog.w(TAG, "Failed to delete state dir for removed user: " + userId); } } - // --------------------------------------------- - // USER LIFECYCLE CALLBACKS - // --------------------------------------------- + // TODO (b/124359804) move to util method in FileUtils + private void createFile(File file) throws IOException { + if (file.exists()) { + return; + } + + file.getParentFile().mkdirs(); + if (!file.createNewFile()) { + Slog.w(TAG, "Failed to create file " + file.getPath()); + } + } + + // TODO (b/124359804) move to util method in FileUtils + private void deleteFile(File file) { + if (!file.exists()) { + return; + } + + if (!file.delete()) { + Slog.w(TAG, "Failed to delete file " + file.getPath()); + } + } + + /** + * Deactivates the backup service for user {@code userId}. If this is the system user, it + * creates a suppress file which disables backup for all users. If this is a non-system user, it + * only deactivates backup for that user by deleting its activate file. + */ + @GuardedBy("mStateLock") + private void deactivateBackupForUserLocked(int userId) throws IOException { + if (userId == UserHandle.USER_SYSTEM) { + createFile(getSuppressFileForSystemUser()); + } else { + deleteFile(getActivatedFileForNonSystemUser(userId)); + } + } + + /** + * Enables the backup service for user {@code userId}. If this is the system user, it deletes + * the suppress file. If this is a non-system user, it creates the user's activate file. Note, + * deleting the suppress file does not automatically enable backup for non-system users, they + * need their own activate file in order to participate in the service. + */ + @GuardedBy("mStateLock") + private void activateBackupForUserLocked(int userId) throws IOException { + if (userId == UserHandle.USER_SYSTEM) { + deleteFile(getSuppressFileForSystemUser()); + } else { + createFile(getActivatedFileForNonSystemUser(userId)); + } + } + + // This method should not perform any I/O (e.g. do not call isBackupActivatedForUser), + // it's used in multiple places where I/O waits would cause system lock-ups. + private boolean isUserReadyForBackup(int userId) { + return mUserServices.get(UserHandle.USER_SYSTEM) != null + && mUserServices.get(userId) != null; + } + + /** + * Backup is activated for the system user if the suppress file does not exist. Backup is + * activated for non-system users if the suppress file does not exist AND the user's activated + * file exists. + */ + private boolean isBackupActivatedForUser(int userId) { + if (getSuppressFileForSystemUser().exists()) { + return false; + } + + return userId == UserHandle.USER_SYSTEM + || getActivatedFileForNonSystemUser(userId).exists(); + } + + protected Context getContext() { + return mContext; + } + + protected UserManager getUserManager() { + return mUserManager; + } + + protected void postToHandler(Runnable runnable) { + mHandler.post(runnable); + } + + /** + * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is unlocked. + * Starts the backup service for this user if backup is active for this user. Offloads work onto + * the handler thread {@link #mHandlerThread} to keep unlock time low since backup is not + * essential for device functioning. + */ + void onUnlockUser(int userId) { + postToHandler(() -> startServiceForUser(userId)); + } /** * Starts the backup service for user {@code userId} by creating a new instance of {@link * UserBackupManagerService} and registering it with this service. */ @VisibleForTesting - protected void startServiceForUser(int userId, Set<ComponentName> transportWhitelist) { - if (mServiceUsers.get(userId) != null) { + void startServiceForUser(int userId) { + // We know that the user is unlocked here because it is called from setBackupServiceActive + // and unlockUser which have these guarantees. So we can check if the file exists. + if (mGlobalDisable) { + Slog.i(TAG, "Backup service not supported"); + return; + } + if (!isBackupActivatedForUser(userId)) { + Slog.i(TAG, "Backup not activated for user " + userId); + return; + } + if (mUserServices.get(userId) != null) { Slog.i(TAG, "userId " + userId + " already started, so not starting again"); return; } - + Slog.i(TAG, "Starting service for user: " + userId); UserBackupManagerService userBackupManagerService = UserBackupManagerService.createAndInitializeService( - userId, mContext, mTrampoline, transportWhitelist); + userId, mContext, this, mTransportWhitelist); startServiceForUser(userId, userBackupManagerService); } @@ -120,7 +348,7 @@ public class BackupManagerService { * UserBackupManagerService} with this service and setting enabled state. */ void startServiceForUser(int userId, UserBackupManagerService userBackupManagerService) { - mServiceUsers.put(userId, userBackupManagerService); + mUserServices.put(userId, userBackupManagerService); Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable"); userBackupManagerService.initializeBackupEnableState(); @@ -130,7 +358,7 @@ public class BackupManagerService { /** Stops the backup service for user {@code userId} when the user is stopped. */ @VisibleForTesting protected void stopServiceForUser(int userId) { - UserBackupManagerService userBackupManagerService = mServiceUsers.removeReturnOld(userId); + UserBackupManagerService userBackupManagerService = mUserServices.removeReturnOld(userId); if (userBackupManagerService != null) { userBackupManagerService.tearDownService(); @@ -140,11 +368,6 @@ public class BackupManagerService { } } - boolean isAbleToServeUser(int userId) { - return getUserServices().get(UserHandle.USER_SYSTEM) != null - && getUserServices().get(userId) != null; - } - /** * Returns a list of users currently unlocked that have a {@link UserBackupManagerService} * registered. @@ -154,43 +377,146 @@ public class BackupManagerService { * TODO: Return a copy or only expose read-only information through other means. */ @VisibleForTesting - public SparseArray<UserBackupManagerService> getUserServices() { - return mServiceUsers; + SparseArray<UserBackupManagerService> getUserServices() { + return mUserServices; } /** - * Returns the {@link UserBackupManagerService} instance for the specified user {@code userId}. - * If the user is not registered with the service (either the user is locked or not eligible for - * the backup service) then return {@code null}. - * - * @param userId The id of the user to retrieve its instance of {@link - * UserBackupManagerService}. - * @param caller A {@link String} identifying the caller for logging purposes. - * @throws SecurityException if {@code userId} is different from the calling user id and the - * caller does NOT have the android.permission.INTERACT_ACROSS_USERS_FULL permission. + * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is stopped. + * Offloads work onto the handler thread {@link #mHandlerThread} to keep stopping time low. */ + void onStopUser(int userId) { + postToHandler( + () -> { + if (!mGlobalDisable) { + Slog.i(TAG, "Stopping service for user: " + userId); + stopServiceForUser(userId); + } + }); + } + + /** Returns {@link UserBackupManagerService} for user {@code userId}. */ @Nullable - @VisibleForTesting - UserBackupManagerService getServiceForUserIfCallerHasPermission( - @UserIdInt int userId, String caller) { - enforceCallingPermissionOnUserId(userId, caller); - UserBackupManagerService userBackupManagerService = mServiceUsers.get(userId); - if (userBackupManagerService == null) { - Slog.w(TAG, "Called " + caller + " for unknown user: " + userId); + public UserBackupManagerService getUserService(int userId) { + return mUserServices.get(userId); + } + + /** + * The system user and managed profiles can only be acted on by callers in the system or root + * processes. Other users can be acted on by callers who have both android.permission.BACKUP and + * android.permission.INTERACT_ACROSS_USERS_FULL permissions. + */ + private void enforcePermissionsOnUser(int userId) throws SecurityException { + boolean isRestrictedUser = + userId == UserHandle.USER_SYSTEM + || getUserManager().getUserInfo(userId).isManagedProfile(); + + if (isRestrictedUser) { + int caller = binderGetCallingUid(); + if (caller != Process.SYSTEM_UID && caller != Process.ROOT_UID) { + throw new SecurityException("No permission to configure backup activity"); + } + } else { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.BACKUP, "No permission to configure backup activity"); + mContext.enforceCallingOrSelfPermission( + Manifest.permission.INTERACT_ACROSS_USERS_FULL, + "No permission to configure backup activity"); } - return userBackupManagerService; } - /* - * The following methods are implementations of IBackupManager methods called from Trampoline. - * They delegate to the appropriate per-user instance of UserBackupManagerService to perform the - * action on the passed in user. Currently this is a straight redirection (see TODO). + /** + * Only privileged callers should be changing the backup state. Deactivating backup in the + * system user also deactivates backup in all users. We are not guaranteed that {@code userId} + * is unlocked at this point yet, so handle both cases. */ - // TODO (b/118520567): Stop hardcoding system user when we pass in user id as a parameter + public void setBackupServiceActive(int userId, boolean makeActive) { + enforcePermissionsOnUser(userId); + + // In Q, backup is OFF by default for non-system users. In the future, we will change that + // to ON unless backup was explicitly deactivated with a (permissioned) call to + // setBackupServiceActive. + // Therefore, remember this for use in the future. Basically the default in the future will + // be: rememberFile.exists() ? rememberFile.value() : ON + // Note that this has to be done right after the permission checks and before any other + // action since we need to remember that a permissioned call was made irrespective of + // whether the call changes the state or not. + if (userId != UserHandle.USER_SYSTEM) { + try { + File rememberFile = getRememberActivatedFileForNonSystemUser(userId); + createFile(rememberFile); + RandomAccessFileUtils.writeBoolean(rememberFile, makeActive); + } catch (IOException e) { + Slog.e(TAG, "Unable to persist backup service activity", e); + } + } - // --------------------------------------------- - // BACKUP AGENT OPERATIONS - // --------------------------------------------- + if (mGlobalDisable) { + Slog.i(TAG, "Backup service not supported"); + return; + } + + synchronized (mStateLock) { + Slog.i(TAG, "Making backup " + (makeActive ? "" : "in") + "active"); + if (makeActive) { + try { + activateBackupForUserLocked(userId); + } catch (IOException e) { + Slog.e(TAG, "Unable to persist backup service activity"); + } + + // If the user is unlocked, we can start the backup service for it. Otherwise we + // will start the service when the user is unlocked as part of its unlock callback. + if (getUserManager().isUserUnlocked(userId)) { + // Clear calling identity as initialization enforces the system identity but we + // can be coming from shell. + long oldId = Binder.clearCallingIdentity(); + try { + startServiceForUser(userId); + } finally { + Binder.restoreCallingIdentity(oldId); + } + } + } else { + try { + //TODO(b/121198006): what if this throws an exception? + deactivateBackupForUserLocked(userId); + } catch (IOException e) { + Slog.e(TAG, "Unable to persist backup service inactivity"); + } + //TODO(b/121198006): loop through active users that have work profile and + // stop them as well. + onStopUser(userId); + } + } + } + + // IBackupManager binder API + + /** + * Querying activity state of backup service. + * + * @param userId The user in which the activity state of backup service is queried. + * @return true if the service is active. + */ + @Override + public boolean isBackupServiceActive(int userId) { + synchronized (mStateLock) { + return !mGlobalDisable && isBackupActivatedForUser(userId); + } + } + + @Override + public void dataChangedForUser(int userId, String packageName) throws RemoteException { + if (isUserReadyForBackup(userId)) { + dataChanged(userId, packageName); + } + } + + @Override + public void dataChanged(String packageName) throws RemoteException { + dataChangedForUser(binderGetCallingUserId(), packageName); + } /** * An app's backup agent calls this method to let the service know that there's new data to @@ -206,6 +532,69 @@ public class BackupManagerService { } } + // --------------------------------------------- + // TRANSPORT OPERATIONS + // --------------------------------------------- + + @Override + public void initializeTransportsForUser( + int userId, String[] transportNames, IBackupObserver observer) throws RemoteException { + if (isUserReadyForBackup(userId)) { + initializeTransports(userId, transportNames, observer); + } + } + + /** Run an initialize operation for the given transports {@code transportNames}. */ + public void initializeTransports( + @UserIdInt int userId, String[] transportNames, IBackupObserver observer) { + UserBackupManagerService userBackupManagerService = + getServiceForUserIfCallerHasPermission(userId, "initializeTransports()"); + + if (userBackupManagerService != null) { + userBackupManagerService.initializeTransports(transportNames, observer); + } + } + + @Override + public void clearBackupDataForUser(int userId, String transportName, String packageName) + throws RemoteException { + if (isUserReadyForBackup(userId)) { + clearBackupData(userId, transportName, packageName); + } + } + + /** + * Clear the given package {@code packageName}'s backup data from the transport {@code + * transportName}. + */ + public void clearBackupData(@UserIdInt int userId, String transportName, String packageName) { + UserBackupManagerService userBackupManagerService = + getServiceForUserIfCallerHasPermission(userId, "clearBackupData()"); + + if (userBackupManagerService != null) { + userBackupManagerService.clearBackupData(transportName, packageName); + } + } + + @Override + public void clearBackupData(String transportName, String packageName) + throws RemoteException { + clearBackupDataForUser(binderGetCallingUserId(), transportName, packageName); + } + + @Override + public void agentConnectedForUser(int userId, String packageName, IBinder agent) + throws RemoteException { + if (isUserReadyForBackup(userId)) { + agentConnected(userId, packageName, agent); + } + } + + @Override + public void agentConnected(String packageName, IBinder agent) throws RemoteException { + agentConnectedForUser(binderGetCallingUserId(), packageName, agent); + } + /** * Callback: a requested backup agent has been instantiated. This should only be called from the * {@link ActivityManager}. @@ -219,6 +608,18 @@ public class BackupManagerService { } } + @Override + public void agentDisconnectedForUser(int userId, String packageName) throws RemoteException { + if (isUserReadyForBackup(userId)) { + agentDisconnected(userId, packageName); + } + } + + @Override + public void agentDisconnected(String packageName) throws RemoteException { + agentDisconnectedForUser(binderGetCallingUserId(), packageName); + } + /** * Callback: a backup agent has failed to come up, or has unexpectedly quit. This should only be * called from the {@link ActivityManager}. @@ -232,47 +633,283 @@ public class BackupManagerService { } } + @Override + public void restoreAtInstallForUser(int userId, String packageName, int token) + throws RemoteException { + if (isUserReadyForBackup(userId)) { + restoreAtInstall(userId, packageName, token); + } + } + + @Override + public void restoreAtInstall(String packageName, int token) throws RemoteException { + restoreAtInstallForUser(binderGetCallingUserId(), packageName, token); + } + + /** + * Used to run a restore pass for an application that is being installed. This should only be + * called from the {@link PackageManager}. + */ + public void restoreAtInstall(@UserIdInt int userId, String packageName, int token) { + UserBackupManagerService userBackupManagerService = + getServiceForUserIfCallerHasPermission(userId, "restoreAtInstall()"); + + if (userBackupManagerService != null) { + userBackupManagerService.restoreAtInstall(packageName, token); + } + } + + @Override + public void setBackupEnabledForUser(@UserIdInt int userId, boolean isEnabled) + throws RemoteException { + if (isUserReadyForBackup(userId)) { + setBackupEnabled(userId, isEnabled); + } + } + + @Override + public void setBackupEnabled(boolean isEnabled) throws RemoteException { + setBackupEnabledForUser(binderGetCallingUserId(), isEnabled); + } + + /** Enable/disable the backup service. This is user-configurable via backup settings. */ + public void setBackupEnabled(@UserIdInt int userId, boolean enable) { + UserBackupManagerService userBackupManagerService = + getServiceForUserIfCallerHasPermission(userId, "setBackupEnabled()"); + + if (userBackupManagerService != null) { + userBackupManagerService.setBackupEnabled(enable); + } + } + + @Override + public void setAutoRestoreForUser(int userId, boolean doAutoRestore) throws RemoteException { + if (isUserReadyForBackup(userId)) { + setAutoRestore(userId, doAutoRestore); + } + } + + @Override + public void setAutoRestore(boolean doAutoRestore) throws RemoteException { + setAutoRestoreForUser(binderGetCallingUserId(), doAutoRestore); + } + + /** Enable/disable automatic restore of app data at install time. */ + public void setAutoRestore(@UserIdInt int userId, boolean autoRestore) { + UserBackupManagerService userBackupManagerService = + getServiceForUserIfCallerHasPermission(userId, "setAutoRestore()"); + + if (userBackupManagerService != null) { + userBackupManagerService.setAutoRestore(autoRestore); + } + } + + @Override + public boolean isBackupEnabledForUser(@UserIdInt int userId) throws RemoteException { + return isUserReadyForBackup(userId) && isBackupEnabled(userId); + } + + @Override + public boolean isBackupEnabled() throws RemoteException { + return isBackupEnabledForUser(binderGetCallingUserId()); + } + /** - * Used by a currently-active backup agent to notify the service that it has completed its given - * outstanding asynchronous backup/restore operation. + * Return {@code true} if the backup mechanism is currently enabled, else returns {@code false}. */ - public void opComplete(@UserIdInt int userId, int token, long result) { + public boolean isBackupEnabled(@UserIdInt int userId) { UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(userId, "opComplete()"); + getServiceForUserIfCallerHasPermission(userId, "isBackupEnabled()"); + + return userBackupManagerService != null && userBackupManagerService.isBackupEnabled(); + } + + /** Sets the backup password used when running adb backup. */ + @Override + public boolean setBackupPassword(String currentPassword, String newPassword) { + int userId = binderGetCallingUserId(); + if (!isUserReadyForBackup(userId)) { + return false; + } + UserBackupManagerService userBackupManagerService = + getServiceForUserIfCallerHasPermission( + UserHandle.USER_SYSTEM, "setBackupPassword()"); + + return userBackupManagerService != null + && userBackupManagerService.setBackupPassword(currentPassword, newPassword); + } + + /** Returns {@code true} if adb backup was run with a password, else returns {@code false}. */ + @Override + public boolean hasBackupPassword() throws RemoteException { + int userId = binderGetCallingUserId(); + if (!isUserReadyForBackup(userId)) { + return false; + } + UserBackupManagerService userBackupManagerService = + getServiceForUserIfCallerHasPermission( + UserHandle.USER_SYSTEM, "hasBackupPassword()"); + + return userBackupManagerService != null && userBackupManagerService.hasBackupPassword(); + } + + @Override + public void backupNowForUser(@UserIdInt int userId) throws RemoteException { + if (isUserReadyForBackup(userId)) { + backupNow(userId); + } + } + + @Override + public void backupNow() throws RemoteException { + backupNowForUser(binderGetCallingUserId()); + } + + /** + * Run a backup pass immediately for any key-value backup applications that have declared that + * they have pending updates. + */ + public void backupNow(@UserIdInt int userId) { + UserBackupManagerService userBackupManagerService = + getServiceForUserIfCallerHasPermission(userId, "backupNow()"); if (userBackupManagerService != null) { - userBackupManagerService.opComplete(token, result); + userBackupManagerService.backupNow(); } } - // --------------------------------------------- - // TRANSPORT OPERATIONS - // --------------------------------------------- + /** + * Used by 'adb backup' to run a backup pass for packages {@code packageNames} supplied via the + * command line, writing the resulting data stream to the supplied {@code fd}. This method is + * synchronous and does not return to the caller until the backup has been completed. It + * requires on-screen confirmation by the user. + */ + @Override + public void adbBackup( + @UserIdInt int userId, + ParcelFileDescriptor fd, + boolean includeApks, + boolean includeObbs, + boolean includeShared, + boolean doWidgets, + boolean doAllApps, + boolean includeSystem, + boolean doCompress, + boolean doKeyValue, + String[] packageNames) { + if (!isUserReadyForBackup(userId)) { + return; + } + UserBackupManagerService userBackupManagerService = + getServiceForUserIfCallerHasPermission(userId, "adbBackup()"); - /** Run an initialize operation for the given transports {@code transportNames}. */ - public void initializeTransports( - @UserIdInt int userId, String[] transportNames, IBackupObserver observer) { + if (userBackupManagerService != null) { + userBackupManagerService.adbBackup( + fd, + includeApks, + includeObbs, + includeShared, + doWidgets, + doAllApps, + includeSystem, + doCompress, + doKeyValue, + packageNames); + } + } + + @Override + public void fullTransportBackupForUser(int userId, String[] packageNames) + throws RemoteException { + if (isUserReadyForBackup(userId)) { + fullTransportBackup(userId, packageNames); + } + } + + /** + * Run a full backup pass for the given packages {@code packageNames}. Used by 'adb shell bmgr'. + */ + public void fullTransportBackup(@UserIdInt int userId, String[] packageNames) { UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(userId, "initializeTransports()"); + getServiceForUserIfCallerHasPermission(userId, "fullTransportBackup()"); if (userBackupManagerService != null) { - userBackupManagerService.initializeTransports(transportNames, observer); + userBackupManagerService.fullTransportBackup(packageNames); } } /** - * Clear the given package {@code packageName}'s backup data from the transport {@code - * transportName}. + * Used by 'adb restore' to run a restore pass reading from the supplied {@code fd}. This method + * is synchronous and does not return to the caller until the restore has been completed. It + * requires on-screen confirmation by the user. */ - public void clearBackupData(@UserIdInt int userId, String transportName, String packageName) { + @Override + public void adbRestore(@UserIdInt int userId, ParcelFileDescriptor fd) { + if (!isUserReadyForBackup(userId)) { + return; + } UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(userId, "clearBackupData()"); + getServiceForUserIfCallerHasPermission(userId, "adbRestore()"); if (userBackupManagerService != null) { - userBackupManagerService.clearBackupData(transportName, packageName); + userBackupManagerService.adbRestore(fd); + } + } + + @Override + public void acknowledgeFullBackupOrRestoreForUser( + int userId, + int token, + boolean allow, + String curPassword, + String encryptionPassword, + IFullBackupRestoreObserver observer) + throws RemoteException { + if (isUserReadyForBackup(userId)) { + acknowledgeAdbBackupOrRestore(userId, token, allow, + curPassword, encryptionPassword, observer); + } + } + + /** + * Confirm that the previously requested adb backup/restore operation can proceed. This is used + * to require a user-facing disclosure about the operation. + */ + public void acknowledgeAdbBackupOrRestore( + @UserIdInt int userId, + int token, + boolean allow, + String currentPassword, + String encryptionPassword, + IFullBackupRestoreObserver observer) { + UserBackupManagerService userBackupManagerService = + getServiceForUserIfCallerHasPermission(userId, "acknowledgeAdbBackupOrRestore()"); + + if (userBackupManagerService != null) { + userBackupManagerService.acknowledgeAdbBackupOrRestore( + token, allow, currentPassword, encryptionPassword, observer); } } + @Override + public void acknowledgeFullBackupOrRestore(int token, boolean allow, String curPassword, + String encryptionPassword, IFullBackupRestoreObserver observer) + throws RemoteException { + acknowledgeFullBackupOrRestoreForUser( + binderGetCallingUserId(), token, allow, curPassword, encryptionPassword, observer); + } + + + @Override + public String getCurrentTransportForUser(int userId) throws RemoteException { + return (isUserReadyForBackup(userId)) ? getCurrentTransport(userId) : null; + } + + @Override + public String getCurrentTransport() throws RemoteException { + return getCurrentTransportForUser(binderGetCallingUserId()); + } + /** Return the name of the currently active transport. */ @Nullable public String getCurrentTransport(@UserIdInt int userId) { @@ -285,6 +922,16 @@ public class BackupManagerService { } /** + * Returns the {@link ComponentName} of the host service of the selected transport or + * {@code null} if no transport selected or if the transport selected is not registered. + */ + @Override + @Nullable + public ComponentName getCurrentTransportComponentForUser(int userId) { + return (isUserReadyForBackup(userId)) ? getCurrentTransportComponent(userId) : null; + } + + /** * Returns the {@link ComponentName} of the host service of the selected transport or {@code * null} if no transport selected or if the transport selected is not registered. */ @@ -298,6 +945,11 @@ public class BackupManagerService { : userBackupManagerService.getCurrentTransportComponent(); } + @Override + public String[] listAllTransportsForUser(int userId) throws RemoteException { + return (isUserReadyForBackup(userId)) ? listAllTransports(userId) : null; + } + /** Report all known, available backup transports by name. */ @Nullable public String[] listAllTransports(@UserIdInt int userId) { @@ -309,6 +961,17 @@ public class BackupManagerService { : userBackupManagerService.listAllTransports(); } + @Override + public String[] listAllTransports() throws RemoteException { + return listAllTransportsForUser(binderGetCallingUserId()); + } + + @Override + public ComponentName[] listAllTransportComponentsForUser(int userId) throws RemoteException { + return (isUserReadyForBackup(userId)) + ? listAllTransportComponents(userId) : null; + } + /** Report all known, available backup transports by {@link ComponentName}. */ @Nullable public ComponentName[] listAllTransportComponents(@UserIdInt int userId) { @@ -320,6 +983,43 @@ public class BackupManagerService { : userBackupManagerService.listAllTransportComponents(); } + @Override + public String[] getTransportWhitelist() { + int userId = binderGetCallingUserId(); + if (!isUserReadyForBackup(userId)) { + return null; + } + // No permission check, intentionally. + String[] whitelistedTransports = new String[mTransportWhitelist.size()]; + int i = 0; + for (ComponentName component : mTransportWhitelist) { + whitelistedTransports[i] = component.flattenToShortString(); + i++; + } + return whitelistedTransports; + } + + @Override + public void updateTransportAttributesForUser( + int userId, + ComponentName transportComponent, + String name, + @Nullable Intent configurationIntent, + String currentDestinationString, + @Nullable Intent dataManagementIntent, + CharSequence dataManagementLabel) { + if (isUserReadyForBackup(userId)) { + updateTransportAttributes( + userId, + transportComponent, + name, + configurationIntent, + currentDestinationString, + dataManagementIntent, + dataManagementLabel); + } + } + /** * Update the attributes of the transport identified by {@code transportComponent}. If the * specified transport has not been bound at least once (for registration), this call will be @@ -365,6 +1065,18 @@ public class BackupManagerService { } } + @Override + public String selectBackupTransportForUser(int userId, String transport) + throws RemoteException { + return (isUserReadyForBackup(userId)) + ? selectBackupTransport(userId, transport) : null; + } + + @Override + public String selectBackupTransport(String transport) throws RemoteException { + return selectBackupTransportForUser(binderGetCallingUserId(), transport); + } + /** * Selects transport {@code transportName} and returns the previously selected transport. * @@ -382,6 +1094,22 @@ public class BackupManagerService { : userBackupManagerService.selectBackupTransport(transportName); } + @Override + public void selectBackupTransportAsyncForUser(int userId, ComponentName transport, + ISelectBackupTransportCallback listener) throws RemoteException { + if (isUserReadyForBackup(userId)) { + selectBackupTransportAsync(userId, transport, listener); + } else { + if (listener != null) { + try { + listener.onFailure(BackupManager.ERROR_BACKUP_NOT_ALLOWED); + } catch (RemoteException ex) { + // ignore + } + } + } + } + /** * Selects transport {@code transportComponent} asynchronously and notifies {@code listener} * with the result upon completion. @@ -398,6 +1126,19 @@ public class BackupManagerService { } } + @Override + public Intent getConfigurationIntentForUser(int userId, String transport) + throws RemoteException { + return isUserReadyForBackup(userId) ? getConfigurationIntent(userId, transport) + : null; + } + + @Override + public Intent getConfigurationIntent(String transport) + throws RemoteException { + return getConfigurationIntentForUser(binderGetCallingUserId(), transport); + } + /** * Supply the configuration intent for the given transport. If the name is not one of the * available transports, or if the transport does not supply any configuration UI, the method @@ -409,59 +1150,19 @@ public class BackupManagerService { getServiceForUserIfCallerHasPermission(userId, "getConfigurationIntent()"); return userBackupManagerService == null - ? null - : userBackupManagerService.getConfigurationIntent(transportName); + ? null + : userBackupManagerService.getConfigurationIntent(transportName); } - /** - * Sets the ancestral work profile for the calling user. - * - * <p> The ancestral work profile corresponds to the profile that was used to restore to the - * callers profile. - */ - public void setAncestralSerialNumber(long ancestralSerialNumber) { - UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission( - Binder.getCallingUserHandle().getIdentifier(), - "setAncestralSerialNumber()"); - - if (userBackupManagerService != null) { - userBackupManagerService.setAncestralSerialNumber(ancestralSerialNumber); - } + @Override + public String getDestinationStringForUser(int userId, String transport) throws RemoteException { + return isUserReadyForBackup(userId) ? getDestinationString(userId, transport) + : null; } - /** - * Returns a {@link UserHandle} for the user that has {@code ancestralSerialNumber} as the - * serial number of the its ancestral work profile or null if there is no {@link - * UserBackupManagerService} associated with that user. - * - * <p> The ancestral work profile is set by {@link #setAncestralSerialNumber(long)} - * and it corresponds to the profile that was used to restore to the callers profile. - */ - @Nullable - public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) { - int callingUserId = Binder.getCallingUserHandle().getIdentifier(); - long oldId = Binder.clearCallingIdentity(); - final int[] userIds; - try { - userIds = - mContext - .getSystemService(UserManager.class) - .getProfileIds(callingUserId, false); - } finally { - Binder.restoreCallingIdentity(oldId); - } - - for (int userId : userIds) { - UserBackupManagerService userBackupManagerService = getUserServices().get(userId); - if (userBackupManagerService != null) { - if (userBackupManagerService.getAncestralSerialNumber() == ancestralSerialNumber) { - return UserHandle.of(userId); - } - } - } - - return null; + @Override + public String getDestinationString(String transport) throws RemoteException { + return getDestinationStringForUser(binderGetCallingUserId(), transport); } /** @@ -483,6 +1184,19 @@ public class BackupManagerService { : userBackupManagerService.getDestinationString(transportName); } + @Override + public Intent getDataManagementIntentForUser(int userId, String transport) + throws RemoteException { + return isUserReadyForBackup(userId) + ? getDataManagementIntent(userId, transport) : null; + } + + @Override + public Intent getDataManagementIntent(String transport) + throws RemoteException { + return getDataManagementIntentForUser(binderGetCallingUserId(), transport); + } + /** Supply the manage-data intent for the given transport. */ @Nullable public Intent getDataManagementIntent(@UserIdInt int userId, String transportName) { @@ -494,6 +1208,13 @@ public class BackupManagerService { : userBackupManagerService.getDataManagementIntent(transportName); } + @Override + public CharSequence getDataManagementLabelForUser(int userId, String transport) + throws RemoteException { + return isUserReadyForBackup(userId) ? getDataManagementLabel(userId, transport) + : null; + } + /** * Supply the menu label for affordances that fire the manage-data intent for the given * transport. @@ -508,43 +1229,76 @@ public class BackupManagerService { : userBackupManagerService.getDataManagementLabel(transportName); } - // --------------------------------------------- - // SETTINGS OPERATIONS - // --------------------------------------------- + @Override + public IRestoreSession beginRestoreSessionForUser( + int userId, String packageName, String transportID) throws RemoteException { + return isUserReadyForBackup(userId) + ? beginRestoreSession(userId, packageName, transportID) : null; + } - /** Enable/disable the backup service. This is user-configurable via backup settings. */ - public void setBackupEnabled(@UserIdInt int userId, boolean enable) { + /** + * Begin a restore for the specified package {@code packageName} using the specified transport + * {@code transportName}. + */ + @Nullable + public IRestoreSession beginRestoreSession( + @UserIdInt int userId, String packageName, String transportName) { UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(userId, "setBackupEnabled()"); + getServiceForUserIfCallerHasPermission(userId, "beginRestoreSession()"); - if (userBackupManagerService != null) { - userBackupManagerService.setBackupEnabled(enable); + return userBackupManagerService == null + ? null + : userBackupManagerService.beginRestoreSession(packageName, transportName); + } + + @Override + public void opCompleteForUser(int userId, int token, long result) throws RemoteException { + if (isUserReadyForBackup(userId)) { + opComplete(userId, token, result); } } - /** Enable/disable automatic restore of app data at install time. */ - public void setAutoRestore(@UserIdInt int userId, boolean autoRestore) { + @Override + public void opComplete(int token, long result) throws RemoteException { + opCompleteForUser(binderGetCallingUserId(), token, result); + } + + /** + * Used by a currently-active backup agent to notify the service that it has completed its given + * outstanding asynchronous backup/restore operation. + */ + public void opComplete(@UserIdInt int userId, int token, long result) { UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(userId, "setAutoRestore()"); + getServiceForUserIfCallerHasPermission(userId, "opComplete()"); if (userBackupManagerService != null) { - userBackupManagerService.setAutoRestore(autoRestore); + userBackupManagerService.opComplete(token, result); } } + @Override + public long getAvailableRestoreTokenForUser(int userId, String packageName) { + return isUserReadyForBackup(userId) ? getAvailableRestoreToken(userId, packageName) : 0; + } + /** - * Return {@code true} if the backup mechanism is currently enabled, else returns {@code false}. + * Get the restore-set token for the best-available restore set for this {@code packageName}: + * the active set if possible, else the ancestral one. Returns zero if none available. */ - public boolean isBackupEnabled(@UserIdInt int userId) { + public long getAvailableRestoreToken(@UserIdInt int userId, String packageName) { UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(userId, "isBackupEnabled()"); + getServiceForUserIfCallerHasPermission(userId, "getAvailableRestoreToken()"); - return userBackupManagerService != null && userBackupManagerService.isBackupEnabled(); + return userBackupManagerService == null + ? 0 + : userBackupManagerService.getAvailableRestoreToken(packageName); } - // --------------------------------------------- - // BACKUP OPERATIONS - // --------------------------------------------- + @Override + public boolean isAppEligibleForBackupForUser(int userId, String packageName) { + return isUserReadyForBackup(userId) && isAppEligibleForBackup(userId, + packageName); + } /** Checks if the given package {@code packageName} is eligible for backup. */ public boolean isAppEligibleForBackup(@UserIdInt int userId, String packageName) { @@ -555,6 +1309,11 @@ public class BackupManagerService { && userBackupManagerService.isAppEligibleForBackup(packageName); } + @Override + public String[] filterAppsEligibleForBackupForUser(int userId, String[] packages) { + return isUserReadyForBackup(userId) ? filterAppsEligibleForBackup(userId, packages) : null; + } + /** * Returns from the inputted packages {@code packages}, the ones that are eligible for backup. */ @@ -568,17 +1327,20 @@ public class BackupManagerService { : userBackupManagerService.filterAppsEligibleForBackup(packages); } - /** - * Run a backup pass immediately for any key-value backup applications that have declared that - * they have pending updates. - */ - public void backupNow(@UserIdInt int userId) { - UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(userId, "backupNow()"); - - if (userBackupManagerService != null) { - userBackupManagerService.backupNow(); + @Override + public int requestBackupForUser(@UserIdInt int userId, String[] packages, IBackupObserver + observer, IBackupManagerMonitor monitor, int flags) throws RemoteException { + if (!isUserReadyForBackup(userId)) { + return BackupManager.ERROR_BACKUP_NOT_ALLOWED; } + return requestBackup(userId, packages, observer, monitor, flags); + } + + @Override + public int requestBackup(String[] packages, IBackupObserver observer, + IBackupManagerMonitor monitor, int flags) throws RemoteException { + return requestBackupForUser(binderGetCallingUserId(), packages, + observer, monitor, flags); } /** @@ -599,6 +1361,18 @@ public class BackupManagerService { : userBackupManagerService.requestBackup(packages, observer, monitor, flags); } + @Override + public void cancelBackupsForUser(@UserIdInt int userId) throws RemoteException { + if (isUserReadyForBackup(userId)) { + cancelBackups(userId); + } + } + + @Override + public void cancelBackups() throws RemoteException { + cancelBackupsForUser(binderGetCallingUserId()); + } + /** Cancel all running backup operations. */ public void cancelBackups(@UserIdInt int userId) { UserBackupManagerService userBackupManagerService = @@ -610,240 +1384,193 @@ public class BackupManagerService { } /** - * Used by the {@link JobScheduler} to run a full backup when conditions are right. The model we - * use is to perform one app backup per scheduled job execution, and to reschedule the job with - * zero latency as long as conditions remain right and we still have work to do. + * Returns a {@link UserHandle} for the user that has {@code ancestralSerialNumber} as the + * serial number of its ancestral work profile or null if there is no {@link + * UserBackupManagerService} associated with that user. * - * @return Whether ongoing work will continue. The return value here will be passed along as the - * return value to the callback {@link JobService#onStartJob(JobParameters)}. + * <p> The ancestral work profile is set by {@link #setAncestralSerialNumber(long)} + * and it corresponds to the profile that was used to restore to the callers profile. */ - public boolean beginFullBackup(@UserIdInt int userId, FullBackupJob scheduledJob) { - UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(userId, "beginFullBackup()"); + @Override + @Nullable + public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) { + if (mGlobalDisable) { + return null; + } + int callingUserId = Binder.getCallingUserHandle().getIdentifier(); + long oldId = Binder.clearCallingIdentity(); + final int[] userIds; + try { + userIds = + mContext + .getSystemService(UserManager.class) + .getProfileIds(callingUserId, false); + } finally { + Binder.restoreCallingIdentity(oldId); + } - return userBackupManagerService != null - && userBackupManagerService.beginFullBackup(scheduledJob); + for (int userId : userIds) { + UserBackupManagerService userBackupManagerService = mUserServices.get(userId); + if (userBackupManagerService != null) { + if (userBackupManagerService.getAncestralSerialNumber() == ancestralSerialNumber) { + return UserHandle.of(userId); + } + } + } + + return null; } /** - * Used by the {@link JobScheduler} to end the current full backup task when conditions are no - * longer met for running the full backup job. + * Sets the ancestral work profile for the calling user. + * + * <p> The ancestral work profile corresponds to the profile that was used to restore to the + * callers profile. */ - public void endFullBackup(@UserIdInt int userId) { + @Override + public void setAncestralSerialNumber(long ancestralSerialNumber) { + if (mGlobalDisable) { + return; + } UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(userId, "endFullBackup()"); + getServiceForUserIfCallerHasPermission( + Binder.getCallingUserHandle().getIdentifier(), + "setAncestralSerialNumber()"); if (userBackupManagerService != null) { - userBackupManagerService.endFullBackup(); + userBackupManagerService.setAncestralSerialNumber(ancestralSerialNumber); } } - /** - * Run a full backup pass for the given packages {@code packageNames}. Used by 'adb shell bmgr'. - */ - public void fullTransportBackup(@UserIdInt int userId, String[] packageNames) { - UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(userId, "fullTransportBackup()"); - - if (userBackupManagerService != null) { - userBackupManagerService.fullTransportBackup(packageNames); + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) { + return; + } + int userId = binderGetCallingUserId(); + if (!isUserReadyForBackup(userId)) { + pw.println("Inactive"); + return; } - } - // --------------------------------------------- - // RESTORE OPERATIONS - // --------------------------------------------- + if (args != null) { + for (String arg : args) { + if ("users".equals(arg.toLowerCase())) { + pw.print(DUMP_RUNNING_USERS_MESSAGE); + for (int i = 0; i < mUserServices.size(); i++) { + pw.print(" " + mUserServices.keyAt(i)); + } + pw.println(); + return; + } + } + } - /** - * Used to run a restore pass for an application that is being installed. This should only be - * called from the {@link PackageManager}. - */ - public void restoreAtInstall(@UserIdInt int userId, String packageName, int token) { UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(userId, "restoreAtInstall()"); + getServiceForUserIfCallerHasPermission(UserHandle.USER_SYSTEM, "dump()"); if (userBackupManagerService != null) { - userBackupManagerService.restoreAtInstall(packageName, token); + userBackupManagerService.dump(fd, pw, args); } } /** - * Begin a restore for the specified package {@code packageName} using the specified transport - * {@code transportName}. - */ - @Nullable - public IRestoreSession beginRestoreSession( - @UserIdInt int userId, String packageName, String transportName) { - UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(userId, "beginRestoreSession()"); - - return userBackupManagerService == null - ? null - : userBackupManagerService.beginRestoreSession(packageName, transportName); - } - - /** - * Get the restore-set token for the best-available restore set for this {@code packageName}: - * the active set if possible, else the ancestral one. Returns zero if none available. + * Used by the {@link JobScheduler} to run a full backup when conditions are right. The model we + * use is to perform one app backup per scheduled job execution, and to reschedule the job with + * zero latency as long as conditions remain right and we still have work to do. + * + * @return Whether ongoing work will continue. The return value here will be passed along as the + * return value to the callback {@link JobService#onStartJob(JobParameters)}. */ - public long getAvailableRestoreToken(@UserIdInt int userId, String packageName) { - UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(userId, "getAvailableRestoreToken()"); - - return userBackupManagerService == null - ? 0 - : userBackupManagerService.getAvailableRestoreToken(packageName); - } - - // --------------------------------------------- - // ADB BACKUP/RESTORE OPERATIONS - // --------------------------------------------- - - /** Sets the backup password used when running adb backup. */ - public boolean setBackupPassword(String currentPassword, String newPassword) { + public boolean beginFullBackup(@UserIdInt int userId, FullBackupJob scheduledJob) { + if (!isUserReadyForBackup(userId)) { + return false; + } UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission( - UserHandle.USER_SYSTEM, "setBackupPassword()"); + getServiceForUserIfCallerHasPermission(userId, "beginFullBackup()"); return userBackupManagerService != null - && userBackupManagerService.setBackupPassword(currentPassword, newPassword); - } - - /** Returns {@code true} if adb backup was run with a password, else returns {@code false}. */ - public boolean hasBackupPassword() { - UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission( - UserHandle.USER_SYSTEM, "hasBackupPassword()"); - - return userBackupManagerService != null && userBackupManagerService.hasBackupPassword(); + && userBackupManagerService.beginFullBackup(scheduledJob); } /** - * Used by 'adb backup' to run a backup pass for packages {@code packageNames} supplied via the - * command line, writing the resulting data stream to the supplied {@code fd}. This method is - * synchronous and does not return to the caller until the backup has been completed. It - * requires on-screen confirmation by the user. + * Used by the {@link JobScheduler} to end the current full backup task when conditions are no + * longer met for running the full backup job. */ - public void adbBackup( - @UserIdInt int userId, - ParcelFileDescriptor fd, - boolean includeApks, - boolean includeObbs, - boolean includeShared, - boolean doWidgets, - boolean doAllApps, - boolean includeSystem, - boolean doCompress, - boolean doKeyValue, - String[] packageNames) { + public void endFullBackup(@UserIdInt int userId) { + if (!isUserReadyForBackup(userId)) { + return; + } UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(userId, "adbBackup()"); + getServiceForUserIfCallerHasPermission(userId, "endFullBackup()"); if (userBackupManagerService != null) { - userBackupManagerService.adbBackup( - fd, - includeApks, - includeObbs, - includeShared, - doWidgets, - doAllApps, - includeSystem, - doCompress, - doKeyValue, - packageNames); + userBackupManagerService.endFullBackup(); } } /** - * Used by 'adb restore' to run a restore pass reading from the supplied {@code fd}. This method - * is synchronous and does not return to the caller until the restore has been completed. It - * requires on-screen confirmation by the user. + * Returns the {@link UserBackupManagerService} instance for the specified user {@code userId}. + * If the user is not registered with the service (either the user is locked or not eligible for + * the backup service) then return {@code null}. + * + * @param userId The id of the user to retrieve its instance of {@link + * UserBackupManagerService}. + * @param caller A {@link String} identifying the caller for logging purposes. + * @throws SecurityException if {@code userId} is different from the calling user id and the + * caller does NOT have the android.permission.INTERACT_ACROSS_USERS_FULL permission. */ - public void adbRestore(@UserIdInt int userId, ParcelFileDescriptor fd) { - UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(userId, "adbRestore()"); - - if (userBackupManagerService != null) { - userBackupManagerService.adbRestore(fd); + @Nullable + @VisibleForTesting + UserBackupManagerService getServiceForUserIfCallerHasPermission( + @UserIdInt int userId, String caller) { + enforceCallingPermissionOnUserId(userId, caller); + UserBackupManagerService userBackupManagerService = mUserServices.get(userId); + if (userBackupManagerService == null) { + Slog.w(TAG, "Called " + caller + " for unknown user: " + userId); } + return userBackupManagerService; } /** - * Confirm that the previously requested adb backup/restore operation can proceed. This is used - * to require a user-facing disclosure about the operation. + * If {@code userId} is different from the calling user id, then the caller must hold the + * android.permission.INTERACT_ACROSS_USERS_FULL permission. + * + * @param userId User id on which the backup operation is being requested. + * @param message A message to include in the exception if it is thrown. */ - public void acknowledgeAdbBackupOrRestore( - @UserIdInt int userId, - int token, - boolean allow, - String currentPassword, - String encryptionPassword, - IFullBackupRestoreObserver observer) { - UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(userId, "acknowledgeAdbBackupOrRestore()"); - - if (userBackupManagerService != null) { - userBackupManagerService.acknowledgeAdbBackupOrRestore( - token, allow, currentPassword, encryptionPassword, observer); - } - } - - // --------------------------------------------- - // SERVICE OPERATIONS - // --------------------------------------------- - - /** Prints service state for 'dumpsys backup'. */ - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) { - return; - } - - if (args != null) { - for (String arg : args) { - if ("users".equals(arg.toLowerCase())) { - pw.print(DUMP_RUNNING_USERS_MESSAGE); - for (int i = 0; i < mServiceUsers.size(); i++) { - pw.print(" " + mServiceUsers.keyAt(i)); - } - pw.println(); - return; - } - } - } - - UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(UserHandle.USER_SYSTEM, "dump()"); - - if (userBackupManagerService != null) { - userBackupManagerService.dump(fd, pw, args); + void enforceCallingPermissionOnUserId(@UserIdInt int userId, String message) { + if (Binder.getCallingUserHandle().getIdentifier() != userId) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); } } /** Implementation to receive lifecycle event callbacks for system services. */ public static class Lifecycle extends SystemService { public Lifecycle(Context context) { - this(context, new Trampoline(context)); + this(context, new BackupManagerService(context)); } @VisibleForTesting - Lifecycle(Context context, Trampoline trampoline) { + Lifecycle(Context context, BackupManagerService backupManagerService) { super(context); - Trampoline.sInstance = trampoline; + sInstance = backupManagerService; } @Override public void onStart() { - publishService(Context.BACKUP_SERVICE, Trampoline.sInstance); + publishService(Context.BACKUP_SERVICE, BackupManagerService.sInstance); } @Override public void onUnlockUser(int userId) { - Trampoline.sInstance.onUnlockUser(userId); + sInstance.onUnlockUser(userId); } @Override public void onStopUser(int userId) { - Trampoline.sInstance.onStopUser(userId); + sInstance.onStopUser(userId); } @VisibleForTesting diff --git a/services/backup/java/com/android/server/backup/FullBackupJob.java b/services/backup/java/com/android/server/backup/FullBackupJob.java index 19a85432875c..0bb25e360f15 100644 --- a/services/backup/java/com/android/server/backup/FullBackupJob.java +++ b/services/backup/java/com/android/server/backup/FullBackupJob.java @@ -91,7 +91,7 @@ public class FullBackupJob extends JobService { mParamsForUser.put(userId, params); } - Trampoline service = Trampoline.getInstance(); + BackupManagerService service = BackupManagerService.getInstance(); return service.beginFullBackup(userId, this); } @@ -105,7 +105,7 @@ public class FullBackupJob extends JobService { } } - Trampoline service = Trampoline.getInstance(); + BackupManagerService service = BackupManagerService.getInstance(); service.endFullBackup(userId); return false; diff --git a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java index 7b5dbd7ce777..058dcae3102f 100644 --- a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java +++ b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java @@ -144,7 +144,7 @@ public class KeyValueBackupJob extends JobService { } // Time to run a key/value backup! - Trampoline service = Trampoline.getInstance(); + BackupManagerService service = BackupManagerService.getInstance(); try { service.backupNowForUser(userId); } catch (RemoteException e) {} diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java deleted file mode 100644 index 59d9c0eb3219..000000000000 --- a/services/backup/java/com/android/server/backup/Trampoline.java +++ /dev/null @@ -1,868 +0,0 @@ -/* - * Copyright (C) 2014 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.backup; - -import static com.android.internal.util.Preconditions.checkNotNull; -import static com.android.server.backup.BackupManagerService.TAG; - -import static java.util.Collections.emptySet; - -import android.Manifest; -import android.annotation.Nullable; -import android.annotation.UserIdInt; -import android.app.admin.DevicePolicyManager; -import android.app.backup.BackupManager; -import android.app.backup.IBackupManager; -import android.app.backup.IBackupManagerMonitor; -import android.app.backup.IBackupObserver; -import android.app.backup.IFullBackupRestoreObserver; -import android.app.backup.IRestoreSession; -import android.app.backup.ISelectBackupTransportCallback; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Binder; -import android.os.FileUtils; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; -import android.os.Process; -import android.os.RemoteException; -import android.os.SystemProperties; -import android.os.UserHandle; -import android.os.UserManager; -import android.util.Slog; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.DumpUtils; -import com.android.server.SystemConfig; -import com.android.server.backup.utils.RandomAccessFileUtils; - -import java.io.File; -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Set; - -/** - * A proxy to the {@link BackupManagerService} implementation. - * - * <p>This is an external interface to the {@link BackupManagerService} which is being accessed via - * published binder {@link BackupManagerService.Lifecycle}. This lets us turn down the heavy - * implementation object on the fly without disturbing binders that have been cached somewhere in - * the system. - * - * <p>Trampoline determines whether the backup service is available. It can be disabled in the - * following two ways: - * - * <ul> - * <li>Temporary - create the file {@link #BACKUP_SUPPRESS_FILENAME}, or - * <li>Permanent - set the system property {@link #BACKUP_DISABLE_PROPERTY} to true. - * </ul> - * - * Temporary disabling is controlled by {@link #setBackupServiceActive(int, boolean)} through - * privileged callers (currently {@link DevicePolicyManager}). This is called on {@link - * UserHandle#USER_SYSTEM} and disables backup for all users. - */ -public class Trampoline extends IBackupManager.Stub { - /** - * Name of file that disables the backup service. If this file exists, then backup is disabled - * for all users. - */ - private static final String BACKUP_SUPPRESS_FILENAME = "backup-suppress"; - - /** - * Name of file for non-system users that enables the backup service for the user. Backup is - * disabled by default in non-system users. - */ - private static final String BACKUP_ACTIVATED_FILENAME = "backup-activated"; - - /** - * Name of file for non-system users that remembers whether backup was explicitly activated or - * deactivated with a call to setBackupServiceActive. - */ - private static final String REMEMBER_ACTIVATED_FILENAME = "backup-remember-activated"; - - // Product-level suppression of backup/restore. - private static final String BACKUP_DISABLE_PROPERTY = "ro.backup.disable"; - - private static final String BACKUP_THREAD = "backup"; - - static Trampoline sInstance; - - static Trampoline getInstance() { - return checkNotNull(sInstance); - } - - private final Context mContext; - private final UserManager mUserManager; - - private final boolean mGlobalDisable; - // Lock to write backup suppress files. - // TODD(b/121198006): remove this object and synchronized all methods on "this". - private final Object mStateLock = new Object(); - - // TODO: This is not marked as final because of test code. Since we'll merge BMS and Trampoline, - // it doesn't make sense to refactor for final. It's never null. - @VisibleForTesting - protected volatile BackupManagerService mService; - private final Handler mHandler; - private final Set<ComponentName> mTransportWhitelist; - - private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) { - int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); - if (userId > 0) { // for only non system users - mHandler.post(() -> onRemovedNonSystemUser(userId)); - } - } - } - }; - - public Trampoline(Context context) { - mContext = context; - mGlobalDisable = isBackupDisabled(); - HandlerThread handlerThread = - new HandlerThread(BACKUP_THREAD, Process.THREAD_PRIORITY_BACKGROUND); - handlerThread.start(); - mHandler = new Handler(handlerThread.getLooper()); - mUserManager = UserManager.get(context); - mService = new BackupManagerService(mContext, this); - Set<ComponentName> transportWhitelist = - SystemConfig.getInstance().getBackupTransportWhitelist(); - mTransportWhitelist = (transportWhitelist == null) ? emptySet() : transportWhitelist; - mContext.registerReceiver( - mUserRemovedReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED)); - } - - // TODO: Remove this when we implement DI by injecting in the construtor. - @VisibleForTesting - Handler getBackupHandler() { - return mHandler; - } - - protected boolean isBackupDisabled() { - return SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false); - } - - protected int binderGetCallingUserId() { - return Binder.getCallingUserHandle().getIdentifier(); - } - - protected int binderGetCallingUid() { - return Binder.getCallingUid(); - } - - /** Stored in the system user's directory. */ - protected File getSuppressFileForSystemUser() { - return new File(UserBackupManagerFiles.getBaseStateDir(UserHandle.USER_SYSTEM), - BACKUP_SUPPRESS_FILENAME); - } - - /** Stored in the system user's directory and the file is indexed by the user it refers to. */ - protected File getRememberActivatedFileForNonSystemUser(int userId) { - return UserBackupManagerFiles.getStateFileInSystemDir(REMEMBER_ACTIVATED_FILENAME, userId); - } - - /** Stored in the system user's directory and the file is indexed by the user it refers to. */ - protected File getActivatedFileForNonSystemUser(int userId) { - return UserBackupManagerFiles.getStateFileInSystemDir(BACKUP_ACTIVATED_FILENAME, userId); - } - - /** - * Remove backup state for non system {@code userId} when the user is removed from the device. - * For non system users, backup state is stored in both the user's own dir and the system dir. - * When the user is removed, the user's own dir gets removed by the OS. This method ensures that - * the part of the user backup state which is in the system dir also gets removed. - */ - private void onRemovedNonSystemUser(int userId) { - Slog.i(TAG, "Removing state for non system user " + userId); - File dir = UserBackupManagerFiles.getStateDirInSystemDir(userId); - if (!FileUtils.deleteContentsAndDir(dir)) { - Slog.w(TAG, "Failed to delete state dir for removed user: " + userId); - } - } - - // TODO (b/124359804) move to util method in FileUtils - private void createFile(File file) throws IOException { - if (file.exists()) { - return; - } - - file.getParentFile().mkdirs(); - if (!file.createNewFile()) { - Slog.w(TAG, "Failed to create file " + file.getPath()); - } - } - - // TODO (b/124359804) move to util method in FileUtils - private void deleteFile(File file) { - if (!file.exists()) { - return; - } - - if (!file.delete()) { - Slog.w(TAG, "Failed to delete file " + file.getPath()); - } - } - - /** - * Deactivates the backup service for user {@code userId}. If this is the system user, it - * creates a suppress file which disables backup for all users. If this is a non-system user, it - * only deactivates backup for that user by deleting its activate file. - */ - @GuardedBy("mStateLock") - private void deactivateBackupForUserLocked(int userId) throws IOException { - if (userId == UserHandle.USER_SYSTEM) { - createFile(getSuppressFileForSystemUser()); - } else { - deleteFile(getActivatedFileForNonSystemUser(userId)); - } - } - - /** - * Enables the backup service for user {@code userId}. If this is the system user, it deletes - * the suppress file. If this is a non-system user, it creates the user's activate file. Note, - * deleting the suppress file does not automatically enable backup for non-system users, they - * need their own activate file in order to participate in the service. - */ - @GuardedBy("mStateLock") - private void activateBackupForUserLocked(int userId) throws IOException { - if (userId == UserHandle.USER_SYSTEM) { - deleteFile(getSuppressFileForSystemUser()); - } else { - createFile(getActivatedFileForNonSystemUser(userId)); - } - } - - // This method should not perform any I/O (e.g. do not call isBackupActivatedForUser), - // it's used in multiple places where I/O waits would cause system lock-ups. - private boolean isUserReadyForBackup(int userId) { - return mService.isAbleToServeUser(userId); - } - - /** - * Backup is activated for the system user if the suppress file does not exist. Backup is - * activated for non-system users if the suppress file does not exist AND the user's activated - * file exists. - */ - private boolean isBackupActivatedForUser(int userId) { - if (getSuppressFileForSystemUser().exists()) { - return false; - } - - return userId == UserHandle.USER_SYSTEM - || getActivatedFileForNonSystemUser(userId).exists(); - } - - protected Context getContext() { - return mContext; - } - - protected UserManager getUserManager() { - return mUserManager; - } - - protected void postToHandler(Runnable runnable) { - mHandler.post(runnable); - } - - /** - * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is unlocked. - * Starts the backup service for this user if backup is active for this user. Offloads work onto - * the handler thread {@link #mHandlerThread} to keep unlock time low since backup is not - * essential for device functioning. - */ - void onUnlockUser(int userId) { - postToHandler(() -> startServiceForUser(userId)); - } - - private void startServiceForUser(int userId) { - // We know that the user is unlocked here because it is called from setBackupServiceActive - // and unlockUser which have these guarantees. So we can check if the file exists. - if (mGlobalDisable) { - Slog.i(TAG, "Backup service not supported"); - return; - } - if (!isBackupActivatedForUser(userId)) { - Slog.i(TAG, "Backup not activated for user " + userId); - return; - } - Slog.i(TAG, "Starting service for user: " + userId); - mService.startServiceForUser(userId, mTransportWhitelist); - } - - /** - * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is stopped. - * Offloads work onto the handler thread {@link #mHandlerThread} to keep stopping time low. - */ - void onStopUser(int userId) { - postToHandler( - () -> { - if (!mGlobalDisable) { - Slog.i(TAG, "Stopping service for user: " + userId); - mService.stopServiceForUser(userId); - } - }); - } - - /** Returns {@link UserBackupManagerService} for user {@code userId}. */ - @Nullable - public UserBackupManagerService getUserService(int userId) { - return mService.getUserServices().get(userId); - } - - /** - * The system user and managed profiles can only be acted on by callers in the system or root - * processes. Other users can be acted on by callers who have both android.permission.BACKUP and - * android.permission.INTERACT_ACROSS_USERS_FULL permissions. - */ - private void enforcePermissionsOnUser(int userId) throws SecurityException { - boolean isRestrictedUser = - userId == UserHandle.USER_SYSTEM - || getUserManager().getUserInfo(userId).isManagedProfile(); - - if (isRestrictedUser) { - int caller = binderGetCallingUid(); - if (caller != Process.SYSTEM_UID && caller != Process.ROOT_UID) { - throw new SecurityException("No permission to configure backup activity"); - } - } else { - mContext.enforceCallingOrSelfPermission( - Manifest.permission.BACKUP, "No permission to configure backup activity"); - mContext.enforceCallingOrSelfPermission( - Manifest.permission.INTERACT_ACROSS_USERS_FULL, - "No permission to configure backup activity"); - } - } - - /** - * Only privileged callers should be changing the backup state. Deactivating backup in the - * system user also deactivates backup in all users. We are not guaranteed that {@code userId} - * is unlocked at this point yet, so handle both cases. - */ - public void setBackupServiceActive(int userId, boolean makeActive) { - enforcePermissionsOnUser(userId); - - // In Q, backup is OFF by default for non-system users. In the future, we will change that - // to ON unless backup was explicitly deactivated with a (permissioned) call to - // setBackupServiceActive. - // Therefore, remember this for use in the future. Basically the default in the future will - // be: rememberFile.exists() ? rememberFile.value() : ON - // Note that this has to be done right after the permission checks and before any other - // action since we need to remember that a permissioned call was made irrespective of - // whether the call changes the state or not. - if (userId != UserHandle.USER_SYSTEM) { - try { - File rememberFile = getRememberActivatedFileForNonSystemUser(userId); - createFile(rememberFile); - RandomAccessFileUtils.writeBoolean(rememberFile, makeActive); - } catch (IOException e) { - Slog.e(TAG, "Unable to persist backup service activity", e); - } - } - - if (mGlobalDisable) { - Slog.i(TAG, "Backup service not supported"); - return; - } - - synchronized (mStateLock) { - Slog.i(TAG, "Making backup " + (makeActive ? "" : "in") + "active"); - if (makeActive) { - try { - activateBackupForUserLocked(userId); - } catch (IOException e) { - Slog.e(TAG, "Unable to persist backup service activity"); - } - - // If the user is unlocked, we can start the backup service for it. Otherwise we - // will start the service when the user is unlocked as part of its unlock callback. - if (getUserManager().isUserUnlocked(userId)) { - // Clear calling identity as initialization enforces the system identity but we - // can be coming from shell. - long oldId = Binder.clearCallingIdentity(); - try { - startServiceForUser(userId); - } finally { - Binder.restoreCallingIdentity(oldId); - } - } - } else { - try { - //TODO(b/121198006): what if this throws an exception? - deactivateBackupForUserLocked(userId); - } catch (IOException e) { - Slog.e(TAG, "Unable to persist backup service inactivity"); - } - //TODO(b/121198006): loop through active users that have work profile and - // stop them as well. - onStopUser(userId); - } - } - } - - // IBackupManager binder API - - /** - * Querying activity state of backup service. - * - * @param userId The user in which the activity state of backup service is queried. - * @return true if the service is active. - */ - @Override - public boolean isBackupServiceActive(int userId) { - synchronized (mStateLock) { - return !mGlobalDisable && isBackupActivatedForUser(userId); - } - } - - @Override - public void dataChangedForUser(int userId, String packageName) throws RemoteException { - if (isUserReadyForBackup(userId)) { - mService.dataChanged(userId, packageName); - } - } - - @Override - public void dataChanged(String packageName) throws RemoteException { - dataChangedForUser(binderGetCallingUserId(), packageName); - } - - @Override - public void initializeTransportsForUser( - int userId, String[] transportNames, IBackupObserver observer) throws RemoteException { - if (isUserReadyForBackup(userId)) { - mService.initializeTransports(userId, transportNames, observer); - } - } - - @Override - public void clearBackupDataForUser(int userId, String transportName, String packageName) - throws RemoteException { - if (isUserReadyForBackup(userId)) { - mService.clearBackupData(userId, transportName, packageName); - } - } - - @Override - public void clearBackupData(String transportName, String packageName) - throws RemoteException { - clearBackupDataForUser(binderGetCallingUserId(), transportName, packageName); - } - - @Override - public void agentConnectedForUser(int userId, String packageName, IBinder agent) - throws RemoteException { - if (isUserReadyForBackup(userId)) { - mService.agentConnected(userId, packageName, agent); - } - } - - @Override - public void agentConnected(String packageName, IBinder agent) throws RemoteException { - agentConnectedForUser(binderGetCallingUserId(), packageName, agent); - } - - @Override - public void agentDisconnectedForUser(int userId, String packageName) throws RemoteException { - if (isUserReadyForBackup(userId)) { - mService.agentDisconnected(userId, packageName); - } - } - - @Override - public void agentDisconnected(String packageName) throws RemoteException { - agentDisconnectedForUser(binderGetCallingUserId(), packageName); - } - - @Override - public void restoreAtInstallForUser(int userId, String packageName, int token) - throws RemoteException { - if (isUserReadyForBackup(userId)) { - mService.restoreAtInstall(userId, packageName, token); - } - } - - @Override - public void restoreAtInstall(String packageName, int token) throws RemoteException { - restoreAtInstallForUser(binderGetCallingUserId(), packageName, token); - } - - @Override - public void setBackupEnabledForUser(@UserIdInt int userId, boolean isEnabled) - throws RemoteException { - if (isUserReadyForBackup(userId)) { - mService.setBackupEnabled(userId, isEnabled); - } - } - - @Override - public void setBackupEnabled(boolean isEnabled) throws RemoteException { - setBackupEnabledForUser(binderGetCallingUserId(), isEnabled); - } - - @Override - public void setAutoRestoreForUser(int userId, boolean doAutoRestore) throws RemoteException { - if (isUserReadyForBackup(userId)) { - mService.setAutoRestore(userId, doAutoRestore); - } - } - - @Override - public void setAutoRestore(boolean doAutoRestore) throws RemoteException { - setAutoRestoreForUser(binderGetCallingUserId(), doAutoRestore); - } - - @Override - public boolean isBackupEnabledForUser(@UserIdInt int userId) throws RemoteException { - return isUserReadyForBackup(userId) && mService.isBackupEnabled(userId); - } - - @Override - public boolean isBackupEnabled() throws RemoteException { - return isBackupEnabledForUser(binderGetCallingUserId()); - } - - @Override - public boolean setBackupPassword(String currentPw, String newPw) throws RemoteException { - int userId = binderGetCallingUserId(); - return (isUserReadyForBackup(userId)) && mService.setBackupPassword(currentPw, newPw); - } - - @Override - public boolean hasBackupPassword() throws RemoteException { - int userId = binderGetCallingUserId(); - return (isUserReadyForBackup(userId)) && mService.hasBackupPassword(); - } - - @Override - public void backupNowForUser(@UserIdInt int userId) throws RemoteException { - if (isUserReadyForBackup(userId)) { - mService.backupNow(userId); - } - } - - @Override - public void backupNow() throws RemoteException { - backupNowForUser(binderGetCallingUserId()); - } - - public void adbBackup(@UserIdInt int userId, ParcelFileDescriptor fd, - boolean includeApks, boolean includeObbs, boolean includeShared, boolean doWidgets, - boolean allApps, boolean allIncludesSystem, boolean doCompress, boolean doKeyValue, - String[] packageNames) throws RemoteException { - if (isUserReadyForBackup(userId)) { - mService.adbBackup(userId, fd, includeApks, includeObbs, includeShared, doWidgets, - allApps, allIncludesSystem, doCompress, doKeyValue, packageNames); - } - } - - @Override - public void fullTransportBackupForUser(int userId, String[] packageNames) - throws RemoteException { - if (isUserReadyForBackup(userId)) { - mService.fullTransportBackup(userId, packageNames); - } - } - - @Override - public void adbRestore(@UserIdInt int userId, ParcelFileDescriptor fd) throws RemoteException { - if (isUserReadyForBackup(userId)) { - mService.adbRestore(userId, fd); - } - } - - @Override - public void acknowledgeFullBackupOrRestoreForUser( - int userId, - int token, - boolean allow, - String curPassword, - String encryptionPassword, - IFullBackupRestoreObserver observer) - throws RemoteException { - if (isUserReadyForBackup(userId)) { - mService.acknowledgeAdbBackupOrRestore(userId, token, allow, - curPassword, encryptionPassword, observer); - } - } - - @Override - public void acknowledgeFullBackupOrRestore(int token, boolean allow, String curPassword, - String encryptionPassword, IFullBackupRestoreObserver observer) - throws RemoteException { - acknowledgeFullBackupOrRestoreForUser( - binderGetCallingUserId(), token, allow, curPassword, encryptionPassword, observer); - } - - - @Override - public String getCurrentTransportForUser(int userId) throws RemoteException { - return (isUserReadyForBackup(userId)) ? mService.getCurrentTransport(userId) : null; - } - - @Override - public String getCurrentTransport() throws RemoteException { - return getCurrentTransportForUser(binderGetCallingUserId()); - } - - /** - * Returns the {@link ComponentName} of the host service of the selected transport or - * {@code null} if no transport selected or if the transport selected is not registered. - */ - @Override - @Nullable - public ComponentName getCurrentTransportComponentForUser(int userId) { - return (isUserReadyForBackup(userId)) - ? mService.getCurrentTransportComponent(userId) : null; - } - - @Override - public String[] listAllTransportsForUser(int userId) throws RemoteException { - return (isUserReadyForBackup(userId)) ? mService.listAllTransports(userId) : null; - } - - @Override - public String[] listAllTransports() throws RemoteException { - return listAllTransportsForUser(binderGetCallingUserId()); - } - - @Override - public ComponentName[] listAllTransportComponentsForUser(int userId) throws RemoteException { - return (isUserReadyForBackup(userId)) - ? mService.listAllTransportComponents(userId) : null; - } - - @Override - public String[] getTransportWhitelist() { - int userId = binderGetCallingUserId(); - if (!isUserReadyForBackup(userId)) { - return null; - } - // No permission check, intentionally. - String[] whitelistedTransports = new String[mTransportWhitelist.size()]; - int i = 0; - for (ComponentName component : mTransportWhitelist) { - whitelistedTransports[i] = component.flattenToShortString(); - i++; - } - return whitelistedTransports; - } - - @Override - public void updateTransportAttributesForUser( - int userId, - ComponentName transportComponent, - String name, - @Nullable Intent configurationIntent, - String currentDestinationString, - @Nullable Intent dataManagementIntent, - CharSequence dataManagementLabel) { - if (isUserReadyForBackup(userId)) { - mService.updateTransportAttributes( - userId, - transportComponent, - name, - configurationIntent, - currentDestinationString, - dataManagementIntent, - dataManagementLabel); - } - } - - @Override - public String selectBackupTransportForUser(int userId, String transport) - throws RemoteException { - return (isUserReadyForBackup(userId)) - ? mService.selectBackupTransport(userId, transport) : null; - } - - @Override - public String selectBackupTransport(String transport) throws RemoteException { - return selectBackupTransportForUser(binderGetCallingUserId(), transport); - } - - @Override - public void selectBackupTransportAsyncForUser(int userId, ComponentName transport, - ISelectBackupTransportCallback listener) throws RemoteException { - if (isUserReadyForBackup(userId)) { - mService.selectBackupTransportAsync(userId, transport, listener); - } else { - if (listener != null) { - try { - listener.onFailure(BackupManager.ERROR_BACKUP_NOT_ALLOWED); - } catch (RemoteException ex) { - // ignore - } - } - } - } - - @Override - public Intent getConfigurationIntentForUser(int userId, String transport) - throws RemoteException { - return isUserReadyForBackup(userId) ? mService.getConfigurationIntent(userId, transport) - : null; - } - - @Override - public Intent getConfigurationIntent(String transport) - throws RemoteException { - return getConfigurationIntentForUser(binderGetCallingUserId(), transport); - } - - @Override - public String getDestinationStringForUser(int userId, String transport) throws RemoteException { - return isUserReadyForBackup(userId) ? mService.getDestinationString(userId, transport) - : null; - } - - @Override - public String getDestinationString(String transport) throws RemoteException { - return getDestinationStringForUser(binderGetCallingUserId(), transport); - } - - @Override - public Intent getDataManagementIntentForUser(int userId, String transport) - throws RemoteException { - return isUserReadyForBackup(userId) - ? mService.getDataManagementIntent(userId, transport) : null; - } - - @Override - public Intent getDataManagementIntent(String transport) - throws RemoteException { - return getDataManagementIntentForUser(binderGetCallingUserId(), transport); - } - - @Override - public CharSequence getDataManagementLabelForUser(int userId, String transport) - throws RemoteException { - return isUserReadyForBackup(userId) ? mService.getDataManagementLabel(userId, transport) - : null; - } - - @Override - public IRestoreSession beginRestoreSessionForUser( - int userId, String packageName, String transportID) throws RemoteException { - return isUserReadyForBackup(userId) ? mService.beginRestoreSession(userId, packageName, - transportID) : null; - } - - @Override - public void opCompleteForUser(int userId, int token, long result) throws RemoteException { - if (isUserReadyForBackup(userId)) { - mService.opComplete(userId, token, result); - } - } - - @Override - public void opComplete(int token, long result) throws RemoteException { - opCompleteForUser(binderGetCallingUserId(), token, result); - } - - @Override - public long getAvailableRestoreTokenForUser(int userId, String packageName) { - return isUserReadyForBackup(userId) ? mService.getAvailableRestoreToken(userId, - packageName) : 0; - } - - @Override - public boolean isAppEligibleForBackupForUser(int userId, String packageName) { - return isUserReadyForBackup(userId) && mService.isAppEligibleForBackup(userId, - packageName); - } - - @Override - public String[] filterAppsEligibleForBackupForUser(int userId, String[] packages) { - return isUserReadyForBackup(userId) ? mService.filterAppsEligibleForBackup(userId, - packages) : null; - } - - @Override - public int requestBackupForUser(@UserIdInt int userId, String[] packages, IBackupObserver - observer, IBackupManagerMonitor monitor, int flags) throws RemoteException { - if (!isUserReadyForBackup(userId)) { - return BackupManager.ERROR_BACKUP_NOT_ALLOWED; - } - return mService.requestBackup(userId, packages, observer, monitor, flags); - } - - @Override - public int requestBackup(String[] packages, IBackupObserver observer, - IBackupManagerMonitor monitor, int flags) throws RemoteException { - return requestBackupForUser(binderGetCallingUserId(), packages, - observer, monitor, flags); - } - - @Override - public void cancelBackupsForUser(@UserIdInt int userId) throws RemoteException { - if (isUserReadyForBackup(userId)) { - mService.cancelBackups(userId); - } - } - - @Override - public void cancelBackups() throws RemoteException { - cancelBackupsForUser(binderGetCallingUserId()); - } - - @Override - @Nullable public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) { - if (mGlobalDisable) { - return null; - } - return mService.getUserForAncestralSerialNumber(ancestralSerialNumber); - } - - @Override - public void setAncestralSerialNumber(long ancestralSerialNumber) { - if (!mGlobalDisable) { - mService.setAncestralSerialNumber(ancestralSerialNumber); - } - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; - int userId = binderGetCallingUserId(); - if (isUserReadyForBackup(userId)) { - mService.dump(fd, pw, args); - } else { - pw.println("Inactive"); - } - } - - // Full backup/restore entry points - non-Binder; called directly - // by the full-backup scheduled job - /* package */ boolean beginFullBackup(@UserIdInt int userId, FullBackupJob scheduledJob) { - return (isUserReadyForBackup(userId)) && mService.beginFullBackup(userId, scheduledJob); - } - - /* package */ void endFullBackup(@UserIdInt int userId) { - if (isUserReadyForBackup(userId)) { - mService.endFullBackup(userId); - } - } -} diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index d599aabbaa28..77888db416a5 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -421,13 +421,13 @@ public class UserBackupManagerService { * Creates an instance of {@link UserBackupManagerService} and initializes state for it. This * includes setting up the directories where we keep our bookkeeping and transport management. * - * @see #createAndInitializeService(int, Context, Trampoline, HandlerThread, File, File, - * TransportManager) + * @see #createAndInitializeService(int, Context, BackupManagerService, HandlerThread, File, + * File, TransportManager) */ static UserBackupManagerService createAndInitializeService( @UserIdInt int userId, Context context, - Trampoline trampoline, + BackupManagerService backupManagerService, Set<ComponentName> transportWhitelist) { String currentTransport = Settings.Secure.getStringForUser( @@ -455,7 +455,7 @@ public class UserBackupManagerService { return createAndInitializeService( userId, context, - trampoline, + backupManagerService, userBackupThread, baseStateDir, dataDir, @@ -467,7 +467,7 @@ public class UserBackupManagerService { * * @param userId The user which this service is for. * @param context The system server context. - * @param trampoline A reference to the proxy to {@link BackupManagerService}. + * @param backupManagerService A reference to the proxy to {@link BackupManagerService}. * @param userBackupThread The thread running backup/restore operations for the user. * @param baseStateDir The directory we store the user's persistent bookkeeping data. * @param dataDir The directory we store the user's temporary staging data. @@ -478,7 +478,7 @@ public class UserBackupManagerService { public static UserBackupManagerService createAndInitializeService( @UserIdInt int userId, Context context, - Trampoline trampoline, + BackupManagerService backupManagerService, HandlerThread userBackupThread, File baseStateDir, File dataDir, @@ -486,7 +486,7 @@ public class UserBackupManagerService { return new UserBackupManagerService( userId, context, - trampoline, + backupManagerService, userBackupThread, baseStateDir, dataDir, @@ -509,7 +509,7 @@ public class UserBackupManagerService { private UserBackupManagerService( @UserIdInt int userId, Context context, - Trampoline parent, + BackupManagerService parent, HandlerThread userBackupThread, File baseStateDir, File dataDir, @@ -525,8 +525,8 @@ public class UserBackupManagerService { mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount")); - checkNotNull(parent, "trampoline cannot be null"); - mBackupManagerBinder = Trampoline.asInterface(parent.asBinder()); + checkNotNull(parent, "parent cannot be null"); + mBackupManagerBinder = BackupManagerService.asInterface(parent.asBinder()); mAgentTimeoutParameters = new BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver()); @@ -649,7 +649,8 @@ public class UserBackupManagerService { } /** Cleans up state when the user of this service is stopped. */ - void tearDownService() { + @VisibleForTesting + protected void tearDownService() { mAgentTimeoutParameters.stop(); mConstants.stop(); mContext.getContentResolver().unregisterContentObserver(mSetupObserver); diff --git a/services/core/Android.bp b/services/core/Android.bp index 474dbfe49d70..c838c6044e1d 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -13,7 +13,6 @@ java_library_static { }, srcs: [ "java/**/*.java", - ":platformcompat_aidl", ":dumpstate_aidl", ":idmap2_aidl", ":installd_aidl", @@ -82,11 +81,3 @@ 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/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index fede48789e97..9a97ddb3e3a7 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -172,7 +172,7 @@ class AlarmManagerService extends SystemService { final LocalLog mLog = new LocalLog(TAG); AppOpsManager mAppOps; - DeviceIdleController.LocalService mLocalDeviceIdleController; + DeviceIdleInternal mLocalDeviceIdleController; private UsageStatsManagerInternal mUsageStatsManagerInternal; final Object mLock = new Object(); @@ -1594,7 +1594,7 @@ class AlarmManagerService extends SystemService { mConstants.start(getContext().getContentResolver()); mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); mLocalDeviceIdleController = - LocalServices.getService(DeviceIdleController.LocalService.class); + LocalServices.getService(DeviceIdleInternal.class); mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class); mUsageStatsManagerInternal.addAppIdleStateChangeListener(new AppStandbyTracker()); diff --git a/services/core/java/com/android/server/AnimationThread.java b/services/core/java/com/android/server/AnimationThread.java index c86042b23460..c607b1e058bc 100644 --- a/services/core/java/com/android/server/AnimationThread.java +++ b/services/core/java/com/android/server/AnimationThread.java @@ -21,6 +21,8 @@ import static android.os.Process.THREAD_PRIORITY_DISPLAY; import android.os.Handler; import android.os.Trace; +import com.android.internal.annotations.VisibleForTesting; + /** * Thread for handling all legacy window animations, or anything that's directly impacting * animations like starting windows or traversals. @@ -55,4 +57,20 @@ public final class AnimationThread extends ServiceThread { return sHandler; } } + + /** + * Disposes current animation thread if it's initialized. Should only be used in tests to set up + * a new environment. + */ + @VisibleForTesting + public static void dispose() { + synchronized (DisplayThread.class) { + if (sInstance == null) { + return; + } + + getHandler().runWithScissors(() -> sInstance.quit(), 0 /* timeout */); + sInstance = null; + } + } } diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index 6a9f5b651016..d18b4f64f039 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -1235,14 +1235,21 @@ public final class BatteryService extends SystemService { } @Override public void scheduleUpdate() throws RemoteException { - traceBegin("HealthScheduleUpdate"); - try { - IHealth service = mHealthServiceWrapper.getLastService(); - if (service == null) throw new RemoteException("no health service"); - service.update(); - } finally { - traceEnd(); - } + mHealthServiceWrapper.getHandlerThread().getThreadHandler().post(() -> { + traceBegin("HealthScheduleUpdate"); + try { + IHealth service = mHealthServiceWrapper.getLastService(); + if (service == null) { + Slog.e(TAG, "no health service"); + return; + } + service.update(); + } catch (RemoteException ex) { + Slog.e(TAG, "Cannot call update on health HAL", ex); + } finally { + traceEnd(); + } + }); } } @@ -1319,7 +1326,7 @@ public final class BatteryService extends SystemService { Arrays.asList(INSTANCE_VENDOR, INSTANCE_HEALTHD); private final IServiceNotification mNotification = new Notification(); - private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceRefresh"); + private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceHwbinder"); // These variables are fixed after init. private Callback mCallback; private IHealthSupplier mHealthSupplier; diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java index 112cf0853722..0bcd9373c660 100644 --- a/services/core/java/com/android/server/BluetoothService.java +++ b/services/core/java/com/android/server/BluetoothService.java @@ -53,8 +53,11 @@ class BluetoothService extends SystemService { @Override public void onSwitchUser(int userHandle) { - initialize(); - mBluetoothManagerService.handleOnSwitchUser(userHandle); + if (!mInitialized) { + initialize(); + } else { + mBluetoothManagerService.handleOnSwitchUser(userHandle); + } } @Override diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index a30371876955..62930b0ff134 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -1636,27 +1636,32 @@ public class DeviceIdleController extends SystemService } } - public class LocalService { + private class LocalService implements DeviceIdleInternal { + @Override public void onConstraintStateChanged(IDeviceIdleConstraint constraint, boolean active) { synchronized (DeviceIdleController.this) { onConstraintStateChangedLocked(constraint, active); } } + @Override public void registerDeviceIdleConstraint(IDeviceIdleConstraint constraint, String name, @IDeviceIdleConstraint.MinimumState int minState) { registerDeviceIdleConstraintInternal(constraint, name, minState); } + @Override public void unregisterDeviceIdleConstraint(IDeviceIdleConstraint constraint) { unregisterDeviceIdleConstraintInternal(constraint); } + @Override public void exitIdle(String reason) { exitIdleInternal(reason); } // duration in milliseconds + @Override public void addPowerSaveTempWhitelistApp(int callingUid, String packageName, long duration, int userId, boolean sync, String reason) { addPowerSaveTempWhitelistAppInternal(callingUid, packageName, duration, @@ -1664,26 +1669,31 @@ public class DeviceIdleController extends SystemService } // duration in milliseconds + @Override public void addPowerSaveTempWhitelistAppDirect(int uid, long duration, boolean sync, String reason) { addPowerSaveTempWhitelistAppDirectInternal(0, uid, duration, sync, reason); } // duration in milliseconds + @Override public long getNotificationWhitelistDuration() { return mConstants.NOTIFICATION_WHITELIST_DURATION; } + @Override public void setJobsActive(boolean active) { DeviceIdleController.this.setJobsActive(active); } // Up-call from alarm manager. + @Override public void setAlarmsActive(boolean active) { DeviceIdleController.this.setAlarmsActive(active); } /** Is the app on any of the power save whitelists, whether system or user? */ + @Override public boolean isAppOnWhitelist(int appid) { return DeviceIdleController.this.isAppOnWhitelistInternal(appid); } @@ -1694,10 +1704,12 @@ public class DeviceIdleController extends SystemService * can change when the list changes, so it needs to be re-acquired when * {@link PowerManager#ACTION_POWER_SAVE_WHITELIST_CHANGED} is sent. */ + @Override public int[] getPowerSaveWhitelistUserAppIds() { return DeviceIdleController.this.getPowerSaveWhitelistUserAppIds(); } + @Override public int[] getPowerSaveTempWhitelistAppIds() { return DeviceIdleController.this.getAppIdTempWhitelistInternal(); } @@ -1767,7 +1779,8 @@ public class DeviceIdleController extends SystemService return mContext.getSystemService(SensorManager.class); } - ConstraintController getConstraintController(Handler handler, LocalService localService) { + ConstraintController getConstraintController(Handler handler, + DeviceIdleInternal localService) { if (mContext.getPackageManager() .hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY)) { return new TvConstraintController(mContext, handler); @@ -1884,7 +1897,7 @@ public class DeviceIdleController extends SystemService mBinderService = new BinderService(); publishBinderService(Context.DEVICE_IDLE_CONTROLLER, mBinderService); - publishLocalService(LocalService.class, new LocalService()); + publishLocalService(DeviceIdleInternal.class, new LocalService()); } @Override diff --git a/services/core/java/com/android/server/DeviceIdleInternal.java b/services/core/java/com/android/server/DeviceIdleInternal.java new file mode 100644 index 000000000000..127324936e09 --- /dev/null +++ b/services/core/java/com/android/server/DeviceIdleInternal.java @@ -0,0 +1,52 @@ +/* + * 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; + +import com.android.server.deviceidle.IDeviceIdleConstraint; + +public interface DeviceIdleInternal { + void onConstraintStateChanged(IDeviceIdleConstraint constraint, boolean active); + + void registerDeviceIdleConstraint(IDeviceIdleConstraint constraint, String name, + @IDeviceIdleConstraint.MinimumState int minState); + + void unregisterDeviceIdleConstraint(IDeviceIdleConstraint constraint); + + void exitIdle(String reason); + + // duration in milliseconds + void addPowerSaveTempWhitelistApp(int callingUid, String packageName, + long duration, int userId, boolean sync, String reason); + + // duration in milliseconds + void addPowerSaveTempWhitelistAppDirect(int uid, long duration, boolean sync, + String reason); + + // duration in milliseconds + long getNotificationWhitelistDuration(); + + void setJobsActive(boolean active); + + // Up-call from alarm manager. + void setAlarmsActive(boolean active); + + boolean isAppOnWhitelist(int appid); + + int[] getPowerSaveWhitelistUserAppIds(); + + int[] getPowerSaveTempWhitelistAppIds(); +} diff --git a/services/core/java/com/android/server/DisplayThread.java b/services/core/java/com/android/server/DisplayThread.java index 85c799cad321..a07ade050e92 100644 --- a/services/core/java/com/android/server/DisplayThread.java +++ b/services/core/java/com/android/server/DisplayThread.java @@ -20,6 +20,8 @@ import android.os.Handler; import android.os.Process; import android.os.Trace; +import com.android.internal.annotations.VisibleForTesting; + /** * Shared singleton foreground thread for the system. This is a thread for * operations that affect what's on the display, which needs to have a minimum @@ -58,4 +60,20 @@ public final class DisplayThread extends ServiceThread { return sHandler; } } + + /** + * Disposes current display thread if it's initialized. Should only be used in tests to set up a + * new environment. + */ + @VisibleForTesting + public static void dispose() { + synchronized (DisplayThread.class) { + if (sInstance == null) { + return; + } + + getHandler().runWithScissors(() -> sInstance.quit(), 0 /* timeout */); + sInstance = null; + } + } } diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java index e53141229e91..18009e191482 100644 --- a/services/core/java/com/android/server/DynamicSystemService.java +++ b/services/core/java/com/android/server/DynamicSystemService.java @@ -25,6 +25,7 @@ import android.gsi.IGsid; import android.os.Environment; import android.os.IBinder; import android.os.IBinder.DeathRecipient; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; @@ -195,7 +196,20 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements } @Override - public boolean write(byte[] buf) throws RemoteException { - return getGsiService().commitGsiChunkFromMemory(buf); + public boolean setAshmem(ParcelFileDescriptor ashmem, long size) { + try { + return getGsiService().setGsiAshmem(ashmem, size); + } catch (RemoteException e) { + throw new RuntimeException(e.toString()); + } + } + + @Override + public boolean submitFromAshmem(long size) { + try { + return getGsiService().commitGsiChunkFromAshmem(size); + } catch (RemoteException e) { + throw new RuntimeException(e.toString()); + } } } diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/services/core/java/com/android/server/GraphicsStatsService.java index 4639d7586f83..70569db5e2d3 100644 --- a/services/core/java/com/android/server/GraphicsStatsService.java +++ b/services/core/java/com/android/server/GraphicsStatsService.java @@ -191,7 +191,7 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { if (!file.getFileDescriptor().valid()) { throw new IllegalStateException("Invalid file descriptor"); } - return new ParcelFileDescriptor(file.getFileDescriptor()); + return ParcelFileDescriptor.dup(file.getFileDescriptor()); } catch (IOException ex) { throw new IllegalStateException("Failed to get PFD from memory file", ex); } diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index dee89e5d5c4d..ea3dd3d4ba8d 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -25,7 +25,7 @@ import android.annotation.Nullable; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.VersionedPackage; -import android.net.NetworkStackClient; +import android.net.ConnectivityModuleConnector; import android.os.Environment; import android.os.Handler; import android.os.Looper; @@ -116,7 +116,7 @@ public class PackageWatchdog { // File containing the XML data of monitored packages /data/system/package-watchdog.xml private final AtomicFile mPolicyFile; private final ExplicitHealthCheckController mHealthCheckController; - private final NetworkStackClient mNetworkStackClient; + private final ConnectivityModuleConnector mConnectivityModuleConnector; @GuardedBy("mLock") private boolean mIsPackagesReady; // Flag to control whether explicit health checks are supported or not @@ -138,7 +138,7 @@ public class PackageWatchdog { "package-watchdog.xml")), new Handler(Looper.myLooper()), BackgroundThread.getHandler(), new ExplicitHealthCheckController(context), - NetworkStackClient.getInstance()); + ConnectivityModuleConnector.getInstance()); } /** @@ -147,13 +147,13 @@ public class PackageWatchdog { @VisibleForTesting PackageWatchdog(Context context, AtomicFile policyFile, Handler shortTaskHandler, Handler longTaskHandler, ExplicitHealthCheckController controller, - NetworkStackClient networkStackClient) { + ConnectivityModuleConnector connectivityModuleConnector) { mContext = context; mPolicyFile = policyFile; mShortTaskHandler = shortTaskHandler; mLongTaskHandler = longTaskHandler; mHealthCheckController = controller; - mNetworkStackClient = networkStackClient; + mConnectivityModuleConnector = connectivityModuleConnector; loadFromFile(); } @@ -179,7 +179,7 @@ public class PackageWatchdog { () -> syncRequestsAsync()); setPropertyChangedListenerLocked(); updateConfigs(); - registerNetworkStackHealthListener(); + registerConnectivityModuleHealthListener(); } } @@ -743,11 +743,11 @@ public class PackageWatchdog { } } - private void registerNetworkStackHealthListener() { + private void registerConnectivityModuleHealthListener() { // TODO: have an internal method to trigger a rollback by reporting high severity errors, // and rely on ActivityManager to inform the watchdog of severe network stack crashes // instead of having this listener in parallel. - mNetworkStackClient.registerHealthListener( + mConnectivityModuleConnector.registerHealthListener( packageName -> { final VersionedPackage pkg = getVersionedPackage(packageName); if (pkg == null) { diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java index 8e9e74ecedbf..4facf4ea62a2 100644 --- a/services/core/java/com/android/server/SystemService.java +++ b/services/core/java/com/android/server/SystemService.java @@ -18,12 +18,17 @@ package com.android.server; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT; +import android.annotation.NonNull; +import android.annotation.UserIdInt; import android.app.ActivityThread; import android.content.Context; +import android.content.pm.UserInfo; import android.os.IBinder; import android.os.ServiceManager; import android.os.UserManager; +import com.android.server.pm.UserManagerService; + /** * The base class for services running in the system process. Override and implement * the lifecycle event callback methods as needed. @@ -145,11 +150,29 @@ public abstract class SystemService { public void onBootPhase(int phase) {} /** + * @deprecated subclasses should extend {@link #onStartUser(int, int)} instead (which by default + * calls this method). + */ + @Deprecated + public void onStartUser(@UserIdInt int userHandle) {} + + /** * Called when a new user is starting, for system services to initialize any per-user * state they maintain for running users. - * @param userHandle The identifier of the user. + * + * @param userInfo The information about the user. <b>NOTE: </b> this is a "live" object + * referenced by {@link UserManagerService} and hence should not be modified. + */ + public void onStartUser(@NonNull UserInfo userInfo) { + onStartUser(userInfo.id); + } + + /** + * @deprecated subclasses should extend {@link #onUnlockUser(int, int)} instead (which by + * default calls this method). */ - public void onStartUser(int userHandle) {} + @Deprecated + public void onUnlockUser(@UserIdInt int userHandle) {} /** * Called when an existing user is in the process of being unlocked. This @@ -163,17 +186,38 @@ public abstract class SystemService { * {@link UserManager#isUserUnlockingOrUnlocked(int)} to handle both of * these states. * - * @param userHandle The identifier of the user. + * @param userInfo The information about the user. <b>NOTE: </b> this is a "live" object + * referenced by {@link UserManagerService} and hence should not be modified. */ - public void onUnlockUser(int userHandle) {} + public void onUnlockUser(@NonNull UserInfo userInfo) { + onUnlockUser(userInfo.id); + } + + /** + * @deprecated subclasses should extend {@link #onSwitchUser(int, int)} instead (which by + * default calls this method). + */ + @Deprecated + public void onSwitchUser(@UserIdInt int userHandle) {} /** * Called when switching to a different foreground user, for system services that have * special behavior for whichever user is currently in the foreground. This is called * before any application processes are aware of the new user. - * @param userHandle The identifier of the user. + * + * @param userInfo The information about the user. <b>NOTE: </b> this is a "live" object + * referenced by {@link UserManagerService} and hence should not be modified. + */ + public void onSwitchUser(@NonNull UserInfo userInfo) { + onSwitchUser(userInfo.id); + } + + /** + * @deprecated subclasses should extend {@link #onStopUser(int, int)} instead (which by default + * calls this method). */ - public void onSwitchUser(int userHandle) {} + @Deprecated + public void onStopUser(@UserIdInt int userHandle) {} /** * Called when an existing user is stopping, for system services to finalize any per-user @@ -183,9 +227,19 @@ public abstract class SystemService { * * <p>NOTE: This is the last callback where the callee may access the target user's CE storage. * - * @param userHandle The identifier of the user. + * @param userInfo The information about the user. <b>NOTE: </b> this is a "live" object + * referenced by {@link UserManagerService} and hence should not be modified. */ - public void onStopUser(int userHandle) {} + public void onStopUser(@NonNull UserInfo userInfo) { + onStopUser(userInfo.id); + } + + /** + * @deprecated subclasses should extend {@link #onCleanupUser(int, int)} instead (which by + * default calls this method). + */ + @Deprecated + public void onCleanupUser(@UserIdInt int userHandle) {} /** * Called when an existing user is stopping, for system services to finalize any per-user @@ -193,11 +247,14 @@ public abstract class SystemService { * teardown of the user is complete. * * <p>NOTE: When this callback is called, the CE storage for the target user may not be - * accessible already. Use {@link #onStopUser} instead if you need to access the CE storage. + * accessible already. Use {@link #onCleanupUser} instead if you need to access the CE storage. * - * @param userHandle The identifier of the user. + * @param userInfo The information about the user. <b>NOTE: </b> this is a "live" object + * referenced by {@link UserManagerService} and hence should not be modified. */ - public void onCleanupUser(int userHandle) {} + public void onCleanupUser(@NonNull UserInfo userInfo) { + onCleanupUser(userInfo.id); + } /** * Publish the service so it is accessible to other services and apps. diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java index 9711152ec5b1..b085946899bd 100644 --- a/services/core/java/com/android/server/SystemServiceManager.java +++ b/services/core/java/com/android/server/SystemServiceManager.java @@ -19,9 +19,11 @@ package com.android.server; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.Context; +import android.content.pm.UserInfo; import android.os.Environment; import android.os.SystemClock; import android.os.Trace; +import android.os.UserManagerInternal; import android.util.Slog; import com.android.server.utils.TimingsTraceAndSlog; @@ -53,6 +55,8 @@ public class SystemServiceManager { private int mCurrentPhase = -1; + private UserManagerInternal mUserManagerInternal; + SystemServiceManager(Context context) { mContext = context; } @@ -187,127 +191,88 @@ public class SystemServiceManager { } /** - * Starts the given user. + * Called at the beginning of {@code ActivityManagerService.systemReady()}. */ - public void startUser(@NonNull TimingsTraceAndSlog t, final @UserIdInt int userHandle) { - t.traceBegin("ssm.startUser-" + userHandle); - Slog.i(TAG, "Calling onStartUser u" + userHandle); - final int serviceLen = mServices.size(); - for (int i = 0; i < serviceLen; i++) { - final SystemService service = mServices.get(i); - final String serviceName = service.getClass().getName(); - t.traceBegin("onStartUser-" + userHandle + " " + serviceName); - long time = SystemClock.elapsedRealtime(); - try { - service.onStartUser(userHandle); - } catch (Exception ex) { - Slog.wtf(TAG, "Failure reporting start of user " + userHandle - + " to service " + service.getClass().getName(), ex); - } - warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStartUser "); - t.traceEnd(); + public void preSystemReady() { + mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); + } + + private @NonNull UserInfo getUserInfo(@UserIdInt int userHandle) { + if (mUserManagerInternal == null) { + throw new IllegalStateException("mUserManagerInternal not set yet"); + } + final UserInfo userInfo = mUserManagerInternal.getUserInfo(userHandle); + if (userInfo == null) { + throw new IllegalStateException("No UserInfo for " + userHandle); } - t.traceEnd(); + return userInfo; + } + + /** + * Starts the given user. + */ + public void startUser(final @NonNull TimingsTraceAndSlog t, final @UserIdInt int userHandle) { + onUser(t, "Start", userHandle, (s, u) -> s.onStartUser(u)); } /** * Unlocks the given user. */ public void unlockUser(final @UserIdInt int userHandle) { - final TimingsTraceAndSlog t = TimingsTraceAndSlog.newAsyncLog(); - t.traceBegin("ssm.unlockUser-" + userHandle); - Slog.i(TAG, "Calling onUnlockUser u" + userHandle); - final int serviceLen = mServices.size(); - for (int i = 0; i < serviceLen; i++) { - final SystemService service = mServices.get(i); - final String serviceName = service.getClass().getName(); - t.traceBegin("onUnlockUser-" + userHandle + " " + serviceName); - long time = SystemClock.elapsedRealtime(); - try { - service.onUnlockUser(userHandle); - } catch (Exception ex) { - Slog.wtf(TAG, "Failure reporting unlock of user " + userHandle - + " to service " + serviceName, ex); - } - warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onUnlockUser "); - t.traceEnd(); - } - t.traceEnd(); + onUser("Unlock", userHandle, (s, u) -> s.onUnlockUser(u)); } /** * Switches to the given user. */ public void switchUser(final @UserIdInt int userHandle) { - final TimingsTraceAndSlog t = TimingsTraceAndSlog.newAsyncLog(); - t.traceBegin("ssm.switchUser-" + userHandle); - Slog.i(TAG, "Calling switchUser u" + userHandle); - final int serviceLen = mServices.size(); - for (int i = 0; i < serviceLen; i++) { - final SystemService service = mServices.get(i); - final String serviceName = service.getClass().getName(); - t.traceBegin("onSwitchUser-" + userHandle + " " + serviceName); - long time = SystemClock.elapsedRealtime(); - try { - service.onSwitchUser(userHandle); - } catch (Exception ex) { - Slog.wtf(TAG, "Failure reporting switch of user " + userHandle - + " to service " + serviceName, ex); - } - warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onSwitchUser"); - t.traceEnd(); - } - t.traceEnd(); + onUser("Switch", userHandle, (s, u) -> s.onSwitchUser(u)); } /** * Stops the given user. */ public void stopUser(final @UserIdInt int userHandle) { - final TimingsTraceAndSlog t = TimingsTraceAndSlog.newAsyncLog(); - t.traceBegin("ssm.stopUser-" + userHandle); - Slog.i(TAG, "Calling onStopUser u" + userHandle); - final int serviceLen = mServices.size(); - for (int i = 0; i < serviceLen; i++) { - final SystemService service = mServices.get(i); - final String serviceName = service.getClass().getName(); - t.traceBegin("onStopUser-" + userHandle + " " + serviceName); - long time = SystemClock.elapsedRealtime(); - try { - service.onStopUser(userHandle); - } catch (Exception ex) { - Slog.wtf(TAG, "Failure reporting stop of user " + userHandle - + " to service " + serviceName, ex); - } - warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStopUser"); - t.traceEnd(); - } - t.traceEnd(); + onUser("Stop", userHandle, (s, u) -> s.onStopUser(u)); } /** * Cleans up the given user. */ public void cleanupUser(final @UserIdInt int userHandle) { - final TimingsTraceAndSlog t = TimingsTraceAndSlog.newAsyncLog(); - t.traceBegin("ssm.cleanupUser-" + userHandle); - Slog.i(TAG, "Calling onCleanupUser u" + userHandle); + onUser("Cleanup", userHandle, (s, u) -> s.onCleanupUser(u)); + } + + private interface ServiceVisitor { + void visit(@NonNull SystemService service, @NonNull UserInfo userInfo); + } + + private void onUser(@NonNull String onWhat, @UserIdInt int userHandle, + @NonNull ServiceVisitor visitor) { + onUser(TimingsTraceAndSlog.newAsyncLog(), onWhat, userHandle, visitor); + } + + private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat, + @UserIdInt int userHandle, @NonNull ServiceVisitor visitor) { + t.traceBegin("ssm." + onWhat + "User-" + userHandle); + Slog.i(TAG, "Calling on" + onWhat + "User u" + userHandle); + final UserInfo userInfo = getUserInfo(userHandle); final int serviceLen = mServices.size(); for (int i = 0; i < serviceLen; i++) { final SystemService service = mServices.get(i); final String serviceName = service.getClass().getName(); - t.traceBegin("onCleanupUser-" + userHandle + " " + serviceName); + t.traceBegin("ssm.on" + onWhat + "User-" + userHandle + " " + serviceName); long time = SystemClock.elapsedRealtime(); try { - service.onCleanupUser(userHandle); + visitor.visit(service, userInfo); } catch (Exception ex) { - Slog.wtf(TAG, "Failure reporting cleanup of user " + userHandle + Slog.wtf(TAG, "Failure reporting " + onWhat + " of user " + userHandle + " to service " + serviceName, ex); } - warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onCleanupUser"); - t.traceEnd(); + warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "on" + onWhat + "User "); + t.traceEnd(); // what on service } - t.traceEnd(); + t.traceEnd(); // main entry } /** Sets the safe mode flag for services to query. */ diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index e66e596d5038..f7e825eecc12 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -1027,7 +1027,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log(str); } mLocalLog.log(str); - if (validatePhoneId(phoneId)) { + // 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)) { mServiceState[phoneId] = state; for (Record r : mRecords) { @@ -1059,7 +1064,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } } else { - log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId); + log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId + + " or subId=" + subId); } handleRemoveListLocked(); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 7b20e5599bad..7ef6032365d2 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -282,6 +282,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.DebugUtils; import android.util.EventLog; +import android.util.FeatureFlagUtils; import android.util.Log; import android.util.Pair; import android.util.PrintWriterPrinter; @@ -330,7 +331,7 @@ import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.TriFunction; import com.android.server.AlarmManagerInternal; import com.android.server.AttributeCache; -import com.android.server.DeviceIdleController; +import com.android.server.DeviceIdleInternal; import com.android.server.DisplayThread; import com.android.server.IntentResolver; import com.android.server.IoThread; @@ -378,7 +379,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; -import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; @@ -437,6 +438,10 @@ public class ActivityManagerService extends IActivityManager.Stub // need not be the case. public static final String ACTION_TRIGGER_IDLE = "com.android.server.ACTION_TRIGGER_IDLE"; + private static final String INTENT_BUGREPORT_REQUESTED = + "com.android.internal.intent.action.BUGREPORT_REQUESTED"; + private static final String SHELL_APP_PACKAGE = "com.android.shell"; + /** Control over CPU and battery monitoring */ // write battery stats every 30 minutes. static final long BATTERY_STATS_TIME = 30 * 60 * 1000; @@ -555,6 +560,10 @@ public class ActivityManagerService extends IActivityManager.Stub OomAdjuster mOomAdjuster; final LowMemDetector mLowMemDetector; + static final String EXTRA_TITLE = "android.intent.extra.TITLE"; + static final String EXTRA_DESCRIPTION = "android.intent.extra.DESCRIPTION"; + static final String EXTRA_BUGREPORT_TYPE = "android.intent.extra.BUGREPORT_TYPE"; + /** All system services */ SystemServiceManager mSystemServiceManager; @@ -1135,7 +1144,7 @@ public class ActivityManagerService extends IActivityManager.Stub /** * Access to DeviceIdleController service. */ - DeviceIdleController.LocalService mLocalDeviceIdleController; + DeviceIdleInternal mLocalDeviceIdleController; /** * Power-save whitelisted app-ids (not including except-idle-whitelisted ones). @@ -1480,8 +1489,9 @@ public class ActivityManagerService extends IActivityManager.Stub public ActivityTaskManagerService mActivityTaskManager; @VisibleForTesting public ActivityTaskManagerInternal mAtmInternal; + UriGrantsManagerInternal mUgmInternal; @VisibleForTesting - public UriGrantsManagerInternal mUgmInternal; + public final ActivityManagerInternal mInternal; final ActivityThread mSystemThread; private final class AppDeathRecipient implements IBinder.DeathRecipient { @@ -2413,6 +2423,8 @@ public class ActivityManagerService extends IActivityManager.Stub mProcStartHandler = null; mHiddenApiBlacklist = null; mFactoryTest = FACTORY_TEST_OFF; + mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class); + mInternal = new LocalService(); } // Note: This method is invoked on the main thread but may need to attach various @@ -2566,6 +2578,7 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.w(TAG, "Setting background thread cpuset failed"); } + mInternal = new LocalService(); } public void setSystemServiceManager(SystemServiceManager mgr) { @@ -2583,7 +2596,7 @@ public class ActivityManagerService extends IActivityManager.Stub mBatteryStatsService.publish(); mAppOpsService.publish(mContext); Slog.d("AppOps", "AppOpsService published"); - LocalServices.addService(ActivityManagerInternal.class, new LocalService()); + LocalServices.addService(ActivityManagerInternal.class, mInternal); mActivityTaskManager.onActivityManagerInternalAdded(); mUgmInternal.onActivityManagerInternalAdded(); mPendingIntentController.onActivityManagerInternalAdded(); @@ -8197,6 +8210,53 @@ public class ActivityManagerService extends IActivityManager.Stub @Deprecated @Override public void requestBugReport(int bugreportType) { + requestBugReportWithDescription(null, null, bugreportType); + } + + /** + * @deprecated This method is only used by a few internal components and it will soon be + * replaced by a proper bug report API (which will be restricted to a few, pre-defined apps). + * No new code should be calling it. + */ + @Deprecated + public void requestBugReportWithDescription(@Nullable String shareTitle, + @Nullable String shareDescription, int bugreportType) { + if (!TextUtils.isEmpty(shareTitle)) { + if (shareTitle.length() > MAX_BUGREPORT_TITLE_SIZE) { + String errorStr = "shareTitle should be less than " + + MAX_BUGREPORT_TITLE_SIZE + " characters"; + throw new IllegalArgumentException(errorStr); + } + if (!TextUtils.isEmpty(shareDescription)) { + int length = shareDescription.getBytes(StandardCharsets.UTF_8).length; + if (length > SystemProperties.PROP_VALUE_MAX) { + String errorStr = "shareTitle should be less than " + + SystemProperties.PROP_VALUE_MAX + " bytes"; + throw new IllegalArgumentException(errorStr); + } else { + SystemProperties.set("dumpstate.options.description", shareDescription); + } + } + SystemProperties.set("dumpstate.options.title", shareTitle); + Slog.d(TAG, "Bugreport notification title " + shareTitle + + " description " + shareDescription); + } + final boolean useApi = FeatureFlagUtils.isEnabled(mContext, + FeatureFlagUtils.USE_BUGREPORT_API); + + if (useApi) { + // Create intent to trigger Bugreport API via Shell + Intent triggerShellBugreport = new Intent(); + triggerShellBugreport.setAction(INTENT_BUGREPORT_REQUESTED); + triggerShellBugreport.setPackage(SHELL_APP_PACKAGE); + triggerShellBugreport.putExtra(EXTRA_BUGREPORT_TYPE, bugreportType); + if (shareTitle != null) { + triggerShellBugreport.putExtra(EXTRA_TITLE, shareTitle); + } + if (shareDescription != null) { + triggerShellBugreport.putExtra(EXTRA_DESCRIPTION, shareDescription); + } + } String extraOptions = null; switch (bugreportType) { case ActivityManager.BUGREPORT_OPTION_FULL: @@ -8238,45 +8298,6 @@ public class ActivityManagerService extends IActivityManager.Stub * No new code should be calling it. */ @Deprecated - private void requestBugReportWithDescription(String shareTitle, String shareDescription, - int bugreportType) { - if (!TextUtils.isEmpty(shareTitle)) { - if (shareTitle.length() > MAX_BUGREPORT_TITLE_SIZE) { - String errorStr = "shareTitle should be less than " + - MAX_BUGREPORT_TITLE_SIZE + " characters"; - throw new IllegalArgumentException(errorStr); - } else { - if (!TextUtils.isEmpty(shareDescription)) { - int length; - try { - length = shareDescription.getBytes("UTF-8").length; - } catch (UnsupportedEncodingException e) { - String errorStr = "shareDescription: UnsupportedEncodingException"; - throw new IllegalArgumentException(errorStr); - } - if (length > SystemProperties.PROP_VALUE_MAX) { - String errorStr = "shareTitle should be less than " + - SystemProperties.PROP_VALUE_MAX + " bytes"; - throw new IllegalArgumentException(errorStr); - } else { - SystemProperties.set("dumpstate.options.description", shareDescription); - } - } - SystemProperties.set("dumpstate.options.title", shareTitle); - } - } - - Slog.d(TAG, "Bugreport notification title " + shareTitle - + " description " + shareDescription); - requestBugReport(bugreportType); - } - - /** - * @deprecated This method is only used by a few internal components and it will soon be - * replaced by a proper bug report API (which will be restricted to a few, pre-defined apps). - * No new code should be calling it. - */ - @Deprecated @Override public void requestTelephonyBugReport(String shareTitle, String shareDescription) { requestBugReportWithDescription(shareTitle, shareDescription, @@ -8990,6 +9011,7 @@ public class ActivityManagerService extends IActivityManager.Stub */ public void systemReady(final Runnable goingCallback, @NonNull TimingsTraceAndSlog t) { t.traceBegin("PhaseActivityManagerReady"); + mSystemServiceManager.preSystemReady(); synchronized(this) { if (mSystemReady) { // If we're done calling all the receivers, run the next "boot phase" passed in @@ -9002,8 +9024,8 @@ public class ActivityManagerService extends IActivityManager.Stub } t.traceBegin("controllersReady"); - mLocalDeviceIdleController - = LocalServices.getService(DeviceIdleController.LocalService.class); + mLocalDeviceIdleController = + LocalServices.getService(DeviceIdleInternal.class); mActivityTaskManager.onSystemReady(); // Make sure we have the current profile info, since it is needed for security checks. mUserController.onSystemReady(); @@ -9139,8 +9161,12 @@ public class ActivityManagerService extends IActivityManager.Stub mAtmInternal.showSystemReadyErrorDialogsIfNeeded(); t.traceEnd(); - boolean isSystemUser = currentUserId == UserHandle.USER_SYSTEM; - if (isSystemUser) { + // Some systems - like automotive - will explicitly unlock system user then switch + // to a secondary user. Hence, we don't want to send duplicate broadcasts for the + // system user here. + boolean sendSystemUserBroadcasts = currentUserId == UserHandle.USER_SYSTEM; + + if (sendSystemUserBroadcasts) { t.traceBegin("sendUserStartBroadcast"); final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); @@ -9181,7 +9207,7 @@ public class ActivityManagerService extends IActivityManager.Stub mAtmInternal.resumeTopActivities(false /* scheduleIdle */); t.traceEnd(); - if (isSystemUser) { + if (sendSystemUserBroadcasts) { t.traceBegin("sendUserSwitchBroadcasts"); mUserController.sendUserSwitchBroadcasts(-1, currentUserId); t.traceEnd(); @@ -12109,39 +12135,44 @@ public class ActivityManagerService extends IActivityManager.Stub final String shortLabel; final long pss; final long swapPss; + final long mRss; final int id; final boolean hasActivities; ArrayList<MemItem> subitems; - public MemItem(String _label, String _shortLabel, long _pss, long _swapPss, int _id, - boolean _hasActivities) { - isProc = true; - label = _label; - shortLabel = _shortLabel; - pss = _pss; - swapPss = _swapPss; - id = _id; - hasActivities = _hasActivities; + MemItem(String label, String shortLabel, long pss, long swapPss, long rss, int id, + boolean hasActivities) { + this.isProc = true; + this.label = label; + this.shortLabel = shortLabel; + this.pss = pss; + this.swapPss = swapPss; + this.mRss = rss; + this.id = id; + this.hasActivities = hasActivities; } - public MemItem(String _label, String _shortLabel, long _pss, long _swapPss, int _id) { - isProc = false; - label = _label; - shortLabel = _shortLabel; - pss = _pss; - swapPss = _swapPss; - id = _id; - hasActivities = false; + MemItem(String label, String shortLabel, long pss, long swapPss, long rss, int id) { + this.isProc = false; + this.label = label; + this.shortLabel = shortLabel; + this.pss = pss; + this.swapPss = swapPss; + this.mRss = rss; + this.id = id; + this.hasActivities = false; } } - private static void sortMemItems(List<MemItem> items) { + private static void sortMemItems(List<MemItem> items, final boolean pss) { Collections.sort(items, new Comparator<MemItem>() { @Override public int compare(MemItem lhs, MemItem rhs) { - if (lhs.pss < rhs.pss) { + long lss = pss ? lhs.pss : lhs.mRss; + long rss = pss ? rhs.pss : rhs.mRss; + if (lss < rss) { return 1; - } else if (lhs.pss > rhs.pss) { + } else if (lss > rss) { return -1; } return 0; @@ -12150,40 +12181,44 @@ public class ActivityManagerService extends IActivityManager.Stub } static final void dumpMemItems(PrintWriter pw, String prefix, String tag, - ArrayList<MemItem> items, boolean sort, boolean isCompact, boolean dumpSwapPss) { + ArrayList<MemItem> items, boolean sort, boolean isCompact, boolean dumpPss, + boolean dumpSwapPss) { if (sort && !isCompact) { - sortMemItems(items); + sortMemItems(items, dumpPss); } for (int i=0; i<items.size(); i++) { MemItem mi = items.get(i); if (!isCompact) { - if (dumpSwapPss) { + if (dumpPss && dumpSwapPss) { pw.printf("%s%s: %-60s (%s in swap)\n", prefix, stringifyKBSize(mi.pss), mi.label, stringifyKBSize(mi.swapPss)); } else { - pw.printf("%s%s: %s\n", prefix, stringifyKBSize(mi.pss), mi.label); + pw.printf("%s%s: %s\n", prefix, stringifyKBSize(dumpPss ? mi.pss : mi.mRss), + mi.label); } } else if (mi.isProc) { pw.print("proc,"); pw.print(tag); pw.print(","); pw.print(mi.shortLabel); - pw.print(","); pw.print(mi.id); pw.print(","); pw.print(mi.pss); pw.print(","); + pw.print(","); pw.print(mi.id); pw.print(","); + pw.print(dumpPss ? mi.pss : mi.mRss); pw.print(","); pw.print(dumpSwapPss ? mi.swapPss : "N/A"); pw.println(mi.hasActivities ? ",a" : ",e"); } else { pw.print(tag); pw.print(","); pw.print(mi.shortLabel); pw.print(","); - pw.print(mi.pss); pw.print(","); pw.println(dumpSwapPss ? mi.swapPss : "N/A"); + pw.print(dumpPss ? mi.pss : mi.mRss); pw.print(","); + pw.println(dumpSwapPss ? mi.swapPss : "N/A"); } if (mi.subitems != null) { dumpMemItems(pw, prefix + " ", mi.shortLabel, mi.subitems, - true, isCompact, dumpSwapPss); + true, isCompact, dumpPss, dumpSwapPss); } } } static final void dumpMemItems(ProtoOutputStream proto, long fieldId, String tag, - ArrayList<MemItem> items, boolean sort, boolean dumpSwapPss) { + ArrayList<MemItem> items, boolean sort, boolean dumpPss, boolean dumpSwapPss) { if (sort) { - sortMemItems(items); + sortMemItems(items, dumpPss); } for (int i=0; i<items.size(); i++) { @@ -12195,13 +12230,17 @@ public class ActivityManagerService extends IActivityManager.Stub proto.write(MemInfoDumpProto.MemItem.IS_PROC, mi.isProc); proto.write(MemInfoDumpProto.MemItem.ID, mi.id); proto.write(MemInfoDumpProto.MemItem.HAS_ACTIVITIES, mi.hasActivities); - proto.write(MemInfoDumpProto.MemItem.PSS_KB, mi.pss); + if (dumpPss) { + proto.write(MemInfoDumpProto.MemItem.PSS_KB, mi.pss); + } else { + proto.write(MemInfoDumpProto.MemItem.RSS_KB, mi.mRss); + } if (dumpSwapPss) { proto.write(MemInfoDumpProto.MemItem.SWAP_PSS_KB, mi.swapPss); } if (mi.subitems != null) { dumpMemItems(proto, MemInfoDumpProto.MemItem.SUB_ITEMS, mi.shortLabel, mi.subitems, - true, dumpSwapPss); + true, dumpPss, dumpSwapPss); } proto.end(token); } @@ -12493,6 +12532,13 @@ public class ActivityManagerService extends IActivityManager.Stub if (!brief && !opts.oomOnly && (procs.size() == 1 || opts.isCheckinRequest || opts.packages)) { opts.dumpDetails = true; } + final int numProcs = procs.size(); + final boolean collectNative = !opts.isCheckinRequest && numProcs > 1 && !opts.packages; + if (collectNative) { + // If we are showing aggregations, also look for native processes to + // include so that our aggregations are more accurate. + updateCpuStatsNow(); + } dumpApplicationMemoryUsageHeader(pw, uptime, realtime, opts.isCheckinRequest, opts.isCompact); @@ -12500,30 +12546,38 @@ public class ActivityManagerService extends IActivityManager.Stub final SparseArray<MemItem> procMemsMap = new SparseArray<MemItem>(); long nativePss = 0; long nativeSwapPss = 0; + long nativeRss = 0; long dalvikPss = 0; long dalvikSwapPss = 0; + long dalvikRss = 0; long[] dalvikSubitemPss = opts.dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] : EmptyArray.LONG; long[] dalvikSubitemSwapPss = opts.dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] : EmptyArray.LONG; + long[] dalvikSubitemRss = opts.dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] : + EmptyArray.LONG; long otherPss = 0; long otherSwapPss = 0; + long otherRss = 0; long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS]; long[] miscSwapPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS]; + long[] miscRss = new long[Debug.MemoryInfo.NUM_OTHER_STATS]; long oomPss[] = new long[DUMP_MEM_OOM_LABEL.length]; long oomSwapPss[] = new long[DUMP_MEM_OOM_LABEL.length]; + long[] oomRss = new long[DUMP_MEM_OOM_LABEL.length]; ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[]) new ArrayList[DUMP_MEM_OOM_LABEL.length]; long totalPss = 0; long totalSwapPss = 0; + long totalRss = 0; long cachedPss = 0; long cachedSwapPss = 0; boolean hasSwapPss = false; Debug.MemoryInfo mi = null; - for (int i = procs.size() - 1 ; i >= 0 ; i--) { + for (int i = numProcs - 1; i >= 0; i--) { final ProcessRecord r = procs.get(i); final IApplicationThread thread; final int pid; @@ -12557,6 +12611,7 @@ public class ActivityManagerService extends IActivityManager.Stub mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null); endTime = SystemClock.currentThreadTimeMillis(); mi.dalvikPrivateDirty = (int)tmpLong[0]; + mi.dalvikRss = (int) tmpLong[2]; } if (opts.dumpDetails) { if (opts.localOnly) { @@ -12617,22 +12672,27 @@ public class ActivityManagerService extends IActivityManager.Stub if (!opts.isCheckinRequest && mi != null) { totalPss += myTotalPss; totalSwapPss += myTotalSwapPss; + totalRss += myTotalRss; MemItem pssItem = new MemItem(r.processName + " (pid " + pid + (hasActivities ? " / activities)" : ")"), r.processName, myTotalPss, - myTotalSwapPss, pid, hasActivities); + myTotalSwapPss, myTotalRss, pid, hasActivities); procMems.add(pssItem); procMemsMap.put(pid, pssItem); nativePss += mi.nativePss; nativeSwapPss += mi.nativeSwappedOutPss; + nativeRss += mi.nativeRss; dalvikPss += mi.dalvikPss; dalvikSwapPss += mi.dalvikSwappedOutPss; + dalvikRss += mi.dalvikRss; for (int j=0; j<dalvikSubitemPss.length; j++) { dalvikSubitemPss[j] += mi.getOtherPss(Debug.MemoryInfo.NUM_OTHER_STATS + j); dalvikSubitemSwapPss[j] += mi.getOtherSwappedOutPss(Debug.MemoryInfo.NUM_OTHER_STATS + j); + dalvikSubitemRss[j] += mi.getOtherRss(Debug.MemoryInfo.NUM_OTHER_STATS + j); } otherPss += mi.otherPss; + otherRss += mi.otherRss; otherSwapPss += mi.otherSwappedOutPss; for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) { long mem = mi.getOtherPss(j); @@ -12641,6 +12701,9 @@ public class ActivityManagerService extends IActivityManager.Stub mem = mi.getOtherSwappedOutPss(j); miscSwapPss[j] += mem; otherSwapPss -= mem; + mem = mi.getOtherRss(j); + miscRss[j] += mem; + otherRss -= mem; } if (oomAdj >= ProcessList.CACHED_APP_MIN_ADJ) { @@ -12658,6 +12721,7 @@ public class ActivityManagerService extends IActivityManager.Stub oomProcs[oomIndex] = new ArrayList<MemItem>(); } oomProcs[oomIndex].add(pssItem); + oomRss[oomIndex] += myTotalRss; break; } } @@ -12667,10 +12731,7 @@ public class ActivityManagerService extends IActivityManager.Stub long nativeProcTotalPss = 0; - if (!opts.isCheckinRequest && procs.size() > 1 && !opts.packages) { - // If we are showing aggregations, also look for native processes to - // include so that our aggregations are more accurate. - updateCpuStatsNow(); + if (collectNative) { mi = null; synchronized (mProcessCpuTracker) { final int N = mProcessCpuTracker.countStats(); @@ -12689,25 +12750,33 @@ public class ActivityManagerService extends IActivityManager.Stub final long myTotalPss = mi.getTotalPss(); final long myTotalSwapPss = mi.getTotalSwappedOutPss(); + final long myTotalRss = mi.getTotalRss(); totalPss += myTotalPss; totalSwapPss += myTotalSwapPss; + totalRss += myTotalRss; nativeProcTotalPss += myTotalPss; MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")", - st.name, myTotalPss, mi.getSummaryTotalSwapPss(), st.pid, false); + st.name, myTotalPss, mi.getSummaryTotalSwapPss(), myTotalRss, + st.pid, false); procMems.add(pssItem); nativePss += mi.nativePss; nativeSwapPss += mi.nativeSwappedOutPss; + nativeRss += mi.nativeRss; dalvikPss += mi.dalvikPss; dalvikSwapPss += mi.dalvikSwappedOutPss; + dalvikRss += mi.dalvikRss; for (int j=0; j<dalvikSubitemPss.length; j++) { dalvikSubitemPss[j] += mi.getOtherPss(Debug.MemoryInfo.NUM_OTHER_STATS + j); dalvikSubitemSwapPss[j] += mi.getOtherSwappedOutPss(Debug.MemoryInfo.NUM_OTHER_STATS + j); + dalvikSubitemRss[j] += mi.getOtherRss(Debug.MemoryInfo.NUM_OTHER_STATS + + j); } otherPss += mi.otherPss; otherSwapPss += mi.otherSwappedOutPss; + otherRss += mi.otherRss; for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) { long mem = mi.getOtherPss(j); miscPss[j] += mem; @@ -12715,6 +12784,9 @@ public class ActivityManagerService extends IActivityManager.Stub mem = mi.getOtherSwappedOutPss(j); miscSwapPss[j] += mem; otherSwapPss -= mem; + mem = mi.getOtherRss(j); + miscRss[j] += mem; + otherRss -= mem; } oomPss[0] += myTotalPss; oomSwapPss[0] += myTotalSwapPss; @@ -12722,19 +12794,21 @@ public class ActivityManagerService extends IActivityManager.Stub oomProcs[0] = new ArrayList<MemItem>(); } oomProcs[0].add(pssItem); + oomRss[0] += myTotalRss; } } } ArrayList<MemItem> catMems = new ArrayList<MemItem>(); - catMems.add(new MemItem("Native", "Native", nativePss, nativeSwapPss, -1)); + catMems.add(new MemItem("Native", "Native", nativePss, nativeSwapPss, nativeRss, -1)); final int dalvikId = -2; - catMems.add(new MemItem("Dalvik", "Dalvik", dalvikPss, dalvikSwapPss, dalvikId)); - catMems.add(new MemItem("Unknown", "Unknown", otherPss, otherSwapPss, -3)); + catMems.add(new MemItem("Dalvik", "Dalvik", dalvikPss, dalvikSwapPss, dalvikRss, + dalvikId)); + catMems.add(new MemItem("Unknown", "Unknown", otherPss, otherSwapPss, otherRss, -3)); for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) { String label = Debug.MemoryInfo.getOtherLabel(j); - catMems.add(new MemItem(label, label, miscPss[j], miscSwapPss[j], j)); + catMems.add(new MemItem(label, label, miscPss[j], miscSwapPss[j], miscRss[j], j)); } if (dalvikSubitemPss.length > 0) { // Add dalvik subitems. @@ -12760,7 +12834,7 @@ public class ActivityManagerService extends IActivityManager.Stub final String name = Debug.MemoryInfo.getOtherLabel( Debug.MemoryInfo.NUM_OTHER_STATS + j); memItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j], - dalvikSubitemSwapPss[j], j)); + dalvikSubitemSwapPss[j], dalvikSubitemRss[j], j)); } } } @@ -12770,31 +12844,53 @@ public class ActivityManagerService extends IActivityManager.Stub if (oomPss[j] != 0) { String label = opts.isCompact ? DUMP_MEM_OOM_COMPACT_LABEL[j] : DUMP_MEM_OOM_LABEL[j]; - MemItem item = new MemItem(label, label, oomPss[j], oomSwapPss[j], + MemItem item = new MemItem(label, label, oomPss[j], oomSwapPss[j], oomRss[j], DUMP_MEM_OOM_ADJ[j]); item.subitems = oomProcs[j]; oomMems.add(item); } } - + if (!opts.isCompact) { + pw.println(); + } + if (!brief && !opts.oomOnly && !opts.isCompact) { + pw.println(); + pw.println("Total RSS by process:"); + dumpMemItems(pw, " ", "proc", procMems, true, opts.isCompact, false, false); + pw.println(); + } + if (!opts.isCompact) { + pw.println("Total RSS by OOM adjustment:"); + } + dumpMemItems(pw, " ", "oom", oomMems, false, opts.isCompact, false, false); + if (!brief && !opts.oomOnly) { + PrintWriter out = categoryPw != null ? categoryPw : pw; + if (!opts.isCompact) { + out.println(); + out.println("Total RSS by category:"); + } + dumpMemItems(out, " ", "cat", catMems, true, opts.isCompact, false, false); + } opts.dumpSwapPss = opts.dumpSwapPss && hasSwapPss && totalSwapPss != 0; if (!brief && !opts.oomOnly && !opts.isCompact) { pw.println(); pw.println("Total PSS by process:"); - dumpMemItems(pw, " ", "proc", procMems, true, opts.isCompact, opts.dumpSwapPss); + dumpMemItems(pw, " ", "proc", procMems, true, opts.isCompact, true, + opts.dumpSwapPss); pw.println(); } if (!opts.isCompact) { pw.println("Total PSS by OOM adjustment:"); } - dumpMemItems(pw, " ", "oom", oomMems, false, opts.isCompact, opts.dumpSwapPss); + dumpMemItems(pw, " ", "oom", oomMems, false, opts.isCompact, true, opts.dumpSwapPss); if (!brief && !opts.oomOnly) { PrintWriter out = categoryPw != null ? categoryPw : pw; if (!opts.isCompact) { out.println(); out.println("Total PSS by category:"); } - dumpMemItems(out, " ", "cat", catMems, true, opts.isCompact, opts.dumpSwapPss); + dumpMemItems(out, " ", "cat", catMems, true, opts.isCompact, true, + opts.dumpSwapPss); } if (!opts.isCompact) { pw.println(); @@ -13003,6 +13099,13 @@ public class ActivityManagerService extends IActivityManager.Stub if (!brief && !opts.oomOnly && (procs.size() == 1 || opts.isCheckinRequest || opts.packages)) { opts.dumpDetails = true; } + final int numProcs = procs.size(); + final boolean collectNative = numProcs > 1 && !opts.packages; + if (collectNative) { + // If we are showing aggregations, also look for native processes to + // include so that our aggregations are more accurate. + updateCpuStatsNow(); + } ProtoOutputStream proto = new ProtoOutputStream(fd); @@ -13013,30 +13116,38 @@ public class ActivityManagerService extends IActivityManager.Stub final SparseArray<MemItem> procMemsMap = new SparseArray<MemItem>(); long nativePss = 0; long nativeSwapPss = 0; + long nativeRss = 0; long dalvikPss = 0; long dalvikSwapPss = 0; + long dalvikRss = 0; long[] dalvikSubitemPss = opts.dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] : EmptyArray.LONG; long[] dalvikSubitemSwapPss = opts.dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] : EmptyArray.LONG; + long[] dalvikSubitemRss = opts.dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] : + EmptyArray.LONG; long otherPss = 0; long otherSwapPss = 0; + long otherRss = 0; long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS]; long[] miscSwapPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS]; + long[] miscRss = new long[Debug.MemoryInfo.NUM_OTHER_STATS]; long oomPss[] = new long[DUMP_MEM_OOM_LABEL.length]; long oomSwapPss[] = new long[DUMP_MEM_OOM_LABEL.length]; + long[] oomRss = new long[DUMP_MEM_OOM_LABEL.length]; ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[]) new ArrayList[DUMP_MEM_OOM_LABEL.length]; long totalPss = 0; long totalSwapPss = 0; + long totalRss = 0; long cachedPss = 0; long cachedSwapPss = 0; boolean hasSwapPss = false; Debug.MemoryInfo mi = null; - for (int i = procs.size() - 1 ; i >= 0 ; i--) { + for (int i = numProcs - 1; i >= 0; i--) { final ProcessRecord r = procs.get(i); final IApplicationThread thread; final int pid; @@ -13069,6 +13180,7 @@ public class ActivityManagerService extends IActivityManager.Stub mi.dalvikPss = (int) Debug.getPss(pid, tmpLong, null); endTime = SystemClock.currentThreadTimeMillis(); mi.dalvikPrivateDirty = (int) tmpLong[0]; + mi.dalvikRss = (int) tmpLong[2]; } if (opts.dumpDetails) { if (opts.localOnly) { @@ -13124,22 +13236,27 @@ public class ActivityManagerService extends IActivityManager.Stub if (!opts.isCheckinRequest && mi != null) { totalPss += myTotalPss; totalSwapPss += myTotalSwapPss; + totalRss += myTotalRss; MemItem pssItem = new MemItem(r.processName + " (pid " + pid + (hasActivities ? " / activities)" : ")"), r.processName, myTotalPss, - myTotalSwapPss, pid, hasActivities); + myTotalSwapPss, myTotalRss, pid, hasActivities); procMems.add(pssItem); procMemsMap.put(pid, pssItem); nativePss += mi.nativePss; nativeSwapPss += mi.nativeSwappedOutPss; + nativeRss += mi.nativeRss; dalvikPss += mi.dalvikPss; dalvikSwapPss += mi.dalvikSwappedOutPss; + dalvikRss += mi.dalvikRss; for (int j=0; j<dalvikSubitemPss.length; j++) { dalvikSubitemPss[j] += mi.getOtherPss(Debug.MemoryInfo.NUM_OTHER_STATS + j); dalvikSubitemSwapPss[j] += mi.getOtherSwappedOutPss(Debug.MemoryInfo.NUM_OTHER_STATS + j); + dalvikSubitemRss[j] += mi.getOtherRss(Debug.MemoryInfo.NUM_OTHER_STATS + j); } otherPss += mi.otherPss; + otherRss += mi.otherRss; otherSwapPss += mi.otherSwappedOutPss; for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) { long mem = mi.getOtherPss(j); @@ -13148,6 +13265,9 @@ public class ActivityManagerService extends IActivityManager.Stub mem = mi.getOtherSwappedOutPss(j); miscSwapPss[j] += mem; otherSwapPss -= mem; + mem = mi.getOtherRss(j); + miscRss[j] += mem; + otherRss -= mem; } if (oomAdj >= ProcessList.CACHED_APP_MIN_ADJ) { @@ -13165,6 +13285,7 @@ public class ActivityManagerService extends IActivityManager.Stub oomProcs[oomIndex] = new ArrayList<MemItem>(); } oomProcs[oomIndex].add(pssItem); + oomRss[oomIndex] += myTotalRss; break; } } @@ -13173,10 +13294,7 @@ public class ActivityManagerService extends IActivityManager.Stub long nativeProcTotalPss = 0; - if (procs.size() > 1 && !opts.packages) { - // If we are showing aggregations, also look for native processes to - // include so that our aggregations are more accurate. - updateCpuStatsNow(); + if (collectNative) { mi = null; synchronized (mProcessCpuTracker) { final int N = mProcessCpuTracker.countStats(); @@ -13195,24 +13313,33 @@ public class ActivityManagerService extends IActivityManager.Stub final long myTotalPss = mi.getTotalPss(); final long myTotalSwapPss = mi.getTotalSwappedOutPss(); + final long myTotalRss = mi.getTotalRss(); totalPss += myTotalPss; + totalSwapPss += myTotalSwapPss; + totalRss += myTotalRss; nativeProcTotalPss += myTotalPss; MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")", - st.name, myTotalPss, mi.getSummaryTotalSwapPss(), st.pid, false); + st.name, myTotalPss, mi.getSummaryTotalSwapPss(), myTotalRss, + st.pid, false); procMems.add(pssItem); nativePss += mi.nativePss; nativeSwapPss += mi.nativeSwappedOutPss; + nativeRss += mi.nativeRss; dalvikPss += mi.dalvikPss; dalvikSwapPss += mi.dalvikSwappedOutPss; + dalvikRss += mi.dalvikRss; for (int j=0; j<dalvikSubitemPss.length; j++) { dalvikSubitemPss[j] += mi.getOtherPss(Debug.MemoryInfo.NUM_OTHER_STATS + j); dalvikSubitemSwapPss[j] += mi.getOtherSwappedOutPss(Debug.MemoryInfo.NUM_OTHER_STATS + j); + dalvikSubitemRss[j] += mi.getOtherRss(Debug.MemoryInfo.NUM_OTHER_STATS + + j); } otherPss += mi.otherPss; otherSwapPss += mi.otherSwappedOutPss; + otherRss += mi.otherRss; for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) { long mem = mi.getOtherPss(j); miscPss[j] += mem; @@ -13220,6 +13347,9 @@ public class ActivityManagerService extends IActivityManager.Stub mem = mi.getOtherSwappedOutPss(j); miscSwapPss[j] += mem; otherSwapPss -= mem; + mem = mi.getOtherRss(j); + miscRss[j] += mem; + otherRss -= mem; } oomPss[0] += myTotalPss; oomSwapPss[0] += myTotalSwapPss; @@ -13227,19 +13357,21 @@ public class ActivityManagerService extends IActivityManager.Stub oomProcs[0] = new ArrayList<MemItem>(); } oomProcs[0].add(pssItem); + oomRss[0] += myTotalRss; } } } ArrayList<MemItem> catMems = new ArrayList<MemItem>(); - catMems.add(new MemItem("Native", "Native", nativePss, nativeSwapPss, -1)); + catMems.add(new MemItem("Native", "Native", nativePss, nativeSwapPss, nativeRss, -1)); final int dalvikId = -2; - catMems.add(new MemItem("Dalvik", "Dalvik", dalvikPss, dalvikSwapPss, dalvikId)); - catMems.add(new MemItem("Unknown", "Unknown", otherPss, otherSwapPss, -3)); + catMems.add(new MemItem("Dalvik", "Dalvik", dalvikPss, dalvikSwapPss, dalvikRss, + dalvikId)); + catMems.add(new MemItem("Unknown", "Unknown", otherPss, otherSwapPss, otherRss, -3)); for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) { String label = Debug.MemoryInfo.getOtherLabel(j); - catMems.add(new MemItem(label, label, miscPss[j], miscSwapPss[j], j)); + catMems.add(new MemItem(label, label, miscPss[j], miscSwapPss[j], miscRss[j], j)); } if (dalvikSubitemPss.length > 0) { // Add dalvik subitems. @@ -13265,7 +13397,7 @@ public class ActivityManagerService extends IActivityManager.Stub final String name = Debug.MemoryInfo.getOtherLabel( Debug.MemoryInfo.NUM_OTHER_STATS + j); memItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j], - dalvikSubitemSwapPss[j], j)); + dalvikSubitemSwapPss[j], dalvikSubitemRss[j], j)); } } } @@ -13275,23 +13407,34 @@ public class ActivityManagerService extends IActivityManager.Stub if (oomPss[j] != 0) { String label = opts.isCompact ? DUMP_MEM_OOM_COMPACT_LABEL[j] : DUMP_MEM_OOM_LABEL[j]; - MemItem item = new MemItem(label, label, oomPss[j], oomSwapPss[j], + MemItem item = new MemItem(label, label, oomPss[j], oomSwapPss[j], oomRss[j], DUMP_MEM_OOM_ADJ[j]); item.subitems = oomProcs[j]; oomMems.add(item); } } + if (!opts.oomOnly) { + dumpMemItems(proto, MemInfoDumpProto.TOTAL_RSS_BY_PROCESS, "proc", + procMems, true, false, false); + } + dumpMemItems(proto, MemInfoDumpProto.TOTAL_RSS_BY_OOM_ADJUSTMENT, "oom", + oomMems, false, false, false); + if (!brief && !opts.oomOnly) { + dumpMemItems(proto, MemInfoDumpProto.TOTAL_RSS_BY_CATEGORY, "cat", + catMems, true, false, false); + } + opts.dumpSwapPss = opts.dumpSwapPss && hasSwapPss && totalSwapPss != 0; if (!opts.oomOnly) { dumpMemItems(proto, MemInfoDumpProto.TOTAL_PSS_BY_PROCESS, "proc", - procMems, true, opts.dumpSwapPss); + procMems, true, true, opts.dumpSwapPss); } dumpMemItems(proto, MemInfoDumpProto.TOTAL_PSS_BY_OOM_ADJUSTMENT, "oom", - oomMems, false, opts.dumpSwapPss); + oomMems, false, true, opts.dumpSwapPss); if (!brief && !opts.oomOnly) { dumpMemItems(proto, MemInfoDumpProto.TOTAL_PSS_BY_CATEGORY, "cat", - catMems, true, opts.dumpSwapPss); + catMems, true, true, opts.dumpSwapPss); } MemInfoReader memInfo = new MemInfoReader(); memInfo.readMemInfo(); diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 9239d0389f1c..a47ea4f95b3e 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -756,7 +756,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } public void noteStartAudio(int uid) { - enforceSelfOrCallingPermission(uid); + enforceCallingPermission(); synchronized (mStats) { mStats.noteAudioOnLocked(uid); StatsLog.write_non_chained(StatsLog.AUDIO_STATE_CHANGED, uid, null, @@ -765,7 +765,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } public void noteStopAudio(int uid) { - enforceSelfOrCallingPermission(uid); + enforceCallingPermission(); synchronized (mStats) { mStats.noteAudioOffLocked(uid); StatsLog.write_non_chained(StatsLog.AUDIO_STATE_CHANGED, uid, null, @@ -774,7 +774,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } public void noteStartVideo(int uid) { - enforceSelfOrCallingPermission(uid); + enforceCallingPermission(); synchronized (mStats) { mStats.noteVideoOnLocked(uid); StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_STATE_CHANGED, uid, null, @@ -783,7 +783,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } public void noteStopVideo(int uid) { - enforceSelfOrCallingPermission(uid); + enforceCallingPermission(); synchronized (mStats) { mStats.noteVideoOffLocked(uid); StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_STATE_CHANGED, uid, @@ -1184,13 +1184,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub Binder.getCallingPid(), Binder.getCallingUid(), null); } - private void enforceSelfOrCallingPermission(int uid) { - if (Binder.getCallingUid() == uid) { - return; - } - enforceCallingPermission(); - } - final class WakeupReasonThread extends Thread { private static final int MAX_REASON_SIZE = 512; private CharsetDecoder mDecoder; diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java index 9cf342c0e4fb..ace0a7d03b85 100644 --- a/services/core/java/com/android/server/appop/HistoricalRegistry.java +++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java @@ -291,7 +291,7 @@ final class HistoricalRegistry { makeRelativeToEpochStart(currentOps, nowMillis); currentOps.accept(visitor); - if(isPersistenceInitializedMLocked()) { + if (!isPersistenceInitializedMLocked()) { Slog.e(LOG_TAG, "Interaction before persistence initialized"); return; } @@ -457,7 +457,7 @@ final class HistoricalRegistry { // it is a part of the persistence initialization process. boolean resampleHistory = false; Slog.i(LOG_TAG, "New history parameters: mode:" - + AppOpsManager.historicalModeToString(mMode) + " baseSnapshotInterval:" + + AppOpsManager.historicalModeToString(mode) + " baseSnapshotInterval:" + baseSnapshotInterval + " intervalCompressionMultiplier:" + intervalCompressionMultiplier); if (mMode != mode) { @@ -1066,7 +1066,7 @@ final class HistoricalRegistry { normalizeSnapshotForSlotDuration(persistedOps, slotDurationMillis); writeHistoricalOpsDLocked(persistedOps, intervalOverflowMillis, newFile); if (DEBUG) { - Slog.i(LOG_TAG, "Persisted at depth: " + depth + Slog.i(LOG_TAG, "Persisted at depth: " + depth + " file: " + newFile + " ops:\n" + opsToDebugString(persistedOps)); enforceOpsWellFormed(persistedOps); } @@ -1160,7 +1160,7 @@ final class HistoricalRegistry { } if (DEBUG) { if (allOps != null) { - Slog.i(LOG_TAG, "Read from file: " + file + "ops:\n" + Slog.i(LOG_TAG, "Read from file: " + file + " ops:\n" + opsToDebugString(allOps)); enforceOpsWellFormed(allOps); } diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java index 4a9ccdee0522..766e5c4d638f 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java @@ -209,8 +209,7 @@ public abstract class AuthenticationClient extends ClientMonitor { // will show briefly and be replaced by "device locked out" message. if (listener != null) { if (isBiometricPrompt()) { - listener.onAuthenticationFailedInternal(getCookie(), - getRequireConfirmation()); + listener.onAuthenticationFailedInternal(); } else { listener.onAuthenticationFailed(getHalDeviceId()); } diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index af2f24f959b4..24e6a75e6844 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -25,11 +25,9 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE; import android.app.ActivityManager; -import android.app.ActivityTaskManager; import android.app.AppOpsManager; -import android.app.IActivityTaskManager; +import android.app.IActivityManager; import android.app.KeyguardManager; -import android.app.TaskStackListener; import android.app.UserSwitchObserver; import android.content.ContentResolver; import android.content.Context; @@ -69,6 +67,7 @@ import android.util.Slog; import android.util.StatsLog; import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.SomeArgs; import com.android.internal.statusbar.IStatusBarService; import com.android.server.SystemService; @@ -88,9 +87,8 @@ public class BiometricService extends SystemService { private static final String TAG = "BiometricService"; private static final boolean DEBUG = true; - private static final int MSG_ON_TASK_STACK_CHANGED = 1; private static final int MSG_ON_AUTHENTICATION_SUCCEEDED = 2; - private static final int MSG_ON_AUTHENTICATION_FAILED = 3; + private static final int MSG_ON_AUTHENTICATION_REJECTED = 3; private static final int MSG_ON_ERROR = 4; private static final int MSG_ON_ACQUIRED = 5; private static final int MSG_ON_DISMISSED = 6; @@ -101,6 +99,7 @@ public class BiometricService extends SystemService { private static final int MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS = 11; private static final int MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR = 12; private static final int MSG_REGISTER_CANCELLATION_CALLBACK = 13; + private static final int MSG_ON_AUTHENTICATION_TIMED_OUT = 14; private static final int[] FEATURE_ID = { TYPE_FINGERPRINT, @@ -112,33 +111,41 @@ public class BiometricService extends SystemService { * Authentication either just called and we have not transitioned to the CALLED state, or * authentication terminated (success or error). */ - private static final int STATE_AUTH_IDLE = 0; + static final int STATE_AUTH_IDLE = 0; /** * Authentication was called and we are waiting for the <Biometric>Services to return their * cookies before starting the hardware and showing the BiometricPrompt. */ - private static final int STATE_AUTH_CALLED = 1; + static final int STATE_AUTH_CALLED = 1; /** * Authentication started, BiometricPrompt is showing and the hardware is authenticating. */ - private static final int STATE_AUTH_STARTED = 2; + static final int STATE_AUTH_STARTED = 2; /** * Authentication is paused, waiting for the user to press "try again" button. Only * passive modalities such as Face or Iris should have this state. Note that for passive * modalities, the HAL enters the idle state after onAuthenticated(false) which differs from * fingerprint. */ - private static final int STATE_AUTH_PAUSED = 3; + static final int STATE_AUTH_PAUSED = 3; /** * Authentication is successful, but we're waiting for the user to press "confirm" button. */ - private static final int STATE_AUTH_PENDING_CONFIRM = 5; + static final int STATE_AUTH_PENDING_CONFIRM = 5; /** * Biometric authentication was canceled, but the device is now showing ConfirmDeviceCredential */ - private static final int STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC = 6; + static final int STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC = 6; + /** + * Biometric authenticated, waiting for SysUI to finish animation + */ + static final int STATE_AUTHENTICATED_PENDING_SYSUI = 7; + /** + * Biometric error, waiting for SysUI to finish animation + */ + static final int STATE_ERROR_PENDING_SYSUI = 8; - private final class AuthSession implements IBinder.DeathRecipient { + final class AuthSession implements IBinder.DeathRecipient { // Map of Authenticator/Cookie pairs. We expect to receive the cookies back from // <Biometric>Services before we can start authenticating. Pairs that have been returned // are moved to mModalitiesMatched. @@ -165,10 +172,13 @@ public class BiometricService extends SystemService { final boolean mRequireConfirmation; // The current state, which can be either idle, called, or started - private int mState = STATE_AUTH_IDLE; + int mState = STATE_AUTH_IDLE; // For explicit confirmation, do not send to keystore until the user has confirmed // the authentication. byte[] mTokenEscrow; + // Waiting for SystemUI to complete animation + int mErrorEscrow; + String mErrorStringEscrow; // Timestamp when authentication started private long mStartTimeMs; @@ -244,42 +254,37 @@ public class BiometricService extends SystemService { } } - private final class BiometricTaskStackListener extends TaskStackListener { - @Override - public void onTaskStackChanged() { - mHandler.sendEmptyMessage(MSG_ON_TASK_STACK_CHANGED); - } - } - + private final Injector mInjector; + @VisibleForTesting + final IBiometricService.Stub mImpl; private final AppOpsManager mAppOps; private final boolean mHasFeatureFingerprint; private final boolean mHasFeatureIris; private final boolean mHasFeatureFace; - private final SettingObserver mSettingObserver; + @VisibleForTesting + SettingObserver mSettingObserver; private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks; - private final BiometricTaskStackListener mTaskStackListener = new BiometricTaskStackListener(); private final Random mRandom = new Random(); - private IFingerprintService mFingerprintService; - private IFaceService mFaceService; - private IActivityTaskManager mActivityTaskManager; - private IStatusBarService mStatusBarService; + @VisibleForTesting + IFingerprintService mFingerprintService; + @VisibleForTesting + IFaceService mFaceService; + @VisibleForTesting + IStatusBarService mStatusBarService; + @VisibleForTesting + KeyStore mKeyStore; // Get and cache the available authenticator (manager) classes. Used since aidl doesn't support // polymorphism :/ final ArrayList<Authenticator> mAuthenticators = new ArrayList<>(); - // Cache the current service that's being used. This is the service which - // cancelAuthentication() must be forwarded to. This is just a cache, and the actual - // check (is caller the current client) is done in the <Biometric>Service. - // Since Settings/System (not application) is responsible for changing preference, this - // should be safe. - private int mCurrentModality; - // The current authentication session, null if idle/done. We need to track both the current // and pending sessions since errors may be sent to either. - private AuthSession mCurrentAuthSession; - private AuthSession mPendingAuthSession; + @VisibleForTesting + AuthSession mCurrentAuthSession; + @VisibleForTesting + AuthSession mPendingAuthSession; // TODO(b/123378871): Remove when moved. // When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the @@ -289,15 +294,11 @@ public class BiometricService extends SystemService { // to this receiver. private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver; - private final Handler mHandler = new Handler(Looper.getMainLooper()) { + @VisibleForTesting + final Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { - case MSG_ON_TASK_STACK_CHANGED: { - handleTaskStackChanged(); - break; - } - case MSG_ON_AUTHENTICATION_SUCCEEDED: { SomeArgs args = (SomeArgs) msg.obj; handleAuthenticationSucceeded( @@ -307,8 +308,8 @@ public class BiometricService extends SystemService { break; } - case MSG_ON_AUTHENTICATION_FAILED: { - handleAuthenticationFailed((String) msg.obj /* failureReason */); + case MSG_ON_AUTHENTICATION_REJECTED: { + handleAuthenticationRejected((String) msg.obj /* failureReason */); break; } @@ -397,6 +398,11 @@ public class BiometricService extends SystemService { break; } + case MSG_ON_AUTHENTICATION_TIMED_OUT: { + handleAuthenticationTimedOut((String) msg.obj /* errorMessage */); + break; + } + default: Slog.e(TAG, "Unknown message: " + msg); break; @@ -422,7 +428,8 @@ public class BiometricService extends SystemService { } } - private final class SettingObserver extends ContentObserver { + @VisibleForTesting + public static class SettingObserver extends ContentObserver { private static final boolean DEFAULT_KEYGUARD_ENABLED = true; private static final boolean DEFAULT_APP_ENABLED = true; @@ -436,6 +443,7 @@ public class BiometricService extends SystemService { Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION); private final ContentResolver mContentResolver; + private final List<BiometricService.EnabledOnKeyguardCallback> mCallbacks; private Map<Integer, Boolean> mFaceEnabledOnKeyguard = new HashMap<>(); private Map<Integer, Boolean> mFaceEnabledForApps = new HashMap<>(); @@ -446,13 +454,15 @@ public class BiometricService extends SystemService { * * @param handler The handler to run {@link #onChange} on, or null if none. */ - SettingObserver(Handler handler) { + public SettingObserver(Context context, Handler handler, + List<BiometricService.EnabledOnKeyguardCallback> callbacks) { super(handler); - mContentResolver = getContext().getContentResolver(); + mContentResolver = context.getContentResolver(); + mCallbacks = callbacks; updateContentObserver(); } - void updateContentObserver() { + public void updateContentObserver() { mContentResolver.unregisterContentObserver(this); mContentResolver.registerContentObserver(FACE_UNLOCK_KEYGUARD_ENABLED, false /* notifyForDescendents */, @@ -495,7 +505,7 @@ public class BiometricService extends SystemService { } } - boolean getFaceEnabledOnKeyguard() { + public boolean getFaceEnabledOnKeyguard() { final int user = ActivityManager.getCurrentUser(); if (!mFaceEnabledOnKeyguard.containsKey(user)) { onChange(true /* selfChange */, FACE_UNLOCK_KEYGUARD_ENABLED, user); @@ -503,22 +513,23 @@ public class BiometricService extends SystemService { return mFaceEnabledOnKeyguard.get(user); } - boolean getFaceEnabledForApps(int userId) { + public boolean getFaceEnabledForApps(int userId) { + Slog.e(TAG, "getFaceEnabledForApps: " + userId, new Exception()); if (!mFaceEnabledForApps.containsKey(userId)) { onChange(true /* selfChange */, FACE_UNLOCK_APP_ENABLED, userId); } return mFaceEnabledForApps.getOrDefault(userId, DEFAULT_APP_ENABLED); } - boolean getFaceAlwaysRequireConfirmation(int userId) { + public boolean getFaceAlwaysRequireConfirmation(int userId) { if (!mFaceAlwaysRequireConfirmation.containsKey(userId)) { onChange(true /* selfChange */, FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, userId); } return mFaceAlwaysRequireConfirmation.get(userId); } - void notifyEnabledOnKeyguardCallbacks(int userId) { - List<EnabledOnKeyguardCallback> callbacks = mEnabledOnKeyguardCallbacks; + public void notifyEnabledOnKeyguardCallbacks(int userId) { + List<EnabledOnKeyguardCallback> callbacks = mCallbacks; for (int i = 0; i < callbacks.size(); i++) { callbacks.get(i).notify(BiometricSourceType.FACE, mFaceEnabledOnKeyguard.getOrDefault(userId, DEFAULT_KEYGUARD_ENABLED), @@ -527,7 +538,7 @@ public class BiometricService extends SystemService { } } - private final class EnabledOnKeyguardCallback implements IBinder.DeathRecipient { + final class EnabledOnKeyguardCallback implements IBinder.DeathRecipient { private final IBiometricEnabledOnKeyguardCallback mCallback; @@ -559,7 +570,8 @@ public class BiometricService extends SystemService { } // Wrap the client's receiver so we can do things with the BiometricDialog first - private final IBiometricServiceReceiverInternal mInternalReceiver = + @VisibleForTesting + final IBiometricServiceReceiverInternal mInternalReceiver = new IBiometricServiceReceiverInternal.Stub() { @Override public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token) @@ -571,10 +583,11 @@ public class BiometricService extends SystemService { } @Override - public void onAuthenticationFailed(int cookie, boolean requireConfirmation) + public void onAuthenticationFailed() throws RemoteException { String failureReason = getContext().getString(R.string.biometric_not_recognized); - mHandler.obtainMessage(MSG_ON_AUTHENTICATION_FAILED, failureReason).sendToTarget(); + Slog.v(TAG, "onAuthenticationFailed: " + failureReason); + mHandler.obtainMessage(MSG_ON_AUTHENTICATION_REJECTED, failureReason).sendToTarget(); } @Override @@ -583,7 +596,7 @@ public class BiometricService extends SystemService { // soft errors and we should allow the user to try authenticating again instead of // dismissing BiometricPrompt. if (error == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT) { - mHandler.obtainMessage(MSG_ON_AUTHENTICATION_FAILED, message).sendToTarget(); + mHandler.obtainMessage(MSG_ON_AUTHENTICATION_TIMED_OUT, message).sendToTarget(); } else { SomeArgs args = SomeArgs.obtain(); args.argi1 = cookie; @@ -873,6 +886,44 @@ public class BiometricService extends SystemService { } } + @VisibleForTesting + static class Injector { + IActivityManager getActivityManagerService() { + return ActivityManager.getService(); + } + + IStatusBarService getStatusBarService() { + return IStatusBarService.Stub.asInterface( + ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + } + + IFingerprintService getFingerprintService() { + return IFingerprintService.Stub.asInterface( + ServiceManager.getService(Context.FINGERPRINT_SERVICE)); + } + + IFaceService getFaceService() { + return IFaceService.Stub.asInterface(ServiceManager.getService(Context.FACE_SERVICE)); + } + + SettingObserver getSettingObserver(Context context, Handler handler, + List<EnabledOnKeyguardCallback> callbacks) { + return new SettingObserver(context, handler, callbacks); + } + + KeyStore getKeyStore() { + return KeyStore.getInstance(); + } + + boolean isDebugEnabled(Context context, int userId) { + return Utils.isDebugEnabled(context, userId); + } + + void publishBinderService(BiometricService service, IBiometricService.Stub impl) { + service.publishBinderService(Context.BIOMETRIC_SERVICE, impl); + } + } + /** * Initializes the system service. * <p> @@ -883,11 +934,19 @@ public class BiometricService extends SystemService { * @param context The system server context. */ public BiometricService(Context context) { + this(context, new Injector()); + } + + @VisibleForTesting + BiometricService(Context context, Injector injector) { super(context); + mInjector = injector; + mImpl = new BiometricServiceWrapper(); mAppOps = context.getSystemService(AppOpsManager.class); mEnabledOnKeyguardCallbacks = new ArrayList<>(); - mSettingObserver = new SettingObserver(mHandler); + mSettingObserver = mInjector.getSettingObserver(context, mHandler, + mEnabledOnKeyguardCallbacks); final PackageManager pm = context.getPackageManager(); mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT); @@ -895,7 +954,7 @@ public class BiometricService extends SystemService { mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE); try { - ActivityManager.getService().registerUserSwitchObserver( + injector.getActivityManagerService().registerUserSwitchObserver( new UserSwitchObserver() { @Override public void onUserSwitchComplete(int newUserId) { @@ -913,17 +972,14 @@ public class BiometricService extends SystemService { public void onStart() { // TODO: maybe get these on-demand if (mHasFeatureFingerprint) { - mFingerprintService = IFingerprintService.Stub.asInterface( - ServiceManager.getService(Context.FINGERPRINT_SERVICE)); + mFingerprintService = mInjector.getFingerprintService(); } if (mHasFeatureFace) { - mFaceService = IFaceService.Stub.asInterface( - ServiceManager.getService(Context.FACE_SERVICE)); + mFaceService = mInjector.getFaceService(); } - mActivityTaskManager = ActivityTaskManager.getService(); - mStatusBarService = IStatusBarService.Stub.asInterface( - ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + mKeyStore = mInjector.getKeyStore(); + mStatusBarService = mInjector.getStatusBarService(); // Cache the authenticators for (int i = 0; i < FEATURE_ID.length; i++) { @@ -934,7 +990,7 @@ public class BiometricService extends SystemService { } } - publishBinderService(Context.BIOMETRIC_SERVICE, new BiometricServiceWrapper()); + mInjector.publishBinderService(this, mImpl); } /** @@ -1068,7 +1124,7 @@ public class BiometricService extends SystemService { } private void logDialogDismissed(int reason) { - if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) { + if (reason == BiometricPrompt.DISMISSED_REASON_CONFIRMED) { // Explicit auth, authentication confirmed. // Latency in this case is authenticated -> confirmed. <Biometric>Service // should have the first half (first acquired -> authenticated). @@ -1094,7 +1150,7 @@ public class BiometricService extends SystemService { mCurrentAuthSession.mRequireConfirmation, StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED, latency, - Utils.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId)); + mInjector.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId)); } else { final long latency = System.currentTimeMillis() - mCurrentAuthSession.mStartTimeMs; @@ -1122,7 +1178,7 @@ public class BiometricService extends SystemService { BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, error, 0 /* vendorCode */, - Utils.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId), + mInjector.isDebugEnabled(getContext(), mCurrentAuthSession.mUserId), latency); } } @@ -1145,51 +1201,22 @@ public class BiometricService extends SystemService { return modality; } - private void handleTaskStackChanged() { - try { - final List<ActivityManager.RunningTaskInfo> runningTasks = - mActivityTaskManager.getTasks(1); - if (!runningTasks.isEmpty()) { - final String topPackage = runningTasks.get(0).topActivity.getPackageName(); - if (mCurrentAuthSession != null - && !topPackage.contentEquals(mCurrentAuthSession.mOpPackageName)) { - mStatusBarService.hideBiometricDialog(); - mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); - mCurrentAuthSession.mClientReceiver.onError( - BiometricConstants.BIOMETRIC_ERROR_CANCELED, - getContext().getString( - com.android.internal.R.string.biometric_error_canceled) - ); - mCurrentAuthSession.mState = STATE_AUTH_IDLE; - mCurrentAuthSession = null; - } - } - } catch (RemoteException e) { - Slog.e(TAG, "Unable to get running tasks", e); - } - } - private void handleAuthenticationSucceeded(boolean requireConfirmation, byte[] token) { - try { // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded // after user dismissed/canceled dialog). if (mCurrentAuthSession == null) { - Slog.e(TAG, "onAuthenticationSucceeded(): Auth session is null"); + Slog.e(TAG, "handleAuthenticationSucceeded: Auth session is null"); return; } + // Store the auth token and submit it to keystore after the dialog is confirmed / + // animating away. + mCurrentAuthSession.mTokenEscrow = token; if (!requireConfirmation) { - mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); - KeyStore.getInstance().addAuthToken(token); - mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded(); - mCurrentAuthSession.mState = STATE_AUTH_IDLE; - mCurrentAuthSession = null; + mCurrentAuthSession.mState = STATE_AUTHENTICATED_PENDING_SYSUI; } else { mCurrentAuthSession.mAuthenticatedTimeMs = System.currentTimeMillis(); - // Store the auth token and submit it to keystore after the confirmation - // button has been pressed. - mCurrentAuthSession.mTokenEscrow = token; mCurrentAuthSession.mState = STATE_AUTH_PENDING_CONFIRM; } @@ -1201,12 +1228,13 @@ public class BiometricService extends SystemService { } } - private void handleAuthenticationFailed(String failureReason) { + private void handleAuthenticationRejected(String failureReason) { + Slog.v(TAG, "handleAuthenticationRejected: " + failureReason); try { // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded // after user dismissed/canceled dialog). if (mCurrentAuthSession == null) { - Slog.e(TAG, "onAuthenticationFailed(): Auth session is null"); + Slog.e(TAG, "handleAuthenticationRejected: Auth session is null"); return; } @@ -1225,16 +1253,31 @@ public class BiometricService extends SystemService { } } + private void handleAuthenticationTimedOut(String message) { + Slog.v(TAG, "handleAuthenticationTimedOut: " + message); + try { + // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded + // after user dismissed/canceled dialog). + if (mCurrentAuthSession == null) { + Slog.e(TAG, "handleAuthenticationTimedOut: Auth session is null"); + return; + } + + mStatusBarService.onBiometricAuthenticated(false, message); + mCurrentAuthSession.mState = STATE_AUTH_PAUSED; + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + } + } + private void handleOnConfirmDeviceCredentialSuccess() { if (mConfirmDeviceCredentialReceiver == null) { - Slog.w(TAG, "onCDCASuccess null!"); + Slog.w(TAG, "handleOnConfirmDeviceCredentialSuccess null!"); return; } try { - mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded(); if (mCurrentAuthSession != null) { - mCurrentAuthSession.mState = STATE_AUTH_IDLE; mCurrentAuthSession = null; } } catch (RemoteException e) { @@ -1245,14 +1288,13 @@ public class BiometricService extends SystemService { private void handleOnConfirmDeviceCredentialError(int error, String message) { if (mConfirmDeviceCredentialReceiver == null) { - Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message); + Slog.w(TAG, "handleOnConfirmDeviceCredentialError null! Error: " + + error + " " + message); return; } try { - mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); mConfirmDeviceCredentialReceiver.onError(error, message); if (mCurrentAuthSession != null) { - mCurrentAuthSession.mState = STATE_AUTH_IDLE; mCurrentAuthSession = null; } } catch (RemoteException e) { @@ -1272,7 +1314,7 @@ public class BiometricService extends SystemService { } private void handleOnError(int cookie, int error, String message) { - Slog.d(TAG, "Error: " + error + " cookie: " + cookie); + Slog.d(TAG, "handleOnError: " + error + " cookie: " + cookie); // Errors can either be from the current auth session or the pending auth session. // The pending auth session may receive errors such as ERROR_LOCKOUT before // it becomes the current auth session. Similarly, the current auth session may @@ -1282,6 +1324,9 @@ public class BiometricService extends SystemService { try { if (mCurrentAuthSession != null && mCurrentAuthSession.containsCookie(cookie)) { + mCurrentAuthSession.mErrorEscrow = error; + mCurrentAuthSession.mErrorStringEscrow = message; + if (mCurrentAuthSession.isFromConfirmDeviceCredential()) { // If we were invoked by ConfirmDeviceCredential, do not delete the current // auth session since we still need to respond to cancel signal while @@ -1293,39 +1338,18 @@ public class BiometricService extends SystemService { mCurrentAuthSession.mState = STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC; mStatusBarService.hideBiometricDialog(); } else if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) { - mStatusBarService.onBiometricError(message); + mCurrentAuthSession.mState = STATE_ERROR_PENDING_SYSUI; if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) { - mActivityTaskManager.unregisterTaskStackListener( - mTaskStackListener); - mCurrentAuthSession.mClientReceiver.onError(error, message); - mCurrentAuthSession.mState = STATE_AUTH_IDLE; - mCurrentAuthSession = null; mStatusBarService.hideBiometricDialog(); } else { - // Send errors after the dialog is dismissed. - mHandler.postDelayed(() -> { - try { - if (mCurrentAuthSession != null) { - mActivityTaskManager.unregisterTaskStackListener( - mTaskStackListener); - mCurrentAuthSession.mClientReceiver.onError(error, - message); - mCurrentAuthSession.mState = STATE_AUTH_IDLE; - mCurrentAuthSession = null; - } - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception", e); - } - }, BiometricPrompt.HIDE_DIALOG_DELAY); + mStatusBarService.onBiometricError(message); } } else if (mCurrentAuthSession.mState == STATE_AUTH_PAUSED) { // In the "try again" state, we should forward canceled errors to - // the client and and clean up. + // the client and and clean up. The only error we should get here is + // ERROR_CANCELED due to another client kicking us out. mCurrentAuthSession.mClientReceiver.onError(error, message); - mStatusBarService.onBiometricError(message); - mActivityTaskManager.unregisterTaskStackListener( - mTaskStackListener); - mCurrentAuthSession.mState = STATE_AUTH_IDLE; + mStatusBarService.hideBiometricDialog(); mCurrentAuthSession = null; } else { Slog.e(TAG, "Impossible session error state: " @@ -1335,7 +1359,6 @@ public class BiometricService extends SystemService { && mPendingAuthSession.containsCookie(cookie)) { if (mPendingAuthSession.mState == STATE_AUTH_CALLED) { mPendingAuthSession.mClientReceiver.onError(error, message); - mPendingAuthSession.mState = STATE_AUTH_IDLE; mPendingAuthSession = null; } else { Slog.e(TAG, "Impossible pending session error state: " @@ -1370,42 +1393,50 @@ public class BiometricService extends SystemService { private void handleOnDismissed(int reason) { if (mCurrentAuthSession == null) { - Slog.e(TAG, "onDialogDismissed: " + reason + ", auth session null"); + Slog.e(TAG, "onDismissed: " + reason + ", auth session null"); return; } logDialogDismissed(reason); try { - if (reason != BiometricPrompt.DISMISSED_REASON_POSITIVE) { - // Positive button is used by passive modalities as a "confirm" button, - // do not send to client - mCurrentAuthSession.mClientReceiver.onDialogDismissed(reason); - // Cancel authentication. Skip the token/package check since we are cancelling - // from system server. The interface is permission protected so this is fine. - cancelInternal(null /* token */, null /* package */, false /* fromClient */); - } - if (reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL) { - mCurrentAuthSession.mClientReceiver.onError( - BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED, - getContext().getString( - com.android.internal.R.string.biometric_error_user_canceled)); - } else if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) { - // Have the service send the token to KeyStore, and send onAuthenticated - // to the application - KeyStore.getInstance().addAuthToken(mCurrentAuthSession.mTokenEscrow); - mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded(); - } + switch (reason) { + case BiometricPrompt.DISMISSED_REASON_CONFIRMED: + case BiometricPrompt.DISMISSED_REASON_CONFIRM_NOT_REQUIRED: + mKeyStore.addAuthToken(mCurrentAuthSession.mTokenEscrow); + mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded(); + break; - // Do not clean up yet if we are from ConfirmDeviceCredential. We should be in the - // STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC. The session should only be removed when - // ConfirmDeviceCredential is confirmed or canceled. - // TODO(b/123378871): Remove when moved - if (!mCurrentAuthSession.isFromConfirmDeviceCredential()) { - mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); - mCurrentAuthSession.mState = STATE_AUTH_IDLE; - mCurrentAuthSession = null; + case BiometricPrompt.DISMISSED_REASON_NEGATIVE: + mCurrentAuthSession.mClientReceiver.onDialogDismissed(reason); + // Cancel authentication. Skip the token/package check since we are cancelling + // from system server. The interface is permission protected so this is fine. + cancelInternal(null /* token */, null /* package */, false /* fromClient */); + break; + + case BiometricPrompt.DISMISSED_REASON_USER_CANCEL: + mCurrentAuthSession.mClientReceiver.onError( + BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED, + getContext().getString(R.string.biometric_error_user_canceled)); + // Cancel authentication. Skip the token/package check since we are cancelling + // from system server. The interface is permission protected so this is fine. + cancelInternal(null /* token */, null /* package */, false /* fromClient */); + break; + + case BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED: + case BiometricPrompt.DISMISSED_REASON_ERROR: + mCurrentAuthSession.mClientReceiver.onError(mCurrentAuthSession.mErrorEscrow, + mCurrentAuthSession.mErrorStringEscrow); + break; + + default: + Slog.w(TAG, "Unhandled reason: " + reason); + break; } + + // Dialog is gone, auth session is done. + mCurrentAuthSession = null; + } catch (RemoteException e) { Slog.e(TAG, "Remote exception", e); } @@ -1472,8 +1503,8 @@ public class BiometricService extends SystemService { if (!continuing) { mStatusBarService.showBiometricDialog(mCurrentAuthSession.mBundle, - mInternalReceiver, modality, requireConfirmation, userId); - mActivityTaskManager.registerTaskStackListener(mTaskStackListener); + mInternalReceiver, modality, requireConfirmation, userId, + mCurrentAuthSession.mOpPackageName); } } catch (RemoteException e) { Slog.e(TAG, "Remote exception", e); @@ -1517,8 +1548,6 @@ public class BiometricService extends SystemService { return; } - mCurrentModality = modality; - // Start preparing for authentication. Authentication starts when // all modalities requested have invoked onReadyForAuthentication. authenticateInternal(token, sessionId, userId, receiver, opPackageName, bundle, @@ -1610,7 +1639,6 @@ public class BiometricService extends SystemService { com.android.internal.R.string.biometric_error_user_canceled) ); - mCurrentAuthSession.mState = STATE_AUTH_IDLE; mCurrentAuthSession = null; mStatusBarService.hideBiometricDialog(); } catch (RemoteException e) { @@ -1637,25 +1665,31 @@ public class BiometricService extends SystemService { final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); final int callingUserId = UserHandle.getCallingUserId(); - mHandler.post(() -> { - try { - // TODO: For multiple modalities, send a single ERROR_CANCELED only when all - // drivers have canceled authentication. - if ((mCurrentModality & TYPE_FINGERPRINT) != 0) { - mFingerprintService.cancelAuthenticationFromService(token, opPackageName, - callingUid, callingPid, callingUserId, fromClient); - } - if ((mCurrentModality & TYPE_IRIS) != 0) { - Slog.w(TAG, "Iris unsupported"); - } - if ((mCurrentModality & TYPE_FACE) != 0) { - mFaceService.cancelAuthenticationFromService(token, opPackageName, - callingUid, callingPid, callingUserId, fromClient); - } - } catch (RemoteException e) { - Slog.e(TAG, "Unable to cancel authentication"); + + try { + if (mCurrentAuthSession == null) { + Slog.w(TAG, "Skipping cancelInternal"); + return; + } else if (mCurrentAuthSession.mState != STATE_AUTH_STARTED) { + Slog.w(TAG, "Skipping cancelInternal, state: " + mCurrentAuthSession.mState); + return; } - }); - } + // TODO: For multiple modalities, send a single ERROR_CANCELED only when all + // drivers have canceled authentication. + if ((mCurrentAuthSession.mModality & TYPE_FINGERPRINT) != 0) { + mFingerprintService.cancelAuthenticationFromService(token, opPackageName, + callingUid, callingPid, callingUserId, fromClient); + } + if ((mCurrentAuthSession.mModality & TYPE_IRIS) != 0) { + Slog.w(TAG, "Iris unsupported"); + } + if ((mCurrentAuthSession.mModality & TYPE_FACE) != 0) { + mFaceService.cancelAuthenticationFromService(token, opPackageName, + callingUid, callingPid, callingUserId, fromClient); + } + } catch (RemoteException e) { + Slog.e(TAG, "Unable to cancel authentication"); + } + } } diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java index f3f9754bd32b..2de18c391d4a 100644 --- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java +++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java @@ -420,7 +420,7 @@ public abstract class BiometricServiceBase extends SystemService throw new UnsupportedOperationException("Stub!"); } - default void onAuthenticationFailedInternal(int cookie, boolean requireConfirmation) + default void onAuthenticationFailedInternal() throws RemoteException { throw new UnsupportedOperationException("Stub!"); } @@ -457,10 +457,10 @@ public abstract class BiometricServiceBase extends SystemService } @Override - public void onAuthenticationFailedInternal(int cookie, boolean requireConfirmation) + public void onAuthenticationFailedInternal() throws RemoteException { if (getWrapperReceiver() != null) { - getWrapperReceiver().onAuthenticationFailed(cookie, requireConfirmation); + getWrapperReceiver().onAuthenticationFailed(); } } } 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 53890a48a674..a0eafb4fc93f 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java @@ -35,6 +35,8 @@ import android.hardware.broadcastradio.V2_0.Result; import android.hardware.broadcastradio.V2_0.VendorKeyValue; import android.hardware.radio.RadioManager; import android.os.DeadObjectException; +import android.os.Handler; +import android.os.Looper; import android.os.RemoteException; import android.util.MutableInt; import android.util.Slog; @@ -45,6 +47,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -56,6 +59,7 @@ class RadioModule { @NonNull public final RadioManager.ModuleProperties mProperties; private final Object mLock = new Object(); + @NonNull private final Handler mHandler; @GuardedBy("mLock") private ITunerSession mHalTunerSession; @@ -77,22 +81,24 @@ class RadioModule { private final ITunerCallback mHalTunerCallback = new ITunerCallback.Stub() { @Override public void onTuneFailed(int result, ProgramSelector programSelector) { - fanoutAidlCallback(cb -> cb.onTuneFailed(result, Convert.programSelectorFromHal( - programSelector))); + lockAndFireLater(() -> { + android.hardware.radio.ProgramSelector csel = + Convert.programSelectorFromHal(programSelector); + fanoutAidlCallbackLocked(cb -> cb.onTuneFailed(result, csel)); + }); } @Override public void onCurrentProgramInfoChanged(ProgramInfo halProgramInfo) { - RadioManager.ProgramInfo programInfo = Convert.programInfoFromHal(halProgramInfo); - synchronized (mLock) { - mCurrentProgramInfo = programInfo; - fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(programInfo)); - } + lockAndFireLater(() -> { + mCurrentProgramInfo = Convert.programInfoFromHal(halProgramInfo); + fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(mCurrentProgramInfo)); + }); } @Override public void onProgramListUpdated(ProgramListChunk programListChunk) { - synchronized (mLock) { + lockAndFireLater(() -> { android.hardware.radio.ProgramList.Chunk chunk = Convert.programListChunkFromHal(programListChunk); mProgramInfoCache.filterAndApplyChunk(chunk); @@ -100,20 +106,23 @@ class RadioModule { for (TunerSession tunerSession : mAidlTunerSessions) { tunerSession.onMergedProgramListUpdateFromHal(chunk); } - } + }); } @Override public void onAntennaStateChange(boolean connected) { - synchronized (mLock) { + lockAndFireLater(() -> { mAntennaConnected = connected; fanoutAidlCallbackLocked(cb -> cb.onAntennaState(connected)); - } + }); } @Override public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) { - fanoutAidlCallback(cb -> cb.onParametersUpdated(Convert.vendorInfoFromHal(parameters))); + lockAndFireLater(() -> { + Map<String, String> cparam = Convert.vendorInfoFromHal(parameters); + fanoutAidlCallbackLocked(cb -> cb.onParametersUpdated(cparam)); + }); } }; @@ -126,6 +135,7 @@ class RadioModule { @NonNull RadioManager.ModuleProperties properties) { mProperties = Objects.requireNonNull(properties); mService = Objects.requireNonNull(service); + mHandler = new Handler(Looper.getMainLooper()); } public static @Nullable RadioModule tryLoadingModule(int idx, @NonNull String fqName) { @@ -310,15 +320,22 @@ class RadioModule { } } + // add to mHandler queue, but ensure the runnable holds mLock when it gets executed + private void lockAndFireLater(Runnable r) { + mHandler.post(() -> { + synchronized (mLock) { + r.run(); + } + }); + } + interface AidlCallbackRunnable { void run(android.hardware.radio.ITunerCallback callback) throws RemoteException; } // Invokes runnable with each TunerSession currently open. void fanoutAidlCallback(AidlCallbackRunnable runnable) { - synchronized (mLock) { - fanoutAidlCallbackLocked(runnable); - } + lockAndFireLater(() -> fanoutAidlCallbackLocked(runnable)); } private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) { diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index 3eea194fd73e..27050faef712 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -16,6 +16,7 @@ package com.android.server.compat; +import android.compat.IPlatformCompat; import android.content.Context; import android.content.pm.ApplicationInfo; import android.util.Slog; diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 73d160d8c444..86d12124785d 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -1314,11 +1314,15 @@ public class Tethering extends BaseNetworkObserver { mOffload.excludeDownstreamInterface(who.interfaceName()); mForwardedDownstreams.remove(who); - // If this is a Wi-Fi interface, tell WifiManager of any errors. + // If this is a Wi-Fi interface, tell WifiManager of any errors + // or the inactive serving state. if (who.interfaceType() == TETHERING_WIFI) { if (who.lastError() != TETHER_ERROR_NO_ERROR) { getWifiManager().updateInterfaceIpState( who.interfaceName(), IFACE_IP_MODE_CONFIGURATION_ERROR); + } else { + getWifiManager().updateInterfaceIpState( + who.interfaceName(), IFACE_IP_MODE_UNSPECIFIED); } } } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index e7a8b132d850..fb94907fc579 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -95,7 +95,7 @@ import com.android.internal.net.VpnProfile; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.util.ArrayUtils; import com.android.server.ConnectivityService; -import com.android.server.DeviceIdleController; +import com.android.server.DeviceIdleInternal; import com.android.server.LocalServices; import com.android.server.net.BaseNetworkObserver; @@ -616,8 +616,8 @@ public class Vpn { // a short time, so we can bootstrap the VPN service. final long oldId = Binder.clearCallingIdentity(); try { - DeviceIdleController.LocalService idleController = - LocalServices.getService(DeviceIdleController.LocalService.class); + DeviceIdleInternal idleController = + LocalServices.getService(DeviceIdleInternal.class); idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage, VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS, mUserHandle, false, "vpn"); diff --git a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java index 836f1e64aa9c..f952bcef5606 100644 --- a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java +++ b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java @@ -161,6 +161,12 @@ public class EntitlementManager { * Check if cellular upstream is permitted. */ public boolean isCellularUpstreamPermitted() { + // If provisioning is required and EntitlementManager don't know any downstream, + // cellular upstream should not be allowed. + final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); + if (mCurrentTethers.size() == 0 && isTetherProvisioningRequired(config)) { + return false; + } return mCellularUpstreamPermitted; } diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index 3e1817bd14ff..36e872a109dd 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -461,7 +461,7 @@ public final class ContentService extends IContentService.Stub { } synchronized (mCache) { - final String providerPackageName = getProviderPackageName(uri); + final String providerPackageName = getProviderPackageName(uri, userHandle); invalidateCacheLocked(userHandle, providerPackageName, uri); } } finally { @@ -1145,9 +1145,9 @@ public final class ContentService extends IContentService.Stub { } } - private @Nullable String getProviderPackageName(Uri uri) { - final ProviderInfo pi = mContext.getPackageManager() - .resolveContentProvider(uri.getAuthority(), 0); + private @Nullable String getProviderPackageName(Uri uri, int userId) { + final ProviderInfo pi = mContext.getPackageManager().resolveContentProviderAsUser( + uri.getAuthority(), 0, userId); return (pi != null) ? pi.packageName : null; } @@ -1200,7 +1200,7 @@ public final class ContentService extends IContentService.Stub { mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(), packageName); - final String providerPackageName = getProviderPackageName(key); + final String providerPackageName = getProviderPackageName(key, userId); final Pair<String, Uri> fullKey = Pair.create(packageName, key); synchronized (mCache) { @@ -1222,7 +1222,7 @@ public final class ContentService extends IContentService.Stub { mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(), packageName); - final String providerPackageName = getProviderPackageName(key); + final String providerPackageName = getProviderPackageName(key, userId); final Pair<String, Uri> fullKey = Pair.create(packageName, key); synchronized (mCache) { diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index f6c49ed4d29e..e7f537b897b9 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -102,7 +102,7 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.function.QuadConsumer; -import com.android.server.DeviceIdleController; +import com.android.server.DeviceIdleInternal; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.accounts.AccountManagerService; @@ -1634,8 +1634,8 @@ public class SyncManager { if (syncOperation.syncExemptionFlag == ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP) { - DeviceIdleController.LocalService dic = - LocalServices.getService(DeviceIdleController.LocalService.class); + DeviceIdleInternal dic = + LocalServices.getService(DeviceIdleInternal.class); if (dic != null) { dic.addPowerSaveTempWhitelistApp(Process.SYSTEM_UID, syncOperation.owningPackage, diff --git a/services/core/java/com/android/server/deviceidle/BluetoothConstraint.java b/services/core/java/com/android/server/deviceidle/BluetoothConstraint.java index cc319bf23ddd..731d8991c53a 100644 --- a/services/core/java/com/android/server/deviceidle/BluetoothConstraint.java +++ b/services/core/java/com/android/server/deviceidle/BluetoothConstraint.java @@ -29,7 +29,7 @@ import android.os.Message; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.DeviceIdleController; +import com.android.server.DeviceIdleInternal; /** * Track whether there are any active Bluetooth devices connected. @@ -40,14 +40,14 @@ public class BluetoothConstraint implements IDeviceIdleConstraint { private final Context mContext; private final Handler mHandler; - private final DeviceIdleController.LocalService mLocalService; + private final DeviceIdleInternal mLocalService; private final BluetoothManager mBluetoothManager; private volatile boolean mConnected = true; private volatile boolean mMonitoring = false; public BluetoothConstraint( - Context context, Handler handler, DeviceIdleController.LocalService localService) { + Context context, Handler handler, DeviceIdleInternal localService) { mContext = context; mHandler = handler; mLocalService = localService; diff --git a/services/core/java/com/android/server/deviceidle/TvConstraintController.java b/services/core/java/com/android/server/deviceidle/TvConstraintController.java index 2d472de6f5e1..7f0a2717ed4a 100644 --- a/services/core/java/com/android/server/deviceidle/TvConstraintController.java +++ b/services/core/java/com/android/server/deviceidle/TvConstraintController.java @@ -21,7 +21,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.os.Handler; -import com.android.server.DeviceIdleController; +import com.android.server.DeviceIdleInternal; import com.android.server.LocalServices; /** @@ -33,7 +33,7 @@ import com.android.server.LocalServices; public class TvConstraintController implements ConstraintController { private final Context mContext; private final Handler mHandler; - private final DeviceIdleController.LocalService mDeviceIdleService; + private final DeviceIdleInternal mDeviceIdleService; @Nullable private final BluetoothConstraint mBluetoothConstraint; @@ -41,7 +41,7 @@ public class TvConstraintController implements ConstraintController { public TvConstraintController(Context context, Handler handler) { mContext = context; mHandler = handler; - mDeviceIdleService = LocalServices.getService(DeviceIdleController.LocalService.class); + mDeviceIdleService = LocalServices.getService(DeviceIdleInternal.class); final PackageManager pm = context.getPackageManager(); mBluetoothConstraint = pm.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH) diff --git a/services/core/java/com/android/server/display/WifiDisplayController.java b/services/core/java/com/android/server/display/WifiDisplayController.java index fc59b5b0ffec..d9d46b8d1f3b 100644 --- a/services/core/java/com/android/server/display/WifiDisplayController.java +++ b/services/core/java/com/android/server/display/WifiDisplayController.java @@ -94,8 +94,8 @@ final class WifiDisplayController implements DumpUtils.Dump { private final Handler mHandler; private final Listener mListener; - private final WifiP2pManager mWifiP2pManager; - private final Channel mWifiP2pChannel; + private WifiP2pManager mWifiP2pManager; + private Channel mWifiP2pChannel; private boolean mWifiP2pEnabled; private boolean mWfdEnabled; @@ -164,9 +164,6 @@ final class WifiDisplayController implements DumpUtils.Dump { mHandler = handler; mListener = listener; - mWifiP2pManager = (WifiP2pManager)context.getSystemService(Context.WIFI_P2P_SERVICE); - mWifiP2pChannel = mWifiP2pManager.initialize(context, handler.getLooper(), null); - IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); @@ -191,6 +188,18 @@ final class WifiDisplayController implements DumpUtils.Dump { updateSettings(); } + /** + * Used to lazily retrieve WifiP2pManager service. + */ + private void retrieveWifiP2pManagerAndChannel() { + if (mWifiP2pManager == null) { + mWifiP2pManager = (WifiP2pManager)mContext.getSystemService(Context.WIFI_P2P_SERVICE); + } + if (mWifiP2pChannel == null && mWifiP2pManager != null) { + mWifiP2pChannel = mWifiP2pManager.initialize(mContext, mHandler.getLooper(), null); + } + } + private void updateSettings() { final ContentResolver resolver = mContext.getContentResolver(); mWifiDisplayOnSetting = Settings.Global.getInt(resolver, @@ -803,6 +812,9 @@ final class WifiDisplayController implements DumpUtils.Dump { private void handleStateChanged(boolean enabled) { mWifiP2pEnabled = enabled; + if (enabled) { + retrieveWifiP2pManagerAndChannel(); + } updateWfdEnableState(); } diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index f1f6d502d575..f38f2f9a0de5 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -106,6 +106,7 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.internal.widget.ICheckCredentialProgressCallback; import com.android.internal.widget.ILockSettings; @@ -137,8 +138,10 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Date; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; @@ -169,6 +172,8 @@ public class LockSettingsService extends ILockSettings.Stub { private static final int PROFILE_KEY_IV_SIZE = 12; private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge"; private static final int SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT = 1; + private static final String PREV_SYNTHETIC_PASSWORD_HANDLE_KEY = "prev-sp-handle"; + private static final String SYNTHETIC_PASSWORD_UPDATE_TIME_KEY = "sp-handle-ts"; // No challenge provided private static final int CHALLENGE_NONE = 0; @@ -357,7 +362,7 @@ public class LockSettingsService extends ILockSettings.Stub { setLong(LockPatternUtils.PASSWORD_TYPE_KEY, quality, managedUserId); tieProfileLockToParent(managedUserId, newPassword); Arrays.fill(newPassword, (byte) 0); - } catch (NoSuchAlgorithmException | RemoteException e) { + } catch (NoSuchAlgorithmException e) { Slog.e(TAG, "Fail to tie managed profile", e); // Nothing client can do to fix this issue, so we do not throw exception out } @@ -604,15 +609,11 @@ public class LockSettingsService extends ILockSettings.Stub { if (ks.state(userId) == KeyStore.State.LOCKED && tiedManagedProfileReadyToUnlock(mUserManager.getUserInfo(userId))) { Slog.i(TAG, "Managed profile got unlocked, will unlock its keystore"); - try { - // If boot took too long and the password in vold got expired, parent keystore will - // be still locked, we ignore this case since the user will be prompted to unlock - // the device after boot. - unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */, - CHALLENGE_NONE, 0 /* challenge */, null /* resetLockouts */); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to unlock child profile"); - } + // If boot took too long and the password in vold got expired, parent keystore will + // be still locked, we ignore this case since the user will be prompted to unlock + // the device after boot. + unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */, + CHALLENGE_NONE, 0 /* challenge */, null /* resetLockouts */); } } @@ -648,20 +649,16 @@ public class LockSettingsService extends ILockSettings.Stub { return; } - try { - final long handle = getSyntheticPasswordHandleLocked(userId); - final byte[] noCredential = null; - AuthenticationResult result = - mSpManager.unwrapPasswordBasedSyntheticPassword( - getGateKeeperService(), handle, noCredential, userId, null); - if (result.authToken != null) { - Slog.i(TAG, "Retrieved auth token for user " + userId); - onAuthTokenKnownForUser(userId, result.authToken); - } else { - Slog.e(TAG, "Auth token not available for user " + userId); - } - } catch (RemoteException e) { - Slog.e(TAG, "Failure retrieving auth token", e); + final long handle = getSyntheticPasswordHandleLocked(userId); + final byte[] noCredential = null; + AuthenticationResult result = + mSpManager.unwrapPasswordBasedSyntheticPassword( + getGateKeeperService(), handle, noCredential, userId, null); + if (result.authToken != null) { + Slog.i(TAG, "Retrieved auth token for user " + userId); + onAuthTokenKnownForUser(userId, result.authToken); + } else { + Slog.e(TAG, "Auth token not available for user " + userId); } } } @@ -698,12 +695,8 @@ public class LockSettingsService extends ILockSettings.Stub { } checkWritePermission(UserHandle.USER_SYSTEM); migrateOldData(); - try { - getGateKeeperService(); - mSpManager.initWeaverService(); - } catch (RemoteException e) { - Slog.e(TAG, "Failure retrieving IGateKeeperService", e); - } + getGateKeeperService(); + mSpManager.initWeaverService(); // Find the AuthSecret HAL try { mAuthSecretService = IAuthSecret.getService(); @@ -872,16 +865,12 @@ public class LockSettingsService extends ILockSettings.Stub { } private void migrateOldDataAfterSystemReady() { - try { - // Migrate the FRP credential to the persistent data block - if (LockPatternUtils.frpCredentialEnabled(mContext) - && !getBoolean("migrated_frp", false, 0)) { - migrateFrpCredential(); - setBoolean("migrated_frp", true, 0); - Slog.i(TAG, "Migrated migrated_frp."); - } - } catch (RemoteException e) { - Slog.e(TAG, "Unable to migrateOldDataAfterSystemReady", e); + // Migrate the FRP credential to the persistent data block + if (LockPatternUtils.frpCredentialEnabled(mContext) + && !getBoolean("migrated_frp", false, 0)) { + migrateFrpCredential(); + setBoolean("migrated_frp", true, 0); + Slog.i(TAG, "Migrated migrated_frp."); } } @@ -891,7 +880,7 @@ public class LockSettingsService extends ILockSettings.Stub { * - the FRP credential is not set up * - the credential is based on a synthetic password. */ - private void migrateFrpCredential() throws RemoteException { + private void migrateFrpCredential() { if (mStorage.readPersistentDataBlock() != PersistentData.NONE) { return; } @@ -1187,8 +1176,7 @@ public class LockSettingsService extends ILockSettings.Stub { private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated, @ChallengeType int challengeType, long challenge, - @Nullable ArrayList<PendingResetLockout> resetLockouts) - throws RemoteException { + @Nullable ArrayList<PendingResetLockout> resetLockouts) { try { doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle), CREDENTIAL_TYPE_PASSWORD, @@ -1263,14 +1251,10 @@ public class LockSettingsService extends ILockSettings.Stub { for (UserInfo profile : mUserManager.getProfiles(userId)) { // Unlock managed profile with unified lock if (tiedManagedProfileReadyToUnlock(profile)) { - try { - // Must pass the challenge on for resetLockout, so it's not over-written, which - // causes LockSettingsService to revokeChallenge inappropriately. - unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */, - challengeType, challenge, resetLockouts); - } catch (RemoteException e) { - Log.d(TAG, "Failed to unlock child profile", e); - } + // Must pass the challenge on for resetLockout, so it's not over-written, which + // causes LockSettingsService to revokeChallenge inappropriately. + unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */, + challengeType, challenge, resetLockouts); } // Now we have unlocked the parent user and attempted to unlock the profile we should // show notifications if the profile is still locked. @@ -1350,7 +1334,7 @@ public class LockSettingsService extends ILockSettings.Stub { * terminates when the user is a managed profile. */ private void synchronizeUnifiedWorkChallengeForProfiles(int userId, - Map<Integer, byte[]> profilePasswordMap) throws RemoteException { + Map<Integer, byte[]> profilePasswordMap) { if (mUserManager.getUserInfo(userId).isManagedProfile()) { return; } @@ -1464,7 +1448,7 @@ public class LockSettingsService extends ILockSettings.Stub { @Override public void setLockCredential(byte[] credential, int type, byte[] savedCredential, int requestedQuality, int userId, - boolean allowUntrustedChange) throws RemoteException { + boolean allowUntrustedChange) { if (!mLockPatternUtils.hasSecureLockScreen()) { throw new UnsupportedOperationException( @@ -1490,7 +1474,7 @@ public class LockSettingsService extends ILockSettings.Stub { */ private void setLockCredentialInternal(byte[] credential, @CredentialType int credentialType, byte[] savedCredential, int requestedQuality, int userId, boolean allowUntrustedChange, - boolean isLockTiedToParent) throws RemoteException { + boolean isLockTiedToParent) { // Normalize savedCredential and credential such that empty string is always represented // as null. if (savedCredential == null || savedCredential.length == 0) { @@ -1512,7 +1496,7 @@ public class LockSettingsService extends ILockSettings.Stub { Slog.wtf(TAG, "CredentialType is none, but credential is non-null."); } clearUserKeyProtection(userId); - getGateKeeperService().clearSecureUserId(userId); + gateKeeperClearSecureUserId(userId); mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId); setKeystorePassword(null, userId); fixateNewestUserKeyAuth(userId); @@ -1523,7 +1507,7 @@ public class LockSettingsService extends ILockSettings.Stub { return; } if (credential == null) { - throw new RemoteException("Null credential with mismatched credential type"); + throw new IllegalArgumentException("Null credential with mismatched credential type"); } CredentialHash currentHandle = mStorage.readCredentialHash(userId); @@ -1565,8 +1549,13 @@ public class LockSettingsService extends ILockSettings.Stub { CredentialHash willStore = CredentialHash.create(enrolledHandle, credentialType); mStorage.writeCredentialHash(willStore, userId); // push new secret and auth token to vold - GateKeeperResponse gkResponse = getGateKeeperService() - .verifyChallenge(userId, 0, willStore.hash, credential); + GateKeeperResponse gkResponse; + try { + gkResponse = getGateKeeperService().verifyChallenge(userId, 0, willStore.hash, + credential); + } catch (RemoteException e) { + throw new IllegalStateException("Failed to verify current credential", e); + } setUserKeyProtection(userId, credential, convertResponse(gkResponse)); fixateNewestUserKeyAuth(userId); // Refresh the auth token @@ -1576,8 +1565,8 @@ public class LockSettingsService extends ILockSettings.Stub { sendCredentialsOnChangeIfRequired( credentialType, credential, userId, isLockTiedToParent); } else { - throw new RemoteException("Failed to enroll " + - (credentialType == CREDENTIAL_TYPE_PASSWORD ? "password" : "pattern")); + throw new IllegalStateException(String.format("Failed to enroll %s", + credentialType == CREDENTIAL_TYPE_PASSWORD ? "password" : "pattern")); } } @@ -1630,27 +1619,32 @@ public class LockSettingsService extends ILockSettings.Stub { } catch (CertificateException | UnrecoverableKeyException | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) { - throw new RuntimeException("Failed to encrypt key", e); + throw new IllegalStateException("Failed to encrypt key", e); } ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try { if (iv.length != PROFILE_KEY_IV_SIZE) { - throw new RuntimeException("Invalid iv length: " + iv.length); + throw new IllegalArgumentException("Invalid iv length: " + iv.length); } outputStream.write(iv); outputStream.write(encryptionResult); } catch (IOException e) { - throw new RuntimeException("Failed to concatenate byte arrays", e); + throw new IllegalStateException("Failed to concatenate byte arrays", e); } mStorage.writeChildProfileLock(userId, outputStream.toByteArray()); } private byte[] enrollCredential(byte[] enrolledHandle, - byte[] enrolledCredential, byte[] toEnroll, int userId) - throws RemoteException { + byte[] enrolledCredential, byte[] toEnroll, int userId) { checkWritePermission(userId); - GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle, - enrolledCredential, toEnroll); + GateKeeperResponse response; + try { + response = getGateKeeperService().enroll(userId, enrolledHandle, + enrolledCredential, toEnroll); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to enroll credential", e); + return null; + } if (response == null) { return null; @@ -1666,34 +1660,33 @@ public class LockSettingsService extends ILockSettings.Stub { return hash; } - private void setAuthlessUserKeyProtection(int userId, byte[] key) throws RemoteException { + private void setAuthlessUserKeyProtection(int userId, byte[] key) { if (DEBUG) Slog.d(TAG, "setAuthlessUserKeyProtectiond: user=" + userId); addUserKeyAuth(userId, null, key); } - private void setUserKeyProtection(int userId, byte[] credential, VerifyCredentialResponse vcr) - throws RemoteException { + private void setUserKeyProtection(int userId, byte[] credential, VerifyCredentialResponse vcr) { if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId); if (vcr == null) { - throw new RemoteException("Null response verifying a credential we just set"); + throw new IllegalArgumentException("Null response verifying a credential we just set"); } if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) { - throw new RemoteException("Non-OK response verifying a credential we just set: " + throw new IllegalArgumentException("Non-OK response verifying a credential we just set " + vcr.getResponseCode()); } byte[] token = vcr.getPayload(); if (token == null) { - throw new RemoteException("Empty payload verifying a credential we just set"); + throw new IllegalArgumentException("Empty payload verifying a credential we just set"); } addUserKeyAuth(userId, token, secretFromCredential(credential)); } - private void clearUserKeyProtection(int userId) throws RemoteException { + private void clearUserKeyProtection(int userId) { if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId); addUserKeyAuth(userId, null, null); } - private static byte[] secretFromCredential(byte[] credential) throws RemoteException { + private static byte[] secretFromCredential(byte[] credential) { try { MessageDigest digest = MessageDigest.getInstance("SHA-512"); // Personalize the hash @@ -1704,7 +1697,7 @@ public class LockSettingsService extends ILockSettings.Stub { digest.update(credential); return digest.digest(); } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("NoSuchAlgorithmException for SHA-512"); + throw new IllegalStateException("NoSuchAlgorithmException for SHA-512"); } } @@ -1718,35 +1711,44 @@ public class LockSettingsService extends ILockSettings.Stub { } /** Unlock disk encryption */ - private void unlockUserKey(int userId, byte[] token, byte[] secret) throws RemoteException { + private void unlockUserKey(int userId, byte[] token, byte[] secret) { final UserInfo userInfo = mUserManager.getUserInfo(userId); - mStorageManager.unlockUserKey(userId, userInfo.serialNumber, token, secret); + try { + mStorageManager.unlockUserKey(userId, userInfo.serialNumber, token, secret); + } catch (RemoteException e) { + throw new IllegalStateException("Failed to unlock user key " + userId, e); + + } } - private void addUserKeyAuth(int userId, byte[] token, byte[] secret) - throws RemoteException { + private void addUserKeyAuth(int userId, byte[] token, byte[] secret) { final UserInfo userInfo = mUserManager.getUserInfo(userId); final long callingId = Binder.clearCallingIdentity(); try { mStorageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret); + } catch (RemoteException e) { + throw new IllegalStateException("Failed to add new key to vold " + userId, e); } finally { Binder.restoreCallingIdentity(callingId); } } - private void fixateNewestUserKeyAuth(int userId) - throws RemoteException { + private void fixateNewestUserKeyAuth(int userId) { if (DEBUG) Slog.d(TAG, "fixateNewestUserKeyAuth: user=" + userId); final long callingId = Binder.clearCallingIdentity(); try { mStorageManager.fixateNewestUserKeyAuth(userId); + } catch (RemoteException e) { + // OK to ignore the exception as vold would just accept both old and new + // keys if this call fails, and will fix itself during the next boot + Slog.w(TAG, "fixateNewestUserKeyAuth failed", e); } finally { Binder.restoreCallingIdentity(callingId); } } @Override - public void resetKeyStore(int userId) throws RemoteException { + public void resetKeyStore(int userId) { checkWritePermission(userId); if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId); int managedUserId = -1; @@ -1794,14 +1796,14 @@ public class LockSettingsService extends ILockSettings.Stub { @Override public VerifyCredentialResponse checkCredential(byte[] credential, int type, int userId, - ICheckCredentialProgressCallback progressCallback) throws RemoteException { + ICheckCredentialProgressCallback progressCallback) { checkPasswordReadPermission(userId); return doVerifyCredential(credential, type, CHALLENGE_NONE, 0, userId, progressCallback); } @Override public VerifyCredentialResponse verifyCredential(byte[] credential, int type, long challenge, - int userId) throws RemoteException { + int userId) { checkPasswordReadPermission(userId); return doVerifyCredential(credential, type, CHALLENGE_FROM_CALLER, challenge, userId, null /* progressCallback */); @@ -1809,7 +1811,7 @@ public class LockSettingsService extends ILockSettings.Stub { private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType, @ChallengeType int challengeType, long challenge, int userId, - ICheckCredentialProgressCallback progressCallback) throws RemoteException { + ICheckCredentialProgressCallback progressCallback) { return doVerifyCredential(credential, credentialType, challengeType, challenge, userId, progressCallback, null /* resetLockouts */); } @@ -1821,7 +1823,7 @@ public class LockSettingsService extends ILockSettings.Stub { private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType, @ChallengeType int challengeType, long challenge, int userId, ICheckCredentialProgressCallback progressCallback, - @Nullable ArrayList<PendingResetLockout> resetLockouts) throws RemoteException { + @Nullable ArrayList<PendingResetLockout> resetLockouts) { if (credential == null || credential.length == 0) { throw new IllegalArgumentException("Credential can't be null or empty"); } @@ -1865,10 +1867,10 @@ public class LockSettingsService extends ILockSettings.Stub { @Override public VerifyCredentialResponse verifyTiedProfileChallenge(byte[] credential, int type, - long challenge, int userId) throws RemoteException { + long challenge, int userId) { checkPasswordReadPermission(userId); if (!isManagedProfileWithUnifiedLock(userId)) { - throw new RemoteException("User id must be managed profile with unified lock"); + throw new IllegalArgumentException("User id must be managed profile with unified lock"); } final int parentProfileId = mUserManager.getProfileParent(userId).id; // Unlock parent by using parent's challenge @@ -1896,7 +1898,7 @@ public class LockSettingsService extends ILockSettings.Stub { | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException | CertificateException | IOException e) { Slog.e(TAG, "Failed to decrypt child profile key", e); - throw new RemoteException("Unable to get tied profile token"); + throw new IllegalStateException("Unable to get tied profile token"); } } @@ -1907,7 +1909,7 @@ public class LockSettingsService extends ILockSettings.Stub { */ private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash, byte[] credential, @ChallengeType int challengeType, long challenge, - ICheckCredentialProgressCallback progressCallback) throws RemoteException { + ICheckCredentialProgressCallback progressCallback) { if ((storedHash == null || storedHash.hash.length == 0) && (credential == null || credential.length == 0)) { // don't need to pass empty credentials to GateKeeper @@ -1922,8 +1924,14 @@ public class LockSettingsService extends ILockSettings.Stub { // of unlocking the user, so yell if calling from the main thread. StrictMode.noteDiskRead(); - GateKeeperResponse gateKeeperResponse = getGateKeeperService() - .verifyChallenge(userId, challenge, storedHash.hash, credential); + GateKeeperResponse gateKeeperResponse; + try { + gateKeeperResponse = getGateKeeperService() + .verifyChallenge(userId, challenge, storedHash.hash, credential); + } catch (RemoteException e) { + Slog.e(TAG, "gatekeeper verify failed", e); + gateKeeperResponse = GateKeeperResponse.ERROR; + } VerifyCredentialResponse response = convertResponse(gateKeeperResponse); boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll(); @@ -1932,7 +1940,11 @@ public class LockSettingsService extends ILockSettings.Stub { // credential has matched if (progressCallback != null) { - progressCallback.onCredentialVerified(); + try { + progressCallback.onCredentialVerified(); + } catch (RemoteException e) { + Log.w(TAG, "progressCallback throws exception", e); + } } notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId); unlockKeystore(credential, userId); @@ -2007,7 +2019,7 @@ public class LockSettingsService extends ILockSettings.Stub { } @Override - public boolean checkVoldPassword(int userId) throws RemoteException { + public boolean checkVoldPassword(int userId) { if (!mFirstCallToVold) { return false; } @@ -2030,6 +2042,9 @@ public class LockSettingsService extends ILockSettings.Stub { try { password = service.getPassword(); service.clearPassword(); + } catch (RemoteException e) { + Slog.w(TAG, "vold getPassword() failed", e); + return false; } finally { Binder.restoreCallingIdentity(identity); } @@ -2071,14 +2086,7 @@ public class LockSettingsService extends ILockSettings.Stub { final KeyStore ks = KeyStore.getInstance(); ks.onUserRemoved(userId); - try { - final IGateKeeperService gk = getGateKeeperService(); - if (gk != null) { - gk.clearSecureUserId(userId); - } - } catch (RemoteException ex) { - Slog.w(TAG, "unable to clear GK secure user id"); - } + gateKeeperClearSecureUserId(userId); if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) { removeKeystoreProfileKey(userId); } @@ -2141,8 +2149,7 @@ public class LockSettingsService extends ILockSettings.Stub { @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, - String[] args, ShellCallback callback, ResultReceiver resultReceiver) - throws RemoteException { + String[] args, ShellCallback callback, ResultReceiver resultReceiver) { enforceShell(); final long origId = Binder.clearCallingIdentity(); try { @@ -2304,15 +2311,18 @@ public class LockSettingsService extends ILockSettings.Stub { } } - protected synchronized IGateKeeperService getGateKeeperService() - throws RemoteException { + protected synchronized IGateKeeperService getGateKeeperService() { if (mGateKeeperService != null) { return mGateKeeperService; } final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE); if (service != null) { - service.linkToDeath(new GateKeeperDiedRecipient(), 0); + try { + service.linkToDeath(new GateKeeperDiedRecipient(), 0); + } catch (RemoteException e) { + Slog.w(TAG, " Unable to register death recipient", e); + } mGateKeeperService = IGateKeeperService.Stub.asInterface(service); return mGateKeeperService; } @@ -2321,6 +2331,14 @@ public class LockSettingsService extends ILockSettings.Stub { return null; } + private void gateKeeperClearSecureUserId(int userId) { + try { + getGateKeeperService().clearSecureUserId(userId); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to clear SID", e); + } + } + /** * A user's synthetic password does not change so it must be cached in certain circumstances to * enable untrusted credential reset. @@ -2330,7 +2348,7 @@ public class LockSettingsService extends ILockSettings.Stub { * credential. */ @GuardedBy("mSpManager") - private SparseArray<AuthenticationToken> mSpCache = new SparseArray(); + private SparseArray<AuthenticationToken> mSpCache = new SparseArray<>(); private void onAuthTokenKnownForUser(@UserIdInt int userId, AuthenticationToken auth) { // Preemptively cache the SP and then try to remove it in a handler. @@ -2435,8 +2453,7 @@ public class LockSettingsService extends ILockSettings.Stub { @GuardedBy("mSpManager") @VisibleForTesting protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash, - byte[] credential, int credentialType, int requestedQuality, - int userId) throws RemoteException { + byte[] credential, int credentialType, int requestedQuality, int userId) { Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId); final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid( getGateKeeperService(), credentialHash, credential, userId); @@ -2459,10 +2476,10 @@ public class LockSettingsService extends ILockSettings.Stub { } else { clearUserKeyProtection(userId); setKeystorePassword(null, userId); - getGateKeeperService().clearSecureUserId(userId); + gateKeeperClearSecureUserId(userId); } fixateNewestUserKeyAuth(userId); - setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, handle, userId); + setSyntheticPasswordHandleLocked(handle, userId); return auth; } @@ -2471,6 +2488,14 @@ public class LockSettingsService extends ILockSettings.Stub { SyntheticPasswordManager.DEFAULT_HANDLE, userId); } + private void setSyntheticPasswordHandleLocked(long handle, int userId) { + final long oldHandle = getSyntheticPasswordHandleLocked(userId); + setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, handle, userId); + setLong(PREV_SYNTHETIC_PASSWORD_HANDLE_KEY, oldHandle, userId); + setLong(SYNTHETIC_PASSWORD_UPDATE_TIME_KEY, System.currentTimeMillis(), userId); + + } + private boolean isSyntheticPasswordBasedCredentialLocked(int userId) { if (userId == USER_FRP) { final int type = mStorage.readPersistentDataBlock().type; @@ -2499,7 +2524,7 @@ public class LockSettingsService extends ILockSettings.Stub { private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential, @CredentialType int credentialType, @ChallengeType int challengeType, long challenge, int userId, ICheckCredentialProgressCallback progressCallback, - @Nullable ArrayList<PendingResetLockout> resetLockouts) throws RemoteException { + @Nullable ArrayList<PendingResetLockout> resetLockouts) { final boolean hasEnrolledBiometrics = mInjector.hasEnrolledBiometrics(userId); @@ -2606,7 +2631,7 @@ public class LockSettingsService extends ILockSettings.Stub { @GuardedBy("mSpManager") private long setLockCredentialWithAuthTokenLocked(byte[] credential, @CredentialType int credentialType, AuthenticationToken auth, int requestedQuality, - int userId) throws RemoteException { + int userId) { if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId); long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(), credential, credentialType, auth, requestedQuality, userId); @@ -2638,7 +2663,7 @@ public class LockSettingsService extends ILockSettings.Stub { // we are clearing password of a secured device, so need to nuke SID as well. mSpManager.clearSidForUser(userId); - getGateKeeperService().clearSecureUserId(userId); + gateKeeperClearSecureUserId(userId); // Clear key from vold so ActivityManager can just unlock the user with empty secret // during boot. Vold storage needs to be unlocked before manipulation of the keys can // succeed. @@ -2648,7 +2673,7 @@ public class LockSettingsService extends ILockSettings.Stub { unlockKeystore(auth.deriveKeyStorePassword(), userId); setKeystorePassword(null, userId); } - setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, newHandle, userId); + setSyntheticPasswordHandleLocked(newHandle, userId); synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords); notifyActivePasswordMetricsAvailable(credentialType, credential, userId); @@ -2665,7 +2690,7 @@ public class LockSettingsService extends ILockSettings.Stub { @GuardedBy("mSpManager") private void spBasedSetLockCredentialInternalLocked(byte[] credential, int credentialType, byte[] savedCredential, int requestedQuality, int userId, - boolean allowUntrustedChange, boolean isLockTiedToParent) throws RemoteException { + boolean allowUntrustedChange, boolean isLockTiedToParent) { if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId); if (isManagedProfileWithUnifiedLock(userId)) { // get credential from keystore when managed profile has unified lock @@ -2688,9 +2713,8 @@ public class LockSettingsService extends ILockSettings.Stub { // If existing credential is provided, the existing credential must match. if (savedCredential != null && auth == null) { - throw new IllegalStateException("Failed to enroll " - + (credentialType == CREDENTIAL_TYPE_PASSWORD - ? "password" : "pattern")); + throw new IllegalStateException(String.format("Failed to enroll %s", + credentialType == CREDENTIAL_TYPE_PASSWORD ? "password" : "pattern")); } boolean untrustedReset = false; if (auth != null) { @@ -2741,7 +2765,7 @@ public class LockSettingsService extends ILockSettings.Stub { * If user is a managed profile with unified challenge, currentCredential is ignored. */ @Override - public byte[] getHashFactor(byte[] currentCredential, int userId) throws RemoteException { + public byte[] getHashFactor(byte[] currentCredential, int userId) { checkPasswordReadPermission(userId); if (currentCredential == null || currentCredential.length == 0) { currentCredential = null; @@ -2770,8 +2794,7 @@ public class LockSettingsService extends ILockSettings.Stub { } } - private long addEscrowToken(byte[] token, int userId, EscrowTokenStateChangeCallback callback) - throws RemoteException { + private long addEscrowToken(byte[] token, int userId, EscrowTokenStateChangeCallback callback) { if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId); synchronized (mSpManager) { enableSyntheticPasswordLocked(); @@ -2847,7 +2870,7 @@ public class LockSettingsService extends ILockSettings.Stub { } private boolean setLockCredentialWithToken(byte[] credential, int type, long tokenHandle, - byte[] token, int requestedQuality, int userId) throws RemoteException { + byte[] token, int requestedQuality, int userId) { boolean result; synchronized (mSpManager) { if (!mSpManager.hasEscrowData(userId)) { @@ -2874,8 +2897,7 @@ public class LockSettingsService extends ILockSettings.Stub { @GuardedBy("mSpManager") private boolean setLockCredentialWithTokenInternalLocked(byte[] credential, int type, - long tokenHandle, byte[] token, int requestedQuality, int userId) - throws RemoteException { + long tokenHandle, byte[] token, int requestedQuality, int userId) { final AuthenticationResult result; result = mSpManager.unwrapTokenBasedSyntheticPassword( getGateKeeperService(), tokenHandle, token, userId); @@ -2901,8 +2923,7 @@ public class LockSettingsService extends ILockSettings.Stub { return true; } - private boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) - throws RemoteException { + private boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) { AuthenticationResult authResult; synchronized (mSpManager) { if (!mSpManager.hasEscrowData(userId)) { @@ -2920,29 +2941,57 @@ public class LockSettingsService extends ILockSettings.Stub { return true; } + static String timestampToString(long timestamp) { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timestamp)); + } + @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args){ - if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; + protected void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { + if (!DumpUtils.checkDumpPermission(mContext, TAG, printWriter)) return; + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println("Current lock settings service state:"); + pw.println(String.format("SP Enabled = %b", mLockPatternUtils.isSyntheticPasswordEnabled())); + pw.println(); + pw.println("User State:"); + pw.increaseIndent(); List<UserInfo> users = mUserManager.getUsers(); for (int user = 0; user < users.size(); user++) { final int userId = users.get(user).id; - pw.println(" User " + userId); + pw.println("User " + userId); + pw.increaseIndent(); synchronized (mSpManager) { - pw.println(String.format(" SP Handle = %x", + pw.println(String.format("SP Handle: %x", getSyntheticPasswordHandleLocked(userId))); + pw.println(String.format("Last changed: %s (%x)", + timestampToString(getLong(SYNTHETIC_PASSWORD_UPDATE_TIME_KEY, 0, userId)), + getLong(PREV_SYNTHETIC_PASSWORD_HANDLE_KEY, 0, userId))); } try { - pw.println(String.format(" SID = %x", + pw.println(String.format("SID: %x", getGateKeeperService().getSecureUserId(userId))); } catch (RemoteException e) { // ignore. } + // It's OK to dump the password type since anyone with physical access can just + // observe it from the keyguard directly. + pw.println("PasswordType: " + getLong(LockPatternUtils.PASSWORD_TYPE_KEY, 0, userId)); + pw.println("hasPassword: " + havePassword(userId)); + pw.println("hasPattern: " + havePattern(userId)); // print raw credential type instead? + pw.println("SeparateChallenge: " + getSeparateProfileChallengeEnabled(userId)); + pw.decreaseIndent(); } + pw.println(); + pw.decreaseIndent(); + + pw.println("Storage:"); + pw.increaseIndent(); + mStorage.dump(pw); + pw.println(); + pw.decreaseIndent(); } private void disableEscrowTokenOnNonManagedDevicesIfNeeded(int userId) { @@ -3081,11 +3130,7 @@ public class LockSettingsService extends ILockSettings.Stub { @Override public long addEscrowToken(byte[] token, int userId, EscrowTokenStateChangeCallback callback) { - try { - return LockSettingsService.this.addEscrowToken(token, userId, callback); - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); - } + return LockSettingsService.this.addEscrowToken(token, userId, callback); } @Override @@ -3105,21 +3150,13 @@ public class LockSettingsService extends ILockSettings.Stub { throw new UnsupportedOperationException( "This operation requires secure lock screen feature."); } - try { - return LockSettingsService.this.setLockCredentialWithToken(credential, type, - tokenHandle, token, requestedQuality, userId); - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); - } + return LockSettingsService.this.setLockCredentialWithToken(credential, type, + tokenHandle, token, requestedQuality, userId); } @Override public boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId) { - try { - return LockSettingsService.this.unlockUserWithToken(tokenHandle, token, userId); - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); - } + return LockSettingsService.this.unlockUserWithToken(tokenHandle, token, userId); } } } diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java index 29b8aa2e12f4..fe12a945bd4c 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java @@ -35,6 +35,7 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternUtils.CredentialType; @@ -140,7 +141,7 @@ class LockSettingsStorage { dos.close(); return os.toByteArray(); } catch (IOException e) { - throw new RuntimeException(e); + throw new IllegalStateException("Fail to serialze credential hash", e); } } @@ -157,7 +158,7 @@ class LockSettingsStorage { } return new CredentialHash(hash, type); } catch (IOException e) { - throw new RuntimeException(e); + throw new IllegalStateException("Fail to deserialze credential hash", e); } } } @@ -666,7 +667,7 @@ class LockSettingsStorage { dos.writeInt(qualityForUi); dos.write(payload); } catch (IOException e) { - throw new RuntimeException("ByteArrayOutputStream cannot throw IOException"); + throw new IllegalStateException("ByteArrayOutputStream cannot throw IOException"); } return os.toByteArray(); } @@ -676,6 +677,26 @@ class LockSettingsStorage { void initialize(SQLiteDatabase db); } + public void dump(IndentingPrintWriter pw) { + final UserManager um = UserManager.get(mContext); + for (UserInfo user : um.getUsers(false)) { + File userPath = getSyntheticPasswordDirectoryForUser(user.id); + pw.println(String.format("User %d [%s]:", user.id, userPath.getAbsolutePath())); + pw.increaseIndent(); + File[] files = userPath.listFiles(); + if (files != null) { + for (File file : files) { + pw.println(String.format("%4d %s %s", file.length(), + LockSettingsService.timestampToString(file.lastModified()), + file.getName())); + } + } else { + pw.println("[Not found]"); + } + pw.decreaseIndent(); + } + } + static class DatabaseHelper extends SQLiteOpenHelper { private static final String TAG = "LockSettingsDB"; private static final String DATABASE_NAME = "locksettings.db"; diff --git a/services/core/java/com/android/server/locksettings/PasswordSlotManager.java b/services/core/java/com/android/server/locksettings/PasswordSlotManager.java index 4ef63c05325c..17aca1576e40 100644 --- a/services/core/java/com/android/server/locksettings/PasswordSlotManager.java +++ b/services/core/java/com/android/server/locksettings/PasswordSlotManager.java @@ -109,7 +109,7 @@ public class PasswordSlotManager { public void markSlotInUse(int slot) throws RuntimeException { ensureSlotMapLoaded(); if (mSlotMap.containsKey(slot) && !mSlotMap.get(slot).equals(getMode())) { - throw new RuntimeException("password slot " + slot + " is not available"); + throw new IllegalStateException("password slot " + slot + " is not available"); } mSlotMap.put(slot, getMode()); saveSlotMap(); @@ -123,7 +123,7 @@ public class PasswordSlotManager { public void markSlotDeleted(int slot) throws RuntimeException { ensureSlotMapLoaded(); if (mSlotMap.containsKey(slot) && !mSlotMap.get(slot).equals(getMode())) { - throw new RuntimeException("password slot " + slot + " cannot be deleted"); + throw new IllegalStateException("password slot " + slot + " cannot be deleted"); } mSlotMap.remove(slot); saveSlotMap(); diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java index 388e51f203ca..ea0fb47a49b3 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java @@ -18,6 +18,7 @@ package com.android.server.locksettings; import android.security.keystore.KeyProperties; import android.security.keystore.KeyProtection; +import android.util.Slog; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -43,6 +44,7 @@ import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; public class SyntheticPasswordCrypto { + private static final String TAG = "SyntheticPasswordCrypto"; private static final int PROFILE_KEY_IV_SIZE = 12; private static final int DEFAULT_TAG_LENGTH_BITS = 128; private static final int AES_KEY_LENGTH = 32; // 256-bit AES key @@ -80,12 +82,12 @@ public class SyntheticPasswordCrypto { byte[] ciphertext = cipher.doFinal(blob); byte[] iv = cipher.getIV(); if (iv.length != PROFILE_KEY_IV_SIZE) { - throw new RuntimeException("Invalid iv length: " + iv.length); + throw new IllegalArgumentException("Invalid iv length: " + iv.length); } final GCMParameterSpec spec = cipher.getParameters().getParameterSpec( GCMParameterSpec.class); if (spec.getTLen() != DEFAULT_TAG_LENGTH_BITS) { - throw new RuntimeException("Invalid tag length: " + spec.getTLen()); + throw new IllegalArgumentException("Invalid tag length: " + spec.getTLen()); } ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); outputStream.write(iv); @@ -102,7 +104,7 @@ public class SyntheticPasswordCrypto { } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | IOException | InvalidParameterSpecException e) { - e.printStackTrace(); + Slog.e(TAG, "Failed to encrypt", e); return null; } } @@ -116,7 +118,7 @@ public class SyntheticPasswordCrypto { } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) { - e.printStackTrace(); + Slog.e(TAG, "Failed to decrypt", e); return null; } } @@ -130,8 +132,8 @@ public class SyntheticPasswordCrypto { byte[] intermediate = decrypt(applicationId, APPLICATION_ID_PERSONALIZATION, blob); return decrypt(decryptionKey, intermediate); } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("Failed to decrypt blob", e); + Slog.e(TAG, "Failed to decrypt V1 blob", e); + throw new IllegalStateException("Failed to decrypt blob", e); } } @@ -148,8 +150,8 @@ public class SyntheticPasswordCrypto { | KeyStoreException | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | UnrecoverableKeyException | InvalidAlgorithmParameterException e) { - e.printStackTrace(); - throw new RuntimeException("Failed to decrypt blob", e); + Slog.e(TAG, "Failed to decrypt blob", e); + throw new IllegalStateException("Failed to decrypt blob", e); } } @@ -180,8 +182,8 @@ public class SyntheticPasswordCrypto { | KeyStoreException | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | InvalidParameterSpecException e) { - e.printStackTrace(); - throw new RuntimeException("Failed to encrypt blob", e); + Slog.e(TAG, "Failed to create blob", e); + throw new IllegalStateException("Failed to encrypt blob", e); } } @@ -193,7 +195,7 @@ public class SyntheticPasswordCrypto { keyStore.deleteEntry(keyAlias); } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) { - e.printStackTrace(); + Slog.e(TAG, "Failed to destroy blob", e); } } @@ -202,7 +204,7 @@ public class SyntheticPasswordCrypto { final int PADDING_LENGTH = 128; MessageDigest digest = MessageDigest.getInstance("SHA-512"); if (personalisation.length > PADDING_LENGTH) { - throw new RuntimeException("Personalisation too long"); + throw new IllegalArgumentException("Personalisation too long"); } // Personalize the hash // Pad it to the block size of the hash function @@ -213,7 +215,7 @@ public class SyntheticPasswordCrypto { } return digest.digest(); } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("NoSuchAlgorithmException for SHA-512", e); + throw new IllegalStateException("NoSuchAlgorithmException for SHA-512", e); } } } diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index 1ba0e8ce7839..955a9aa8d0de 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -349,25 +349,28 @@ public class SyntheticPasswordManager { * a default all-zero key is used. If the value is not specified, a fresh random secret is * generated as the value. * - * @return the value stored in the weaver slot - * @throws RemoteException + * @return the value stored in the weaver slot, or null if the operation fails */ - private byte[] weaverEnroll(int slot, byte[] key, @Nullable byte[] value) - throws RemoteException { + private byte[] weaverEnroll(int slot, byte[] key, @Nullable byte[] value) { if (slot == INVALID_WEAVER_SLOT || slot >= mWeaverConfig.slots) { - throw new RuntimeException("Invalid slot for weaver"); + throw new IllegalArgumentException("Invalid slot for weaver"); } if (key == null) { key = new byte[mWeaverConfig.keySize]; } else if (key.length != mWeaverConfig.keySize) { - throw new RuntimeException("Invalid key size for weaver"); + throw new IllegalArgumentException("Invalid key size for weaver"); } if (value == null) { value = secureRandom(mWeaverConfig.valueSize); } - int writeStatus = mWeaver.write(slot, toByteArrayList(key), toByteArrayList(value)); - if (writeStatus != WeaverStatus.OK) { - Log.e(TAG, "weaver write failed, slot: " + slot + " status: " + writeStatus); + try { + int writeStatus = mWeaver.write(slot, toByteArrayList(key), toByteArrayList(value)); + if (writeStatus != WeaverStatus.OK) { + Log.e(TAG, "weaver write failed, slot: " + slot + " status: " + writeStatus); + return null; + } + } catch (RemoteException e) { + Log.e(TAG, "weaver write failed", e); return null; } return value; @@ -377,47 +380,53 @@ public class SyntheticPasswordManager { * Verify the supplied key against a weaver slot, returning a response indicating whether * the verification is successful, throttled or failed. If successful, the bound secret * is also returned. - * @throws RemoteException */ - private VerifyCredentialResponse weaverVerify(int slot, byte[] key) throws RemoteException { + private VerifyCredentialResponse weaverVerify(int slot, byte[] key) { if (slot == INVALID_WEAVER_SLOT || slot >= mWeaverConfig.slots) { - throw new RuntimeException("Invalid slot for weaver"); + throw new IllegalArgumentException("Invalid slot for weaver"); } if (key == null) { key = new byte[mWeaverConfig.keySize]; } else if (key.length != mWeaverConfig.keySize) { - throw new RuntimeException("Invalid key size for weaver"); + throw new IllegalArgumentException("Invalid key size for weaver"); } final VerifyCredentialResponse[] response = new VerifyCredentialResponse[1]; - mWeaver.read(slot, toByteArrayList(key), (int status, WeaverReadResponse readResponse) -> { - switch (status) { - case WeaverReadStatus.OK: - response[0] = new VerifyCredentialResponse( - fromByteArrayList(readResponse.value)); - break; - case WeaverReadStatus.THROTTLE: - response[0] = new VerifyCredentialResponse(readResponse.timeout); - Log.e(TAG, "weaver read failed (THROTTLE), slot: " + slot); - break; - case WeaverReadStatus.INCORRECT_KEY: - if (readResponse.timeout == 0) { - response[0] = VerifyCredentialResponse.ERROR; - Log.e(TAG, "weaver read failed (INCORRECT_KEY), slot: " + slot); - } else { - response[0] = new VerifyCredentialResponse(readResponse.timeout); - Log.e(TAG, "weaver read failed (INCORRECT_KEY/THROTTLE), slot: " + slot); + try { + mWeaver.read(slot, toByteArrayList(key), + (int status, WeaverReadResponse readResponse) -> { + switch (status) { + case WeaverReadStatus.OK: + response[0] = new VerifyCredentialResponse( + fromByteArrayList(readResponse.value)); + break; + case WeaverReadStatus.THROTTLE: + response[0] = new VerifyCredentialResponse(readResponse.timeout); + Log.e(TAG, "weaver read failed (THROTTLE), slot: " + slot); + break; + case WeaverReadStatus.INCORRECT_KEY: + if (readResponse.timeout == 0) { + response[0] = VerifyCredentialResponse.ERROR; + Log.e(TAG, "weaver read failed (INCORRECT_KEY), slot: " + slot); + } else { + response[0] = new VerifyCredentialResponse(readResponse.timeout); + Log.e(TAG, "weaver read failed (INCORRECT_KEY/THROTTLE), slot: " + + slot); + } + break; + case WeaverReadStatus.FAILED: + response[0] = VerifyCredentialResponse.ERROR; + Log.e(TAG, "weaver read failed (FAILED), slot: " + slot); + break; + default: + response[0] = VerifyCredentialResponse.ERROR; + Log.e(TAG, "weaver read unknown status " + status + ", slot: " + slot); + break; } - break; - case WeaverReadStatus.FAILED: - response[0] = VerifyCredentialResponse.ERROR; - Log.e(TAG, "weaver read failed (FAILED), slot: " + slot); - break; - default: - response[0] = VerifyCredentialResponse.ERROR; - Log.e(TAG, "weaver read unknown status " + status + ", slot: " + slot); - break; - } - }); + }); + } catch (RemoteException e) { + response[0] = VerifyCredentialResponse.ERROR; + Log.e(TAG, "weaver read failed, slot: " + slot, e); + } return response[0]; } @@ -460,12 +469,15 @@ public class SyntheticPasswordManager { * */ public AuthenticationToken newSyntheticPasswordAndSid(IGateKeeperService gatekeeper, - byte[] hash, byte[] credential, int userId) throws RemoteException { + byte[] hash, byte[] credential, int userId) { AuthenticationToken result = AuthenticationToken.create(); GateKeeperResponse response; if (hash != null) { - response = gatekeeper.enroll(userId, hash, credential, - result.deriveGkPassword()); + try { + response = gatekeeper.enroll(userId, hash, credential, result.deriveGkPassword()); + } catch (RemoteException e) { + throw new IllegalStateException("Failed to enroll credential duing SP init", e); + } if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) { Log.w(TAG, "Fail to migrate SID, assuming no SID, user " + userId); clearSidForUser(userId); @@ -484,9 +496,13 @@ public class SyntheticPasswordManager { * Used when adding password to previously-unsecured devices. */ public void newSidForUser(IGateKeeperService gatekeeper, AuthenticationToken authToken, - int userId) throws RemoteException { - GateKeeperResponse response = gatekeeper.enroll(userId, null, null, - authToken.deriveGkPassword()); + int userId) { + GateKeeperResponse response; + try { + response = gatekeeper.enroll(userId, null, null, authToken.deriveGkPassword()); + } catch (RemoteException e) { + throw new IllegalStateException("Failed to create new SID for user", e); + } if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) { Log.e(TAG, "Fail to create new SID for user " + userId); return; @@ -565,12 +581,8 @@ public class SyntheticPasswordManager { Set<Integer> usedSlots = getUsedWeaverSlots(); if (!usedSlots.contains(slot)) { Log.i(TAG, "Destroy weaver slot " + slot + " for user " + userId); - try { - weaverEnroll(slot, null, null); - mPasswordSlotManager.markSlotDeleted(slot); - } catch (RemoteException e) { - Log.w(TAG, "Failed to destroy slot", e); - } + weaverEnroll(slot, null, null); + mPasswordSlotManager.markSlotDeleted(slot); } else { Log.w(TAG, "Skip destroying reused weaver slot " + slot + " for user " + userId); } @@ -608,7 +620,7 @@ public class SyntheticPasswordManager { return i; } } - throw new RuntimeException("Run out of weaver slots."); + throw new IllegalStateException("Run out of weaver slots."); } /** @@ -622,11 +634,12 @@ public class SyntheticPasswordManager { * * @see #newSidForUser * @see #clearSidForUser + * @return a new password handle for the wrapped SP blob + * @throw IllegalStateException if creation fails. */ public long createPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper, byte[] credential, int credentialType, AuthenticationToken authToken, - int requestedQuality, int userId) - throws RemoteException { + int requestedQuality, int userId) { if (credential == null || credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) { credentialType = LockPatternUtils.CREDENTIAL_TYPE_NONE; credential = DEFAULT_PASSWORD; @@ -642,10 +655,11 @@ public class SyntheticPasswordManager { // Weaver based user password int weaverSlot = getNextAvailableWeaverSlot(); Log.i(TAG, "Weaver enroll password to slot " + weaverSlot + " for user " + userId); - byte[] weaverSecret = weaverEnroll(weaverSlot, passwordTokenToWeaverKey(pwdToken), null); + byte[] weaverSecret = weaverEnroll(weaverSlot, passwordTokenToWeaverKey(pwdToken), + null); if (weaverSecret == null) { - Log.e(TAG, "Fail to enroll user password under weaver " + userId); - return DEFAULT_HANDLE; + throw new IllegalStateException( + "Fail to enroll user password under weaver " + userId); } saveWeaverSlot(weaverSlot, handle, userId); mPasswordSlotManager.markSlotInUse(weaverSlot); @@ -657,13 +671,22 @@ public class SyntheticPasswordManager { } else { // In case GK enrollment leaves persistent state around (in RPMB), this will nuke them // to prevent them from accumulating and causing problems. - gatekeeper.clearSecureUserId(fakeUid(userId)); + try { + gatekeeper.clearSecureUserId(fakeUid(userId)); + } catch (RemoteException ignore) { + Log.w(TAG, "Failed to clear SID from gatekeeper"); + } // GateKeeper based user password - GateKeeperResponse response = gatekeeper.enroll(fakeUid(userId), null, null, - passwordTokenToGkInput(pwdToken)); + GateKeeperResponse response; + try { + response = gatekeeper.enroll(fakeUid(userId), null, null, + passwordTokenToGkInput(pwdToken)); + } catch (RemoteException e) { + throw new IllegalStateException("Failed to enroll password for new SP blob", e); + } if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) { - Log.e(TAG, "Fail to enroll user password when creating SP for user " + userId); - return DEFAULT_HANDLE; + throw new IllegalStateException( + "Fail to enroll user password when creating SP for user " + userId); } pwd.passwordHandle = response.getPayload(); sid = sidFromPasswordHandle(pwd.passwordHandle); @@ -680,14 +703,20 @@ public class SyntheticPasswordManager { public VerifyCredentialResponse verifyFrpCredential(IGateKeeperService gatekeeper, byte[] userCredential, int credentialType, - ICheckCredentialProgressCallback progressCallback) throws RemoteException { + ICheckCredentialProgressCallback progressCallback) { PersistentData persistentData = mStorage.readPersistentDataBlock(); if (persistentData.type == PersistentData.TYPE_SP) { PasswordData pwd = PasswordData.fromBytes(persistentData.payload); byte[] pwdToken = computePasswordToken(userCredential, pwd); - GateKeeperResponse response = gatekeeper.verifyChallenge(fakeUid(persistentData.userId), - 0 /* challenge */, pwd.passwordHandle, passwordTokenToGkInput(pwdToken)); + GateKeeperResponse response; + try { + response = gatekeeper.verifyChallenge(fakeUid(persistentData.userId), + 0 /* challenge */, pwd.passwordHandle, passwordTokenToGkInput(pwdToken)); + } catch (RemoteException e) { + Log.e(TAG, "FRP verifyChallenge failed", e); + return VerifyCredentialResponse.ERROR; + } return VerifyCredentialResponse.fromGateKeeperResponse(response); } else if (persistentData.type == PersistentData.TYPE_SP_WEAVER) { PasswordData pwd = PasswordData.fromBytes(persistentData.payload); @@ -805,11 +834,9 @@ public class SyntheticPasswordManager { } if (isWeaverAvailable()) { int slot = getNextAvailableWeaverSlot(); - try { - Log.i(TAG, "Weaver enroll token to slot " + slot + " for user " + userId); - weaverEnroll(slot, null, tokenData.weaverSecret); - } catch (RemoteException e) { - Log.e(TAG, "Failed to enroll weaver secret when activating token", e); + Log.i(TAG, "Weaver enroll token to slot " + slot + " for user " + userId); + if (weaverEnroll(slot, null, tokenData.weaverSecret) == null) { + Log.e(TAG, "Failed to enroll weaver secret when activating token"); return false; } saveWeaverSlot(slot, handle, userId); @@ -859,7 +886,7 @@ public class SyntheticPasswordManager { */ public AuthenticationResult unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper, long handle, byte[] credential, int userId, - ICheckCredentialProgressCallback progressCallback) throws RemoteException { + ICheckCredentialProgressCallback progressCallback) { if (credential == null) { credential = DEFAULT_PASSWORD; } @@ -886,14 +913,28 @@ public class SyntheticPasswordManager { applicationId = transformUnderWeaverSecret(pwdToken, result.gkResponse.getPayload()); } else { byte[] gkPwdToken = passwordTokenToGkInput(pwdToken); - GateKeeperResponse response = gatekeeper.verifyChallenge(fakeUid(userId), 0L, - pwd.passwordHandle, gkPwdToken); + GateKeeperResponse response; + try { + response = gatekeeper.verifyChallenge(fakeUid(userId), 0L, + pwd.passwordHandle, gkPwdToken); + } catch (RemoteException e) { + Log.e(TAG, "gatekeeper verify failed", e); + result.gkResponse = VerifyCredentialResponse.ERROR; + return result; + } int responseCode = response.getResponseCode(); if (responseCode == GateKeeperResponse.RESPONSE_OK) { result.gkResponse = VerifyCredentialResponse.OK; if (response.getShouldReEnroll()) { - GateKeeperResponse reenrollResponse = gatekeeper.enroll(fakeUid(userId), - pwd.passwordHandle, gkPwdToken, gkPwdToken); + GateKeeperResponse reenrollResponse; + try { + reenrollResponse = gatekeeper.enroll(fakeUid(userId), + pwd.passwordHandle, gkPwdToken, gkPwdToken); + } catch (RemoteException e) { + Log.w(TAG, "Fail to invoke gatekeeper.enroll", e); + reenrollResponse = GateKeeperResponse.ERROR; + // continue the flow anyway + } if (reenrollResponse.getResponseCode() == GateKeeperResponse.RESPONSE_OK) { pwd.passwordHandle = reenrollResponse.getPayload(); saveState(PASSWORD_DATA_NAME, pwd.toBytes(), handle, userId); @@ -922,7 +963,11 @@ public class SyntheticPasswordManager { // Supplied credential passes first stage weaver/gatekeeper check so it should be correct. // Notify the callback so the keyguard UI can proceed immediately. if (progressCallback != null) { - progressCallback.onCredentialVerified(); + try { + progressCallback.onCredentialVerified(); + } catch (RemoteException e) { + Log.w(TAG, "progressCallback throws exception", e); + } } result.authToken = unwrapSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_PASSWORD_BASED, applicationId, sid, userId); @@ -938,8 +983,7 @@ public class SyntheticPasswordManager { * verification to referesh the SID & Auth token maintained by the system. */ public @NonNull AuthenticationResult unwrapTokenBasedSyntheticPassword( - IGateKeeperService gatekeeper, long handle, byte[] token, int userId) - throws RemoteException { + IGateKeeperService gatekeeper, long handle, byte[] token, int userId) { AuthenticationResult result = new AuthenticationResult(); byte[] secdiscardable = loadSecdiscardable(handle, userId); int slotId = loadWeaverSlot(handle, userId); @@ -985,10 +1029,10 @@ public class SyntheticPasswordManager { if (version != SYNTHETIC_PASSWORD_VERSION_V3 && version != SYNTHETIC_PASSWORD_VERSION_V2 && version != SYNTHETIC_PASSWORD_VERSION_V1) { - throw new RuntimeException("Unknown blob version"); + throw new IllegalArgumentException("Unknown blob version"); } if (blob[1] != type) { - throw new RuntimeException("Invalid blob type"); + throw new IllegalArgumentException("Invalid blob type"); } final byte[] secret; if (version == SYNTHETIC_PASSWORD_VERSION_V1) { @@ -1028,38 +1072,48 @@ public class SyntheticPasswordManager { * decrypt SP. */ public @Nullable VerifyCredentialResponse verifyChallenge(IGateKeeperService gatekeeper, - @NonNull AuthenticationToken auth, long challenge, int userId) throws RemoteException { + @NonNull AuthenticationToken auth, long challenge, int userId) { byte[] spHandle = loadSyntheticPasswordHandle(userId); if (spHandle == null) { // There is no password handle associated with the given user, i.e. the user is not // secured by lockscreen and has no SID, so just return here; return null; } - VerifyCredentialResponse result; - GateKeeperResponse response = gatekeeper.verifyChallenge(userId, challenge, - spHandle, auth.deriveGkPassword()); + GateKeeperResponse response; + try { + response = gatekeeper.verifyChallenge(userId, challenge, + spHandle, auth.deriveGkPassword()); + } catch (RemoteException e) { + Log.e(TAG, "Fail to verify with gatekeeper " + userId, e); + return VerifyCredentialResponse.ERROR; + } int responseCode = response.getResponseCode(); if (responseCode == GateKeeperResponse.RESPONSE_OK) { - result = new VerifyCredentialResponse(response.getPayload()); + VerifyCredentialResponse result = new VerifyCredentialResponse(response.getPayload()); if (response.getShouldReEnroll()) { - response = gatekeeper.enroll(userId, spHandle, - spHandle, auth.deriveGkPassword()); + try { + response = gatekeeper.enroll(userId, spHandle, spHandle, + auth.deriveGkPassword()); + } catch (RemoteException e) { + Log.e(TAG, "Failed to invoke gatekeeper.enroll", e); + response = GateKeeperResponse.ERROR; + } if (response.getResponseCode() == GateKeeperResponse.RESPONSE_OK) { spHandle = response.getPayload(); saveSyntheticPasswordHandle(spHandle, userId); // Call self again to re-verify with updated handle return verifyChallenge(gatekeeper, auth, challenge, userId); } else { + // Fall through, return result from the previous verification attempt. Log.w(TAG, "Fail to re-enroll SP handle for user " + userId); - // Fall through, return existing handle } } + return result; } else if (responseCode == GateKeeperResponse.RESPONSE_RETRY) { - result = new VerifyCredentialResponse(response.getTimeout()); + return new VerifyCredentialResponse(response.getTimeout()); } else { - result = VerifyCredentialResponse.ERROR; + return VerifyCredentialResponse.ERROR; } - return result; } public boolean existsHandle(long handle, int userId) { @@ -1183,7 +1237,7 @@ public class SyntheticPasswordManager { private byte[] passwordTokenToWeaverKey(byte[] token) { byte[] key = SyntheticPasswordCrypto.personalisedHash(PERSONALISATION_WEAVER_KEY, token); if (key.length < mWeaverConfig.keySize) { - throw new RuntimeException("weaver key length too small"); + throw new IllegalArgumentException("weaver key length too small"); } return Arrays.copyOf(key, mWeaverConfig.keySize); } diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index c05655a6a5de..193e0afc529e 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -1912,16 +1912,17 @@ public class MediaSessionService extends SystemService implements Monitor { && AudioSystem.isStreamActive(suggestedStream, 0)) { preferSuggestedStream = true; } - if (DEBUG_KEY_EVENT) { - Log.d(TAG, "Adjusting " + session + " by " + direction + ". flags=" - + flags + ", suggestedStream=" + suggestedStream - + ", preferSuggestedStream=" + preferSuggestedStream); - } if (session == null || preferSuggestedStream) { + if (DEBUG_KEY_EVENT) { + Log.d(TAG, "Adjusting suggestedStream=" + suggestedStream + " by " + direction + + ". flags=" + flags + ", preferSuggestedStream=" + + preferSuggestedStream + ", session=" + session); + } if ((flags & AudioManager.FLAG_ACTIVE_MEDIA_ONLY) != 0 && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) { - if (DEBUG) { - Log.d(TAG, "No active session to adjust, skipping media only volume event"); + if (DEBUG_KEY_EVENT) { + Log.d(TAG, "Nothing is playing on the music stream. Skipping volume event," + + " flags=" + flags); } return; } @@ -1955,6 +1956,11 @@ public class MediaSessionService extends SystemService implements Monitor { } }); } else { + if (DEBUG_KEY_EVENT) { + Log.d(TAG, "Adjusting " + session + " by " + direction + ". flags=" + + flags + ", suggestedStream=" + suggestedStream + + ", preferSuggestedStream=" + preferSuggestedStream); + } session.adjustVolume(packageName, opPackageName, pid, uid, null, asSystemService, direction, flags, true); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 6fe924e7432d..3ed776348f47 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -231,7 +231,7 @@ import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.internal.util.function.TriPredicate; -import com.android.server.DeviceIdleController; +import com.android.server.DeviceIdleInternal; import com.android.server.EventLogTags; import com.android.server.IoThread; import com.android.server.LocalServices; @@ -315,7 +315,7 @@ public class NotificationManagerService extends SystemService { static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps - static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; + static final int INVALID_UID = -1; static final boolean ENABLE_BLOCKED_TOASTS = true; @@ -621,6 +621,8 @@ public class NotificationManagerService extends SystemService { mConditionProviders.readXml( parser, mAllowedManagedServicePackages, forRestore, userId); migratedManagedServices = true; + } else if (mSnoozeHelper.XML_TAG_NAME.equals(parser.getName())) { + mSnoozeHelper.readXml(parser); } if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) { if (forRestore && userId != UserHandle.USER_SYSTEM) { @@ -709,6 +711,7 @@ public class NotificationManagerService extends SystemService { mPreferencesHelper.writeXml(out, forBackup, userId); mListeners.writeXml(out, forBackup, userId); mAssistants.writeXml(out, forBackup, userId); + mSnoozeHelper.writeXml(out); mConditionProviders.writeXml(out, forBackup, userId); if (!forBackup || userId == UserHandle.USER_SYSTEM) { writeSecureNotificationsPolicy(out); @@ -1753,6 +1756,7 @@ public class NotificationManagerService extends SystemService { com.android.internal.R.integer.config_notificationWarnRemoteViewSizeBytes); mStripRemoteViewsSizeBytes = getContext().getResources().getInteger( com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes); + } @Override @@ -4695,6 +4699,12 @@ public class NotificationManagerService extends SystemService { // ensure opPkg is delegate if does not match pkg int uid = resolveNotificationUid(opPkg, pkg, callingUid, userId); + if (uid == INVALID_UID) { + Slog.w(TAG, opPkg + ":" + callingUid + " trying to cancel notification " + + "for nonexistent pkg " + pkg + " in user " + userId); + return; + } + // if opPkg is not the same as pkg, make sure the notification given was posted // by opPkg if (!Objects.equals(pkg, opPkg)) { @@ -4739,6 +4749,11 @@ public class NotificationManagerService extends SystemService { // as "pkg" final int notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId); + if (notificationUid == INVALID_UID) { + throw new SecurityException("Caller " + opPkg + ":" + callingUid + + " trying to post for invalid pkg " + pkg + " in user " + incomingUserId); + } + checkRestrictedCategories(notification); // Fix the notification as best we can. @@ -4830,7 +4845,7 @@ public class NotificationManagerService extends SystemService { final ActivityManagerInternal am = LocalServices .getService(ActivityManagerInternal.class); final long duration = LocalServices.getService( - DeviceIdleController.LocalService.class).getNotificationWhitelistDuration(); + DeviceIdleInternal.class).getNotificationWhitelistDuration(); for (int i = 0; i < intentCount; i++) { PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i); if (pendingIntent != null) { @@ -5059,8 +5074,7 @@ public class NotificationManagerService extends SystemService { } @VisibleForTesting - int resolveNotificationUid(String callingPkg, String targetPkg, - int callingUid, int userId) { + int resolveNotificationUid(String callingPkg, String targetPkg, int callingUid, int userId) { if (userId == UserHandle.USER_ALL) { userId = USER_SYSTEM; } @@ -5071,16 +5085,16 @@ public class NotificationManagerService extends SystemService { return callingUid; } - int targetUid = -1; + int targetUid = INVALID_UID; try { targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId); } catch (NameNotFoundException e) { - /* ignore */ + /* ignore, handled by caller */ } // posted from app A on behalf of app B - if (targetUid != -1 && (isCallerAndroid(callingPkg, callingUid) + if (isCallerAndroid(callingPkg, callingUid) || mPreferencesHelper.isDelegateAllowed( - targetPkg, targetUid, callingPkg, callingUid))) { + targetPkg, targetUid, callingPkg, callingUid)) { return targetUid; } @@ -5284,7 +5298,7 @@ public class NotificationManagerService extends SystemService { updateLightsLocked(); if (mSnoozeCriterionId != null) { mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId); - mSnoozeHelper.snooze(r); + mSnoozeHelper.snooze(r, mSnoozeCriterionId); } else { mSnoozeHelper.snooze(r, mDuration); } @@ -5387,6 +5401,27 @@ public class NotificationManagerService extends SystemService { @Override public void run() { synchronized (mNotificationLock) { + final Long snoozeAt = + mSnoozeHelper.getSnoozeTimeForUnpostedNotification( + r.getUser().getIdentifier(), + r.sbn.getPackageName(), r.sbn.getKey()); + final long currentTime = System.currentTimeMillis(); + if (snoozeAt.longValue() > currentTime) { + (new SnoozeNotificationRunnable(r.sbn.getKey(), + snoozeAt.longValue() - currentTime, null)).snoozeLocked(r); + return; + } + + final String contextId = + mSnoozeHelper.getSnoozeContextForUnpostedNotification( + r.getUser().getIdentifier(), + r.sbn.getPackageName(), r.sbn.getKey()); + if (contextId != null) { + (new SnoozeNotificationRunnable(r.sbn.getKey(), + 0, contextId)).snoozeLocked(r); + return; + } + mEnqueuedNotifications.add(r); scheduleTimeoutLocked(r); @@ -6937,6 +6972,7 @@ public class NotificationManagerService extends SystemService { if (DBG) { Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName)); } + mSnoozeHelper.cleanupPersistedContext(key); mSnoozeHelper.repost(key); handleSavePolicyFile(); } diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java index 91f497cf9607..8125d0d653ad 100644 --- a/services/core/java/com/android/server/notification/SnoozeHelper.java +++ b/services/core/java/com/android/server/notification/SnoozeHelper.java @@ -55,6 +55,21 @@ import java.util.Set; * NotificationManagerService helper for handling snoozed notifications. */ public class SnoozeHelper { + public static final String XML_SNOOZED_NOTIFICATION_VERSION = "1"; + + protected static final String XML_TAG_NAME = "snoozed-notifications"; + + private static final String XML_SNOOZED_NOTIFICATION = "notification"; + private static final String XML_SNOOZED_NOTIFICATION_CONTEXT = "context"; + private static final String XML_SNOOZED_NOTIFICATION_PKG = "pkg"; + private static final String XML_SNOOZED_NOTIFICATION_USER_ID = "user-id"; + private static final String XML_SNOOZED_NOTIFICATION_KEY = "key"; + //the time the snoozed notification should be reposted + private static final String XML_SNOOZED_NOTIFICATION_TIME = "time"; + private static final String XML_SNOOZED_NOTIFICATION_CONTEXT_ID = "id"; + private static final String XML_SNOOZED_NOTIFICATION_VERSION_LABEL = "version"; + + private static final String TAG = "SnoozeHelper"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final String INDENT = " "; @@ -72,6 +87,17 @@ public class SnoozeHelper { // User id : package name : notification key : record. private ArrayMap<Integer, ArrayMap<String, ArrayMap<String, NotificationRecord>>> mSnoozedNotifications = new ArrayMap<>(); + // User id : package name : notification key : time-milliseconds . + // This member stores persisted snoozed notification trigger times. it persists through reboots + // It should have the notifications that haven't expired or re-posted yet + private ArrayMap<Integer, ArrayMap<String, ArrayMap<String, Long>>> + mPersistedSnoozedNotifications = new ArrayMap<>(); + // User id : package name : notification key : creation ID . + // This member stores persisted snoozed notification trigger context for the assistant + // it persists through reboots. + // It should have the notifications that haven't expired or re-posted yet + private ArrayMap<Integer, ArrayMap<String, ArrayMap<String, String>>> + mPersistedSnoozedNotificationsWithContext = new ArrayMap<>(); // notification key : package. private ArrayMap<String, String> mPackages = new ArrayMap<>(); // key : userId @@ -89,6 +115,34 @@ public class SnoozeHelper { mUserProfiles = userProfiles; } + void cleanupPersistedContext(String key){ + int userId = mUsers.get(key); + String pkg = mPackages.get(key); + synchronized (mPersistedSnoozedNotificationsWithContext) { + removeRecord(pkg, key, userId, mPersistedSnoozedNotificationsWithContext); + } + } + + //This function has a side effect of removing the time from the list of persisted notifications. + //IT IS NOT IDEMPOTENT! + @NonNull + protected Long getSnoozeTimeForUnpostedNotification(int userId, String pkg, String key) { + Long time; + synchronized (mPersistedSnoozedNotifications) { + time = removeRecord(pkg, key, userId, mPersistedSnoozedNotifications); + } + if (time == null) { + return 0L; + } + return time; + } + + protected String getSnoozeContextForUnpostedNotification(int userId, String pkg, String key) { + synchronized (mPersistedSnoozedNotificationsWithContext) { + return removeRecord(pkg, key, userId, mPersistedSnoozedNotificationsWithContext); + } + } + protected boolean isSnoozed(int userId, String pkg, String key) { return mSnoozedNotifications.containsKey(userId) && mSnoozedNotifications.get(userId).containsKey(pkg) @@ -169,32 +223,82 @@ public class SnoozeHelper { * Snoozes a notification and schedules an alarm to repost at that time. */ protected void snooze(NotificationRecord record, long duration) { + String pkg = record.sbn.getPackageName(); + String key = record.getKey(); + int userId = record.getUser().getIdentifier(); + snooze(record); - scheduleRepost(record.sbn.getPackageName(), record.getKey(), record.getUserId(), duration); + scheduleRepost(pkg, key, userId, duration); + Long activateAt = System.currentTimeMillis() + duration; + synchronized (mPersistedSnoozedNotifications) { + storeRecord(pkg, key, userId, mPersistedSnoozedNotifications, activateAt); + } } /** * Records a snoozed notification. */ - protected void snooze(NotificationRecord record) { + protected void snooze(NotificationRecord record, String contextId) { + int userId = record.getUser().getIdentifier(); + if (contextId != null) { + synchronized (mPersistedSnoozedNotificationsWithContext) { + storeRecord(record.sbn.getPackageName(), record.getKey(), + userId, mPersistedSnoozedNotificationsWithContext, contextId); + } + } + snooze(record); + } + + private void snooze(NotificationRecord record) { int userId = record.getUser().getIdentifier(); if (DEBUG) { Slog.d(TAG, "Snoozing " + record.getKey()); } - ArrayMap<String, ArrayMap<String, NotificationRecord>> records = - mSnoozedNotifications.get(userId); + storeRecord(record.sbn.getPackageName(), record.getKey(), + userId, mSnoozedNotifications, record); + mPackages.put(record.getKey(), record.sbn.getPackageName()); + mUsers.put(record.getKey(), userId); + } + + private <T> void storeRecord(String pkg, String key, Integer userId, + ArrayMap<Integer, ArrayMap<String, ArrayMap<String, T>>> targets, T object) { + + ArrayMap<String, ArrayMap<String, T>> records = + targets.get(userId); if (records == null) { records = new ArrayMap<>(); } - ArrayMap<String, NotificationRecord> pkgRecords = records.get(record.sbn.getPackageName()); + ArrayMap<String, T> pkgRecords = records.get(pkg); if (pkgRecords == null) { pkgRecords = new ArrayMap<>(); } - pkgRecords.put(record.getKey(), record); - records.put(record.sbn.getPackageName(), pkgRecords); - mSnoozedNotifications.put(userId, records); - mPackages.put(record.getKey(), record.sbn.getPackageName()); - mUsers.put(record.getKey(), userId); + pkgRecords.put(key, object); + records.put(pkg, pkgRecords); + targets.put(userId, records); + + } + + private <T> T removeRecord(String pkg, String key, Integer userId, + ArrayMap<Integer, ArrayMap<String, ArrayMap<String, T>>> targets) { + T object = null; + + ArrayMap<String, ArrayMap<String, T>> records = + targets.get(userId); + if (records == null) { + return null; + } + ArrayMap<String, T> pkgRecords = records.get(pkg); + if (pkgRecords == null) { + return null; + } + object = pkgRecords.remove(key); + if (pkgRecords.size() == 0) { + records.remove(pkg); + } + if (records.size() == 0) { + targets.remove(userId); + } + return object; } protected boolean cancel(int userId, String pkg, String tag, int id) { @@ -414,13 +518,121 @@ public class SnoozeHelper { } } - protected void writeXml(XmlSerializer out, boolean forBackup) throws IOException { + protected void writeXml(XmlSerializer out) throws IOException { + final long currentTime = System.currentTimeMillis(); + out.startTag(null, XML_TAG_NAME); + writeXml(out, mPersistedSnoozedNotifications, XML_SNOOZED_NOTIFICATION, + value -> { + if (value < currentTime) { + return; + } + out.attribute(null, XML_SNOOZED_NOTIFICATION_TIME, + value.toString()); + }); + writeXml(out, mPersistedSnoozedNotificationsWithContext, XML_SNOOZED_NOTIFICATION_CONTEXT, + value -> { + out.attribute(null, XML_SNOOZED_NOTIFICATION_CONTEXT_ID, + value); + }); + out.endTag(null, XML_TAG_NAME); + } + + private interface Inserter<T> { + void insert(T t) throws IOException; + } + private <T> void writeXml(XmlSerializer out, + ArrayMap<Integer, ArrayMap<String, ArrayMap<String, T>>> targets, String tag, + Inserter<T> attributeInserter) + throws IOException { + synchronized (targets) { + final int M = targets.size(); + for (int i = 0; i < M; i++) { + final ArrayMap<String, ArrayMap<String, T>> packages = + targets.valueAt(i); + if (packages == null) { + continue; + } + final int N = packages.size(); + for (int j = 0; j < N; j++) { + final ArrayMap<String, T> keyToValue = packages.valueAt(j); + if (keyToValue == null) { + continue; + } + final int O = keyToValue.size(); + for (int k = 0; k < O; k++) { + T value = keyToValue.valueAt(k); + + out.startTag(null, tag); + attributeInserter.insert(value); + + out.attribute(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL, + XML_SNOOZED_NOTIFICATION_VERSION); + out.attribute(null, XML_SNOOZED_NOTIFICATION_KEY, keyToValue.keyAt(k)); + out.attribute(null, XML_SNOOZED_NOTIFICATION_PKG, packages.keyAt(j)); + out.attribute(null, XML_SNOOZED_NOTIFICATION_USER_ID, + targets.keyAt(i).toString()); + + out.endTag(null, tag); + + } + } + } + } } - public void readXml(XmlPullParser parser, boolean forRestore) + protected void readXml(XmlPullParser parser) throws XmlPullParserException, IOException { + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { + String tag = parser.getName(); + if (type == XmlPullParser.END_TAG + && XML_TAG_NAME.equals(tag)) { + break; + } + if (type == XmlPullParser.START_TAG + && (XML_SNOOZED_NOTIFICATION.equals(tag) + || tag.equals(XML_SNOOZED_NOTIFICATION_CONTEXT)) + && parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL) + .equals(XML_SNOOZED_NOTIFICATION_VERSION)) { + try { + final String key = parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_KEY); + final String pkg = parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_PKG); + final int userId = Integer.parseInt( + parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_USER_ID)); + if (tag.equals(XML_SNOOZED_NOTIFICATION)) { + final Long time = Long.parseLong( + parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_TIME)); + if (time > System.currentTimeMillis()) { //only read new stuff + synchronized (mPersistedSnoozedNotifications) { + storeRecord(pkg, key, userId, mPersistedSnoozedNotifications, time); + } + scheduleRepost(pkg, key, userId, time - System.currentTimeMillis()); + } + continue; + } + if (tag.equals(XML_SNOOZED_NOTIFICATION_CONTEXT)) { + final String creationId = parser.getAttributeValue( + null, XML_SNOOZED_NOTIFICATION_CONTEXT_ID); + synchronized (mPersistedSnoozedNotificationsWithContext) { + storeRecord(pkg, key, userId, mPersistedSnoozedNotificationsWithContext, + creationId); + } + continue; + } + + } catch (Exception e) { + //we dont cre if it is a number format exception or a null pointer exception. + //we just want to debug it and continue with our lives + if (DEBUG) { + Slog.d(TAG, + "Exception in reading snooze data from policy xml: " + + e.getMessage()); + } + } + } + } } @VisibleForTesting diff --git a/services/core/java/com/android/server/om/IdmapDaemon.java b/services/core/java/com/android/server/om/IdmapDaemon.java index 91824c3e9f43..20a4c75a1ce6 100644 --- a/services/core/java/com/android/server/om/IdmapDaemon.java +++ b/services/core/java/com/android/server/om/IdmapDaemon.java @@ -129,11 +129,11 @@ class IdmapDaemon { } } - static void startIdmapService() { + private static void startIdmapService() { SystemProperties.set("ctl.start", IDMAP_DAEMON); } - static void stopIdmapService() { + private static void stopIdmapService() { SystemProperties.set("ctl.stop", IDMAP_DAEMON); } diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index ce951816d3a6..965ddc9f2782 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -262,7 +262,6 @@ public final class OverlayManagerService extends SystemService { initIfNeeded(); onSwitchUser(UserHandle.USER_SYSTEM); - IdmapDaemon.stopIdmapService(); publishBinderService(Context.OVERLAY_SERVICE, mService); publishLocalService(OverlayManagerService.class, this); @@ -752,7 +751,7 @@ public final class OverlayManagerService extends SystemService { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { final DumpState dumpState = new DumpState(); - dumpState.setUserId(UserHandle.getUserId(Binder.getCallingUid())); + dumpState.setUserId(UserHandle.USER_ALL); int opti = 0; while (opti < args.length) { @@ -772,13 +771,13 @@ public final class OverlayManagerService extends SystemService { pw.println(" so the following are equivalent: mState, mstate, State, state."); return; } else if ("--user".equals(opt)) { - opti++; if (opti >= args.length) { pw.println("Error: user missing argument"); return; } try { dumpState.setUserId(Integer.parseInt(args[opti])); + opti++; } catch (NumberFormatException e) { pw.println("Error: user argument is not a number: " + args[opti]); return; diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index c87ab9794563..7eb74381f7ae 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -16,10 +16,10 @@ package com.android.server.pm; +import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE; + 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; @@ -34,13 +34,15 @@ import android.util.Slog; import android.util.SparseArray; import com.android.internal.R; +import com.android.server.FgThread; +import com.android.server.compat.PlatformCompat; -import java.util.ArrayList; +import java.io.PrintWriter; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; /** @@ -50,26 +52,37 @@ import java.util.Set; class AppsFilter { private static final String TAG = PackageManagerService.TAG; + + // Forces filtering logic to run for debug purposes. + // STOPSHIP (b/136675067): should be false after development is complete + private static final boolean DEBUG_RUN_WHEN_DISABLED = true; + + // Logs all filtering instead of enforcing + private static final boolean DEBUG_ALLOW_ALL = false; + + @SuppressWarnings("ConstantExpression") + private static final boolean DEBUG_LOGGING = false | DEBUG_RUN_WHEN_DISABLED | DEBUG_ALLOW_ALL; + /** * 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 = + private final SparseArray<HashMap<String, Set<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<>(); + private final HashMap<String, Set<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<>(); + private final HashMap<String, Set<String>> mQueriesViaIntent = new HashMap<>(); /** * A set of packages that are always queryable by any package, regardless of their manifest @@ -87,14 +100,11 @@ class AppsFilter { private final IPermissionManager mPermissionManager; - private final AppOpsManager mAppOpsManager; - private final ConfigProvider mConfigProvider; + private final FeatureConfig mFeatureConfig; - AppsFilter(ConfigProvider configProvider, IPermissionManager permissionManager, - AppOpsManager appOpsManager, String[] forceQueryableWhitelist, - boolean systemAppsQueryable) { - mConfigProvider = configProvider; - mAppOpsManager = appOpsManager; + AppsFilter(FeatureConfig featureConfig, IPermissionManager permissionManager, + String[] forceQueryableWhitelist, boolean systemAppsQueryable) { + mFeatureConfig = featureConfig; final HashSet<String> forceQueryableByDeviceSet = new HashSet<>(); Collections.addAll(forceQueryableByDeviceSet, forceQueryableWhitelist); this.mForceQueryableByDevice = Collections.unmodifiableSet(forceQueryableByDeviceSet); @@ -103,28 +113,83 @@ class AppsFilter { mSystemAppsQueryable = systemAppsQueryable; } - public static AppsFilter create(Context context) { + public interface FeatureConfig { + /** Called when the system is ready and components can be queried. */ + void onSystemReady(); + + /** @return true if we should filter apps at all. */ + boolean isGloballyEnabled(); + + /** @return true if the feature is enabled for the given package. */ + boolean packageIsEnabled(PackageParser.Package pkg); + } + + private static class FeatureConfigImpl implements FeatureConfig { + private static final String FILTERING_ENABLED_NAME = "package_query_filtering_enabled"; + + // STOPSHIP(patb): set this to true if we plan to launch this in R + private static final boolean DEFAULT_ENABLED_STATE = false; + private final PackageManagerService.Injector mInjector; + private volatile boolean mFeatureEnabled = DEFAULT_ENABLED_STATE; + + private FeatureConfigImpl(PackageManagerService.Injector injector) { + mInjector = injector; + } + + @Override + public void onSystemReady() { + mFeatureEnabled = DeviceConfig.getBoolean( + NAMESPACE_PACKAGE_MANAGER_SERVICE, FILTERING_ENABLED_NAME, + DEFAULT_ENABLED_STATE); + DeviceConfig.addOnPropertiesChangedListener( + NAMESPACE_PACKAGE_MANAGER_SERVICE, FgThread.getExecutor(), + properties -> { + synchronized (FeatureConfigImpl.this) { + mFeatureEnabled = properties.getBoolean( + FILTERING_ENABLED_NAME, DEFAULT_ENABLED_STATE); + } + }); + } + + @Override + public boolean isGloballyEnabled() { + return mFeatureEnabled; + } + + @Override + public boolean packageIsEnabled(PackageParser.Package pkg) { + final PlatformCompat compatibility = mInjector.getCompatibility(); + if (compatibility == null) { + Slog.wtf(TAG, "PlatformCompat is null"); + return mFeatureEnabled; + } + return compatibility.isChangeEnabled( + PackageManager.FILTER_APPLICATION_QUERY, pkg.applicationInfo); + } + } + + + public static AppsFilter create(PackageManagerService.Injector injector) { 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); + injector.getContext().getResources() + .getBoolean(R.bool.config_forceSystemPackagesQueryable); + final FeatureConfig featureConfig = new FeatureConfigImpl(injector); 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); + injector.getContext().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, + + return new AppsFilter(featureConfig, permissionmgr, forcedQueryablePackageNames, forceSystemAppsQueryable); } @@ -165,17 +230,21 @@ class AppsFilter { */ private void markAppInteraction( PackageSetting initiatingPackage, PackageSetting targetPackage, int userId) { - HashMap<String, ArrayList<String>> currentUser = mImplicitlyQueryable.get(userId); + HashMap<String, Set<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.put(targetPackage.pkg.packageName, new HashSet<>()); } currentUser.get(targetPackage.pkg.packageName).add(initiatingPackage.pkg.packageName); } + public void onSystemReady() { + mFeatureConfig.onSystemReady(); + } + /** * Adds a package that should be considered when filtering visibility between apps. * @@ -200,7 +269,7 @@ class AppsFilter { } } // if the new package declares them, let's evaluate its ability to see existing packages - mQueriesViaIntent.put(newPkg.packageName, new ArrayList<>()); + mQueriesViaIntent.put(newPkg.packageName, new HashSet<>()); for (PackageParser.Package existingPackage : existing.values()) { if (existingPackage.packageName == newPkg.packageName) { continue; @@ -214,7 +283,7 @@ class AppsFilter { mQueriesViaIntent.get(newPkg.packageName).add(existingPackage.packageName); } } - final ArrayList<String> queriesPackages = new ArrayList<>( + final HashSet<String> queriesPackages = new HashSet<>( newPkg.mQueriesPackages == null ? 0 : newPkg.mQueriesPackages.size()); if (newPkg.mQueriesPackages != null) { queriesPackages.addAll(newPkg.mQueriesPackages); @@ -232,13 +301,13 @@ class AppsFilter { for (int i = 0; i < mImplicitlyQueryable.size(); i++) { mImplicitlyQueryable.valueAt(i).remove(packageName); - for (ArrayList<String> initiators : mImplicitlyQueryable.valueAt(i).values()) { + for (Set<String> initiators : mImplicitlyQueryable.valueAt(i).values()) { initiators.remove(packageName); } } mQueriesViaIntent.remove(packageName); - for (List<String> declarators : mQueriesViaIntent.values()) { + for (Set<String> declarators : mQueriesViaIntent.values()) { declarators.remove(packageName); } @@ -257,6 +326,10 @@ class AppsFilter { */ public boolean shouldFilterApplication(int callingUid, @Nullable SettingBase callingSetting, PackageSetting targetPkgSetting, int userId) { + final boolean featureEnabled = mFeatureConfig.isGloballyEnabled(); + if (!featureEnabled && !DEBUG_RUN_WHEN_DISABLED) { + return false; + } if (callingUid < Process.FIRST_APPLICATION_UID) { return false; } @@ -277,7 +350,8 @@ class AppsFilter { final ArraySet<PackageSetting> packageSettings = ((SharedUserSetting) callingSetting).packages; if (packageSettings != null && packageSettings.size() > 0) { - for (PackageSetting packageSetting : packageSettings) { + for (int i = 0, max = packageSettings.size(); i < max; i++) { + final PackageSetting packageSetting = packageSettings.valueAt(i); if (!shouldFilterApplicationInternal(packageSetting, targetPkgSetting, userId)) { // TODO: actually base this on a start / launch (not just a query) @@ -288,33 +362,30 @@ class AppsFilter { callingPkgSetting = packageSetting; } } + if (callingPkgSetting == null) { + Slog.wtf(TAG, callingSetting + " does not have any non-null packages!"); + return true; + } } else { + Slog.wtf(TAG, callingSetting + " has no packages!"); return true; } } - if (callingPkgSetting == null) { - Slog.wtf(TAG, "What... " + callingSetting); - return true; + if (!featureEnabled) { + return false; } - 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; + if (mFeatureConfig.packageIsEnabled(callingPkgSetting.pkg)) { + if (DEBUG_LOGGING) { + Slog.d(TAG, "interaction: " + callingPkgSetting.name + " -> " + + targetPkgSetting.name + (DEBUG_ALLOW_ALL ? " ALLOWED" : "BLOCKED")); + } + return !DEBUG_ALLOW_ALL; + } else { + if (DEBUG_LOGGING) { + Slog.d(TAG, "interaction: " + callingPkgSetting.name + " -> " + + targetPkgSetting.name + " DISABLED"); + } + return false; } } @@ -355,6 +426,13 @@ class AppsFilter { && mImplicitlyQueryable.get(userId).get(callingName).contains(targetName)) { return false; } + if (callingPkgSetting.pkg.instrumentation.size() > 0) { + for (int i = 0, max = callingPkgSetting.pkg.instrumentation.size(); i < max; i++) { + if (callingPkgSetting.pkg.instrumentation.get(i).info.targetPackage == targetName) { + return false; + } + } + } try { if (mPermissionManager.checkPermission( Manifest.permission.QUERY_ALL_PACKAGES, callingName, userId) @@ -372,8 +450,51 @@ class AppsFilter { || mForceQueryableByDevice.contains(targetPkgSetting.pkg.packageName)); } - public interface ConfigProvider { - boolean isEnabled(); + public void dumpQueries( + PrintWriter pw, @Nullable String filteringPackageName, DumpState dumpState, + int[] users) { + pw.println(); + pw.println("Queries:"); + dumpState.onTitlePrinted(); + pw.println(" system apps queryable: " + mSystemAppsQueryable); + dumpPackageSet(pw, filteringPackageName, mForceQueryableByDevice, "System whitelist", " "); + dumpPackageSet(pw, filteringPackageName, mForceQueryable, "forceQueryable", " "); + pw.println(" queries via package name:"); + dumpQueriesMap(pw, filteringPackageName, mQueriesViaPackage, " "); + pw.println(" queries via intent:"); + dumpQueriesMap(pw, filteringPackageName, mQueriesViaIntent, " "); + pw.println(" queryable via interaction:"); + for (int user : users) { + pw.append(" User ").append(Integer.toString(user)).println(":"); + final HashMap<String, Set<String>> queryMapForUser = mImplicitlyQueryable.get(user); + dumpQueriesMap(pw, filteringPackageName, queryMapForUser, " "); + } + } + + private static void dumpQueriesMap(PrintWriter pw, @Nullable String filteringPackageName, + HashMap<String, Set<String>> queriesMap, String spacing) { + for (String callingPkg : queriesMap.keySet()) { + if (Objects.equals(callingPkg, filteringPackageName)) { + // don't filter target package names if the calling is filteringPackageName + dumpPackageSet(pw, null /*filteringPackageName*/, queriesMap.get(callingPkg), + callingPkg, spacing); + } else { + dumpPackageSet(pw, filteringPackageName, queriesMap.get(callingPkg), callingPkg, + spacing); + } + } } + private static void dumpPackageSet(PrintWriter pw, @Nullable String filteringPackageName, + Set<String> targetPkgSet, String subTitle, String spacing) { + if (targetPkgSet != null && targetPkgSet.size() > 0 + && (filteringPackageName == null || targetPkgSet.contains(filteringPackageName))) { + pw.append(spacing).append(subTitle).println(":"); + for (String pkgName : targetPkgSet) { + if (filteringPackageName == null || Objects.equals(filteringPackageName, pkgName)) { + pw.append(spacing).append(" ").println(pkgName); + } + } + } + } } diff --git a/services/core/java/com/android/server/pm/DumpState.java b/services/core/java/com/android/server/pm/DumpState.java index d473fbf5ed51..99a109367afc 100644 --- a/services/core/java/com/android/server/pm/DumpState.java +++ b/services/core/java/com/android/server/pm/DumpState.java @@ -42,6 +42,7 @@ public final class DumpState { public static final int DUMP_VOLUMES = 1 << 23; public static final int DUMP_SERVICE_PERMISSIONS = 1 << 24; public static final int DUMP_APEX = 1 << 25; + public static final int DUMP_QUERIES = 1 << 26; public static final int OPTION_SHOW_FILTERS = 1 << 0; public static final int OPTION_DUMP_ALL_COMPONENTS = 1 << 1; diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 0032e9a8ea51..3aeb2b102afe 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -1184,9 +1184,26 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements synchronized (mSessions) { pw.println("Active install sessions:"); pw.increaseIndent(); + + List<PackageInstallerSession> finalizedSessions = new ArrayList<>(); int N = mSessions.size(); for (int i = 0; i < N; i++) { final PackageInstallerSession session = mSessions.valueAt(i); + if (session.isStagedAndInTerminalState()) { + finalizedSessions.add(session); + continue; + } + session.dump(pw); + pw.println(); + } + pw.println(); + pw.decreaseIndent(); + + pw.println("Finalized install sessions:"); + pw.increaseIndent(); + N = finalizedSessions.size(); + for (int i = 0; i < N; i++) { + final PackageInstallerSession session = finalizedSessions.get(i); session.dump(pw); pw.println(); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 4eddb9301a69..b72029046067 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -2337,6 +2337,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { pw.printPair("mInstallerPackageName", mInstallerPackageName); pw.printPair("mInstallerUid", mInstallerUid); pw.printPair("createdMillis", createdMillis); + pw.printPair("updatedMillis", updatedMillis); pw.printPair("stageDir", stageDir); pw.printPair("stageCid", stageCid); pw.println(); @@ -2356,6 +2357,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { pw.printPair("mFinalMessage", mFinalMessage); pw.printPair("params.isMultiPackage", params.isMultiPackage); pw.printPair("params.isStaged", params.isStaged); + pw.printPair("mParentSessionId", mParentSessionId); + pw.printPair("mChildSessionIds", mChildSessionIds); + pw.printPair("mStagedSessionApplied", mStagedSessionApplied); + pw.printPair("mStagedSessionFailed", mStagedSessionFailed); + pw.printPair("mStagedSessionReady", mStagedSessionReady); + pw.printPair("mStagedSessionErrorCode", mStagedSessionErrorCode); + pw.printPair("mStagedSessionErrorMessage", mStagedSessionErrorMessage); pw.println(); pw.decreaseIndent(); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 3f6d4dfcdfcb..15a3a725d69d 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -290,7 +290,7 @@ import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.AttributeCache; -import com.android.server.DeviceIdleController; +import com.android.server.DeviceIdleInternal; import com.android.server.EventLogTags; import com.android.server.FgThread; import com.android.server.LocalServices; @@ -300,6 +300,7 @@ import com.android.server.ServiceThread; import com.android.server.SystemConfig; import com.android.server.SystemServerInitThreadPool; import com.android.server.Watchdog; +import com.android.server.compat.PlatformCompat; import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.Settings.DatabaseVersion; @@ -816,7 +817,7 @@ public class PackageManagerService extends IPackageManager.Stub private final Singleton<UserManagerService> mUserManagerProducer; private final Singleton<Settings> mSettingsProducer; private final Singleton<ActivityTaskManagerInternal> mActivityTaskManagerProducer; - private final Singleton<DeviceIdleController.LocalService> mLocalDeviceIdleController; + private final Singleton<DeviceIdleInternal> mLocalDeviceIdleController; private final Singleton<StorageManagerInternal> mStorageManagerInternalProducer; private final Singleton<NetworkPolicyManagerInternal> mNetworkPolicyManagerProducer; private final Singleton<PermissionPolicyInternal> mPermissionPolicyProducer; @@ -824,6 +825,8 @@ public class PackageManagerService extends IPackageManager.Stub private final Singleton<DisplayManager> mDisplayManagerProducer; private final Singleton<StorageManager> mStorageManagerProducer; private final Singleton<AppOpsManager> mAppOpsManagerProducer; + private final Singleton<AppsFilter> mAppsFilterProducer; + private final Singleton<PlatformCompat> mPlatformCompatProducer; Injector(Context context, Object lock, Installer installer, Object installLock, PackageAbiHelper abiHelper, @@ -832,14 +835,16 @@ public class PackageManagerService extends IPackageManager.Stub Producer<UserManagerService> userManagerProducer, Producer<Settings> settingsProducer, Producer<ActivityTaskManagerInternal> activityTaskManagerProducer, - Producer<DeviceIdleController.LocalService> deviceIdleControllerProducer, + Producer<DeviceIdleInternal> deviceIdleControllerProducer, Producer<StorageManagerInternal> storageManagerInternalProducer, Producer<NetworkPolicyManagerInternal> networkPolicyManagerProducer, Producer<PermissionPolicyInternal> permissionPolicyProvider, Producer<DeviceStorageMonitorInternal> deviceStorageMonitorProducer, Producer<DisplayManager> displayManagerProducer, Producer<StorageManager> storageManagerProducer, - Producer<AppOpsManager> appOpsManagerProducer) { + Producer<AppOpsManager> appOpsManagerProducer, + Producer<AppsFilter> appsFilterProducer, + Producer<PlatformCompat> platformCompatProducer) { mContext = context; mLock = lock; mInstaller = installer; @@ -858,6 +863,8 @@ public class PackageManagerService extends IPackageManager.Stub mDisplayManagerProducer = new Singleton<>(displayManagerProducer); mStorageManagerProducer = new Singleton<>(storageManagerProducer); mAppOpsManagerProducer = new Singleton<>(appOpsManagerProducer); + mAppsFilterProducer = new Singleton<>(appsFilterProducer); + mPlatformCompatProducer = new Singleton<>(platformCompatProducer); } /** @@ -912,7 +919,7 @@ public class PackageManagerService extends IPackageManager.Stub return mActivityTaskManagerProducer.get(this, mPackageManager); } - public DeviceIdleController.LocalService getLocalDeviceIdleController() { + public DeviceIdleInternal getLocalDeviceIdleController() { return mLocalDeviceIdleController.get(this, mPackageManager); } @@ -943,6 +950,14 @@ public class PackageManagerService extends IPackageManager.Stub public AppOpsManager getAppOpsManager() { return mAppOpsManagerProducer.get(this, mPackageManager); } + + public AppsFilter getAppsFilter() { + return mAppsFilterProducer.get(this, mPackageManager); + } + + public PlatformCompat getCompatibility() { + return mPlatformCompatProducer.get(this, mPackageManager); + } } private final AppsFilter mAppsFilter; @@ -1249,7 +1264,7 @@ public class PackageManagerService extends IPackageManager.Stub final BroadcastOptions options = BroadcastOptions.makeBasic(); options.setTemporaryAppWhitelistDuration(whitelistTimeout); - DeviceIdleController.LocalService idleController = + DeviceIdleInternal idleController = mInjector.getLocalDeviceIdleController(); idleController.addPowerSaveTempWhitelistApp(Process.myUid(), mIntentFilterVerifierComponent.getPackageName(), whitelistTimeout, @@ -2273,9 +2288,9 @@ public class PackageManagerService extends IPackageManager.Stub * @param packageVolume The storage volume of the package. * @param packageIsExternal true if the package is currently installed on * 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. + * @return {@link StorageEnums#UNKNOWN} if the package is not stored externally or the + * corresponding {@link StorageEnums} storage type value if it is. + * corresponding {@link StorageEnums} storage type value if it is. */ private static int getPackageExternalStorageType(VolumeInfo packageVolume, boolean packageIsExternal) { @@ -2425,14 +2440,16 @@ public class PackageManagerService extends IPackageManager.Stub i.getPermissionManagerServiceInternal().getPermissionSettings(), lock), new Injector.LocalServicesProducer<>(ActivityTaskManagerInternal.class), - new Injector.LocalServicesProducer<>(DeviceIdleController.LocalService.class), + new Injector.LocalServicesProducer<>(DeviceIdleInternal.class), new Injector.LocalServicesProducer<>(StorageManagerInternal.class), new Injector.LocalServicesProducer<>(NetworkPolicyManagerInternal.class), new Injector.LocalServicesProducer<>(PermissionPolicyInternal.class), new Injector.LocalServicesProducer<>(DeviceStorageMonitorInternal.class), new Injector.SystemServiceProducer<>(DisplayManager.class), new Injector.SystemServiceProducer<>(StorageManager.class), - new Injector.SystemServiceProducer<>(AppOpsManager.class)); + new Injector.SystemServiceProducer<>(AppOpsManager.class), + (i, pm) -> AppsFilter.create(i), + (i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat")); PackageManagerService m = new PackageManagerService(injector, factoryTest, onlyCore); t.traceEnd(); // "create package manager" @@ -2617,7 +2634,7 @@ public class PackageManagerService extends IPackageManager.Stub mProtectedPackages = new ProtectedPackages(mContext); mApexManager = ApexManager.create(mContext); - mAppsFilter = AppsFilter.create(mContext); + mAppsFilter = mInjector.getAppsFilter(); // CHECKSTYLE:OFF IndentationCheck synchronized (mInstallLock) { @@ -2725,14 +2742,10 @@ public class PackageManagerService extends IPackageManager.Stub mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1; mIsPreQUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.Q; - int preUpgradeSdkVersion = ver.sdkVersion; - // save off the names of pre-existing system packages prior to scanning; we don't // want to automatically grant runtime permissions for new system apps if (mPromoteSystemApps) { - Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator(); - while (pkgSettingIter.hasNext()) { - PackageSetting ps = pkgSettingIter.next(); + for (PackageSetting ps : mSettings.mPackages.values()) { if (isSystemApp(ps)) { mExistingSystemPackages.add(ps.name); } @@ -14511,7 +14524,7 @@ public class PackageManagerService extends IPackageManager.Stub final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite, receivers, verificationState); - DeviceIdleController.LocalService idleController = + DeviceIdleInternal idleController = mInjector.getLocalDeviceIdleController(); final long idleDuration = getVerificationTimeout(); @@ -14580,17 +14593,6 @@ public class PackageManagerService extends IPackageManager.Stub TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken); mPendingEnableRollback.append(enableRollbackToken, this); - final int[] installedUsers; - synchronized (mLock) { - PackageSetting ps = mSettings.getPackageLPr(pkgLite.packageName); - if (ps != null) { - installedUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), - true); - } else { - installedUsers = new int[0]; - } - } - Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK); enableRollbackIntent.putExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, @@ -14599,9 +14601,6 @@ public class PackageManagerService extends IPackageManager.Stub PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, installFlags); enableRollbackIntent.putExtra( - PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS, - installedUsers); - enableRollbackIntent.putExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER, getRollbackUser().getIdentifier()); enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)), @@ -20459,6 +20458,8 @@ public class PackageManagerService extends IPackageManager.Stub .getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_ALL); co.onChange(true); + mAppsFilter.onSystemReady(); + // Disable any carrier apps. We do this very early in boot to prevent the apps from being // disabled after already being started. CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this, @@ -20663,6 +20664,7 @@ public class PackageManagerService extends IPackageManager.Stub pw.println(" preferred-xml [--full]: print preferred package settings as xml"); pw.println(" prov[iders]: dump content providers"); pw.println(" p[ackages]: dump installed packages"); + pw.println(" q[ueries]: dump app queryability calculations"); pw.println(" s[hared-users]: dump shared user IDs"); pw.println(" m[essages]: print collected runtime messages"); pw.println(" v[erifiers]: print package verifier info"); @@ -20785,6 +20787,8 @@ public class PackageManagerService extends IPackageManager.Stub dumpState.setDump(DumpState.DUMP_DOMAIN_PREFERRED); } else if ("p".equals(cmd) || "packages".equals(cmd)) { dumpState.setDump(DumpState.DUMP_PACKAGES); + } else if ("q".equals(cmd) || "queries".equals(cmd)) { + dumpState.setDump(DumpState.DUMP_QUERIES); } else if ("s".equals(cmd) || "shared-users".equals(cmd)) { dumpState.setDump(DumpState.DUMP_SHARED_USERS); if (opti < args.length && "noperm".equals(args[opti])) { @@ -21079,6 +21083,10 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.dumpPackagesLPr(pw, packageName, permissionNames, dumpState, checkin); } + if (dumpState.isDumping(DumpState.DUMP_QUERIES)) { + mAppsFilter.dumpQueries(pw, packageName, dumpState, mUserManager.getUserIds()); + } + if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) { mSettings.dumpSharedUsersLPr(pw, packageName, permissionNames, dumpState, checkin); } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index c1cb53d4ff0f..597246884ca5 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -4570,6 +4570,13 @@ public final class Settings { pw.print(prefix); pw.print(" privateFlags="); printFlags(pw, ps.pkg.applicationInfo.privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println(); } + pw.print(prefix); pw.print(" forceQueryable="); pw.println(ps.pkg.mForceQueryable); + if (ps.pkg.mQueriesPackages != null) { + pw.append(prefix).append(" queriesPackages=").println(ps.pkg.mQueriesPackages); + } + if (ps.pkg.mQueriesIntents != null) { + pw.append(prefix).append(" queriesIntents=").println(ps.pkg.mQueriesIntents); + } pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir); pw.print(prefix); pw.print(" supportsScreens=["); boolean first = true; diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 6d3424cf3942..dd1eb8355de1 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -35,7 +35,6 @@ import android.content.pm.PackageParser.PackageParserException; import android.content.pm.PackageParser.SigningDetails; import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion; import android.content.pm.ParceledListSlice; -import android.content.pm.Signature; import android.content.rollback.IRollbackManager; import android.os.Bundle; import android.os.Handler; @@ -106,8 +105,19 @@ public class StagingManager { return new ParceledListSlice<>(result); } - private void validateApexSignature(String apexPath, String packageName) + /** + * Validates the signature used to sign the container of the new apex package + * + * @param newApexPkg The new apex package that is being installed + * @param installFlags flags related to the session + * @throws PackageManagerException + */ + private void validateApexSignature(PackageInfo newApexPkg, int installFlags) throws PackageManagerException { + // Get signing details of the new package + final String apexPath = newApexPkg.applicationInfo.sourceDir; + final String packageName = newApexPkg.packageName; + final SigningDetails signingDetails; try { signingDetails = ApkSignatureVerifier.verify(apexPath, SignatureSchemeVersion.JAR); @@ -116,9 +126,10 @@ public class StagingManager { "Failed to parse APEX package " + apexPath, e); } - final PackageInfo packageInfo = mApexManager.getPackageInfo(packageName, + // Get signing details of the existing package + final PackageInfo existingApexPkg = mApexManager.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE); - if (packageInfo == null) { + if (existingApexPkg == null) { // This should never happen, because submitSessionToApexService ensures that no new // apexes were installed. throw new IllegalStateException("Unknown apex package " + packageName); @@ -127,22 +138,22 @@ public class StagingManager { final SigningDetails existingSigningDetails; try { existingSigningDetails = ApkSignatureVerifier.verify( - packageInfo.applicationInfo.sourceDir, SignatureSchemeVersion.JAR); + existingApexPkg.applicationInfo.sourceDir, SignatureSchemeVersion.JAR); } catch (PackageParserException e) { throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, - "Failed to parse APEX package " + packageInfo.applicationInfo.sourceDir, e); + "Failed to parse APEX package " + existingApexPkg.applicationInfo.sourceDir, e); } - // Now that we have both sets of signatures, demand that they're an exact match. - if (Signature.areExactMatch(existingSigningDetails.signatures, signingDetails.signatures)) { + // Verify signing details for upgrade + if (signingDetails.checkCapability(existingSigningDetails, + PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)) { return; } throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, - "APK-container signature verification failed for package " - + packageName + ". Signature of file " - + apexPath + " does not match the signature of " - + " the package already installed."); + "APK-container signature of APEX package " + packageName + " with version " + + newApexPkg.versionCodeMajor + " and path " + apexPath + " is not" + + " compatible with the one currently installed on device"); } private List<PackageInfo> submitSessionToApexService( @@ -239,8 +250,7 @@ public class StagingManager { try { final List<PackageInfo> apexPackages = submitSessionToApexService(session); for (PackageInfo apexPackage : apexPackages) { - validateApexSignature(apexPackage.applicationInfo.sourceDir, - apexPackage.packageName); + validateApexSignature(apexPackage, session.params.installFlags); } } catch (PackageManagerException e) { session.setStagedSessionFailed(e.error, e.getMessage()); diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index a707aa884966..1fe551222a06 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -75,6 +75,7 @@ import android.os.storage.StorageManager; import android.security.GateKeeper; import android.service.gatekeeper.IGateKeeperService; import android.stats.devicepolicy.DevicePolicyEnums; +import android.util.ArraySet; import android.util.AtomicFile; import android.util.IntArray; import android.util.Log; @@ -125,6 +126,7 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Objects; +import java.util.Set; /** * Service for {@link UserManager}. @@ -214,7 +216,7 @@ public class UserManagerService extends IUserManager.Stub { @VisibleForTesting static final int MAX_RECENTLY_REMOVED_IDS_SIZE = 100; - private static final int USER_VERSION = 7; + private static final int USER_VERSION = 8; private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms @@ -2139,6 +2141,7 @@ public class UserManagerService extends IUserManager.Stub { */ @GuardedBy({"mRestrictionsLock", "mPackagesLock"}) private void upgradeIfNecessaryLP(Bundle oldGlobalUserRestrictions) { + Set<Integer> userIdsToWrite = new ArraySet<>(); final int originalVersion = mUserVersion; int userVersion = mUserVersion; if (userVersion < 1) { @@ -2147,7 +2150,7 @@ public class UserManagerService extends IUserManager.Stub { if ("Primary".equals(userData.info.name)) { userData.info.name = mContext.getResources().getString(com.android.internal.R.string.owner_name); - scheduleWriteUser(userData); + userIdsToWrite.add(userData.info.id); } userVersion = 1; } @@ -2157,7 +2160,7 @@ public class UserManagerService extends IUserManager.Stub { UserData userData = getUserDataNoChecks(UserHandle.USER_SYSTEM); if ((userData.info.flags & UserInfo.FLAG_INITIALIZED) == 0) { userData.info.flags |= UserInfo.FLAG_INITIALIZED; - scheduleWriteUser(userData); + userIdsToWrite.add(userData.info.id); } userVersion = 2; } @@ -2182,7 +2185,7 @@ public class UserManagerService extends IUserManager.Stub { && (userData.info.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID)) { userData.info.restrictedProfileParentId = UserHandle.USER_SYSTEM; - scheduleWriteUser(userData); + userIdsToWrite.add(userData.info.id); } } } @@ -2206,6 +2209,29 @@ public class UserManagerService extends IUserManager.Stub { userVersion = 7; } + if (userVersion < 8) { + // Added FLAG_FULL and FLAG_SYSTEM flags. + synchronized (mUsersLock) { + UserData userData = mUsers.get(UserHandle.USER_SYSTEM); + userData.info.flags |= UserInfo.FLAG_SYSTEM; + if (!UserManager.isHeadlessSystemUserMode()) { + userData.info.flags |= UserInfo.FLAG_FULL; + } + userIdsToWrite.add(userData.info.id); + + // Mark FULL all non-profile users except USER_SYSTEM. + // Start index at 1 since USER_SYSTEM is the smallest userId and we're skipping it. + for (int i = 1; i < mUsers.size(); i++) { + userData = mUsers.valueAt(i); + if ((userData.info.flags & UserInfo.FLAG_MANAGED_PROFILE) == 0) { + userData.info.flags |= UserInfo.FLAG_FULL; + userIdsToWrite.add(userData.info.id); + } + } + } + userVersion = 8; + } + if (userVersion < USER_VERSION) { Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to " + USER_VERSION); @@ -2213,6 +2239,12 @@ public class UserManagerService extends IUserManager.Stub { mUserVersion = userVersion; if (originalVersion < mUserVersion) { + for (int userId : userIdsToWrite) { + UserData userData = getUserDataNoChecks(userId); + if (userData != null) { + writeUserLP(userData); + } + } writeUserListLP(); } } @@ -2220,11 +2252,10 @@ public class UserManagerService extends IUserManager.Stub { @GuardedBy({"mPackagesLock", "mRestrictionsLock"}) private void fallbackToSingleUserLP() { - int flags = UserInfo.FLAG_INITIALIZED; - // In split system user mode, the admin and primary flags are assigned to the first human - // user. - if (!UserManager.isSplitSystemUser()) { - flags |= UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY; + int flags = UserInfo.FLAG_SYSTEM | UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN; + // In headless system user mode, the primary flag is assigned to the first human user. + if (!UserManager.isHeadlessSystemUserMode()) { + flags |= UserInfo.FLAG_PRIMARY | UserInfo.FLAG_FULL; } // Create the system user UserInfo system = new UserInfo(UserHandle.USER_SYSTEM, null, null, flags); @@ -2262,14 +2293,14 @@ public class UserManagerService extends IUserManager.Stub { return mContext.getResources().getString(com.android.internal.R.string.owner_name); } - private void scheduleWriteUser(UserData UserData) { + private void scheduleWriteUser(UserData userData) { if (DBG) { debug("scheduleWriteUser"); } // No need to wrap it within a lock -- worst case, we'll just post the same message // twice. - if (!mHandler.hasMessages(WRITE_USER_MSG, UserData)) { - Message msg = mHandler.obtainMessage(WRITE_USER_MSG, UserData); + if (!mHandler.hasMessages(WRITE_USER_MSG, userData)) { + Message msg = mHandler.obtainMessage(WRITE_USER_MSG, userData); mHandler.sendMessageDelayed(msg, WRITE_USER_DELAY); } } @@ -2738,9 +2769,9 @@ public class UserManagerService extends IUserManager.Stub { return null; } } - // In split system user mode, we assign the first human user the primary flag. + // In headless system user mode, we assign the first human user the primary flag. // And if there is no device owner, we also assign the admin flag to primary user. - if (UserManager.isSplitSystemUser() + if (UserManager.isHeadlessSystemUserMode() && !isGuest && !isManagedProfile && getPrimaryUser() == null) { flags |= UserInfo.FLAG_PRIMARY; synchronized (mUsersLock) { @@ -2749,6 +2780,10 @@ public class UserManagerService extends IUserManager.Stub { } } } + if (!isManagedProfile) { + // New users cannot be system, and it's not a profile, so per-force it's FULL. + flags |= UserInfo.FLAG_FULL; + } userId = getNextAvailableId(); Environment.getUserSystemDirectory(userId).mkdirs(); @@ -3723,6 +3758,8 @@ public class UserManagerService extends IUserManager.Stub { pw.print(" <partial>"); } pw.println(); + pw.print(" Flags: "); pw.print(userInfo.flags); pw.print(" ("); + pw.print(UserInfo.flagsToString(userInfo.flags)); pw.println(")"); pw.print(" State: "); final int state; synchronized (mUserStates) { @@ -3807,6 +3844,8 @@ public class UserManagerService extends IUserManager.Stub { pw.println(" All guests ephemeral: " + Resources.getSystem().getBoolean( com.android.internal.R.bool.config_guestUserEphemeral)); pw.println(" Is split-system user: " + UserManager.isSplitSystemUser()); + pw.println(" Is headless-system mode: " + UserManager.isHeadlessSystemUserMode()); + pw.println(" User version: " + mUserVersion); } private static void dumpTimeAgo(PrintWriter pw, StringBuilder sb, long nowTime, long time) { @@ -4133,6 +4172,14 @@ public class UserManagerService extends IUserManager.Stub { Bundle restrictions = getEffectiveUserRestrictions(userId); return restrictions != null && restrictions.getBoolean(restrictionKey); } + + public @Nullable UserInfo getUserInfo(@UserIdInt int userId) { + UserData userData; + synchronized (mUsersLock) { + userData = mUsers.get(userId); + } + return userData == null ? null : userData.info; + } } /* Remove all the users except of the system one. */ diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING index af94e441f3c0..c0d71ac26853 100644 --- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING +++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING @@ -62,5 +62,10 @@ } ] } + ], + "imports": [ + { + "path": "vendor/xts/gts-tests/tests/permission" + } ] } diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java index f5f7d67ba0b1..cae09ea37f2a 100644 --- a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java +++ b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java @@ -52,12 +52,13 @@ public class AppDataRollbackHelper { } /** - * Creates an app data snapshot for a specified {@code packageRollbackInfo}. Updates said {@code - * packageRollbackInfo} with the inodes of the CE user data snapshot folders. + * Creates an app data snapshot for a specified {@code packageRollbackInfo} and the specified + * {@code userIds}. Updates said {@code packageRollbackInfo} with the inodes of the CE user data + * snapshot folders. */ - public void snapshotAppData(int snapshotId, PackageRollbackInfo packageRollbackInfo) { - final int[] installedUsers = packageRollbackInfo.getInstalledUsers().toArray(); - for (int user : installedUsers) { + public void snapshotAppData( + int snapshotId, PackageRollbackInfo packageRollbackInfo, int[] userIds) { + for (int user : userIds) { final int storageFlags; if (isUserCredentialLocked(user)) { // We've encountered a user that hasn't unlocked on a FBE device, so we can't copy @@ -80,6 +81,7 @@ public class AppDataRollbackHelper { + packageRollbackInfo.getPackageName() + ", userId: " + user, ie); } } + packageRollbackInfo.getSnapshottedUsers().addAll(IntArray.wrap(userIds)); } /** @@ -96,14 +98,14 @@ public class AppDataRollbackHelper { final IntArray pendingBackups = packageRollbackInfo.getPendingBackups(); final List<RestoreInfo> pendingRestores = packageRollbackInfo.getPendingRestores(); - boolean changedRollbackData = false; + boolean changedRollback = false; // If we still have a userdata backup pending for this user, it implies that the user // hasn't unlocked their device between the point of backup and the point of restore, // so the data cannot have changed. We simply skip restoring CE data in this case. if (pendingBackups != null && pendingBackups.indexOf(userId) != -1) { pendingBackups.remove(pendingBackups.indexOf(userId)); - changedRollbackData = true; + changedRollback = true; } else { // There's no pending CE backup for this user, which means that we successfully // managed to backup data for the user, which means we seek to restore it @@ -111,7 +113,7 @@ public class AppDataRollbackHelper { // We've encountered a user that hasn't unlocked on a FBE device, so we can't // copy across app user data until the user unlocks their device. pendingRestores.add(new RestoreInfo(userId, appId, seInfo)); - changedRollbackData = true; + changedRollback = true; } else { // This user has unlocked, we can proceed to restore both CE and DE data. storageFlags = storageFlags | Installer.FLAG_STORAGE_CE; @@ -126,7 +128,7 @@ public class AppDataRollbackHelper { + packageRollbackInfo.getPackageName(), ie); } - return changedRollbackData; + return changedRollback; } /** @@ -158,29 +160,29 @@ public class AppDataRollbackHelper { * Packages pending backup for the given user are added to {@code pendingBackupPackages} along * with their corresponding {@code PackageRollbackInfo}. * - * @return the list of {@code RollbackData} that has pending backups. Note that some of the + * @return the list of rollbacks that have pending backups. Note that some of the * backups won't be performed, because they might be counteracted by pending restores. */ - private static List<RollbackData> computePendingBackups(int userId, + private static List<Rollback> computePendingBackups(int userId, Map<String, PackageRollbackInfo> pendingBackupPackages, - List<RollbackData> rollbacks) { - List<RollbackData> rd = new ArrayList<>(); + List<Rollback> rollbacks) { + List<Rollback> rollbacksWithPendingBackups = new ArrayList<>(); - for (RollbackData data : rollbacks) { - for (PackageRollbackInfo info : data.info.getPackages()) { + for (Rollback rollback : rollbacks) { + for (PackageRollbackInfo info : rollback.info.getPackages()) { final IntArray pendingBackupUsers = info.getPendingBackups(); if (pendingBackupUsers != null) { final int idx = pendingBackupUsers.indexOf(userId); if (idx != -1) { pendingBackupPackages.put(info.getPackageName(), info); - if (rd.indexOf(data) == -1) { - rd.add(data); + if (rollbacksWithPendingBackups.indexOf(rollback) == -1) { + rollbacksWithPendingBackups.add(rollback); } } } } } - return rd; + return rollbacksWithPendingBackups; } /** @@ -188,45 +190,45 @@ public class AppDataRollbackHelper { * Packages pending restore are added to {@code pendingRestores} along with their corresponding * {@code PackageRollbackInfo}. * - * @return the list of {@code RollbackData} that has pending restores. Note that some of the + * @return the list of rollbacks that have pending restores. Note that some of the * restores won't be performed, because they might be counteracted by pending backups. */ - private static List<RollbackData> computePendingRestores(int userId, + private static List<Rollback> computePendingRestores(int userId, Map<String, PackageRollbackInfo> pendingRestorePackages, - List<RollbackData> rollbacks) { - List<RollbackData> rd = new ArrayList<>(); + List<Rollback> rollbacks) { + List<Rollback> rollbacksWithPendingRestores = new ArrayList<>(); - for (RollbackData data : rollbacks) { - for (PackageRollbackInfo info : data.info.getPackages()) { + for (Rollback rollback : rollbacks) { + for (PackageRollbackInfo info : rollback.info.getPackages()) { final RestoreInfo ri = info.getRestoreInfo(userId); if (ri != null) { pendingRestorePackages.put(info.getPackageName(), info); - if (rd.indexOf(data) == -1) { - rd.add(data); + if (rollbacksWithPendingRestores.indexOf(rollback) == -1) { + rollbacksWithPendingRestores.add(rollback); } } } } - return rd; + return rollbacksWithPendingRestores; } /** - * Commits the list of pending backups and restores for a given {@code userId}. For the pending - * backups updates corresponding {@code changedRollbackData} with a mapping from {@code userId} - * to a inode of theirs CE user data snapshot. + * Commits the list of pending backups and restores for a given {@code userId}. For rollbacks + * with pending backups, updates the {@code Rollback} instance with a mapping from + * {@code userId} to inode of the CE user data snapshot. * - * @return the set of {@code RollbackData} that have been changed and should be stored on disk. + * @return the set of rollbacks with changes that should be stored on disk. */ - public Set<RollbackData> commitPendingBackupAndRestoreForUser(int userId, - List<RollbackData> rollbacks) { + public Set<Rollback> commitPendingBackupAndRestoreForUser(int userId, + List<Rollback> rollbacks) { final Map<String, PackageRollbackInfo> pendingBackupPackages = new HashMap<>(); - final List<RollbackData> pendingBackups = computePendingBackups(userId, + final List<Rollback> pendingBackups = computePendingBackups(userId, pendingBackupPackages, rollbacks); final Map<String, PackageRollbackInfo> pendingRestorePackages = new HashMap<>(); - final List<RollbackData> pendingRestores = computePendingRestores(userId, + final List<Rollback> pendingRestores = computePendingRestores(userId, pendingRestorePackages, rollbacks); // First remove unnecessary backups, i.e. when user did not unlock their phone between the @@ -246,14 +248,15 @@ public class AppDataRollbackHelper { } if (!pendingBackupPackages.isEmpty()) { - for (RollbackData data : pendingBackups) { - for (PackageRollbackInfo info : data.info.getPackages()) { + for (Rollback rollback : pendingBackups) { + for (PackageRollbackInfo info : rollback.info.getPackages()) { final IntArray pendingBackupUsers = info.getPendingBackups(); final int idx = pendingBackupUsers.indexOf(userId); if (idx != -1) { try { long ceSnapshotInode = mInstaller.snapshotAppData(info.getPackageName(), - userId, data.info.getRollbackId(), Installer.FLAG_STORAGE_CE); + userId, rollback.info.getRollbackId(), + Installer.FLAG_STORAGE_CE); info.putCeSnapshotInode(userId, ceSnapshotInode); pendingBackupUsers.remove(idx); } catch (InstallerException ie) { @@ -267,13 +270,13 @@ public class AppDataRollbackHelper { } if (!pendingRestorePackages.isEmpty()) { - for (RollbackData data : pendingRestores) { - for (PackageRollbackInfo info : data.info.getPackages()) { + for (Rollback rollback : pendingRestores) { + for (PackageRollbackInfo info : rollback.info.getPackages()) { final RestoreInfo ri = info.getRestoreInfo(userId); if (ri != null) { try { mInstaller.restoreAppDataSnapshot(info.getPackageName(), ri.appId, - ri.seInfo, userId, data.info.getRollbackId(), + ri.seInfo, userId, rollback.info.getRollbackId(), Installer.FLAG_STORAGE_CE); info.removeRestoreInfo(ri); } catch (InstallerException ie) { @@ -285,7 +288,7 @@ public class AppDataRollbackHelper { } } - final Set<RollbackData> changed = new HashSet<>(pendingBackups); + final Set<Rollback> changed = new HashSet<>(pendingBackups); changed.addAll(pendingRestores); return changed; } diff --git a/services/core/java/com/android/server/rollback/RollbackData.java b/services/core/java/com/android/server/rollback/Rollback.java index b37e2680605b..0d5746bf547f 100644 --- a/services/core/java/com/android/server/rollback/RollbackData.java +++ b/services/core/java/com/android/server/rollback/Rollback.java @@ -32,7 +32,7 @@ import java.util.ArrayList; * Information about a rollback available for a set of atomically installed * packages. */ -class RollbackData { +class Rollback { @IntDef(flag = true, prefix = { "ROLLBACK_STATE_" }, value = { ROLLBACK_STATE_ENABLING, ROLLBACK_STATE_AVAILABLE, @@ -102,13 +102,13 @@ class RollbackData { public boolean restoreUserDataInProgress = false; /** - * Constructs a new, empty RollbackData instance. + * Constructs a new, empty Rollback instance. * * @param rollbackId the id of the rollback. * @param backupDir the directory where the rollback data is stored. * @param stagedSessionId the session id if this is a staged rollback, -1 otherwise. */ - RollbackData(int rollbackId, File backupDir, int stagedSessionId) { + Rollback(int rollbackId, File backupDir, int stagedSessionId) { this.info = new RollbackInfo(rollbackId, /* packages */ new ArrayList<>(), /* isStaged */ stagedSessionId != -1, @@ -121,9 +121,9 @@ class RollbackData { } /** - * Constructs a RollbackData instance with full rollback data information. + * Constructs a pre-populated Rollback instance. */ - RollbackData(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId, + Rollback(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId, @RollbackState int state, int apkSessionId, boolean restoreUserDataInProgress) { this.info = info; this.backupDir = backupDir; @@ -143,9 +143,9 @@ class RollbackData { static String rollbackStateToString(@RollbackState int state) { switch (state) { - case RollbackData.ROLLBACK_STATE_ENABLING: return "enabling"; - case RollbackData.ROLLBACK_STATE_AVAILABLE: return "available"; - case RollbackData.ROLLBACK_STATE_COMMITTED: return "committed"; + case Rollback.ROLLBACK_STATE_ENABLING: return "enabling"; + case Rollback.ROLLBACK_STATE_AVAILABLE: return "available"; + case Rollback.ROLLBACK_STATE_COMMITTED: return "committed"; } throw new AssertionError("Invalid rollback state: " + state); } @@ -153,9 +153,9 @@ class RollbackData { static @RollbackState int rollbackStateFromString(String state) throws ParseException { switch (state) { - case "enabling": return RollbackData.ROLLBACK_STATE_ENABLING; - case "available": return RollbackData.ROLLBACK_STATE_AVAILABLE; - case "committed": return RollbackData.ROLLBACK_STATE_COMMITTED; + case "enabling": return Rollback.ROLLBACK_STATE_ENABLING; + case "available": return Rollback.ROLLBACK_STATE_AVAILABLE; + case "committed": return Rollback.ROLLBACK_STATE_COMMITTED; } throw new ParseException("Invalid rollback state: " + state, 0); } diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index f0cf9cf56d0b..bfd280c14f6d 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -110,13 +110,13 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { @GuardedBy("mLock") private final SparseBooleanArray mAllocatedRollbackIds = new SparseBooleanArray(); - // Package rollback data for rollbacks we are in the process of enabling. + // Rollbacks we are in the process of enabling. @GuardedBy("mLock") private final Set<NewRollback> mNewRollbacks = new ArraySet<>(); // The list of all rollbacks, including available and committed rollbacks. @GuardedBy("mLock") - private final List<RollbackData> mRollbacks; + private final List<Rollback> mRollbacks; private final RollbackStore mRollbackStore; @@ -127,7 +127,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { private final AppDataRollbackHelper mAppDataRollbackHelper; // This field stores the difference in Millis between the uptime (millis since device - // has booted) and current time (device wall clock) - it's used to update rollback data + // has booted) and current time (device wall clock) - it's used to update rollback // timestamps when the time is changed, by the user or by change of timezone. // No need for guarding with lock because value is only accessed in handler thread. private long mRelativeBootTime = calculateRelativeBootTime(); @@ -146,9 +146,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // Load rollback data from device storage. synchronized (mLock) { - mRollbacks = mRollbackStore.loadAllRollbackData(); - for (RollbackData data : mRollbacks) { - mAllocatedRollbackIds.put(data.info.getRollbackId(), true); + mRollbacks = mRollbackStore.loadRollbacks(); + for (Rollback rollback : mRollbacks) { + mAllocatedRollbackIds.put(rollback.info.getRollbackId(), true); } } @@ -177,16 +177,14 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1); int installFlags = intent.getIntExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, 0); - int[] installedUsers = intent.getIntArrayExtra( - PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS); int user = intent.getIntExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER, 0); File newPackageCodePath = new File(intent.getData().getPath()); getHandler().post(() -> { - boolean success = enableRollback(installFlags, newPackageCodePath, - installedUsers, user, token); + boolean success = + enableRollback(installFlags, newPackageCodePath, user, token); int ret = PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED; if (!success) { ret = PackageManagerInternal.ENABLE_ROLLBACK_FAILED; @@ -273,39 +271,24 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { }, filter, null, getHandler()); } - /** - * This method posts a blocking call to the handler thread, so it should not be called from - * that same thread. - * @throws {@link IllegalStateException} if called from {@link #mHandlerThread} - */ @Override public ParceledListSlice getAvailableRollbacks() { enforceManageRollbacks("getAvailableRollbacks"); - if (Thread.currentThread().equals(mHandlerThread)) { - Slog.wtf(TAG, "Calling getAvailableRollbacks from mHandlerThread " - + "causes a deadlock"); - throw new IllegalStateException("Cannot call RollbackManager#getAvailableRollbacks " - + "from the handler thread!"); - } - - // Wait for the handler thread to get the list of available rollbacks - // to get the most up-to-date results. This is intended to reduce test - // flakiness when checking available rollbacks immediately after - // installing a package with rollback enabled. - CountDownLatch latch = new CountDownLatch(1); - getHandler().post(() -> latch.countDown()); - try { - latch.await(); - } catch (InterruptedException ie) { - throw new IllegalStateException("RollbackManagerHandlerThread interrupted"); - } - synchronized (mLock) { List<RollbackInfo> rollbacks = new ArrayList<>(); for (int i = 0; i < mRollbacks.size(); ++i) { - RollbackData data = mRollbacks.get(i); - if (data.state == RollbackData.ROLLBACK_STATE_AVAILABLE) { - rollbacks.add(data.info); + Rollback rollback = mRollbacks.get(i); + if (rollback.state == Rollback.ROLLBACK_STATE_AVAILABLE) { + rollbacks.add(rollback.info); + } + } + + // Also return new rollbacks for which the PackageRollbackInfo is complete. + for (NewRollback newRollback : mNewRollbacks) { + if (newRollback.rollback.info.getPackages().size() + == newRollback.packageSessionIds.length + && !newRollback.isCancelled) { + rollbacks.add(newRollback.rollback.info); } } return new ParceledListSlice<>(rollbacks); @@ -319,9 +302,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { synchronized (mLock) { List<RollbackInfo> rollbacks = new ArrayList<>(); for (int i = 0; i < mRollbacks.size(); ++i) { - RollbackData data = mRollbacks.get(i); - if (data.state == RollbackData.ROLLBACK_STATE_COMMITTED) { - rollbacks.add(data.info); + Rollback rollback = mRollbacks.get(i); + if (rollback.state == Rollback.ROLLBACK_STATE_COMMITTED) { + rollbacks.add(rollback.info); } } return new ParceledListSlice<>(rollbacks); @@ -351,11 +334,11 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { final long timeDifference = mRelativeBootTime - oldRelativeBootTime; synchronized (mLock) { - Iterator<RollbackData> iter = mRollbacks.iterator(); + Iterator<Rollback> iter = mRollbacks.iterator(); while (iter.hasNext()) { - RollbackData data = iter.next(); - data.timestamp = data.timestamp.plusMillis(timeDifference); - saveRollbackData(data); + Rollback rollback = iter.next(); + rollback.timestamp = rollback.timestamp.plusMillis(timeDifference); + saveRollback(rollback); } } } @@ -379,8 +362,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { String callerPackageName, IntentSender statusReceiver) { Slog.i(TAG, "Initiating rollback"); - RollbackData data = getRollbackForId(rollbackId); - if (data == null || data.state != RollbackData.ROLLBACK_STATE_AVAILABLE) { + Rollback rollback = getRollbackForId(rollbackId); + if (rollback == null || rollback.state != Rollback.ROLLBACK_STATE_AVAILABLE) { sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE, "Rollback unavailable"); return; @@ -404,14 +387,14 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { PackageInstaller.SessionParams.MODE_FULL_INSTALL); parentParams.setRequestDowngrade(true); parentParams.setMultiPackage(); - if (data.isStaged()) { + if (rollback.isStaged()) { parentParams.setStaged(); } int parentSessionId = packageInstaller.createSession(parentParams); PackageInstaller.Session parentSession = packageInstaller.openSession(parentSessionId); - for (PackageRollbackInfo info : data.info.getPackages()) { + for (PackageRollbackInfo info : rollback.info.getPackages()) { PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( PackageInstaller.SessionParams.MODE_FULL_INSTALL); // TODO: We can't get the installerPackageName for apex @@ -426,7 +409,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { params.setRequestDowngrade(true); params.setRequiredInstalledVersionCode( info.getVersionRolledBackFrom().getLongVersionCode()); - if (data.isStaged()) { + if (rollback.isStaged()) { params.setStaged(); } if (info.isApex()) { @@ -435,7 +418,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { int sessionId = packageInstaller.createSession(params); PackageInstaller.Session session = packageInstaller.openSession(sessionId); File[] packageCodePaths = RollbackStore.getPackageCodePaths( - data, info.getPackageName()); + rollback, info.getPackageName()); if (packageCodePaths == null) { sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE, "Backup copy of package inaccessible"); @@ -476,8 +459,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // TODO: Could this cause a rollback to be // resurrected if it should otherwise have // expired by now? - data.state = RollbackData.ROLLBACK_STATE_AVAILABLE; - data.restoreUserDataInProgress = false; + rollback.state = Rollback.ROLLBACK_STATE_AVAILABLE; + rollback.restoreUserDataInProgress = false; } sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_INSTALL, "Rollback downgrade install failed: " @@ -487,17 +470,17 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } synchronized (mLock) { - if (!data.isStaged()) { + if (!rollback.isStaged()) { // All calls to restoreUserData should have // completed by now for a non-staged install. - data.restoreUserDataInProgress = false; + rollback.restoreUserDataInProgress = false; } - data.info.setCommittedSessionId(parentSessionId); - data.info.getCausePackages().addAll(causePackages); + rollback.info.setCommittedSessionId(parentSessionId); + rollback.info.getCausePackages().addAll(causePackages); } - mRollbackStore.deletePackageCodePaths(data); - saveRollbackData(data); + mRollbackStore.deletePackageCodePaths(rollback); + saveRollback(rollback); sendSuccess(statusReceiver); @@ -512,8 +495,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { ); synchronized (mLock) { - data.state = RollbackData.ROLLBACK_STATE_COMMITTED; - data.restoreUserDataInProgress = true; + rollback.state = Rollback.ROLLBACK_STATE_COMMITTED; + rollback.restoreUserDataInProgress = true; } parentSession.commit(receiver.getIntentSender()); } catch (IOException e) { @@ -535,7 +518,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { updateRollbackLifetimeDurationInMillis(); synchronized (mLock) { mRollbacks.clear(); - mRollbacks.addAll(mRollbackStore.loadAllRollbackData()); + mRollbacks.addAll(mRollbackStore.loadRollbacks()); } latch.countDown(); }); @@ -553,13 +536,21 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Manifest.permission.TEST_MANAGE_ROLLBACKS, "expireRollbackForPackage"); synchronized (mLock) { - Iterator<RollbackData> iter = mRollbacks.iterator(); + Iterator<Rollback> iter = mRollbacks.iterator(); while (iter.hasNext()) { - RollbackData data = iter.next(); - for (PackageRollbackInfo info : data.info.getPackages()) { + Rollback rollback = iter.next(); + for (PackageRollbackInfo info : rollback.info.getPackages()) { if (info.getPackageName().equals(packageName)) { iter.remove(); - deleteRollback(data); + deleteRollback(rollback); + break; + } + } + } + for (NewRollback newRollback : mNewRollbacks) { + for (PackageRollbackInfo info : newRollback.rollback.info.getPackages()) { + if (info.getPackageName().equals(packageName)) { + newRollback.isCancelled = true; break; } } @@ -583,16 +574,16 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { void onUnlockUser(int userId) { getHandler().post(() -> { - final List<RollbackData> rollbacks; + final List<Rollback> rollbacks; synchronized (mLock) { rollbacks = new ArrayList<>(mRollbacks); } - final Set<RollbackData> changed = + final Set<Rollback> changed = mAppDataRollbackHelper.commitPendingBackupAndRestoreForUser(userId, rollbacks); - for (RollbackData rd : changed) { - saveRollbackData(rd); + for (Rollback rollback : changed) { + saveRollback(rollback); } }); } @@ -615,19 +606,19 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { getHandler().post(() -> { // Check to see if any rollback-enabled staged sessions or staged // rollback sessions been applied. - List<RollbackData> enabling = new ArrayList<>(); - List<RollbackData> restoreInProgress = new ArrayList<>(); + List<Rollback> enabling = new ArrayList<>(); + List<Rollback> restoreInProgress = new ArrayList<>(); Set<String> apexPackageNames = new HashSet<>(); synchronized (mLock) { - for (RollbackData data : mRollbacks) { - if (data.isStaged()) { - if (data.state == RollbackData.ROLLBACK_STATE_ENABLING) { - enabling.add(data); - } else if (data.restoreUserDataInProgress) { - restoreInProgress.add(data); + for (Rollback rollback : mRollbacks) { + if (rollback.isStaged()) { + if (rollback.state == Rollback.ROLLBACK_STATE_ENABLING) { + enabling.add(rollback); + } else if (rollback.restoreUserDataInProgress) { + restoreInProgress.add(rollback); } - for (PackageRollbackInfo info : data.info.getPackages()) { + for (PackageRollbackInfo info : rollback.info.getPackages()) { if (info.isApex()) { apexPackageNames.add(info.getPackageName()); } @@ -636,32 +627,32 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } } - for (RollbackData data : enabling) { + for (Rollback rollback : enabling) { PackageInstaller installer = mContext.getPackageManager().getPackageInstaller(); PackageInstaller.SessionInfo session = installer.getSessionInfo( - data.stagedSessionId); + rollback.stagedSessionId); if (session == null || session.isStagedSessionFailed()) { // TODO: Do we need to remove this from // mRollbacks, or is it okay to leave as // unavailable until the next reboot when it will go // away on its own? - deleteRollback(data); + deleteRollback(rollback); } else if (session.isStagedSessionApplied()) { - makeRollbackAvailable(data); + makeRollbackAvailable(rollback); } } - for (RollbackData data : restoreInProgress) { + for (Rollback rollback : restoreInProgress) { PackageInstaller installer = mContext.getPackageManager().getPackageInstaller(); PackageInstaller.SessionInfo session = installer.getSessionInfo( - data.stagedSessionId); + rollback.stagedSessionId); // TODO: What if session is null? if (session != null) { if (session.isStagedSessionApplied() || session.isStagedSessionFailed()) { synchronized (mLock) { - data.restoreUserDataInProgress = false; + rollback.restoreUserDataInProgress = false; } - saveRollbackData(data); + saveRollback(rollback); } } } @@ -688,19 +679,19 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { VersionedPackage installedVersion = getInstalledPackageVersion(packageName); synchronized (mLock) { - Iterator<RollbackData> iter = mRollbacks.iterator(); + Iterator<Rollback> iter = mRollbacks.iterator(); while (iter.hasNext()) { - RollbackData data = iter.next(); + Rollback rollback = iter.next(); // TODO: Should we remove rollbacks in the ENABLING state here? - if (data.state == RollbackData.ROLLBACK_STATE_AVAILABLE - || data.state == RollbackData.ROLLBACK_STATE_ENABLING) { - for (PackageRollbackInfo info : data.info.getPackages()) { + if (rollback.state == Rollback.ROLLBACK_STATE_AVAILABLE + || rollback.state == Rollback.ROLLBACK_STATE_ENABLING) { + for (PackageRollbackInfo info : rollback.info.getPackages()) { if (info.getPackageName().equals(packageName) && !packageVersionsEqual( info.getVersionRolledBackFrom(), installedVersion)) { iter.remove(); - deleteRollback(data); + deleteRollback(rollback); break; } } @@ -756,17 +747,18 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Instant now = Instant.now(); Instant oldest = null; synchronized (mLock) { - Iterator<RollbackData> iter = mRollbacks.iterator(); + Iterator<Rollback> iter = mRollbacks.iterator(); while (iter.hasNext()) { - RollbackData data = iter.next(); - if (data.state != RollbackData.ROLLBACK_STATE_AVAILABLE) { + Rollback rollback = iter.next(); + if (rollback.state != Rollback.ROLLBACK_STATE_AVAILABLE) { continue; } - if (!now.isBefore(data.timestamp.plusMillis(mRollbackLifetimeDurationInMillis))) { + if (!now.isBefore( + rollback.timestamp.plusMillis(mRollbackLifetimeDurationInMillis))) { iter.remove(); - deleteRollback(data); - } else if (oldest == null || oldest.isAfter(data.timestamp)) { - oldest = data.timestamp; + deleteRollback(rollback); + } else if (oldest == null || oldest.isAfter(rollback.timestamp)) { + oldest = rollback.timestamp; } } } @@ -821,13 +813,12 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { * * @param installFlags information about what is being installed. * @param newPackageCodePath path to the package about to be installed. - * @param installedUsers the set of users for which a given package is installed. * @param user the user that owns the install session to enable rollback on. * @param token the distinct rollback token sent by package manager. * @return true if enabling the rollback succeeds, false otherwise. */ - private boolean enableRollback(int installFlags, File newPackageCodePath, - int[] installedUsers, @UserIdInt int user, int token) { + private boolean enableRollback( + int installFlags, File newPackageCodePath, @UserIdInt int user, int token) { // Find the session id associated with this install. // TODO: It would be nice if package manager or package installer told @@ -872,38 +863,15 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // Check to see if this is the apk session for a staged session with // rollback enabled. - // TODO: This check could be made more efficient. - RollbackData rd = null; synchronized (mLock) { for (int i = 0; i < mRollbacks.size(); ++i) { - RollbackData data = mRollbacks.get(i); - if (data.apkSessionId == parentSession.getSessionId()) { - rd = data; - break; - } - } - } - - if (rd != null) { - // This is the apk session for a staged session. We do not need to create a new rollback - // for this session. - PackageParser.PackageLite newPackage = null; - try { - newPackage = PackageParser.parsePackageLite( - new File(packageSession.resolvedBaseCodePath), 0); - } catch (PackageParser.PackageParserException e) { - Slog.e(TAG, "Unable to parse new package", e); - return false; - } - String packageName = newPackage.packageName; - for (PackageRollbackInfo info : rd.info.getPackages()) { - if (info.getPackageName().equals(packageName)) { - info.getInstalledUsers().addAll(IntArray.wrap(installedUsers)); + Rollback rollback = mRollbacks.get(i); + if (rollback.apkSessionId == parentSession.getSessionId()) { + // This is the apk session for a staged session with rollback enabled. We do not + // need to create a new rollback for this session. return true; } } - Slog.e(TAG, "Unable to find package in apk session"); - return false; } NewRollback newRollback; @@ -919,7 +887,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } newRollback.addToken(token); - return enableRollbackForPackageSession(newRollback.data, packageSession, installedUsers); + return enableRollbackForPackageSession(newRollback.rollback, packageSession); } /** @@ -929,8 +897,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { * * @return true on success, false on failure. */ - private boolean enableRollbackForPackageSession(RollbackData data, - PackageInstaller.SessionInfo session, @NonNull int[] installedUsers) { + private boolean enableRollbackForPackageSession(Rollback rollback, + PackageInstaller.SessionInfo session) { // TODO: Don't attempt to enable rollback for split installs. final int installFlags = session.installFlags; if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) { @@ -988,15 +956,14 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo( newVersion, installedVersion, new IntArray() /* pendingBackups */, new ArrayList<>() /* pendingRestores */, - isApex, IntArray.wrap(installedUsers), - new SparseLongArray() /* ceSnapshotInodes */); + isApex, new IntArray(), new SparseLongArray() /* ceSnapshotInodes */); try { ApplicationInfo appInfo = pkgInfo.applicationInfo; - RollbackStore.backupPackageCodePath(data, packageName, appInfo.sourceDir); + RollbackStore.backupPackageCodePath(rollback, packageName, appInfo.sourceDir); if (!ArrayUtils.isEmpty(appInfo.splitSourceDirs)) { for (String sourceDir : appInfo.splitSourceDirs) { - RollbackStore.backupPackageCodePath(data, packageName, sourceDir); + RollbackStore.backupPackageCodePath(rollback, packageName, sourceDir); } } } catch (IOException e) { @@ -1005,7 +972,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } synchronized (mLock) { - data.info.getPackages().add(packageRollbackInfo); + rollback.info.getPackages().add(packageRollbackInfo); } return true; } @@ -1019,7 +986,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } getHandler().post(() -> { - snapshotUserDataInternal(packageName); + snapshotUserDataInternal(packageName, userIds); restoreUserDataInternal(packageName, userIds, appId, ceDataInode, seInfo, token); final PackageManagerInternal pmi = LocalServices.getService( PackageManagerInternal.class); @@ -1027,19 +994,20 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { }); } - private void snapshotUserDataInternal(String packageName) { + private void snapshotUserDataInternal(String packageName, int[] userIds) { synchronized (mLock) { // staged installs for (int i = 0; i < mRollbacks.size(); i++) { - RollbackData data = mRollbacks.get(i); - if (data.state != RollbackData.ROLLBACK_STATE_ENABLING) { + Rollback rollback = mRollbacks.get(i); + if (rollback.state != Rollback.ROLLBACK_STATE_ENABLING) { continue; } - for (PackageRollbackInfo info : data.info.getPackages()) { + for (PackageRollbackInfo info : rollback.info.getPackages()) { if (info.getPackageName().equals(packageName)) { - mAppDataRollbackHelper.snapshotAppData(data.info.getRollbackId(), info); - saveRollbackData(data); + mAppDataRollbackHelper.snapshotAppData( + rollback.info.getRollbackId(), info, userIds); + saveRollback(rollback); break; } } @@ -1047,11 +1015,11 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // non-staged installs PackageRollbackInfo info; for (NewRollback rollback : mNewRollbacks) { - info = getPackageRollbackInfo(rollback.data, packageName); + info = getPackageRollbackInfo(rollback.rollback, packageName); if (info != null) { - mAppDataRollbackHelper.snapshotAppData(rollback.data.info.getRollbackId(), - info); - saveRollbackData(rollback.data); + mAppDataRollbackHelper.snapshotAppData( + rollback.rollback.info.getRollbackId(), info, userIds); + saveRollback(rollback.rollback); } } } @@ -1060,31 +1028,31 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { private void restoreUserDataInternal(String packageName, int[] userIds, int appId, long ceDataInode, String seInfo, int token) { PackageRollbackInfo info = null; - RollbackData rollbackData = null; + Rollback rollback = null; synchronized (mLock) { for (int i = 0; i < mRollbacks.size(); ++i) { - RollbackData data = mRollbacks.get(i); - if (data.restoreUserDataInProgress) { - info = getPackageRollbackInfo(data, packageName); + Rollback candidate = mRollbacks.get(i); + if (candidate.restoreUserDataInProgress) { + info = getPackageRollbackInfo(candidate, packageName); if (info != null) { - rollbackData = data; + rollback = candidate; break; } } } } - if (rollbackData == null) { + if (rollback == null) { return; } for (int userId : userIds) { - final boolean changedRollbackData = mAppDataRollbackHelper.restoreAppData( - rollbackData.info.getRollbackId(), info, userId, appId, seInfo); + final boolean changedRollback = mAppDataRollbackHelper.restoreAppData( + rollback.info.getRollbackId(), info, userId, appId, seInfo); // We've updated metadata about this rollback, so save it to flash. - if (changedRollbackData) { - saveRollbackData(rollbackData); + if (changedRollback) { + saveRollback(rollback); } } } @@ -1114,8 +1082,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } if (!session.isMultiPackage()) { - if (!enableRollbackForPackageSession(newRollback.data, session, - new int[0])) { + if (!enableRollbackForPackageSession(newRollback.rollback, session)) { Slog.e(TAG, "Unable to enable rollback for session: " + sessionId); result.offer(false); return; @@ -1129,8 +1096,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { result.offer(false); return; } - if (!enableRollbackForPackageSession(newRollback.data, childSession, - new int[0])) { + if (!enableRollbackForPackageSession(newRollback.rollback, childSession)) { Slog.e(TAG, "Unable to enable rollback for session: " + sessionId); result.offer(false); return; @@ -1155,20 +1121,20 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { throw new SecurityException("notifyStagedApkSession may only be called by the system."); } getHandler().post(() -> { - RollbackData rd = null; + Rollback rollback = null; synchronized (mLock) { for (int i = 0; i < mRollbacks.size(); ++i) { - RollbackData data = mRollbacks.get(i); - if (data.stagedSessionId == originalSessionId) { - data.apkSessionId = apkSessionId; - rd = data; + Rollback candidate = mRollbacks.get(i); + if (candidate.stagedSessionId == originalSessionId) { + candidate.apkSessionId = apkSessionId; + rollback = candidate; break; } } } - if (rd != null) { - saveRollbackData(rd); + if (rollback != null) { + saveRollback(rollback); } }); } @@ -1278,7 +1244,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } if (newRollback != null) { - RollbackData rollback = completeEnableRollback(newRollback, success); + Rollback rollback = completeEnableRollback(newRollback, success); if (rollback != null && !rollback.isStaged()) { makeRollbackAvailable(rollback); } @@ -1291,32 +1257,32 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { * This should be called after rollback has been enabled for all packages * in the rollback. It does not make the rollback available yet. * - * @return the rollback data for a successfully enable-completed rollback, + * @return the Rollback instance for a successfully enable-completed rollback, * or null on error. */ - private RollbackData completeEnableRollback(NewRollback newRollback, boolean success) { - RollbackData data = newRollback.data; + private Rollback completeEnableRollback(NewRollback newRollback, boolean success) { + Rollback rollback = newRollback.rollback; if (!success) { // The install session was aborted, clean up the pending install. - deleteRollback(data); + deleteRollback(rollback); return null; } if (newRollback.isCancelled) { Slog.e(TAG, "Rollback has been cancelled by PackageManager"); - deleteRollback(data); + deleteRollback(rollback); return null; } - // It's safe to access data.info outside a synchronized block because + // It's safe to access rollback.info outside a synchronized block because // this is running on the handler thread and all changes to the - // data.info occur on the handler thread. - if (data.info.getPackages().size() != newRollback.packageSessionIds.length) { + // rollback.info occur on the handler thread. + if (rollback.info.getPackages().size() != newRollback.packageSessionIds.length) { Slog.e(TAG, "Failed to enable rollback for all packages in session."); - deleteRollback(data); + deleteRollback(rollback); return null; } - saveRollbackData(data); + saveRollback(rollback); synchronized (mLock) { // Note: There is a small window of time between when // the session has been committed by the package @@ -1324,25 +1290,25 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // here. Presumably the window is small enough that // nobody will want to roll back the newly installed // package before we make the rollback available. - // TODO: We'll lose the rollback data if the + // TODO: We'll lose the rollback if the // device reboots between when the session is // committed and this point. Revisit this after // adding support for rollback of staged installs. - mRollbacks.add(data); + mRollbacks.add(rollback); } - return data; + return rollback; } - private void makeRollbackAvailable(RollbackData data) { + private void makeRollbackAvailable(Rollback rollback) { // TODO: What if the rollback has since been expired, for example due // to a new package being installed. Won't this revive an expired // rollback? Consider adding a ROLLBACK_STATE_EXPIRED to address this. synchronized (mLock) { - data.state = RollbackData.ROLLBACK_STATE_AVAILABLE; - data.timestamp = Instant.now(); + rollback.state = Rollback.ROLLBACK_STATE_AVAILABLE; + rollback.timestamp = Instant.now(); } - saveRollbackData(data); + saveRollback(rollback); // TODO(zezeozue): Provide API to explicitly start observing instead // of doing this for all rollbacks. If we do this for all rollbacks, @@ -1350,8 +1316,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // After enabling and commiting any rollback, observe packages and // prepare to rollback if packages crashes too frequently. List<String> packages = new ArrayList<>(); - for (int i = 0; i < data.info.getPackages().size(); i++) { - packages.add(data.info.getPackages().get(i).getPackageName()); + for (int i = 0; i < rollback.info.getPackages().size(); i++) { + packages.add(rollback.info.getPackages().get(i).getPackageName()); } mPackageHealthObserver.startObservingHealth(packages, mRollbackLifetimeDurationInMillis); @@ -1359,15 +1325,14 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } /* - * Returns the RollbackData, if any, for a rollback with the given - * rollbackId. + * Returns the rollback with the given rollbackId, if any. */ - private RollbackData getRollbackForId(int rollbackId) { + private Rollback getRollbackForId(int rollbackId) { synchronized (mLock) { for (int i = 0; i < mRollbacks.size(); ++i) { - RollbackData data = mRollbacks.get(i); - if (data.info.getRollbackId() == rollbackId) { - return data; + Rollback rollback = mRollbacks.get(i); + if (rollback.info.getRollbackId() == rollbackId) { + return rollback; } } } @@ -1377,11 +1342,11 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { /** * Returns the {@code PackageRollbackInfo} associated with {@code packageName} from - * a specified {@code RollbackData}. + * a specified {@code Rollback}. */ - private static PackageRollbackInfo getPackageRollbackInfo(RollbackData data, + private static PackageRollbackInfo getPackageRollbackInfo(Rollback rollback, String packageName) { - for (PackageRollbackInfo info : data.info.getPackages()) { + for (PackageRollbackInfo info : rollback.info.getPackages()) { if (info.getPackageName().equals(packageName)) { return info; } @@ -1405,30 +1370,30 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { throw new IllegalStateException("Failed to allocate rollback ID"); } - private void deleteRollback(RollbackData rollbackData) { - for (PackageRollbackInfo info : rollbackData.info.getPackages()) { - IntArray installedUsers = info.getInstalledUsers(); - for (int i = 0; i < installedUsers.size(); i++) { - int userId = installedUsers.get(i); - mAppDataRollbackHelper.destroyAppDataSnapshot(rollbackData.info.getRollbackId(), + private void deleteRollback(Rollback rollback) { + for (PackageRollbackInfo info : rollback.info.getPackages()) { + IntArray snapshottedUsers = info.getSnapshottedUsers(); + for (int i = 0; i < snapshottedUsers.size(); i++) { + int userId = snapshottedUsers.get(i); + mAppDataRollbackHelper.destroyAppDataSnapshot(rollback.info.getRollbackId(), info, userId); } } - mRollbackStore.deleteRollbackData(rollbackData); + mRollbackStore.deleteRollback(rollback); } /** - * Saves rollback data, swallowing any IOExceptions. + * Saves a rollback, swallowing any IOExceptions. * For those times when it's not obvious what to do about the IOException. * TODO: Double check we can't do a better job handling the IOException in * a cases where this method is called. */ - private void saveRollbackData(RollbackData rollbackData) { + private void saveRollback(Rollback rollback) { try { - mRollbackStore.saveRollbackData(rollbackData); + mRollbackStore.saveRollback(rollback); } catch (IOException ioe) { - Slog.e(TAG, "Unable to save rollback info for: " - + rollbackData.info.getRollbackId(), ioe); + Slog.e(TAG, "Unable to save rollback for: " + + rollback.info.getRollbackId(), ioe); } } @@ -1436,14 +1401,14 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); synchronized (mLock) { - for (RollbackData data : mRollbacks) { - RollbackInfo info = data.info; + for (Rollback rollback : mRollbacks) { + RollbackInfo info = rollback.info; ipw.println(info.getRollbackId() + ":"); ipw.increaseIndent(); - ipw.println("-state: " + data.getStateAsString()); - ipw.println("-timestamp: " + data.timestamp); - if (data.stagedSessionId != -1) { - ipw.println("-stagedSessionId: " + data.stagedSessionId); + ipw.println("-state: " + rollback.getStateAsString()); + ipw.println("-timestamp: " + rollback.timestamp); + if (rollback.stagedSessionId != -1) { + ipw.println("-stagedSessionId: " + rollback.stagedSessionId); } ipw.println("-packages:"); ipw.increaseIndent(); @@ -1453,7 +1418,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { + " -> " + pkg.getVersionRolledBackTo().getLongVersionCode()); } ipw.decreaseIndent(); - if (data.state == RollbackData.ROLLBACK_STATE_COMMITTED) { + if (rollback.state == Rollback.ROLLBACK_STATE_COMMITTED) { ipw.println("-causePackages:"); ipw.increaseIndent(); for (VersionedPackage cPkg : info.getCausePackages()) { @@ -1479,7 +1444,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } private static class NewRollback { - public final RollbackData data; + public final Rollback rollback; /** * This array holds all of the rollback tokens associated with package sessions included @@ -1497,9 +1462,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { public final int[] packageSessionIds; /** - * Flag to determine whether the RollbackData has been cancelled. + * Flag to determine whether the rollback has been cancelled. * - * <p>RollbackData could be invalidated and cancelled if RollbackManager receives + * <p>Rollback could be invalidated and cancelled if RollbackManager receives * {@link Intent#ACTION_CANCEL_ENABLE_ROLLBACK} from {@link PackageManager}. * * <p>The main underlying assumption here is that if enabling the rollback times out, then @@ -1509,8 +1474,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { */ public boolean isCancelled = false; - NewRollback(RollbackData data, int[] packageSessionIds) { - this.data = data; + NewRollback(Rollback rollback, int[] packageSessionIds) { + this.rollback = rollback; this.packageSessionIds = packageSessionIds; } @@ -1525,13 +1490,13 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { NewRollback createNewRollbackLocked(PackageInstaller.SessionInfo parentSession) { int rollbackId = allocateRollbackIdLocked(); - final RollbackData data; + final Rollback rollback; int parentSessionId = parentSession.getSessionId(); if (parentSession.isStaged()) { - data = mRollbackStore.createStagedRollback(rollbackId, parentSessionId); + rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId); } else { - data = mRollbackStore.createNonStagedRollback(rollbackId); + rollback = mRollbackStore.createNonStagedRollback(rollbackId); } int[] packageSessionIds; @@ -1541,7 +1506,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { packageSessionIds = new int[]{parentSessionId}; } - return new NewRollback(data, packageSessionIds); + return new NewRollback(rollback, packageSessionIds); } /** @@ -1552,10 +1517,10 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { NewRollback getNewRollbackForPackageSessionLocked(int packageSessionId) { // We expect mNewRollbacks to be a very small list; linear search // should be plenty fast. - for (NewRollback newRollbackData : mNewRollbacks) { - for (int id : newRollbackData.packageSessionIds) { + for (NewRollback newRollback: mNewRollbacks) { + for (int id : newRollback.packageSessionIds) { if (id == packageSessionId) { - return newRollbackData; + return newRollback; } } } diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java index 1c36dc7791e6..b2448f62bcd7 100644 --- a/services/core/java/com/android/server/rollback/RollbackStore.java +++ b/services/core/java/com/android/server/rollback/RollbackStore.java @@ -16,8 +16,8 @@ package com.android.server.rollback; -import static com.android.server.rollback.RollbackData.rollbackStateFromString; -import static com.android.server.rollback.RollbackData.rollbackStateToString; +import static com.android.server.rollback.Rollback.rollbackStateFromString; +import static com.android.server.rollback.Rollback.rollbackStateToString; import android.annotation.NonNull; import android.content.pm.VersionedPackage; @@ -73,17 +73,17 @@ class RollbackStore { } /** - * Reads the rollback data from persistent storage. + * Reads the rollbacks from persistent storage. */ - List<RollbackData> loadAllRollbackData() { - List<RollbackData> rollbacks = new ArrayList<>(); + List<Rollback> loadRollbacks() { + List<Rollback> rollbacks = new ArrayList<>(); mRollbackDataDir.mkdirs(); for (File rollbackDir : mRollbackDataDir.listFiles()) { if (rollbackDir.isDirectory()) { try { - rollbacks.add(loadRollbackData(rollbackDir)); + rollbacks.add(loadRollback(rollbackDir)); } catch (IOException e) { - Slog.e(TAG, "Unable to read rollback data at " + rollbackDir, e); + Slog.e(TAG, "Unable to read rollback at " + rollbackDir, e); removeFile(rollbackDir); } } @@ -191,21 +191,21 @@ class RollbackStore { } /** - * Creates a new RollbackData instance for a non-staged rollback with + * Creates a new Rollback instance for a non-staged rollback with * backupDir assigned. */ - RollbackData createNonStagedRollback(int rollbackId) { + Rollback createNonStagedRollback(int rollbackId) { File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId)); - return new RollbackData(rollbackId, backupDir, -1); + return new Rollback(rollbackId, backupDir, -1); } /** - * Creates a new RollbackData instance for a staged rollback with + * Creates a new Rollback instance for a staged rollback with * backupDir assigned. */ - RollbackData createStagedRollback(int rollbackId, int stagedSessionId) { + Rollback createStagedRollback(int rollbackId, int stagedSessionId) { File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId)); - return new RollbackData(rollbackId, backupDir, stagedSessionId); + return new Rollback(rollbackId, backupDir, stagedSessionId); } /** @@ -213,10 +213,10 @@ class RollbackStore { * For packages containing splits, this method should be called for each * of the package's split apks in addition to the base apk. */ - static void backupPackageCodePath(RollbackData data, String packageName, String codePath) + static void backupPackageCodePath(Rollback rollback, String packageName, String codePath) throws IOException { File sourceFile = new File(codePath); - File targetDir = new File(data.backupDir, packageName); + File targetDir = new File(rollback.backupDir, packageName); targetDir.mkdirs(); File targetFile = new File(targetDir, sourceFile.getName()); @@ -228,8 +228,8 @@ class RollbackStore { * Returns the apk or apex files backed up for the given package. * Includes the base apk and any splits. Returns null if none found. */ - static File[] getPackageCodePaths(RollbackData data, String packageName) { - File targetDir = new File(data.backupDir, packageName); + static File[] getPackageCodePaths(Rollback rollback, String packageName) { + File targetDir = new File(rollback.backupDir, packageName); File[] files = targetDir.listFiles(); if (files == null || files.length == 0) { return null; @@ -241,27 +241,27 @@ class RollbackStore { * Deletes all backed up apks and apex files associated with the given * rollback. */ - static void deletePackageCodePaths(RollbackData data) { - for (PackageRollbackInfo info : data.info.getPackages()) { - File targetDir = new File(data.backupDir, info.getPackageName()); + static void deletePackageCodePaths(Rollback rollback) { + for (PackageRollbackInfo info : rollback.info.getPackages()) { + File targetDir = new File(rollback.backupDir, info.getPackageName()); removeFile(targetDir); } } /** - * Saves the rollback data to persistent storage. + * Saves the given rollback to persistent storage. */ - void saveRollbackData(RollbackData data) throws IOException { + void saveRollback(Rollback rollback) throws IOException { try { JSONObject dataJson = new JSONObject(); - dataJson.put("info", rollbackInfoToJson(data.info)); - dataJson.put("timestamp", data.timestamp.toString()); - dataJson.put("stagedSessionId", data.stagedSessionId); - dataJson.put("state", rollbackStateToString(data.state)); - dataJson.put("apkSessionId", data.apkSessionId); - dataJson.put("restoreUserDataInProgress", data.restoreUserDataInProgress); - - PrintWriter pw = new PrintWriter(new File(data.backupDir, "rollback.json")); + dataJson.put("info", rollbackInfoToJson(rollback.info)); + dataJson.put("timestamp", rollback.timestamp.toString()); + dataJson.put("stagedSessionId", rollback.stagedSessionId); + dataJson.put("state", rollbackStateToString(rollback.state)); + dataJson.put("apkSessionId", rollback.apkSessionId); + dataJson.put("restoreUserDataInProgress", rollback.restoreUserDataInProgress); + + PrintWriter pw = new PrintWriter(new File(rollback.backupDir, "rollback.json")); pw.println(dataJson.toString()); pw.close(); } catch (JSONException e) { @@ -270,23 +270,23 @@ class RollbackStore { } /** - * Removes all persistant storage associated with the given rollback data. + * Removes all persistent storage associated with the given rollback. */ - void deleteRollbackData(RollbackData data) { - removeFile(data.backupDir); + void deleteRollback(Rollback rollback) { + removeFile(rollback.backupDir); } /** * Reads the metadata for a rollback from the given directory. * @throws IOException in case of error reading the data. */ - private static RollbackData loadRollbackData(File backupDir) throws IOException { + private static Rollback loadRollback(File backupDir) throws IOException { try { File rollbackJsonFile = new File(backupDir, "rollback.json"); JSONObject dataJson = new JSONObject( IoUtils.readFileAsString(rollbackJsonFile.getAbsolutePath())); - return new RollbackData( + return new Rollback( rollbackInfoFromJson(dataJson.getJSONObject("info")), backupDir, Instant.parse(dataJson.getString("timestamp")), @@ -319,13 +319,14 @@ class RollbackStore { IntArray pendingBackups = info.getPendingBackups(); List<RestoreInfo> pendingRestores = info.getPendingRestores(); - IntArray installedUsers = info.getInstalledUsers(); + IntArray snapshottedUsers = info.getSnapshottedUsers(); json.put("pendingBackups", convertToJsonArray(pendingBackups)); json.put("pendingRestores", convertToJsonArray(pendingRestores)); json.put("isApex", info.isApex()); - json.put("installedUsers", convertToJsonArray(installedUsers)); + // Field is named 'installedUsers' for legacy reasons. + json.put("installedUsers", convertToJsonArray(snapshottedUsers)); json.put("ceSnapshotInodes", ceSnapshotInodesToJson(info.getCeSnapshotInodes())); return json; @@ -345,12 +346,13 @@ class RollbackStore { final boolean isApex = json.getBoolean("isApex"); - final IntArray installedUsers = convertToIntArray(json.getJSONArray("installedUsers")); + // Field is named 'installedUsers' for legacy reasons. + final IntArray snapshottedUsers = convertToIntArray(json.getJSONArray("installedUsers")); final SparseLongArray ceSnapshotInodes = ceSnapshotInodesFromJson( json.getJSONArray("ceSnapshotInodes")); return new PackageRollbackInfo(versionRolledBackFrom, versionRolledBackTo, - pendingBackups, pendingRestores, isApex, installedUsers, ceSnapshotInodes); + pendingBackups, pendingRestores, isApex, snapshottedUsers, ceSnapshotInodes); } private static JSONArray versionedPackagesToJson(List<VersionedPackage> packages) diff --git a/services/core/java/com/android/server/security/KeyChainSystemService.java b/services/core/java/com/android/server/security/KeyChainSystemService.java index 2f681a3f568e..3c06d0ec7950 100644 --- a/services/core/java/com/android/server/security/KeyChainSystemService.java +++ b/services/core/java/com/android/server/security/KeyChainSystemService.java @@ -27,7 +27,7 @@ import android.os.UserHandle; import android.security.IKeyChainService; import android.util.Slog; -import com.android.server.DeviceIdleController; +import com.android.server.DeviceIdleInternal; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -99,8 +99,8 @@ public class KeyChainSystemService extends SystemService { } final String packageName = intent.getComponent().getPackageName(); - final DeviceIdleController.LocalService idleController = - LocalServices.getService(DeviceIdleController.LocalService.class); + final DeviceIdleInternal idleController = + LocalServices.getService(DeviceIdleInternal.class); idleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName, KEYCHAIN_IDLE_WHITELIST_DURATION_MS, user.getIdentifier(), false, "keychain"); diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index d67048fe548d..8897eca85d7a 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -610,11 +610,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver, - int type, boolean requireConfirmation, int userId) { + int type, boolean requireConfirmation, int userId, String opPackageName) { enforceBiometricDialog(); if (mBar != null) { try { - mBar.showBiometricDialog(bundle, receiver, type, requireConfirmation, userId); + mBar.showBiometricDialog(bundle, receiver, type, requireConfirmation, userId, + opPackageName); } catch (RemoteException ex) { } } diff --git a/services/core/java/com/android/server/tv/TvRemoteProviderProxy.java b/services/core/java/com/android/server/tv/TvRemoteProviderProxy.java index 557e9c8c8557..b27d5ea30c67 100644 --- a/services/core/java/com/android/server/tv/TvRemoteProviderProxy.java +++ b/services/core/java/com/android/server/tv/TvRemoteProviderProxy.java @@ -255,8 +255,6 @@ final class TvRemoteProviderProxy implements ServiceConnection { void clearInputBridge(TvRemoteProviderProxy provider, IBinder token); - void sendTimeStamp(TvRemoteProviderProxy provider, IBinder token, long timestamp); - void sendKeyDown(TvRemoteProviderProxy provider, IBinder token, int keyCode); void sendKeyUp(TvRemoteProviderProxy provider, IBinder token, int keyCode); @@ -400,24 +398,8 @@ final class TvRemoteProviderProxy implements ServiceConnection { } void sendTimestamp(final IBinder token, final long timestamp) { - synchronized (mLock) { - if (mActiveConnection == this && Binder.getCallingUid() == mUid) { - final long idToken = Binder.clearCallingIdentity(); - try { - if (mProviderMethods != null) { - mProviderMethods.sendTimeStamp(TvRemoteProviderProxy.this, token, - timestamp); - } - } finally { - Binder.restoreCallingIdentity(idToken); - } - } else { - if (DEBUG) { - Slog.w(TAG, - "sendTimeStamp, Invalid connection or incorrect uid: " + Binder - .getCallingUid()); - } - } + if (DEBUG) { + Slog.e(TAG, "sendTimestamp is deprecated, please remove all usages of this API."); } } diff --git a/services/core/java/com/android/server/tv/TvRemoteService.java b/services/core/java/com/android/server/tv/TvRemoteService.java index 961c9925414a..4a41bf8133c3 100644 --- a/services/core/java/com/android/server/tv/TvRemoteService.java +++ b/services/core/java/com/android/server/tv/TvRemoteService.java @@ -147,13 +147,6 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor { } } - private void sendTimeStampInternalLocked(IBinder token, long timestamp) { - UinputBridge inputBridge = mBridgeMap.get(token); - if (inputBridge != null) { - inputBridge.sendTimestamp(token, timestamp); - } - } - private void sendKeyDownInternalLocked(IBinder token, int keyCode) { if (DEBUG_KEYS) { Slog.d(TAG, "sendKeyDownInternalLocked(), token: " + token + ", keyCode: " + keyCode); @@ -298,15 +291,6 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor { } @Override - public void sendTimeStamp(TvRemoteProviderProxy provider, IBinder token, long timestamp) { - synchronized (mLock) { - if (mProviderList.contains(provider)) { - mService.sendTimeStampInternalLocked(token, timestamp); - } - } - } - - @Override public void sendKeyDown(TvRemoteProviderProxy provider, IBinder token, int keyCode) { if (DEBUG_KEYS) { Slog.d(TAG, "sendKeyDown(), token: " + token + ", keyCode: " + keyCode); diff --git a/services/core/java/com/android/server/tv/UinputBridge.java b/services/core/java/com/android/server/tv/UinputBridge.java index 1a984f98051f..752aa6683a88 100644 --- a/services/core/java/com/android/server/tv/UinputBridge.java +++ b/services/core/java/com/android/server/tv/UinputBridge.java @@ -16,13 +16,12 @@ package com.android.server.tv; -import android.os.Binder; import android.os.IBinder; -import java.io.IOException; - import dalvik.system.CloseGuard; +import java.io.IOException; + /** * Sends the input event to the linux driver. */ @@ -35,7 +34,6 @@ public final class UinputBridge { int maxPointers); private static native void nativeClose(long ptr); private static native void nativeClear(long ptr); - private static native void nativeSendTimestamp(long ptr, long timestamp); private static native void nativeSendKey(long ptr, int keyCode, boolean down); private static native void nativeSendPointerDown(long ptr, int pointerId, int x, int y); private static native void nativeSendPointerUp(long ptr, int pointerId); @@ -93,12 +91,6 @@ public final class UinputBridge { return mToken.equals(token); } - public void sendTimestamp(IBinder token, long timestamp) { - if (isTokenValid(token)) { - nativeSendTimestamp(mPtr, timestamp); - } - } - public void sendKeyDown(IBinder token, int keyCode) { if (isTokenValid(token)) { nativeSendKey(mPtr, keyCode, true /*down*/); diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java index f1cd721cfd8c..5a0dfd02b7b0 100644 --- a/services/core/java/com/android/server/wm/ActivityDisplay.java +++ b/services/core/java/com/android/server/wm/ActivityDisplay.java @@ -41,6 +41,7 @@ import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY; import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE; import static com.android.server.am.ActivityDisplayProto.STACKS; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; +import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK; @@ -173,18 +174,10 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> mService = root.mService; mDisplayId = display.getDisplayId(); mDisplay = display; - mDisplayContent = createDisplayContent(); + mDisplayContent = mService.mWindowManager.mRoot.createDisplayContent(mDisplay, this); mDisplayContent.reconfigureDisplayLocked(); - updateBounds(); - } - - protected DisplayContent createDisplayContent() { - return mService.mWindowManager.mRoot.createDisplayContent(mDisplay, this); - } - - private void updateBounds() { - mDisplay.getRealSize(mTmpDisplaySize); - setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y); + onRequestedOverrideConfigurationChanged( + mDisplayContent.getRequestedOverrideConfiguration()); } void onDisplayChanged() { @@ -200,7 +193,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> } } - updateBounds(); + mDisplay.getRealSize(mTmpDisplaySize); + setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y); if (mDisplayContent != null) { mDisplayContent.updateDisplayInfo(); mService.mWindowManager.requestTraversal(); @@ -1541,6 +1535,17 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> return mSingleTaskInstance; } + @VisibleForTesting + void removeAllTasks() { + for (int i = getChildCount() - 1; i >= 0; --i) { + final ActivityStack stack = getChildAt(i); + final ArrayList<TaskRecord> tasks = stack.getAllTasks(); + for (int j = tasks.size() - 1; j >= 0; --j) { + stack.removeTask(tasks.get(j), "removeAllTasks", REMOVE_TASK_MODE_DESTROYING); + } + } + } + public void dump(PrintWriter pw, String prefix) { pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size() + (mSingleTaskInstance ? " mSingleTaskInstance" : "")); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 31e8bbdab71c..2269537c7cae 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -121,6 +121,7 @@ import static com.android.server.wm.ActivityStack.PAUSE_TIMEOUT_MSG; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; import static com.android.server.wm.ActivityStack.STOP_TIMEOUT_MSG; import static com.android.server.wm.ActivityStackSupervisor.PAUSE_IMMEDIATELY; +import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONTAINERS; @@ -1372,16 +1373,17 @@ final class ActivityRecord extends ConfigurationContainer { return stack != null ? stack.getDisplay() : null; } - boolean changeWindowTranslucency(boolean toOpaque) { - if (fullscreen == toOpaque) { - return false; + boolean setOccludesParent(boolean occludesParent) { + final boolean changed = mAppWindowToken.setOccludesParent(occludesParent); + if (changed) { + if (!occludesParent) { + getActivityStack().convertActivityToTranslucent(this); + } + // Keep track of the number of fullscreen activities in this task. + task.numFullscreen += occludesParent ? +1 : -1; + mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); } - - // Keep track of the number of fullscreen activities in this task. - task.numFullscreen += toOpaque ? +1 : -1; - - fullscreen = toOpaque; - return true; + return changed; } void takeFromHistory() { diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 17536e42acc8..daf32862e287 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -2492,7 +2492,7 @@ class ActivityStack extends ConfigurationContainer { mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG); if (waitingActivity != null) { - mWindowManager.setWindowOpaque(waitingActivity.appToken, false); + mWindowManager.setWindowOpaqueLocked(waitingActivity.appToken, false); if (waitingActivity.attachedToProcess()) { try { waitingActivity.app.getThread().scheduleTranslucentConversionComplete( @@ -2813,7 +2813,7 @@ class ActivityStack extends ConfigurationContainer { // Launching this app's activity, make sure the app is no longer // considered stopped. try { - AppGlobals.getPackageManager().setPackageStoppedState( + mService.getPackageManager().setPackageStoppedState( next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */ } catch (RemoteException e1) { } catch (IllegalArgumentException e) { @@ -5370,13 +5370,20 @@ class ActivityStack extends ConfigurationContainer { void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration, boolean fromFullscreen) { if (!inPinnedWindowingMode()) return; - if (skipResizeAnimation(toBounds == null /* toFullscreen */)) { - mService.moveTasksToFullscreenStack(mStackId, true /* onTop */); - } else { - if (getTaskStack() == null) return; - getTaskStack().animateResizePinnedStack(toBounds, sourceHintBounds, - animationDuration, fromFullscreen); + if (toBounds == null /* toFullscreen */) { + final Configuration parentConfig = getParent().getConfiguration(); + final ActivityRecord top = topRunningNonOverlayTaskActivity(); + if (top != null && !top.isConfigurationCompatible(parentConfig)) { + // The final orientation of this activity will change after moving to full screen. + // Start freezing screen here to prevent showing a temporary full screen window. + top.startFreezingScreenLocked(top.app, CONFIG_SCREEN_LAYOUT); + mService.moveTasksToFullscreenStack(mStackId, true /* onTop */); + return; + } } + if (getTaskStack() == null) return; + getTaskStack().animateResizePinnedStack(toBounds, sourceHintBounds, + animationDuration, fromFullscreen); } /** @@ -5392,15 +5399,6 @@ class ActivityStack extends ConfigurationContainer { stack.getAnimationOrCurrentBounds(outBounds); } - private boolean skipResizeAnimation(boolean toFullscreen) { - if (!toFullscreen) { - return false; - } - final Configuration parentConfig = getParent().getConfiguration(); - final ActivityRecord top = topRunningNonOverlayTaskActivity(); - return top != null && !top.isConfigurationCompatible(parentConfig); - } - void setPictureInPictureAspectRatio(float aspectRatio) { if (getTaskStack() == null) return; getTaskStack().setPictureInPictureAspectRatio(aspectRatio); diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 1c56a107ab9e..22f72a499aff 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -250,7 +250,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { RecentTasks mRecentTasks; /** Helper class to abstract out logic for fetching the set of currently running tasks */ - RunningTasks mRunningTasks; + private RunningTasks mRunningTasks; final ActivityStackSupervisorHandler mHandler; final Looper mLooper; @@ -444,7 +444,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } mInitialized = true; - mRunningTasks = createRunningTasks(); + setRunningTasks(new RunningTasks()); mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext, mHandler.getLooper()); @@ -485,13 +485,20 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } void setRecentTasks(RecentTasks recentTasks) { + if (mRecentTasks != null) { + mRecentTasks.unregisterCallback(this); + } mRecentTasks = recentTasks; mRecentTasks.registerCallback(this); } @VisibleForTesting - RunningTasks createRunningTasks() { - return new RunningTasks(); + void setRunningTasks(RunningTasks runningTasks) { + mRunningTasks = runningTasks; + } + + RunningTasks getRunningTasks() { + return mRunningTasks; } /** @@ -2735,7 +2742,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { mWindowManager.deferSurfaceLayout(); try { if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - mWindowManager.setDockedStackCreateState( + mWindowManager.setDockedStackCreateStateLocked( activityOptions.getSplitScreenCreateMode(), null /* initialBounds */); // Defer updating the stack in which recents is until the app transition is done, to diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index a3ab27e4f06b..a7b6e0ff0630 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -43,7 +43,6 @@ import static android.content.pm.ApplicationInfo.FLAG_FACTORY_TEST; import static android.content.pm.ConfigurationInfo.GL_ES_VERSION_UNDEFINED; import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS; import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT; -import static android.content.pm.PackageManager.FEATURE_PC; import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION; @@ -211,7 +210,7 @@ import android.service.voice.VoiceInteractionManagerInternal; import android.sysprop.DisplayProperties; import android.telecom.TelecomManager; import android.text.TextUtils; -import android.text.format.Time; +import android.text.format.TimeMigrationUtils; import android.util.ArrayMap; import android.util.EventLog; import android.util.Log; @@ -361,7 +360,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /* Global service lock used by the package the owns this service. */ final WindowManagerGlobalLock mGlobalLock = new WindowManagerGlobalLock(); /** - * It is the same instance as {@link mGlobalLock}, just declared as a type that the + * It is the same instance as {@link #mGlobalLock}, just declared as a type that the * locked-region-code-injection does't recognize it. It is used to skip wrapping priority * booster for places that are already in the scope of another booster (e.g. computing oom-adj). * @@ -730,7 +729,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0; final boolean forceResizable = Settings.Global.getInt( resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0; - final boolean isPc = mContext.getPackageManager().hasSystemFeature(FEATURE_PC); // Transfer any global setting for forcing RTL layout, into a System Property DisplayProperties.debug_force_rtl(forceRtl); @@ -761,10 +759,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mSupportsPictureInPicture = false; mSupportsMultiDisplay = false; } - mWindowManager.setForceResizableTasks(mForceResizableActivities); - mWindowManager.setSupportsPictureInPicture(mSupportsPictureInPicture); - mWindowManager.setSupportsFreeformWindowManagement(mSupportsFreeformWindowManagement); - mWindowManager.setIsPc(isPc); mWindowManager.mRoot.onSettingsRetrieved(); // This happens before any activities are started, so we can change global configuration // in-place. @@ -821,8 +815,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { new TaskChangeNotificationController(mGlobalLock, mStackSupervisor, mH); mLockTaskController = new LockTaskController(mContext, mStackSupervisor, mH); mActivityStartController = new ActivityStartController(this); - mRecentTasks = createRecentTasks(); - mStackSupervisor.setRecentTasks(mRecentTasks); + setRecentTasks(new RecentTasks(this, mStackSupervisor)); mVrController = new VrController(mGlobalLock); mKeyguardController = mStackSupervisor.getKeyguardController(); } @@ -890,8 +883,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return mode == AppOpsManager.MODE_ALLOWED; } - protected RecentTasks createRecentTasks() { - return new RecentTasks(this, mStackSupervisor); + @VisibleForTesting + protected void setRecentTasks(RecentTasks recentTasks) { + mRecentTasks = recentTasks; + mStackSupervisor.setRecentTasks(recentTasks); } RecentTasks getRecentTasks() { @@ -1954,12 +1949,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (r == null) { return false; } - final boolean translucentChanged = r.changeWindowTranslucency(true); - if (translucentChanged) { - mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); - } - mWindowManager.setAppFullscreen(token, true); - return translucentChanged; + return r.setOccludesParent(true); } } finally { Binder.restoreCallingIdentity(origId); @@ -1982,13 +1972,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { ActivityRecord under = task.mActivities.get(index - 1); under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null; } - final boolean translucentChanged = r.changeWindowTranslucency(false); - if (translucentChanged) { - r.getActivityStack().convertActivityToTranslucent(r); - } - mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); - mWindowManager.setAppFullscreen(token, false); - return translucentChanged; + return r.setOccludesParent(false); } } finally { Binder.restoreCallingIdentity(origId); @@ -2581,7 +2565,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { + taskId + " to stack " + stackId); } if (stack.inSplitScreenPrimaryWindowingMode()) { - mWindowManager.setDockedStackCreateState( + mWindowManager.setDockedStackCreateStateLocked( SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */); } task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME, @@ -2700,7 +2684,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { + " non-standard task " + taskId + " to split-screen windowing mode"); } - mWindowManager.setDockedStackCreateState(createMode, initialBounds); + mWindowManager.setDockedStackCreateStateLocked(createMode, initialBounds); final int windowingMode = task.getWindowingMode(); final ActivityStack stack = task.getStack(); if (toTop) { @@ -2802,7 +2786,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { try { synchronized (mGlobalLock) { // Cancel the recents animation synchronously (do not hold the WM lock) - mWindowManager.cancelRecentsAnimationSynchronously(restoreHomeStackPosition + mWindowManager.cancelRecentsAnimation(restoreHomeStackPosition ? REORDER_MOVE_TO_ORIGINAL_POSITION : REORDER_KEEP_IN_PLACE, "cancelRecentsAnimation/uid=" + callingUid); } @@ -5878,9 +5862,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { tracesFile = File.createTempFile("app_slow", null, tracesDir); StringBuilder sb = new StringBuilder(); - Time tobj = new Time(); - tobj.set(System.currentTimeMillis()); - sb.append(tobj.format("%Y-%m-%d %H:%M:%S")); + String timeString = + TimeMigrationUtils.formatMillisWithFixedFormat(System.currentTimeMillis()); + sb.append(timeString); sb.append(": "); TimeUtils.formatDuration(SystemClock.uptimeMillis()-startTime, sb); sb.append(" since "); diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 7fde6dee63e3..7e0d9a05c524 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -92,6 +92,7 @@ import android.content.ComponentName; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.GraphicBuffer; +import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.os.Binder; @@ -153,8 +154,11 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree final ComponentName mActivityComponent; final boolean mVoiceInteraction; - /** @see WindowContainer#fillsParent() */ - private boolean mFillsParent; + /** + * The activity is opaque and fills the entire space of this task. + * @see WindowContainer#fillsParent() + */ + private boolean mOccludesParent; boolean mShowForAllUsers; int mTargetSdk; @@ -373,7 +377,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree appToken = token; mActivityComponent = activityComponent; mVoiceInteraction = voiceInteraction; - mFillsParent = fillsParent; + mOccludesParent = fillsParent; mInputApplicationHandle = new InputApplicationHandle(appToken.asBinder()); } @@ -2354,11 +2358,29 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree @Override boolean fillsParent() { - return mFillsParent; + return occludesParent(); + } + + /** Returns true if this activity is opaque and fills the entire space of this task. */ + boolean occludesParent() { + return mOccludesParent; + } + + boolean setOccludesParent(boolean occludesParent) { + final boolean changed = occludesParent != mOccludesParent; + mOccludesParent = occludesParent; + setMainWindowOpaque(occludesParent); + mWmService.mWindowPlacerLocked.requestTraversal(); + return changed; } - void setFillsParent(boolean fillsParent) { - mFillsParent = fillsParent; + void setMainWindowOpaque(boolean isOpaque) { + final WindowState win = findMainWindow(); + if (win == null) { + return; + } + isOpaque = isOpaque & !PixelFormat.formatHasAlpha(win.getAttrs().format); + win.mWinAnimator.setOpaqueLocked(isOpaque); } boolean containsDismissKeyguardWindow() { @@ -3035,7 +3057,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } pw.println(prefix + "component=" + mActivityComponent.flattenToShortString()); pw.print(prefix); pw.print("task="); pw.println(getTask()); - pw.print(prefix); pw.print(" mFillsParent="); pw.print(mFillsParent); + pw.print(prefix); pw.print(" mOccludesParent="); pw.print(mOccludesParent); pw.print(" mOrientation="); pw.println(mOrientation); pw.println(prefix + "hiddenRequested=" + hiddenRequested + " mClientHidden=" + mClientHidden + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "") @@ -3152,7 +3174,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (mThumbnail != null){ mThumbnail.writeToProto(proto, THUMBNAIL); } - proto.write(FILLS_PARENT, mFillsParent); + proto.write(FILLS_PARENT, mOccludesParent); proto.write(APP_STOPPED, mAppStopped); proto.write(HIDDEN_REQUESTED, hiddenRequested); proto.write(CLIENT_HIDDEN, mClientHidden); diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 282ed42468dd..410cc94869d8 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -295,7 +295,8 @@ public class DisplayRotation { false /* forceRelayout */); } - private void setUserRotation(int userRotationMode, int userRotation) { + @VisibleForTesting + void setUserRotation(int userRotationMode, int userRotation) { if (isDefaultDisplay) { // We'll be notified via settings listener, so we don't need to update internal values. final ContentResolver res = mContext.getContentResolver(); diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java index 207e8ef728eb..8507918df480 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java +++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java @@ -275,14 +275,14 @@ class DisplayWindowSettings { // This display used to be in freeform, but we don't support freeform anymore, so fall // back to fullscreen. if (windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM - && !mService.mSupportsFreeformWindowManagement) { + && !mService.mAtmService.mSupportsFreeformWindowManagement) { return WindowConfiguration.WINDOWING_MODE_FULLSCREEN; } // No record is present so use default windowing mode policy. if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) { final boolean forceDesktopMode = mService.mForceDesktopModeOnExternalDisplays && displayId != Display.DEFAULT_DISPLAY; - windowingMode = mService.mSupportsFreeformWindowManagement + windowingMode = mService.mAtmService.mSupportsFreeformWindowManagement && (mService.mIsPc || forceDesktopMode) ? WindowConfiguration.WINDOWING_MODE_FREEFORM : WindowConfiguration.WINDOWING_MODE_FULLSCREEN; diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index b1bc21977405..120ce3eb146e 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -355,7 +355,9 @@ public class DockedStackDividerController { void getTouchRegion(Rect outRegion) { outRegion.set(mTouchRegion); - outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top); + if (mWindow != null) { + outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top); + } } private void resetDragResizingChangeReported() { diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index 4f0332c58deb..caa836376248 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -241,7 +241,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, // Fetch all the surface controls and pass them to the client to get the animation // started. Cancel any existing recents animation running synchronously (do not hold the // WM lock) - mWindowManager.cancelRecentsAnimationSynchronously(REORDER_MOVE_TO_ORIGINAL_POSITION, + mWindowManager.cancelRecentsAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "startRecentsActivity"); mWindowManager.initializeRecentsAnimation(mTargetActivityType, recentsAnimationRunner, this, mDefaultDisplay.mDisplayId, @@ -396,12 +396,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, @Override public void onAnimationFinished(@RecentsAnimationController.ReorderMode int reorderMode, - boolean runSychronously, boolean sendUserLeaveHint) { - if (runSychronously) { - finishAnimation(reorderMode, sendUserLeaveHint); - } else { - mService.mH.post(() -> finishAnimation(reorderMode, sendUserLeaveHint)); - } + boolean sendUserLeaveHint) { + finishAnimation(reorderMode, sendUserLeaveHint); } @Override @@ -435,8 +431,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, } else { // Just cancel directly to unleash from launcher when the next launching task is the // current top task. - mWindowManager.cancelRecentsAnimationSynchronously(REORDER_KEEP_IN_PLACE, - "stackOrderChanged"); + mWindowManager.cancelRecentsAnimation(REORDER_KEEP_IN_PLACE, "stackOrderChanged"); } } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 724a72e1861e..8752f3796c58 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -168,8 +168,7 @@ public class RecentsAnimationController implements DeathRecipient { public interface RecentsAnimationCallbacks { /** Callback when recents animation is finished. */ - void onAnimationFinished(@ReorderMode int reorderMode, boolean runSychronously, - boolean sendUserLeaveHint); + void onAnimationFinished(@ReorderMode int reorderMode, boolean sendUserLeaveHint); } private final IRecentsAnimationController mController = @@ -221,8 +220,7 @@ public class RecentsAnimationController implements DeathRecipient { // prior to calling the callback mCallbacks.onAnimationFinished(moveHomeToTop ? REORDER_MOVE_TO_TOP - : REORDER_MOVE_TO_ORIGINAL_POSITION, - true /* runSynchronously */, sendUserLeaveHint); + : REORDER_MOVE_TO_ORIGINAL_POSITION, sendUserLeaveHint); mDisplayContent.mBoundsAnimationController.setAnimationType(FADE_IN); } finally { Binder.restoreCallingIdentity(token); @@ -498,21 +496,15 @@ public class RecentsAnimationController implements DeathRecipient { } void cancelAnimation(@ReorderMode int reorderMode, String reason) { - cancelAnimation(reorderMode, false /* runSynchronously */, false /*screenshot */, reason); - } - - void cancelAnimationSynchronously(@ReorderMode int reorderMode, String reason) { - cancelAnimation(reorderMode, true /* runSynchronously */, false /* screenshot */, reason); + cancelAnimation(reorderMode, false /*screenshot */, reason); } void cancelAnimationWithScreenshot(boolean screenshot) { - cancelAnimation(REORDER_KEEP_IN_PLACE, true /* sync */, screenshot, "stackOrderChanged"); + cancelAnimation(REORDER_KEEP_IN_PLACE, screenshot, "stackOrderChanged"); } - private void cancelAnimation(@ReorderMode int reorderMode, boolean runSynchronously, - boolean screenshot, String reason) { - if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason - + " runSynchronously=" + runSynchronously); + private void cancelAnimation(@ReorderMode int reorderMode, boolean screenshot, String reason) { + if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason); synchronized (mService.getWindowManagerLock()) { if (mCanceled) { // We've already canceled the animation @@ -525,16 +517,14 @@ public class RecentsAnimationController implements DeathRecipient { // 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; - final TaskSnapshot taskSnapshot = screenshotRecentTask(task, reorderMode, - runSynchronously); + final TaskSnapshot taskSnapshot = screenshotRecentTask(task, reorderMode); try { mRunner.onAnimationCanceled(taskSnapshot); } catch (RemoteException e) { Slog.e(TAG, "Failed to cancel recents animation", e); } if (taskSnapshot == null) { - mCallbacks.onAnimationFinished(reorderMode, runSynchronously, - false /* sendUserLeaveHint */); + mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */); } } else { // Otherwise, notify the runner and clean up the animation immediately @@ -545,8 +535,7 @@ public class RecentsAnimationController implements DeathRecipient { } catch (RemoteException e) { Slog.e(TAG, "Failed to cancel recents animation", e); } - mCallbacks.onAnimationFinished(reorderMode, runSynchronously, - false /* sendUserLeaveHint */); + mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */); } } } @@ -592,8 +581,7 @@ public class RecentsAnimationController implements DeathRecipient { return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot; } - TaskSnapshot screenshotRecentTask(Task task, @ReorderMode int reorderMode, - boolean runSynchronously) { + TaskSnapshot screenshotRecentTask(Task task, @ReorderMode int reorderMode) { final TaskSnapshotController snapshotController = mService.mTaskSnapshotController; final ArraySet<Task> tasks = Sets.newArraySet(task); snapshotController.snapshotTasks(tasks); @@ -613,8 +601,7 @@ public class RecentsAnimationController implements DeathRecipient { if (DEBUG_RECENTS_ANIMATIONS) { Slog.d(TAG, "mRecentScreenshotAnimator finish"); } - mCallbacks.onAnimationFinished(reorderMode, runSynchronously, - false /* sendUserLeaveHint */); + mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */); }, mService); mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator); return taskSnapshot; diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java index 66d42db9b4dd..3401de629268 100644 --- a/services/core/java/com/android/server/wm/RootActivityContainer.java +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -227,15 +227,10 @@ class RootActivityContainer extends ConfigurationContainer mStackSupervisor.mRootActivityContainer = this; } - @VisibleForTesting - void setWindowContainer(RootWindowContainer container) { - mRootWindowContainer = container; - mRootWindowContainer.setRootActivityContainer(this); - } - void setWindowManager(WindowManagerService wm) { mWindowManager = wm; - setWindowContainer(mWindowManager.mRoot); + mRootWindowContainer = mWindowManager.mRoot; + mRootWindowContainer.setRootActivityContainer(this); mDisplayManager = mService.mContext.getSystemService(DisplayManager.class); mDisplayManager.registerDisplayListener(this, mService.mUiHandler); mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); @@ -2266,7 +2261,7 @@ class RootActivityContainer extends ConfigurationContainer @WindowConfiguration.ActivityType int ignoreActivityType, @WindowConfiguration.WindowingMode int ignoreWindowingMode, int callingUid, boolean allowed) { - mStackSupervisor.mRunningTasks.getTasks(maxNum, list, ignoreActivityType, + mStackSupervisor.getRunningTasks().getTasks(maxNum, list, ignoreActivityType, ignoreWindowingMode, mActivityDisplays, callingUid, allowed); } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index fd86faa6d035..3a2eb57f1d80 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -380,7 +380,7 @@ class Task extends WindowContainer<AppWindowToken> implements ConfigurationConta boolean isResizeable() { return ActivityInfo.isResizeableMode(mResizeMode) || mSupportsPictureInPicture - || mWmService.mForceResizableTasks; + || mWmService.mAtmService.mForceResizableActivities; } /** diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 79367a050d46..cc2112ea5248 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -1666,7 +1666,7 @@ public class TaskStack extends WindowContainer<Task> implements * default bounds. */ Rect getPictureInPictureBounds(float aspectRatio, Rect stackBounds) { - if (!mWmService.mSupportsPictureInPicture) { + if (!mWmService.mAtmService.mSupportsPictureInPicture) { return null; } @@ -1762,7 +1762,7 @@ public class TaskStack extends WindowContainer<Task> implements * Sets the current picture-in-picture aspect ratio. */ void setPictureInPictureAspectRatio(float aspectRatio) { - if (!mWmService.mSupportsPictureInPicture) { + if (!mWmService.mAtmService.mSupportsPictureInPicture) { return; } @@ -1792,7 +1792,7 @@ public class TaskStack extends WindowContainer<Task> implements * Sets the current picture-in-picture actions. */ void setPictureInPictureActions(List<RemoteAction> actions) { - if (!mWmService.mSupportsPictureInPicture) { + if (!mWmService.mAtmService.mSupportsPictureInPicture) { return; } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index bbef261d17bb..29d232fc0511 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -767,11 +767,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< */ void setOrientation(int orientation, @Nullable IBinder freezeDisplayToken, @Nullable ConfigurationContainer requestingContainer) { - final boolean changed = mOrientation != orientation; - mOrientation = orientation; - if (!changed) { + if (mOrientation == orientation) { return; } + + mOrientation = orientation; final WindowContainer parent = getParent(); if (parent != null) { onDescendantOrientationChanged(freezeDisplayToken, requestingContainer); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 86faad0db965..d8d6841fe942 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -28,6 +28,7 @@ import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LE import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.app.StatusBarManager.DISABLE_MASK; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED; +import static android.content.pm.PackageManager.FEATURE_PC; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Process.SYSTEM_UID; import static android.os.Process.myPid; @@ -591,9 +592,6 @@ public class WindowManagerService extends IWindowManager.Stub int mDockedStackCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; Rect mDockedStackCreateBounds; - boolean mForceResizableTasks; - boolean mSupportsPictureInPicture; - boolean mSupportsFreeformWindowManagement; boolean mIsPc; /** * Flag that indicates that desktop mode is forced for public secondary screens. @@ -819,7 +817,7 @@ public class WindowManagerService extends IWindowManager.Stub int mTransactionSequence; final WindowAnimator mAnimator; - final SurfaceAnimationRunner mSurfaceAnimationRunner; + SurfaceAnimationRunner mSurfaceAnimationRunner; /** * Keeps track of which animations got transferred to which animators. Entries will get cleaned @@ -957,6 +955,9 @@ public class WindowManagerService extends IWindowManager.Stub final ArrayList<AppFreezeListener> mAppFreezeListeners = new ArrayList<>(); + @VisibleForTesting + final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener; + interface AppFreezeListener { void onAppFreezeTimeout(); } @@ -1010,6 +1011,7 @@ public class WindowManagerService extends IWindowManager.Stub mGlobalLock = atm.getGlobalLock(); mAtmService = atm; mContext = context; + mIsPc = mContext.getPackageManager().hasSystemFeature(FEATURE_PC); mAllowBootMessages = showBootMsgs; mOnlyCore = onlyCore; mLimitedAlphaCompositing = context.getResources().getBoolean( @@ -1159,26 +1161,28 @@ public class WindowManagerService extends IWindowManager.Stub mSystemGestureExcludedByPreQStickyImmersive = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false); - DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER, - new HandlerExecutor(mH), properties -> { - synchronized (mGlobalLock) { - final int exclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP, - properties.getInt(KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0)); - final boolean excludedByPreQSticky = DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_WINDOW_MANAGER, - KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false); - if (mSystemGestureExcludedByPreQStickyImmersive != excludedByPreQSticky - || mSystemGestureExclusionLimitDp != exclusionLimitDp) { - mSystemGestureExclusionLimitDp = exclusionLimitDp; - mSystemGestureExcludedByPreQStickyImmersive = excludedByPreQSticky; - mRoot.forAllDisplays(DisplayContent::updateSystemGestureExclusionLimit); - } - mSystemGestureExclusionLogDebounceTimeoutMillis = - DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER, - KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0); - } - }); + mPropertiesChangedListener = properties -> { + synchronized (mGlobalLock) { + final int exclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP, + properties.getInt(KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0)); + final boolean excludedByPreQSticky = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_WINDOW_MANAGER, + KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false); + if (mSystemGestureExcludedByPreQStickyImmersive != excludedByPreQSticky + || mSystemGestureExclusionLimitDp != exclusionLimitDp) { + mSystemGestureExclusionLimitDp = exclusionLimitDp; + mSystemGestureExcludedByPreQStickyImmersive = excludedByPreQSticky; + mRoot.forAllDisplays(DisplayContent::updateSystemGestureExclusionLimit); + } + + mSystemGestureExclusionLogDebounceTimeoutMillis = + DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS, 0); + } + }; + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + new HandlerExecutor(mH), mPropertiesChangedListener); LocalServices.addService(WindowManagerInternal.class, new LocalService()); } @@ -2595,7 +2599,7 @@ public class WindowManagerService extends IWindowManager.Stub mRecentsAnimationController = controller; } - public RecentsAnimationController getRecentsAnimationController() { + RecentsAnimationController getRecentsAnimationController() { return mRecentsAnimationController; } @@ -2603,74 +2607,37 @@ public class WindowManagerService extends IWindowManager.Stub * @return Whether the next recents animation can continue to start. Called from * {@link RecentsAnimation#startRecentsActivity}. */ - public boolean canStartRecentsAnimation() { - synchronized (mGlobalLock) { - // TODO(multi-display): currently only default display support recent activity - if (getDefaultDisplayContentLocked().mAppTransition.isTransitionSet()) { - return false; - } - return true; + boolean canStartRecentsAnimation() { + // TODO(multi-display): currently only default display support recent activity + if (getDefaultDisplayContentLocked().mAppTransition.isTransitionSet()) { + return false; } + return true; } - /** - * Cancels any running recents animation. The caller should NOT hold the WM lock while calling - * this method, as it will call back into AM and may cause a deadlock. Any locking will be done - * in the animation controller itself. - */ - public void cancelRecentsAnimationSynchronously( + void cancelRecentsAnimation( @RecentsAnimationController.ReorderMode int reorderMode, String reason) { if (mRecentsAnimationController != null) { // This call will call through to cleanupAnimation() below after the animation is // canceled - mRecentsAnimationController.cancelAnimationSynchronously(reorderMode, reason); - } - } - - public void cleanupRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) { - synchronized (mGlobalLock) { - if (mRecentsAnimationController != null) { - final RecentsAnimationController controller = mRecentsAnimationController; - mRecentsAnimationController = null; - controller.cleanupAnimation(reorderMode); - // TODO(mult-display): currently only default display support recents animation. - getDefaultDisplayContentLocked().mAppTransition.updateBooster(); - } - } - } - - public void setAppFullscreen(IBinder token, boolean toOpaque) { - synchronized (mGlobalLock) { - final AppWindowToken atoken = mRoot.getAppWindowToken(token); - if (atoken != null) { - atoken.setFillsParent(toOpaque); - setWindowOpaqueLocked(token, toOpaque); - mWindowPlacerLocked.requestTraversal(); - } + mRecentsAnimationController.cancelAnimation(reorderMode, reason); } } - public void setWindowOpaque(IBinder token, boolean isOpaque) { - synchronized (mGlobalLock) { - setWindowOpaqueLocked(token, isOpaque); + void cleanupRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) { + if (mRecentsAnimationController != null) { + final RecentsAnimationController controller = mRecentsAnimationController; + mRecentsAnimationController = null; + controller.cleanupAnimation(reorderMode); + // TODO(mult-display): currently only default display support recents animation. + getDefaultDisplayContentLocked().mAppTransition.updateBooster(); } } - private void setWindowOpaqueLocked(IBinder token, boolean isOpaque) { + void setWindowOpaqueLocked(IBinder token, boolean isOpaque) { final AppWindowToken wtoken = mRoot.getAppWindowToken(token); if (wtoken != null) { - final WindowState win = wtoken.findMainWindow(); - if (win == null) { - return; - } - isOpaque = isOpaque & !PixelFormat.formatHasAlpha(win.getAttrs().format); - win.mWinAnimator.setOpaqueLocked(isOpaque); - } - } - - public void setDockedStackCreateState(int mode, Rect bounds) { - synchronized (mGlobalLock) { - setDockedStackCreateStateLocked(mode, bounds); + wtoken.setMainWindowOpaque(isOpaque); } } @@ -2679,14 +2646,12 @@ public class WindowManagerService extends IWindowManager.Stub mDockedStackCreateBounds = bounds; } - public void checkSplitScreenMinimizedChanged(boolean animate) { - synchronized (mGlobalLock) { - final DisplayContent displayContent = getDefaultDisplayContentLocked(); - displayContent.getDockedDividerController().checkMinimizeChanged(animate); - } + void checkSplitScreenMinimizedChanged(boolean animate) { + final DisplayContent displayContent = getDefaultDisplayContentLocked(); + displayContent.getDockedDividerController().checkMinimizeChanged(animate); } - public boolean isValidPictureInPictureAspectRatio(int displayId, float aspectRatio) { + boolean isValidPictureInPictureAspectRatio(int displayId, float aspectRatio) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); return displayContent.getPinnedStackController().isValidPictureInPictureAspectRatio( aspectRatio); @@ -4847,8 +4812,10 @@ public class WindowManagerService extends IWindowManager.Stub case UPDATE_DOCKED_STACK_DIVIDER: { synchronized (mGlobalLock) { final DisplayContent displayContent = getDefaultDisplayContentLocked(); - displayContent.getDockedDividerController().reevaluateVisibility(false); - displayContent.adjustForImeIfNeeded(); + if (displayContent != null) { + displayContent.getDockedDividerController().reevaluateVisibility(false); + displayContent.adjustForImeIfNeeded(); + } } break; } @@ -6495,31 +6462,14 @@ public class WindowManagerService extends IWindowManager.Stub } } - public void setForceResizableTasks(boolean forceResizableTasks) { - synchronized (mGlobalLock) { - mForceResizableTasks = forceResizableTasks; - } - } - - public void setSupportsPictureInPicture(boolean supportsPictureInPicture) { - synchronized (mGlobalLock) { - mSupportsPictureInPicture = supportsPictureInPicture; - } - } - - public void setSupportsFreeformWindowManagement(boolean supportsFreeformWindowManagement) { - synchronized (mGlobalLock) { - mSupportsFreeformWindowManagement = supportsFreeformWindowManagement; - } - } - void setForceDesktopModeOnExternalDisplays(boolean forceDesktopModeOnExternalDisplays) { synchronized (mGlobalLock) { mForceDesktopModeOnExternalDisplays = forceDesktopModeOnExternalDisplays; } } - public void setIsPc(boolean isPc) { + @VisibleForTesting + void setIsPc(boolean isPc) { synchronized (mGlobalLock) { mIsPc = isPc; } @@ -6546,7 +6496,7 @@ public class WindowManagerService extends IWindowManager.Stub "registerPinnedStackListener()")) { return; } - if (!mSupportsPictureInPicture) { + if (!mAtmService.mSupportsPictureInPicture) { return; } synchronized (mGlobalLock) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index e14514be2207..d87a0ed966dc 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -5125,9 +5125,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // relative layering of multiple APPLICATION_MEDIA/OVERLAY has never // been defined and so we can use static layers and leave it that way. if (w.mAttrs.type == TYPE_APPLICATION_MEDIA) { - w.assignLayer(t, -2); + if (mWinAnimator.hasSurface()) { + w.assignRelativeLayer(t, mWinAnimator.mSurfaceController.mSurfaceControl, -2); + } else { + w.assignLayer(t, -2); + } } else if (w.mAttrs.type == TYPE_APPLICATION_MEDIA_OVERLAY) { - w.assignLayer(t, -1); + if (mWinAnimator.hasSurface()) { + w.assignRelativeLayer(t, mWinAnimator.mSurfaceController.mSurfaceControl, -1); + } else { + w.assignLayer(t, -1); + } } else { w.assignLayer(t, layer); } diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 466ca9315f6f..03f475582a5a 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -165,6 +165,7 @@ static void loadSystemIconAsSpriteWithPointerIcon(JNIEnv* env, jobject contextOb outPointerIcon->bitmap.readPixels(bitmapCopy->info(), bitmapCopy->getPixels(), bitmapCopy->rowBytes(), 0, 0); } + outSpriteIcon->style = outPointerIcon->style; outSpriteIcon->hotSpotX = outPointerIcon->hotSpotX; outSpriteIcon->hotSpotY = outPointerIcon->hotSpotY; } @@ -1252,7 +1253,8 @@ void NativeInputManager::loadPointerIcon(SpriteIcon* icon, int32_t displayId) { status_t status = android_view_PointerIcon_load(env, pointerIconObj.get(), displayContext.get(), &pointerIcon); if (!status && !pointerIcon.isNullIcon()) { - *icon = SpriteIcon(pointerIcon.bitmap, pointerIcon.hotSpotX, pointerIcon.hotSpotY); + *icon = SpriteIcon( + pointerIcon.bitmap, pointerIcon.style, pointerIcon.hotSpotX, pointerIcon.hotSpotY); } else { *icon = SpriteIcon(); } @@ -1293,10 +1295,12 @@ void NativeInputManager::loadAdditionalMouseResources(std::map<int32_t, SpriteIc milliseconds_to_nanoseconds(pointerIcon.durationPerFrame); animationData.animationFrames.reserve(numFrames); animationData.animationFrames.push_back(SpriteIcon( - pointerIcon.bitmap, pointerIcon.hotSpotX, pointerIcon.hotSpotY)); + pointerIcon.bitmap, pointerIcon.style, + pointerIcon.hotSpotX, pointerIcon.hotSpotY)); for (size_t i = 0; i < numFrames - 1; ++i) { animationData.animationFrames.push_back(SpriteIcon( - pointerIcon.bitmapFrames[i], pointerIcon.hotSpotX, pointerIcon.hotSpotY)); + pointerIcon.bitmapFrames[i], pointerIcon.style, + pointerIcon.hotSpotX, pointerIcon.hotSpotY)); } } } @@ -1711,6 +1715,7 @@ static void nativeSetCustomPointerIcon(JNIEnv* env, jclass /* clazz */, pointerIcon.bitmap.readPixels(spriteInfo, spriteIcon.bitmap.getPixels(), spriteIcon.bitmap.rowBytes(), 0, 0); } + spriteIcon.style = pointerIcon.style; spriteIcon.hotSpotX = pointerIcon.hotSpotX; spriteIcon.hotSpotY = pointerIcon.hotSpotY; im->setCustomPointerIcon(spriteIcon); diff --git a/services/core/jni/com_android_server_tv_TvUinputBridge.cpp b/services/core/jni/com_android_server_tv_TvUinputBridge.cpp index 980922a806f5..c832c18517ce 100644 --- a/services/core/jni/com_android_server_tv_TvUinputBridge.cpp +++ b/services/core/jni/com_android_server_tv_TvUinputBridge.cpp @@ -43,10 +43,6 @@ #include <sys/stat.h> #include <sys/types.h> -// Refer to EventHub.h -#define MSC_ANDROID_TIME_SEC 0x6 -#define MSC_ANDROID_TIME_USEC 0x7 - #define SLOT_UNKNOWN -1 namespace android { @@ -153,11 +149,6 @@ NativeConnection* NativeConnection::open(const char* name, const char* uniqueId, ioctl(fd, UI_SET_KEYBIT, KEYS[i].linuxKeyCode); } - // set the misc events maps - ioctl(fd, UI_SET_EVBIT, EV_MSC); - ioctl(fd, UI_SET_MSCBIT, MSC_ANDROID_TIME_SEC); - ioctl(fd, UI_SET_MSCBIT, MSC_ANDROID_TIME_USEC); - // register the input device if (write(fd, &uinp, sizeof(uinp)) != sizeof(uinp)) { ALOGE("Cannot write uinput_user_dev to fd %d: %s.", fd, strerror(errno)); @@ -200,13 +191,6 @@ static void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) { delete connection; } -static void nativeSendTimestamp(JNIEnv* env, jclass clazz, jlong ptr, jlong timestamp) { - NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr); - - connection->sendEvent(EV_MSC, MSC_ANDROID_TIME_SEC, timestamp / 1000L); - connection->sendEvent(EV_MSC, MSC_ANDROID_TIME_USEC, (timestamp % 1000L) * 1000L); -} - static void nativeSendKey(JNIEnv* env, jclass clazz, jlong ptr, jint keyCode, jboolean down) { int32_t code = getLinuxKeyCode(keyCode); NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr); @@ -281,8 +265,6 @@ static JNINativeMethod gUinputBridgeMethods[] = { (void*)nativeOpen }, { "nativeClose", "(J)V", (void*)nativeClose }, - { "nativeSendTimestamp", "(JJ)V", - (void*)nativeSendTimestamp }, { "nativeSendKey", "(JIZ)V", (void*)nativeSendKey }, { "nativeSendPointerDown", "(JIII)V", diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index f800cca3ab3d..f933b09b0c15 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -10846,6 +10846,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { public void setGlobalSetting(ComponentName who, String setting, String value) { Preconditions.checkNotNull(who, "ComponentName is null"); + DevicePolicyEventLogger + .createEvent(DevicePolicyEnums.SET_GLOBAL_SETTING) + .setAdmin(who) + .setStrings(setting, value) + .write(); + synchronized (getLockObject()) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 83b3194815e4..67ae4070966d 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -25,6 +25,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static com.android.server.utils.TimingsTraceAndSlog.SYSTEM_SERVER_TIMING_TAG; import android.annotation.NonNull; +import android.annotation.StringRes; import android.app.ActivityThread; import android.app.INotificationManager; import android.app.usage.UsageStatsManagerInternal; @@ -39,7 +40,9 @@ import android.content.res.Resources.Theme; import android.database.sqlite.SQLiteCompatibilityWalFlags; import android.database.sqlite.SQLiteGlobal; import android.hardware.display.DisplayManagerInternal; +import android.net.ConnectivityModuleConnector; import android.net.NetworkStackClient; +import android.net.wifi.WifiStackClient; import android.os.BaseBundle; import android.os.Binder; import android.os.Build; @@ -632,6 +635,13 @@ public final class SystemServer { SystemServerInitThreadPool.get().submit(SystemConfig::getInstance, TAG_SYSTEM_CONFIG); t.traceEnd(); + // Platform compat service is used by ActivityManagerService, PackageManagerService, and + // possibly others in the future. b/135010838. + t.traceBegin("PlatformCompat"); + ServiceManager.addService(Context.PLATFORM_COMPAT_SERVICE, + new PlatformCompat(mSystemContext)); + t.traceEnd(); + // Wait for installd to finish starting up so that it has a chance to // create critical directories such as /data/user with the appropriate // permissions. We need this to complete before we initialize other services. @@ -1099,10 +1109,6 @@ public final class SystemServer { 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); @@ -1265,13 +1271,29 @@ public final class SystemServer { startSystemCaptionsManagerService(context, t); // App prediction manager service - t.traceBegin("StartAppPredictionService"); - mSystemServiceManager.startService(APP_PREDICTION_MANAGER_SERVICE_CLASS); - t.traceEnd(); + if (deviceHasConfigString(context, R.string.config_defaultAppPredictionService)) { + t.traceBegin("StartAppPredictionService"); + mSystemServiceManager.startService(APP_PREDICTION_MANAGER_SERVICE_CLASS); + t.traceEnd(); + } else { + Slog.d(TAG, "AppPredictionService not defined by OEM"); + } // Content suggestions manager service - t.traceBegin("StartContentSuggestionsService"); - mSystemServiceManager.startService(CONTENT_SUGGESTIONS_SERVICE_CLASS); + if (deviceHasConfigString(context, R.string.config_defaultContentSuggestionsService)) { + t.traceBegin("StartContentSuggestionsService"); + mSystemServiceManager.startService(CONTENT_SUGGESTIONS_SERVICE_CLASS); + t.traceEnd(); + } else { + Slog.d(TAG, "ContentSuggestionsService not defined by OEM"); + } + + t.traceBegin("InitConnectivityModuleConnector"); + try { + ConnectivityModuleConnector.getInstance().init(context); + } catch (Throwable e) { + reportWtf("initializing ConnectivityModuleConnector", e); + } t.traceEnd(); t.traceBegin("InitNetworkStackClient"); @@ -1336,40 +1358,6 @@ public final class SystemServer { t.traceEnd(); if (context.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_WIFI)) { - // Wifi Service must be started first for wifi-related services. - t.traceBegin("StartWifi"); - mSystemServiceManager.startService(WIFI_SERVICE_CLASS); - t.traceEnd(); - t.traceBegin("StartWifiScanning"); - mSystemServiceManager.startService( - "com.android.server.wifi.scanner.WifiScanningService"); - t.traceEnd(); - } - - if (context.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_WIFI_RTT)) { - t.traceBegin("StartRttService"); - mSystemServiceManager.startService( - "com.android.server.wifi.rtt.RttService"); - t.traceEnd(); - } - - if (context.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_WIFI_AWARE)) { - t.traceBegin("StartWifiAware"); - mSystemServiceManager.startService(WIFI_AWARE_SERVICE_CLASS); - t.traceEnd(); - } - - if (context.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_WIFI_DIRECT)) { - t.traceBegin("StartWifiP2P"); - mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS); - t.traceEnd(); - } - - if (context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_LOWPAN)) { t.traceBegin("StartLowpan"); mSystemServiceManager.startService(LOWPAN_SERVICE_CLASS); @@ -2168,12 +2156,21 @@ public final class SystemServer { // ActivityManagerService.mSystemReady and ActivityManagerService.mProcessesReady // are set to true. Be careful if moving this to a different place in the // startup sequence. - NetworkStackClient.getInstance().start(context); + NetworkStackClient.getInstance().start(); } catch (Throwable e) { reportWtf("starting Network Stack", e); } t.traceEnd(); + t.traceBegin("StartWifiStack"); + try { + WifiStackClient.getInstance().start(); + } catch (Throwable e) { + reportWtf("starting Wifi Stack", e); + } + t.traceEnd(); + + t.traceBegin("MakeLocationServiceReady"); try { if (locationF != null) { @@ -2257,11 +2254,14 @@ public final class SystemServer { t.traceEnd(); // startOtherServices } + private boolean deviceHasConfigString(@NonNull Context context, @StringRes int resId) { + String serviceName = context.getString(resId); + return !TextUtils.isEmpty(serviceName); + } + private void startSystemCaptionsManagerService(@NonNull Context context, @NonNull TimingsTraceAndSlog t) { - String serviceName = context.getString( - com.android.internal.R.string.config_defaultSystemCaptionsManagerService); - if (TextUtils.isEmpty(serviceName)) { + if (!deviceHasConfigString(context, R.string.config_defaultSystemCaptionsManagerService)) { Slog.d(TAG, "SystemCaptionsManagerService disabled because resource is not overlaid"); return; } @@ -2289,9 +2289,7 @@ public final class SystemServer { // Then check if OEM overlaid the resource that defines the service. if (!explicitlyEnabled) { - final String serviceName = context - .getString(com.android.internal.R.string.config_defaultContentCaptureService); - if (TextUtils.isEmpty(serviceName)) { + if (!deviceHasConfigString(context, R.string.config_defaultContentCaptureService)) { Slog.d(TAG, "ContentCaptureService disabled because resource is not overlaid"); return; } diff --git a/services/net/java/android/net/ConnectivityModuleConnector.java b/services/net/java/android/net/ConnectivityModuleConnector.java new file mode 100644 index 000000000000..7333f583e8e8 --- /dev/null +++ b/services/net/java/android/net/ConnectivityModuleConnector.java @@ -0,0 +1,389 @@ +/* + * 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.net; + +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.net.util.SharedLog; +import android.os.Build; +import android.os.Environment; +import android.os.IBinder; +import android.os.Process; +import android.os.SystemClock; +import android.os.UserHandle; +import android.provider.DeviceConfig; +import android.text.format.DateUtils; +import android.util.ArraySet; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; + +import java.io.File; +import java.io.PrintWriter; + +/** + * Class used to communicate to the various networking mainline modules running in the network stack + * process from {@link com.android.server.SystemServer}. + * @hide + */ +public class ConnectivityModuleConnector { + private static final String TAG = ConnectivityModuleConnector.class.getSimpleName(); + private static final String IN_PROCESS_SUFFIX = ".InProcess"; + + private static final String PREFS_FILE = "ConnectivityModuleConnector.xml"; + private static final String PREF_KEY_LAST_CRASH_TIME = "lastcrash_time"; + private static final String CONFIG_MIN_CRASH_INTERVAL_MS = "min_crash_interval"; + private static final String CONFIG_MIN_UPTIME_BEFORE_CRASH_MS = "min_uptime_before_crash"; + private static final String CONFIG_ALWAYS_RATELIMIT_NETWORKSTACK_CRASH = + "always_ratelimit_networkstack_crash"; + + // Even if the network stack is lost, do not crash the system more often than this. + // Connectivity would be broken, but if the user needs the device for something urgent + // (like calling emergency services) we should not bootloop the device. + // This is the default value: the actual value can be adjusted via device config. + private static final long DEFAULT_MIN_CRASH_INTERVAL_MS = 6 * DateUtils.HOUR_IN_MILLIS; + + // Even if the network stack is lost, do not crash the system server if it was less than + // this much after boot. This avoids bootlooping the device, and crashes should address very + // infrequent failures, not failures on boot. + private static final long DEFAULT_MIN_UPTIME_BEFORE_CRASH_MS = 30 * DateUtils.MINUTE_IN_MILLIS; + + private static ConnectivityModuleConnector sInstance; + + private Context mContext; + @GuardedBy("mLog") + private final SharedLog mLog = new SharedLog(TAG); + @GuardedBy("mHealthListeners") + private final ArraySet<ConnectivityModuleHealthListener> mHealthListeners = new ArraySet<>(); + + private ConnectivityModuleConnector() { } + + /** + * Get the {@link ConnectivityModuleConnector} singleton instance. + */ + public static synchronized ConnectivityModuleConnector getInstance() { + if (sInstance == null) { + sInstance = new ConnectivityModuleConnector(); + } + return sInstance; + } + + /** + * Initialize the network stack connector. Should be called only once on device startup, before + * any client attempts to use the network stack. + */ + public void init(Context context) { + log("Network stack init"); + mContext = context; + } + + /** + * Callback interface for severe failures of the NetworkStack. + * + * <p>Useful for health monitors such as PackageWatchdog. + */ + public interface ConnectivityModuleHealthListener { + /** + * Called when there is a severe failure of the network stack. + * @param packageName Package name of the network stack. + */ + void onNetworkStackFailure(@NonNull String packageName); + } + + /** + * Callback invoked by the connector once the connection to the corresponding module is + * established. + */ + public interface ModuleServiceCallback { + /** + * Invoked when the corresponding service has connected. + * + * @param iBinder Binder object for the service. + */ + void onModuleServiceConnected(@NonNull IBinder iBinder); + } + + + /** + * Add a {@link ConnectivityModuleHealthListener} to listen to network stack health events. + */ + public void registerHealthListener(@NonNull ConnectivityModuleHealthListener listener) { + synchronized (mHealthListeners) { + mHealthListeners.add(listener); + } + } + + /** + * Start a module running in the network stack or system_server process. Should be called only + * once for each module per device startup. + * + * <p>This method will start a networking module either in the network stack + * process, or inside the system server on devices that do not support the corresponding + * mainline network . The corresponding networking module service's binder + * object will then be delivered asynchronously via the provided {@link ModuleServiceCallback}. + * + * @param serviceIntentBaseAction Base action to use for constructing the intent needed to + * bind to the corresponding module. + * @param servicePermissionName Permission to be held by the corresponding module. + */ + public void startModuleService( + @NonNull String serviceIntentBaseAction, + @NonNull String servicePermissionName, + @NonNull ModuleServiceCallback callback) { + log("Starting networking module " + serviceIntentBaseAction); + + final PackageManager pm = mContext.getPackageManager(); + + // Try to bind in-process if the device was shipped with an in-process version + Intent intent = getModuleServiceIntent(pm, serviceIntentBaseAction, servicePermissionName, + true /* inSystemProcess */); + + // Otherwise use the updatable module version + if (intent == null) { + intent = getModuleServiceIntent(pm, serviceIntentBaseAction, servicePermissionName, + false /* inSystemProcess */); + log("Starting networking module in network_stack process"); + } else { + log("Starting networking module in system_server process"); + } + + if (intent == null) { + maybeCrashWithTerribleFailure("Could not resolve the networking module", null); + return; + } + + final String packageName = intent.getComponent().getPackageName(); + + // Start the network stack. The service will be added to the service manager by the + // corresponding client in ModuleServiceCallback.onModuleServiceConnected(). + if (!mContext.bindServiceAsUser( + intent, new ModuleServiceConnection(packageName, callback), + Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) { + maybeCrashWithTerribleFailure( + "Could not bind to networking module in-process, or in app with " + + intent, packageName); + return; + } + + log("Networking module service start requested"); + } + + private class ModuleServiceConnection implements ServiceConnection { + @NonNull + private final String mPackageName; + @NonNull + private final ModuleServiceCallback mModuleServiceCallback; + + private ModuleServiceConnection( + @NonNull String packageName, + @NonNull ModuleServiceCallback moduleCallback) { + mPackageName = packageName; + mModuleServiceCallback = moduleCallback; + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + logi("Networking module service connected"); + mModuleServiceCallback.onModuleServiceConnected(service); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + // onServiceDisconnected is not being called on device shutdown, so this method being + // called always indicates a bad state for the system server. + // This code path is only run by the system server: only the system server binds + // to the NetworkStack as a service. Other processes get the NetworkStack from + // the ServiceManager. + maybeCrashWithTerribleFailure("Lost network stack", mPackageName); + } + } + + @Nullable + private Intent getModuleServiceIntent( + @NonNull PackageManager pm, @NonNull String serviceIntentBaseAction, + @NonNull String servicePermissionName, boolean inSystemProcess) { + final Intent intent = + new Intent(inSystemProcess + ? serviceIntentBaseAction + IN_PROCESS_SUFFIX + : serviceIntentBaseAction); + final ComponentName comp = intent.resolveSystemService(pm, 0); + if (comp == null) { + return null; + } + intent.setComponent(comp); + + int uid = -1; + try { + uid = pm.getPackageUidAsUser(comp.getPackageName(), UserHandle.USER_SYSTEM); + } catch (PackageManager.NameNotFoundException e) { + logWtf("Networking module package not found", e); + // Fall through + } + + final int expectedUid = inSystemProcess ? Process.SYSTEM_UID : Process.NETWORK_STACK_UID; + if (uid != expectedUid) { + throw new SecurityException("Invalid network stack UID: " + uid); + } + + if (!inSystemProcess) { + checkModuleServicePermission(pm, comp, servicePermissionName); + } + + return intent; + } + + private void checkModuleServicePermission( + @NonNull PackageManager pm, @NonNull ComponentName comp, + @NonNull String servicePermissionName) { + final int hasPermission = + pm.checkPermission(servicePermissionName, comp.getPackageName()); + if (hasPermission != PERMISSION_GRANTED) { + throw new SecurityException( + "Networking module does not have permission " + servicePermissionName); + } + } + + private synchronized void maybeCrashWithTerribleFailure(@NonNull String message, + @Nullable String packageName) { + logWtf(message, null); + // uptime is monotonic even after a framework restart + final long uptime = SystemClock.elapsedRealtime(); + final long now = System.currentTimeMillis(); + final long minCrashIntervalMs = DeviceConfig.getLong(DeviceConfig.NAMESPACE_CONNECTIVITY, + CONFIG_MIN_CRASH_INTERVAL_MS, DEFAULT_MIN_CRASH_INTERVAL_MS); + final long minUptimeBeforeCrash = DeviceConfig.getLong(DeviceConfig.NAMESPACE_CONNECTIVITY, + CONFIG_MIN_UPTIME_BEFORE_CRASH_MS, DEFAULT_MIN_UPTIME_BEFORE_CRASH_MS); + final boolean alwaysRatelimit = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_CONNECTIVITY, + CONFIG_ALWAYS_RATELIMIT_NETWORKSTACK_CRASH, false); + + final SharedPreferences prefs = getSharedPreferences(); + final long lastCrashTime = tryGetLastCrashTime(prefs); + + // Only crash if there was enough time since boot, and (if known) enough time passed since + // the last crash. + // time and lastCrashTime may be unreliable if devices have incorrect clock time, but they + // are only used to limit the number of crashes compared to only using the time since boot, + // which would also be OK behavior by itself. + // - If lastCrashTime is incorrectly more than the current time, only look at uptime + // - If it is much less than current time, only look at uptime + // - If current time is during the next few hours after last crash time, don't crash. + // Considering that this only matters if last boot was some time ago, it's likely that + // time will be set correctly. Otherwise, not crashing is not a big problem anyway. Being + // in this last state would also not last for long since the window is only a few hours. + final boolean alwaysCrash = Build.IS_DEBUGGABLE && !alwaysRatelimit; + final boolean justBooted = uptime < minUptimeBeforeCrash; + final boolean haveLastCrashTime = (lastCrashTime != 0) && (lastCrashTime < now); + final boolean haveKnownRecentCrash = + haveLastCrashTime && (now < lastCrashTime + minCrashIntervalMs); + if (alwaysCrash || (!justBooted && !haveKnownRecentCrash)) { + // The system is not bound to its network stack (for example due to a crash in the + // network stack process): better crash rather than stay in a bad state where all + // networking is broken. + // Using device-encrypted SharedPreferences as DeviceConfig does not have a synchronous + // API to persist settings before a crash. + tryWriteLastCrashTime(prefs, now); + throw new IllegalStateException(message); + } + + // Here the system crashed recently already. Inform listeners that something is + // definitely wrong. + if (packageName != null) { + final ArraySet<ConnectivityModuleHealthListener> listeners; + synchronized (mHealthListeners) { + listeners = new ArraySet<>(mHealthListeners); + } + for (ConnectivityModuleHealthListener listener : listeners) { + listener.onNetworkStackFailure(packageName); + } + } + } + + @Nullable + private SharedPreferences getSharedPreferences() { + try { + final File prefsFile = new File( + Environment.getDataSystemDeDirectory(UserHandle.USER_SYSTEM), PREFS_FILE); + return mContext.createDeviceProtectedStorageContext() + .getSharedPreferences(prefsFile, Context.MODE_PRIVATE); + } catch (Throwable e) { + logWtf("Error loading shared preferences", e); + return null; + } + } + + private long tryGetLastCrashTime(@Nullable SharedPreferences prefs) { + if (prefs == null) return 0L; + try { + return prefs.getLong(PREF_KEY_LAST_CRASH_TIME, 0L); + } catch (Throwable e) { + logWtf("Error getting last crash time", e); + return 0L; + } + } + + private void tryWriteLastCrashTime(@Nullable SharedPreferences prefs, long value) { + if (prefs == null) return; + try { + prefs.edit().putLong(PREF_KEY_LAST_CRASH_TIME, value).commit(); + } catch (Throwable e) { + logWtf("Error writing last crash time", e); + } + } + + private void log(@NonNull String message) { + Slog.d(TAG, message); + synchronized (mLog) { + mLog.log(message); + } + } + + private void logWtf(@NonNull String message, @Nullable Throwable e) { + Slog.wtf(TAG, message, e); + synchronized (mLog) { + mLog.e(message); + } + } + + private void loge(@NonNull String message, @Nullable Throwable e) { + Slog.e(TAG, message, e); + synchronized (mLog) { + mLog.e(message); + } + } + + private void logi(@NonNull String message) { + Slog.i(TAG, message); + synchronized (mLog) { + mLog.i(message); + } + } + + /** + * Dump ConnectivityModuleConnector logs to the specified {@link PrintWriter}. + */ + public void dump(PrintWriter pw) { + // dump is thread-safe on SharedLog + mLog.dump(null, pw, null); + } +} diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java index 56b728c87180..abb46664e40d 100644 --- a/services/net/java/android/net/NetworkStackClient.java +++ b/services/net/java/android/net/NetworkStackClient.java @@ -15,40 +15,27 @@ */ package android.net; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.ComponentName; import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.content.SharedPreferences; -import android.content.pm.PackageManager; import android.net.dhcp.DhcpServingParamsParcel; import android.net.dhcp.IDhcpServerCallbacks; import android.net.ip.IIpClientCallbacks; import android.net.util.SharedLog; import android.os.Binder; -import android.os.Build; -import android.os.Environment; import android.os.IBinder; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.SystemClock; import android.os.UserHandle; -import android.provider.DeviceConfig; -import android.text.format.DateUtils; -import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.GuardedBy; -import java.io.File; import java.io.PrintWriter; import java.util.ArrayList; @@ -60,24 +47,6 @@ public class NetworkStackClient { private static final String TAG = NetworkStackClient.class.getSimpleName(); private static final int NETWORKSTACK_TIMEOUT_MS = 10_000; - private static final String IN_PROCESS_SUFFIX = ".InProcess"; - private static final String PREFS_FILE = "NetworkStackClientPrefs.xml"; - private static final String PREF_KEY_LAST_CRASH_TIME = "lastcrash_time"; - private static final String CONFIG_MIN_CRASH_INTERVAL_MS = "min_crash_interval"; - private static final String CONFIG_MIN_UPTIME_BEFORE_CRASH_MS = "min_uptime_before_crash"; - private static final String CONFIG_ALWAYS_RATELIMIT_NETWORKSTACK_CRASH = - "always_ratelimit_networkstack_crash"; - - // Even if the network stack is lost, do not crash the system more often than this. - // Connectivity would be broken, but if the user needs the device for something urgent - // (like calling emergency services) we should not bootloop the device. - // This is the default value: the actual value can be adjusted via device config. - private static final long DEFAULT_MIN_CRASH_INTERVAL_MS = 6 * DateUtils.HOUR_IN_MILLIS; - - // Even if the network stack is lost, do not crash the system server if it was less than - // this much after boot. This avoids bootlooping the device, and crashes should address very - // infrequent failures, not failures on boot. - private static final long DEFAULT_MIN_UPTIME_BEFORE_CRASH_MS = 30 * DateUtils.MINUTE_IN_MILLIS; private static NetworkStackClient sInstance; @@ -93,26 +62,10 @@ public class NetworkStackClient { private volatile boolean mWasSystemServerInitialized = false; - @GuardedBy("mHealthListeners") - private final ArraySet<NetworkStackHealthListener> mHealthListeners = new ArraySet<>(); - private interface NetworkStackCallback { void onNetworkStackConnected(INetworkStackConnector connector); } - /** - * Callback interface for severe failures of the NetworkStack. - * - * <p>Useful for health monitors such as PackageWatchdog. - */ - public interface NetworkStackHealthListener { - /** - * Called when there is a severe failure of the network stack. - * @param packageName Package name of the network stack. - */ - void onNetworkStackFailure(@NonNull String packageName); - } - private NetworkStackClient() { } /** @@ -126,15 +79,6 @@ public class NetworkStackClient { } /** - * Add a {@link NetworkStackHealthListener} to listen to network stack health events. - */ - public void registerHealthListener(@NonNull NetworkStackHealthListener listener) { - synchronized (mHealthListeners) { - mHealthListeners.add(listener); - } - } - - /** * Create a DHCP server according to the specified parameters. * * <p>The server will be returned asynchronously through the provided callbacks. @@ -195,32 +139,13 @@ public class NetworkStackClient { }); } - private class NetworkStackConnection implements ServiceConnection { - @NonNull - private final Context mContext; - @NonNull - private final String mPackageName; - - private NetworkStackConnection(@NonNull Context context, @NonNull String packageName) { - mContext = context; - mPackageName = packageName; - } - + private class NetworkStackConnection implements + ConnectivityModuleConnector.ModuleServiceCallback { @Override - public void onServiceConnected(ComponentName name, IBinder service) { + public void onModuleServiceConnected(IBinder service) { logi("Network stack service connected"); registerNetworkStackService(service); } - - @Override - public void onServiceDisconnected(ComponentName name) { - // onServiceDisconnected is not being called on device shutdown, so this method being - // called always indicates a bad state for the system server. - // This code path is only run by the system server: only the system server binds - // to the NetworkStack as a service. Other processes get the NetworkStack from - // the ServiceManager. - maybeCrashWithTerribleFailure("Lost network stack", mContext, mPackageName); - } } private void registerNetworkStackService(@NonNull IBinder service) { @@ -259,171 +184,13 @@ public class NetworkStackClient { * connector will then be delivered asynchronously to clients that requested it before it was * started. */ - public void start(Context context) { - log("Starting network stack"); - - final PackageManager pm = context.getPackageManager(); - - // Try to bind in-process if the device was shipped with an in-process version - Intent intent = getNetworkStackIntent(pm, true /* inSystemProcess */); - - // Otherwise use the updatable module version - if (intent == null) { - intent = getNetworkStackIntent(pm, false /* inSystemProcess */); - log("Starting network stack process"); - } else { - log("Starting network stack in-process"); - } - - if (intent == null) { - maybeCrashWithTerribleFailure("Could not resolve the network stack", context, null); - return; - } - - final String packageName = intent.getComponent().getPackageName(); - - // Start the network stack. The service will be added to the service manager in - // NetworkStackConnection.onServiceConnected(). - if (!context.bindServiceAsUser(intent, new NetworkStackConnection(context, packageName), - Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) { - maybeCrashWithTerribleFailure( - "Could not bind to network stack in-process, or in app with " + intent, - context, packageName); - return; - } - + public void start() { + ConnectivityModuleConnector.getInstance().startModuleService( + INetworkStackConnector.class.getName(), PERMISSION_MAINLINE_NETWORK_STACK, + new NetworkStackConnection()); log("Network stack service start requested"); } - @Nullable - private Intent getNetworkStackIntent(@NonNull PackageManager pm, boolean inSystemProcess) { - final String baseAction = INetworkStackConnector.class.getName(); - final Intent intent = - new Intent(inSystemProcess ? baseAction + IN_PROCESS_SUFFIX : baseAction); - final ComponentName comp = intent.resolveSystemService(pm, 0); - - if (comp == null) { - return null; - } - intent.setComponent(comp); - - int uid = -1; - try { - uid = pm.getPackageUidAsUser(comp.getPackageName(), UserHandle.USER_SYSTEM); - } catch (PackageManager.NameNotFoundException e) { - logWtf("Network stack package not found", e); - // Fall through - } - - final int expectedUid = inSystemProcess ? Process.SYSTEM_UID : Process.NETWORK_STACK_UID; - if (uid != expectedUid) { - throw new SecurityException("Invalid network stack UID: " + uid); - } - - if (!inSystemProcess) { - checkNetworkStackPermission(pm, comp); - } - - return intent; - } - - private void checkNetworkStackPermission( - @NonNull PackageManager pm, @NonNull ComponentName comp) { - final int hasPermission = - pm.checkPermission(PERMISSION_MAINLINE_NETWORK_STACK, comp.getPackageName()); - if (hasPermission != PERMISSION_GRANTED) { - throw new SecurityException( - "Network stack does not have permission " + PERMISSION_MAINLINE_NETWORK_STACK); - } - } - - private void maybeCrashWithTerribleFailure(@NonNull String message, - @NonNull Context context, @Nullable String packageName) { - logWtf(message, null); - // uptime is monotonic even after a framework restart - final long uptime = SystemClock.elapsedRealtime(); - final long now = System.currentTimeMillis(); - final long minCrashIntervalMs = DeviceConfig.getLong(DeviceConfig.NAMESPACE_CONNECTIVITY, - CONFIG_MIN_CRASH_INTERVAL_MS, DEFAULT_MIN_CRASH_INTERVAL_MS); - final long minUptimeBeforeCrash = DeviceConfig.getLong(DeviceConfig.NAMESPACE_CONNECTIVITY, - CONFIG_MIN_UPTIME_BEFORE_CRASH_MS, DEFAULT_MIN_UPTIME_BEFORE_CRASH_MS); - final boolean alwaysRatelimit = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_CONNECTIVITY, - CONFIG_ALWAYS_RATELIMIT_NETWORKSTACK_CRASH, false); - - final SharedPreferences prefs = getSharedPreferences(context); - final long lastCrashTime = tryGetLastCrashTime(prefs); - - // Only crash if there was enough time since boot, and (if known) enough time passed since - // the last crash. - // time and lastCrashTime may be unreliable if devices have incorrect clock time, but they - // are only used to limit the number of crashes compared to only using the time since boot, - // which would also be OK behavior by itself. - // - If lastCrashTime is incorrectly more than the current time, only look at uptime - // - If it is much less than current time, only look at uptime - // - If current time is during the next few hours after last crash time, don't crash. - // Considering that this only matters if last boot was some time ago, it's likely that - // time will be set correctly. Otherwise, not crashing is not a big problem anyway. Being - // in this last state would also not last for long since the window is only a few hours. - final boolean alwaysCrash = Build.IS_DEBUGGABLE && !alwaysRatelimit; - final boolean justBooted = uptime < minUptimeBeforeCrash; - final boolean haveLastCrashTime = (lastCrashTime != 0) && (lastCrashTime < now); - final boolean haveKnownRecentCrash = - haveLastCrashTime && (now < lastCrashTime + minCrashIntervalMs); - if (alwaysCrash || (!justBooted && !haveKnownRecentCrash)) { - // The system is not bound to its network stack (for example due to a crash in the - // network stack process): better crash rather than stay in a bad state where all - // networking is broken. - // Using device-encrypted SharedPreferences as DeviceConfig does not have a synchronous - // API to persist settings before a crash. - tryWriteLastCrashTime(prefs, now); - throw new IllegalStateException(message); - } - - // Here the system crashed recently already. Inform listeners that something is - // definitely wrong. - if (packageName != null) { - final ArraySet<NetworkStackHealthListener> listeners; - synchronized (mHealthListeners) { - listeners = new ArraySet<>(mHealthListeners); - } - for (NetworkStackHealthListener listener : listeners) { - listener.onNetworkStackFailure(packageName); - } - } - } - - @Nullable - private SharedPreferences getSharedPreferences(@NonNull Context context) { - try { - final File prefsFile = new File( - Environment.getDataSystemDeDirectory(UserHandle.USER_SYSTEM), PREFS_FILE); - return context.createDeviceProtectedStorageContext() - .getSharedPreferences(prefsFile, Context.MODE_PRIVATE); - } catch (Throwable e) { - logWtf("Error loading shared preferences", e); - return null; - } - } - - private long tryGetLastCrashTime(@Nullable SharedPreferences prefs) { - if (prefs == null) return 0L; - try { - return prefs.getLong(PREF_KEY_LAST_CRASH_TIME, 0L); - } catch (Throwable e) { - logWtf("Error getting last crash time", e); - return 0L; - } - } - - private void tryWriteLastCrashTime(@Nullable SharedPreferences prefs, long value) { - if (prefs == null) return; - try { - prefs.edit().putLong(PREF_KEY_LAST_CRASH_TIME, value).commit(); - } catch (Throwable e) { - logWtf("Error writing last crash time", e); - } - } - /** * Log a message in the local log. */ @@ -524,6 +291,8 @@ public class NetworkStackClient { public void dump(PrintWriter pw) { // dump is thread-safe on SharedLog mLog.dump(null, pw, null); + // dump connectivity module connector logs. + ConnectivityModuleConnector.getInstance().dump(pw); final int requestsQueueLength; synchronized (mPendingNetStackRequests) { diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java index 0d99561af889..a1bfcdf4bdfa 100644 --- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java +++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 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. @@ -36,8 +36,6 @@ import static org.mockito.Mockito.verify; import static org.robolectric.Shadows.shadowOf; import static org.testng.Assert.expectThrows; -import static java.util.Collections.emptySet; - import android.annotation.UserIdInt; import android.app.Application; import android.app.backup.IBackupManagerMonitor; @@ -48,16 +46,19 @@ import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.Process; import android.os.UserHandle; +import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.util.SparseArray; import com.android.server.backup.testing.TransportData; import com.android.server.testing.shadows.ShadowApplicationPackageManager; import com.android.server.testing.shadows.ShadowBinder; +import com.android.server.testing.shadows.ShadowEnvironment; import com.android.server.testing.shadows.ShadowSystemServiceRegistry; +import com.android.server.testing.shadows.ShadowUserManager; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -66,6 +67,7 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowContextWrapper; import java.io.File; @@ -74,28 +76,32 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; -/** Tests for the user-aware backup/restore system service {@link BackupManagerService}. */ +/** Tests for {@link BackupManagerService}. */ @RunWith(RobolectricTestRunner.class) @Config( shadows = { - ShadowApplicationPackageManager.class, - ShadowBinder.class, - ShadowSystemServiceRegistry.class + ShadowApplicationPackageManager.class, + ShadowBinder.class, + ShadowUserManager.class, + ShadowEnvironment.class, + ShadowSystemServiceRegistry.class }) @Presubmit -public class BackupManagerServiceTest { +public class BackupManagerServiceRoboTest { private static final String TEST_PACKAGE = "package"; private static final String TEST_TRANSPORT = "transport"; private static final String[] ADB_TEST_PACKAGES = {TEST_PACKAGE}; - private ShadowContextWrapper mShadowContext; private Context mContext; + private ShadowContextWrapper mShadowContext; + private ShadowUserManager mShadowUserManager; @UserIdInt private int mUserOneId; @UserIdInt private int mUserTwoId; + @Mock private UserBackupManagerService mUserSystemService; @Mock private UserBackupManagerService mUserOneService; @Mock private UserBackupManagerService mUserTwoService; - /** Initialize {@link BackupManagerService}. */ + /** Setup */ @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -103,66 +109,26 @@ public class BackupManagerServiceTest { Application application = RuntimeEnvironment.application; mContext = application; mShadowContext = shadowOf(application); + mShadowUserManager = Shadow.extract(UserManager.get(application)); mUserOneId = UserHandle.USER_SYSTEM + 1; mUserTwoId = mUserOneId + 1; - } - - /** - * Clean up and reset state that was created for testing {@link BackupManagerService} - * operations. - */ - @After - public void tearDown() throws Exception { - ShadowBinder.reset(); - } - - /** - * Test verifying that {@link BackupManagerService#MORE_DEBUG} is set to {@code false}. This is - * specifically to prevent overloading the logs in production. - */ - @Test - public void testMoreDebug_isFalse() throws Exception { - boolean moreDebug = BackupManagerService.MORE_DEBUG; + mShadowUserManager.addUser(mUserOneId, "mUserOneId", 0); + mShadowUserManager.addUser(mUserTwoId, "mUserTwoId", 0); - assertThat(moreDebug).isFalse(); - } - - /** Test that the constructor does not create {@link UserBackupManagerService} instances. */ - @Test - public void testConstructor_doesNotRegisterUsers() throws Exception { - BackupManagerService backupManagerService = createService(); - - assertThat(backupManagerService.getUserServices().size()).isEqualTo(0); - } - - /** Test that the constructor handles {@code null} parameters. */ - @Test - public void testConstructor_withNullContext_throws() throws Exception { - expectThrows( - NullPointerException.class, - () -> - new BackupManagerService( - /* context */ null, - new Trampoline(mContext))); - } + mShadowContext.grantPermissions(BACKUP); + mShadowContext.grantPermissions(INTERACT_ACROSS_USERS_FULL); - /** Test that the constructor handles {@code null} parameters. */ - @Test - public void testConstructor_withNullTrampoline_throws() throws Exception { - expectThrows( - NullPointerException.class, - () -> - new BackupManagerService( - mContext, /* trampoline */ null)); + ShadowBinder.setCallingUid(Process.SYSTEM_UID); } /** Test that the service registers users. */ @Test public void testStartServiceForUser_registersUser() throws Exception { BackupManagerService backupManagerService = createService(); + backupManagerService.setBackupServiceActive(mUserOneId, true); - backupManagerService.startServiceForUser(mUserOneId, emptySet()); + backupManagerService.startServiceForUser(mUserOneId); SparseArray<UserBackupManagerService> serviceUsers = backupManagerService.getUserServices(); assertThat(serviceUsers.size()).isEqualTo(1); @@ -173,6 +139,7 @@ public class BackupManagerServiceTest { @Test public void testStartServiceForUser_withServiceInstance_registersUser() throws Exception { BackupManagerService backupManagerService = createService(); + backupManagerService.setBackupServiceActive(mUserOneId, true); backupManagerService.startServiceForUser(mUserOneId, mUserOneService); @@ -187,6 +154,7 @@ public class BackupManagerServiceTest { BackupManagerService backupManagerService = createServiceAndRegisterUser(mUserOneId, mUserOneService); backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService); + ShadowBinder.setCallingUid(Process.SYSTEM_UID); backupManagerService.stopServiceForUser(mUserOneId); @@ -201,6 +169,7 @@ public class BackupManagerServiceTest { public void testStopServiceForUser_forRegisteredUser_tearsDownCorrectUser() throws Exception { BackupManagerService backupManagerService = createServiceAndRegisterUser(mUserOneId, mUserOneService); + backupManagerService.setBackupServiceActive(mUserTwoId, true); backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService); backupManagerService.stopServiceForUser(mUserOneId); @@ -213,6 +182,8 @@ public class BackupManagerServiceTest { @Test public void testStopServiceForUser_forUnknownUser_doesNothing() throws Exception { BackupManagerService backupManagerService = createService(); + backupManagerService.setBackupServiceActive(mUserOneId, true); + ShadowBinder.setCallingUid(Process.SYSTEM_UID); backupManagerService.stopServiceForUser(mUserOneId); @@ -220,53 +191,6 @@ public class BackupManagerServiceTest { assertThat(serviceUsers.size()).isEqualTo(0); } - /** - * Test that the backup services throws a {@link SecurityException} if the caller does not have - * INTERACT_ACROSS_USERS_FULL permission and passes a different user id. - */ - @Test - public void testGetServiceForUser_withoutPermission_throwsSecurityExceptionForNonCallingUser() { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); - setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); - - expectThrows( - SecurityException.class, - () -> - backupManagerService.getServiceForUserIfCallerHasPermission( - mUserOneId, "test")); - } - - /** - * Test that the backup services does not throw a {@link SecurityException} if the caller has - * INTERACT_ACROSS_USERS_FULL permission and passes a different user id. - */ - @Test - public void testGetServiceForUserIfCallerHasPermission_withPermission_worksForNonCallingUser() { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); - setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ true); - - assertEquals( - mUserOneService, - backupManagerService.getServiceForUserIfCallerHasPermission(mUserOneId, "test")); - } - - /** - * Test that the backup services does not throw a {@link SecurityException} if the caller does - * not have INTERACT_ACROSS_USERS_FULL permission and passes in the calling user id. - */ - @Test - public void testGetServiceForUserIfCallerHasPermission_withoutPermission_worksForCallingUser() { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); - setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); - - assertEquals( - mUserOneService, - backupManagerService.getServiceForUserIfCallerHasPermission(mUserOneId, "test")); - } - // --------------------------------------------- // Backup agent tests // --------------------------------------------- @@ -274,8 +198,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testDataChanged_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.dataChanged(mUserOneId, TEST_PACKAGE); @@ -286,8 +210,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testDataChanged_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.dataChanged(mUserTwoId, TEST_PACKAGE); @@ -298,8 +222,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testAgentConnected_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); IBinder agentBinder = mock(IBinder.class); @@ -311,8 +235,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testAgentConnected_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); IBinder agentBinder = mock(IBinder.class); @@ -323,33 +247,9 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test - public void testAgentDisconnected_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); - setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); - - backupManagerService.agentDisconnected(mUserOneId, TEST_PACKAGE); - - verify(mUserOneService).agentDisconnected(TEST_PACKAGE); - } - - /** Test that the backup service does not route methods for non-registered users. */ - @Test - public void testAgentDisconnected_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); - setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); - - backupManagerService.agentDisconnected(mUserTwoId, TEST_PACKAGE); - - verify(mUserOneService, never()).agentDisconnected(TEST_PACKAGE); - } - - /** Test that the backup service routes methods correctly to the user that requests it. */ - @Test public void testOpComplete_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.opComplete(mUserOneId, /* token */ 0, /* result */ 0L); @@ -360,8 +260,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testOpComplete_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.opComplete(mUserTwoId, /* token */ 0, /* result */ 0L); @@ -376,8 +276,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testInitializeTransports_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); String[] transports = {TEST_TRANSPORT}; @@ -389,8 +289,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testInitializeTransports_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); String[] transports = {TEST_TRANSPORT}; @@ -402,8 +302,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testClearBackupData_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.clearBackupData(mUserOneId, TEST_TRANSPORT, TEST_PACKAGE); @@ -414,8 +314,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testClearBackupData_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.clearBackupData(mUserTwoId, TEST_TRANSPORT, TEST_PACKAGE); @@ -426,8 +326,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testGetCurrentTransport_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.getCurrentTransport(mUserOneId); @@ -438,8 +338,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testGetCurrentTransport_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.getCurrentTransport(mUserTwoId); @@ -451,8 +351,8 @@ public class BackupManagerServiceTest { @Test public void testGetCurrentTransportComponent_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.getCurrentTransportComponent(mUserOneId); @@ -464,8 +364,8 @@ public class BackupManagerServiceTest { @Test public void testGetCurrentTransportComponent_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.getCurrentTransportComponent(mUserTwoId); @@ -476,8 +376,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testListAllTransports_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.listAllTransports(mUserOneId); @@ -488,8 +388,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testListAllTransports_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.listAllTransports(mUserTwoId); @@ -501,8 +401,8 @@ public class BackupManagerServiceTest { @Test public void testListAllTransportComponents_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.listAllTransportComponents(mUserOneId); @@ -514,8 +414,8 @@ public class BackupManagerServiceTest { @Test public void testListAllTransportComponents_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.listAllTransportComponents(mUserTwoId); @@ -525,69 +425,9 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test - public void testUpdateTransportAttributes_onRegisteredUser_callsMethodForUser() - throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); - setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); - TransportData transport = backupTransport(); - Intent configurationIntent = new Intent(); - Intent dataManagementIntent = new Intent(); - - backupManagerService.updateTransportAttributes( - mUserOneId, - transport.getTransportComponent(), - transport.transportName, - configurationIntent, - "currentDestinationString", - dataManagementIntent, - "dataManagementLabel"); - - verify(mUserOneService) - .updateTransportAttributes( - transport.getTransportComponent(), - transport.transportName, - configurationIntent, - "currentDestinationString", - dataManagementIntent, - "dataManagementLabel"); - } - - /** Test that the backup service does not route methods for non-registered users. */ - @Test - public void testUpdateTransportAttributes_onUnknownUser_doesNotPropagateCall() - throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); - setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); - TransportData transport = backupTransport(); - Intent configurationIntent = new Intent(); - Intent dataManagementIntent = new Intent(); - - backupManagerService.updateTransportAttributes( - mUserTwoId, - transport.getTransportComponent(), - transport.transportName, - configurationIntent, - "currentDestinationString", - dataManagementIntent, - "dataManagementLabel"); - - verify(mUserOneService, never()) - .updateTransportAttributes( - transport.getTransportComponent(), - transport.transportName, - configurationIntent, - "currentDestinationString", - dataManagementIntent, - "dataManagementLabel"); - } - - /** Test that the backup service routes methods correctly to the user that requests it. */ - @Test public void testSelectBackupTransport_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.selectBackupTransport(mUserOneId, TEST_TRANSPORT); @@ -598,8 +438,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testSelectBackupTransport_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.selectBackupTransport(mUserTwoId, TEST_TRANSPORT); @@ -610,8 +450,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testSelectTransportAsync_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); TransportData transport = backupTransport(); ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class); @@ -627,8 +467,8 @@ public class BackupManagerServiceTest { @Test public void testSelectBackupTransportAsync_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); TransportData transport = backupTransport(); ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class); @@ -643,8 +483,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testGetConfigurationIntent_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.getConfigurationIntent(mUserOneId, TEST_TRANSPORT); @@ -655,8 +495,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testGetConfigurationIntent_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.getConfigurationIntent(mUserTwoId, TEST_TRANSPORT); @@ -667,8 +507,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testGetDestinationString_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.getDestinationString(mUserOneId, TEST_TRANSPORT); @@ -679,8 +519,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testGetDestinationString_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.getDestinationString(mUserTwoId, TEST_TRANSPORT); @@ -691,8 +531,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testGetDataManagementIntent_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.getDataManagementIntent(mUserOneId, TEST_TRANSPORT); @@ -703,8 +543,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testGetDataManagementIntent_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.getDataManagementIntent(mUserTwoId, TEST_TRANSPORT); @@ -715,8 +555,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testGetDataManagementLabel_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.getDataManagementLabel(mUserOneId, TEST_TRANSPORT); @@ -727,8 +567,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testGetDataManagementLabel_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.getDataManagementLabel(mUserTwoId, TEST_TRANSPORT); @@ -736,17 +576,78 @@ public class BackupManagerServiceTest { verify(mUserOneService, never()).getDataManagementLabel(TEST_TRANSPORT); } + /** Test that the backup service routes methods correctly to the user that requests it. */ + @Test + public void testUpdateTransportAttributes_onRegisteredUser_callsMethodForUser() + throws Exception { + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); + setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); + TransportData transport = backupTransport(); + Intent configurationIntent = new Intent(); + Intent dataManagementIntent = new Intent(); + + backupManagerService.updateTransportAttributes( + mUserOneId, + transport.getTransportComponent(), + transport.transportName, + configurationIntent, + "currentDestinationString", + dataManagementIntent, + "dataManagementLabel"); + + verify(mUserOneService) + .updateTransportAttributes( + transport.getTransportComponent(), + transport.transportName, + configurationIntent, + "currentDestinationString", + dataManagementIntent, + "dataManagementLabel"); + } + + /** Test that the backup service does not route methods for non-registered users. */ + @Test + public void testUpdateTransportAttributes_onUnknownUser_doesNotPropagateCall() + throws Exception { + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); + setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); + TransportData transport = backupTransport(); + Intent configurationIntent = new Intent(); + Intent dataManagementIntent = new Intent(); + + backupManagerService.updateTransportAttributes( + mUserTwoId, + transport.getTransportComponent(), + transport.transportName, + configurationIntent, + "currentDestinationString", + dataManagementIntent, + "dataManagementLabel"); + + verify(mUserOneService, never()) + .updateTransportAttributes( + transport.getTransportComponent(), + transport.transportName, + configurationIntent, + "currentDestinationString", + dataManagementIntent, + "dataManagementLabel"); + } + // --------------------------------------------- // Settings tests // --------------------------------------------- + /** * Test that the backup services throws a {@link SecurityException} if the caller does not have * INTERACT_ACROSS_USERS_FULL permission and passes a different user id. */ @Test public void testSetBackupEnabled_withoutPermission_throwsSecurityExceptionForNonCallingUser() { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); expectThrows( @@ -760,9 +661,10 @@ public class BackupManagerServiceTest { */ @Test public void testSetBackupEnabled_withPermission_propagatesForNonCallingUser() { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); - backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); + registerUser(backupManagerService, mUserTwoId, mUserTwoService); + setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true); backupManagerService.setBackupEnabled(mUserTwoId, true); @@ -773,8 +675,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testSetBackupEnabled_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.setBackupEnabled(mUserOneId, true); @@ -785,8 +687,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testSetBackupEnabled_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.setBackupEnabled(mUserTwoId, true); @@ -797,8 +699,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testSetAutoRestore_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.setAutoRestore(mUserOneId, true); @@ -809,8 +711,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testSetAutoRestore_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.setAutoRestore(mUserTwoId, true); @@ -821,8 +723,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testIsBackupEnabled_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.isBackupEnabled(mUserOneId); @@ -833,8 +735,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testIsBackupEnabled_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.isBackupEnabled(mUserTwoId); @@ -849,8 +751,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testIsAppEligibleForBackup_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.isAppEligibleForBackup(mUserOneId, TEST_PACKAGE); @@ -861,8 +763,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testIsAppEligibleForBackup_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.isAppEligibleForBackup(mUserTwoId, TEST_PACKAGE); @@ -874,8 +776,8 @@ public class BackupManagerServiceTest { @Test public void testFilterAppsEligibleForBackup_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); String[] packages = {TEST_PACKAGE}; @@ -888,8 +790,8 @@ public class BackupManagerServiceTest { @Test public void testFilterAppsEligibleForBackup_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); String[] packages = {TEST_PACKAGE}; @@ -904,8 +806,8 @@ public class BackupManagerServiceTest { */ @Test public void testBackupNow_withoutPermission_throwsSecurityExceptionForNonCallingUser() { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); expectThrows(SecurityException.class, () -> backupManagerService.backupNow(mUserTwoId)); @@ -917,9 +819,10 @@ public class BackupManagerServiceTest { */ @Test public void testBackupNow_withPermission_propagatesForNonCallingUser() { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); - backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); + registerUser(backupManagerService, mUserTwoId, mUserTwoService); + setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true); backupManagerService.backupNow(mUserTwoId); @@ -930,8 +833,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testBackupNow_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.backupNow(mUserOneId); @@ -942,8 +845,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testBackupNow_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.backupNow(mUserTwoId); @@ -957,8 +860,8 @@ public class BackupManagerServiceTest { */ @Test public void testRequestBackup_withoutPermission_throwsSecurityExceptionForNonCallingUser() { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); String[] packages = {TEST_PACKAGE}; IBackupObserver observer = mock(IBackupObserver.class); @@ -977,9 +880,10 @@ public class BackupManagerServiceTest { */ @Test public void testRequestBackup_withPermission_propagatesForNonCallingUser() { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); - backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); + registerUser(backupManagerService, mUserTwoId, mUserTwoService); + String[] packages = {TEST_PACKAGE}; IBackupObserver observer = mock(IBackupObserver.class); IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class); @@ -993,8 +897,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testRequestBackup_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); String[] packages = {TEST_PACKAGE}; IBackupObserver observer = mock(IBackupObserver.class); IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class); @@ -1008,8 +912,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testRequestBackup_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); String[] packages = {TEST_PACKAGE}; IBackupObserver observer = mock(IBackupObserver.class); IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class); @@ -1026,8 +930,8 @@ public class BackupManagerServiceTest { */ @Test public void testCancelBackups_withoutPermission_throwsSecurityExceptionForNonCallingUser() { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); expectThrows(SecurityException.class, () -> backupManagerService.cancelBackups(mUserTwoId)); @@ -1039,9 +943,9 @@ public class BackupManagerServiceTest { */ @Test public void testCancelBackups_withPermission_propagatesForNonCallingUser() { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); - backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); + registerUser(backupManagerService, mUserTwoId, mUserTwoService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true); backupManagerService.cancelBackups(mUserTwoId); @@ -1052,8 +956,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testCancelBackups_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.cancelBackups(mUserOneId); @@ -1064,8 +968,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testCancelBackups_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.cancelBackups(mUserTwoId); @@ -1076,8 +980,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testBeginFullBackup_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserOneService); FullBackupJob job = new FullBackupJob(); backupManagerService.beginFullBackup(UserHandle.USER_SYSTEM, job); @@ -1099,8 +1003,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testEndFullBackup_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserOneService); backupManagerService.endFullBackup(UserHandle.USER_SYSTEM); @@ -1120,8 +1024,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testFullTransportBackup_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); String[] packages = {TEST_PACKAGE}; @@ -1133,8 +1037,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testFullTransportBackup_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); String[] packages = {TEST_PACKAGE}; @@ -1150,8 +1054,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testRestoreAtInstall_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.restoreAtInstall(mUserOneId, TEST_PACKAGE, /* token */ 0); @@ -1162,8 +1066,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testRestoreAtInstall_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.restoreAtInstall(mUserTwoId, TEST_PACKAGE, /* token */ 0); @@ -1174,8 +1078,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testBeginRestoreSession_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.beginRestoreSession(mUserOneId, TEST_PACKAGE, TEST_TRANSPORT); @@ -1186,8 +1090,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testBeginRestoreSession_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.beginRestoreSession(mUserTwoId, TEST_PACKAGE, TEST_TRANSPORT); @@ -1199,8 +1103,8 @@ public class BackupManagerServiceTest { @Test public void testGetAvailableRestoreToken_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); backupManagerService.getAvailableRestoreToken(mUserOneId, TEST_PACKAGE); @@ -1211,8 +1115,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testGetAvailableRestoreToken_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); backupManagerService.getAvailableRestoreToken(mUserTwoId, TEST_PACKAGE); @@ -1227,8 +1131,9 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testSetBackupPassword_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserOneService); + ShadowBinder.setCallingUserHandle(UserHandle.of(UserHandle.USER_SYSTEM)); backupManagerService.setBackupPassword("currentPassword", "newPassword"); @@ -1248,8 +1153,9 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testHasBackupPassword_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserOneService); + ShadowBinder.setCallingUserHandle(UserHandle.of(UserHandle.USER_SYSTEM)); backupManagerService.hasBackupPassword(); @@ -1272,8 +1178,9 @@ public class BackupManagerServiceTest { */ @Test public void testAdbBackup_withoutPermission_throwsSecurityExceptionForNonCallingUser() { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createSystemRegisteredService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); + registerUser(backupManagerService, mUserTwoId, mUserTwoService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); expectThrows( @@ -1299,9 +1206,10 @@ public class BackupManagerServiceTest { */ @Test public void testAdbBackup_withPermission_propagatesForNonCallingUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); - backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService); + BackupManagerService backupManagerService = createSystemRegisteredService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); + registerUser(backupManagerService, mUserTwoId, mUserTwoService); + ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest(); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true); @@ -1335,8 +1243,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testAdbBackup_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createSystemRegisteredService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest(); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); @@ -1370,8 +1278,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testAdbBackup_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createSystemRegisteredService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest(); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); @@ -1408,8 +1316,9 @@ public class BackupManagerServiceTest { */ @Test public void testAdbRestore_withoutPermission_throwsSecurityExceptionForNonCallingUser() { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createSystemRegisteredService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); + registerUser(backupManagerService, mUserTwoId, mUserTwoService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); expectThrows( @@ -1422,9 +1331,9 @@ public class BackupManagerServiceTest { */ @Test public void testAdbRestore_withPermission_propagatesForNonCallingUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); - backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService); + BackupManagerService backupManagerService = createSystemRegisteredService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); + registerUser(backupManagerService, mUserTwoId, mUserTwoService); ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest(); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true); @@ -1436,8 +1345,8 @@ public class BackupManagerServiceTest { /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testAdbRestore_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createSystemRegisteredService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest(); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); @@ -1449,8 +1358,8 @@ public class BackupManagerServiceTest { /** Test that the backup service does not route methods for non-registered users. */ @Test public void testAdbRestore_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createSystemRegisteredService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest(); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); @@ -1459,12 +1368,18 @@ public class BackupManagerServiceTest { verify(mUserOneService, never()).adbRestore(parcelFileDescriptor); } + private ParcelFileDescriptor getFileDescriptorForAdbTest() throws Exception { + File testFile = new File(mContext.getFilesDir(), "test"); + testFile.createNewFile(); + return ParcelFileDescriptor.open(testFile, ParcelFileDescriptor.MODE_READ_WRITE); + } + /** Test that the backup service routes methods correctly to the user that requests it. */ @Test public void testAcknowledgeAdbBackupOrRestore_onRegisteredUser_callsMethodForUser() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); IFullBackupRestoreObserver observer = mock(IFullBackupRestoreObserver.class); @@ -1489,8 +1404,8 @@ public class BackupManagerServiceTest { @Test public void testAcknowledgeAdbBackupOrRestore_onUnknownUser_doesNotPropagateCall() throws Exception { - BackupManagerService backupManagerService = - createServiceAndRegisterUser(mUserOneId, mUserOneService); + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); IFullBackupRestoreObserver observer = mock(IFullBackupRestoreObserver.class); @@ -1512,48 +1427,6 @@ public class BackupManagerServiceTest { } // --------------------------------------------- - // Lifecycle tests - // --------------------------------------------- - - - /** testOnStart_publishesService */ - @Test - public void testOnStart_publishesService() { - Trampoline trampoline = mock(Trampoline.class); - BackupManagerService.Lifecycle lifecycle = - spy(new BackupManagerService.Lifecycle(mContext, trampoline)); - doNothing().when(lifecycle).publishService(anyString(), any()); - - lifecycle.onStart(); - - verify(lifecycle).publishService(Context.BACKUP_SERVICE, trampoline); - } - - /** testOnUnlockUser_forwards */ - @Test - public void testOnUnlockUser_forwards() { - Trampoline trampoline = mock(Trampoline.class); - BackupManagerService.Lifecycle lifecycle = - new BackupManagerService.Lifecycle(mContext, trampoline); - - lifecycle.onUnlockUser(UserHandle.USER_SYSTEM); - - verify(trampoline).onUnlockUser(UserHandle.USER_SYSTEM); - } - - /** testOnStopUser_forwards */ - @Test - public void testOnStopUser_forwards() { - Trampoline trampoline = mock(Trampoline.class); - BackupManagerService.Lifecycle lifecycle = - new BackupManagerService.Lifecycle(mContext, trampoline); - - lifecycle.onStopUser(UserHandle.USER_SYSTEM); - - verify(trampoline).onStopUser(UserHandle.USER_SYSTEM); - } - - // --------------------------------------------- // Service tests // --------------------------------------------- @@ -1561,24 +1434,22 @@ public class BackupManagerServiceTest { @Test public void testDump_onRegisteredUser_callsMethodForUser() throws Exception { grantDumpPermissions(); - - BackupManagerService backupManagerService = - createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService); + BackupManagerService backupManagerService = createSystemRegisteredService(); File testFile = createTestFile(); FileDescriptor fileDescriptor = new FileDescriptor(); PrintWriter printWriter = new PrintWriter(testFile); String[] args = {"1", "2"}; + ShadowBinder.setCallingUserHandle(UserHandle.of(UserHandle.USER_SYSTEM)); backupManagerService.dump(fileDescriptor, printWriter, args); - verify(mUserOneService).dump(fileDescriptor, printWriter, args); + verify(mUserSystemService).dump(fileDescriptor, printWriter, args); } /** Test that the backup service does not route methods for non-registered users. */ @Test public void testDump_onUnknownUser_doesNotPropagateCall() throws Exception { grantDumpPermissions(); - BackupManagerService backupManagerService = createService(); File testFile = createTestFile(); FileDescriptor fileDescriptor = new FileDescriptor(); @@ -1594,9 +1465,8 @@ public class BackupManagerServiceTest { @Test public void testDump_users_dumpsListOfRegisteredUsers() { grantDumpPermissions(); - - BackupManagerService backupManagerService = createServiceAndRegisterUser(mUserOneId, - mUserOneService); + BackupManagerService backupManagerService = createSystemRegisteredService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); StringWriter out = new StringWriter(); PrintWriter writer = new PrintWriter(out); String[] args = {"users"}; @@ -1605,30 +1475,162 @@ public class BackupManagerServiceTest { writer.flush(); assertEquals( - String.format("%s %d\n", BackupManagerService.DUMP_RUNNING_USERS_MESSAGE, - mUserOneId), + String.format("%s %d %d\n", BackupManagerService.DUMP_RUNNING_USERS_MESSAGE, + UserHandle.USER_SYSTEM, mUserOneId), out.toString()); } + private File createTestFile() throws IOException { + File testFile = new File(mContext.getFilesDir(), "test"); + testFile.createNewFile(); + return testFile; + } + private void grantDumpPermissions() { mShadowContext.grantPermissions(DUMP); mShadowContext.grantPermissions(PACKAGE_USAGE_STATS); } - private File createTestFile() throws IOException { - File testFile = new File(mContext.getFilesDir(), "test"); - testFile.createNewFile(); - return testFile; + /** + * Test that the backup services throws a {@link SecurityException} if the caller does not have + * INTERACT_ACROSS_USERS_FULL permission and passes a different user id. + */ + @Test + public void testGetServiceForUser_withoutPermission_throwsSecurityExceptionForNonCallingUser() { + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); + setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); + + expectThrows( + SecurityException.class, + () -> + backupManagerService.getServiceForUserIfCallerHasPermission( + mUserOneId, "test")); + } + + /** + * Test that the backup services does not throw a {@link SecurityException} if the caller has + * INTERACT_ACROSS_USERS_FULL permission and passes a different user id. + */ + @Test + public void testGetServiceForUserIfCallerHasPermission_withPermission_worksForNonCallingUser() { + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); + setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ true); + + assertEquals( + mUserOneService, + backupManagerService.getServiceForUserIfCallerHasPermission(mUserOneId, "test")); + } + + /** + * Test that the backup services does not throw a {@link SecurityException} if the caller does + * not have INTERACT_ACROSS_USERS_FULL permission and passes in the calling user id. + */ + @Test + public void testGetServiceForUserIfCallerHasPermission_withoutPermission_worksForCallingUser() { + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, mUserOneId, mUserOneService); + setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); + + assertEquals( + mUserOneService, + backupManagerService.getServiceForUserIfCallerHasPermission(mUserOneId, "test")); + } + + /** + * Test verifying that {@link BackupManagerService#MORE_DEBUG} is set to {@code false}. This is + * specifically to prevent overloading the logs in production. + */ + @Test + public void testMoreDebug_isFalse() throws Exception { + boolean moreDebug = BackupManagerService.MORE_DEBUG; + + assertThat(moreDebug).isFalse(); + } + + /** Test that the constructor handles {@code null} parameters. */ + @Test + public void testConstructor_withNullContext_throws() throws Exception { + expectThrows( + NullPointerException.class, + () -> + new BackupManagerService( + /* context */ null, + new SparseArray<>())); + } + + /** Test that the constructor does not create {@link UserBackupManagerService} instances. */ + @Test + public void testConstructor_doesNotRegisterUsers() throws Exception { + BackupManagerService backupManagerService = createService(); + + assertThat(backupManagerService.getUserServices().size()).isEqualTo(0); + } + + // --------------------------------------------- + // Lifecycle tests + // --------------------------------------------- + + /** testOnStart_publishesService */ + @Test + public void testOnStart_publishesService() { + BackupManagerService backupManagerService = mock(BackupManagerService.class); + BackupManagerService.Lifecycle lifecycle = + spy(new BackupManagerService.Lifecycle(mContext, backupManagerService)); + doNothing().when(lifecycle).publishService(anyString(), any()); + + lifecycle.onStart(); + + verify(lifecycle).publishService(Context.BACKUP_SERVICE, backupManagerService); + } + + /** testOnUnlockUser_forwards */ + @Test + public void testOnUnlockUser_forwards() { + BackupManagerService backupManagerService = mock(BackupManagerService.class); + BackupManagerService.Lifecycle lifecycle = + new BackupManagerService.Lifecycle(mContext, backupManagerService); + + lifecycle.onUnlockUser(UserHandle.USER_SYSTEM); + + verify(backupManagerService).onUnlockUser(UserHandle.USER_SYSTEM); + } + + /** testOnStopUser_forwards */ + @Test + public void testOnStopUser_forwards() { + BackupManagerService backupManagerService = mock(BackupManagerService.class); + BackupManagerService.Lifecycle lifecycle = + new BackupManagerService.Lifecycle(mContext, backupManagerService); + + lifecycle.onStopUser(UserHandle.USER_SYSTEM); + + verify(backupManagerService).onStopUser(UserHandle.USER_SYSTEM); } private BackupManagerService createService() { - mShadowContext.grantPermissions(BACKUP); - return new BackupManagerService(mContext, new Trampoline(mContext)); + return new BackupManagerService(mContext); + } + + private BackupManagerService createSystemRegisteredService() { + BackupManagerService backupManagerService = createService(); + registerUser(backupManagerService, UserHandle.USER_SYSTEM, mUserSystemService); + return backupManagerService; + } + + private void registerUser( + BackupManagerService backupManagerService, + int userId, + UserBackupManagerService userBackupManagerService) { + backupManagerService.setBackupServiceActive(userId, true); + backupManagerService.startServiceForUser(userId, userBackupManagerService); } private BackupManagerService createServiceAndRegisterUser( int userId, UserBackupManagerService userBackupManagerService) { BackupManagerService backupManagerService = createService(); + backupManagerService.setBackupServiceActive(userBackupManagerService.getUserId(), true); backupManagerService.startServiceForUser(userId, userBackupManagerService); return backupManagerService; } @@ -1647,10 +1649,4 @@ public class BackupManagerServiceTest { mShadowContext.denyPermissions(INTERACT_ACROSS_USERS_FULL); } } - - private ParcelFileDescriptor getFileDescriptorForAdbTest() throws Exception { - File testFile = new File(mContext.getFilesDir(), "test"); - testFile.createNewFile(); - return ParcelFileDescriptor.open(testFile, ParcelFileDescriptor.MODE_READ_WRITE); - } } diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java index 84e810dbb325..8632ca4c2898 100644 --- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java +++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java @@ -1005,7 +1005,7 @@ public class UserBackupManagerServiceTest { UserBackupManagerService.createAndInitializeService( USER_ID, mContext, - new Trampoline(mContext), + new BackupManagerService(mContext), mBackupThread, mBaseStateDir, mDataDir, @@ -1026,7 +1026,7 @@ public class UserBackupManagerServiceTest { UserBackupManagerService.createAndInitializeService( USER_ID, mContext, - new Trampoline(mContext), + new BackupManagerService(mContext), mBackupThread, mBaseStateDir, mDataDir, @@ -1045,7 +1045,7 @@ public class UserBackupManagerServiceTest { UserBackupManagerService.createAndInitializeService( USER_ID, /* context */ null, - new Trampoline(mContext), + new BackupManagerService(mContext), mBackupThread, mBaseStateDir, mDataDir, @@ -1077,7 +1077,7 @@ public class UserBackupManagerServiceTest { UserBackupManagerService.createAndInitializeService( USER_ID, mContext, - new Trampoline(mContext), + new BackupManagerService(mContext), /* backupThread */ null, mBaseStateDir, mDataDir, @@ -1093,7 +1093,7 @@ public class UserBackupManagerServiceTest { UserBackupManagerService.createAndInitializeService( USER_ID, mContext, - new Trampoline(mContext), + new BackupManagerService(mContext), mBackupThread, /* baseStateDir */ null, mDataDir, @@ -1102,8 +1102,8 @@ public class UserBackupManagerServiceTest { /** * Test checking non-null argument on {@link - * UserBackupManagerService#createAndInitializeService(int, Context, Trampoline, HandlerThread, - * File, File, TransportManager)}. + * UserBackupManagerService#createAndInitializeService(int, Context, BackupManagerService, + * HandlerThread, File, File, TransportManager)}. */ @Test public void testCreateAndInitializeService_withNullDataDir_throws() { @@ -1113,7 +1113,7 @@ public class UserBackupManagerServiceTest { UserBackupManagerService.createAndInitializeService( USER_ID, mContext, - new Trampoline(mContext), + new BackupManagerService(mContext), mBackupThread, mBaseStateDir, /* dataDir */ null, @@ -1122,8 +1122,8 @@ public class UserBackupManagerServiceTest { /** * Test checking non-null argument on {@link - * UserBackupManagerService#createAndInitializeService(int, Context, Trampoline, HandlerThread, - * File, File, TransportManager)}. + * UserBackupManagerService#createAndInitializeService(int, Context, BackupManagerService, + * HandlerThread, File, File, TransportManager)}. */ @Test public void testCreateAndInitializeService_withNullTransportManager_throws() { @@ -1133,7 +1133,7 @@ public class UserBackupManagerServiceTest { UserBackupManagerService.createAndInitializeService( USER_ID, mContext, - new Trampoline(mContext), + new BackupManagerService(mContext), mBackupThread, mBaseStateDir, mDataDir, @@ -1151,7 +1151,7 @@ public class UserBackupManagerServiceTest { UserBackupManagerService service = UserBackupManagerService.createAndInitializeService( USER_ID, contextSpy, - new Trampoline(mContext), + new BackupManagerService(mContext), mBackupThread, mBaseStateDir, mDataDir, diff --git a/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java b/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java index 392d182328a5..84421ef178c9 100644 --- a/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java +++ b/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java @@ -37,7 +37,7 @@ import android.os.Process; import android.util.Log; import com.android.server.backup.BackupAgentTimeoutParameters; -import com.android.server.backup.Trampoline; +import com.android.server.backup.BackupManagerService; import com.android.server.backup.TransportManager; import com.android.server.backup.UserBackupManagerService; @@ -89,7 +89,7 @@ public class BackupManagerServiceTestUtils { UserBackupManagerService.createAndInitializeService( userId, context, - new Trampoline(context), + new BackupManagerService(context), backupThread, baseStateDir, dataDir, diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowEnvironment.java b/services/robotests/src/com/android/server/testing/shadows/ShadowEnvironment.java new file mode 100644 index 000000000000..577b0824e775 --- /dev/null +++ b/services/robotests/src/com/android/server/testing/shadows/ShadowEnvironment.java @@ -0,0 +1,50 @@ +/* + * 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.testing.shadows; + +import android.annotation.Nullable; +import android.os.Environment; + +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.annotation.Resetter; + +import java.io.File; +import java.nio.file.Path; + +/** Implementation mimics {@link org.robolectric.shadows.ShadowEnvironment}. */ +@Implements(Environment.class) +public class ShadowEnvironment extends org.robolectric.shadows.ShadowEnvironment { + @Nullable private static Path sDataDirectory; + + /** @see Environment#getDataDirectory() */ + @Implementation + public static File getDataDirectory() { + if (sDataDirectory == null) { + sDataDirectory = RuntimeEnvironment.getTempDirectory().create("data"); + } + return sDataDirectory.toFile(); + } + + /** Resets static state. */ + @Resetter + public static void reset() { + org.robolectric.shadows.ShadowEnvironment.reset(); + sDataDirectory = null; + } +} diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowUserManager.java b/services/robotests/src/com/android/server/testing/shadows/ShadowUserManager.java new file mode 100644 index 000000000000..c6ae1a1b6863 --- /dev/null +++ b/services/robotests/src/com/android/server/testing/shadows/ShadowUserManager.java @@ -0,0 +1,33 @@ +/* + * 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.testing.shadows; + +import android.annotation.UserIdInt; +import android.os.UserManager; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +/** Shadow for {@link UserManager}. */ +@Implements(UserManager.class) +public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager { + /** @see UserManager#isUserUnlocked() */ + @Implementation + public boolean isUserUnlocked(@UserIdInt int userId) { + return false; + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java index 1e29ed6ba5f3..6e8b86add2c4 100644 --- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java @@ -253,7 +253,7 @@ public class AlarmManagerServiceTest { doReturn(mIActivityManager).when(ActivityManager::getService); doReturn(mAppStateTracker).when(() -> LocalServices.getService(AppStateTracker.class)); doReturn(null) - .when(() -> LocalServices.getService(DeviceIdleController.LocalService.class)); + .when(() -> LocalServices.getService(DeviceIdleInternal.class)); doReturn(mUsageStatsManagerInternal).when( () -> LocalServices.getService(UsageStatsManagerInternal.class)); when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java index 6feac520e538..108b017fc76c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java @@ -186,7 +186,7 @@ public class DeviceIdleControllerTest { @Override ConstraintController getConstraintController( - Handler handler, DeviceIdleController.LocalService localService) { + Handler handler, DeviceIdleInternal localService) { return constraintController; } @@ -291,7 +291,7 @@ public class DeviceIdleControllerTest { // DeviceIdleController adds these to LocalServices in the constructor, so we have to remove // them after each test, otherwise, subsequent tests will fail. LocalServices.removeServiceForTest(AppStateTracker.class); - LocalServices.removeServiceForTest(DeviceIdleController.LocalService.class); + LocalServices.removeServiceForTest(DeviceIdleInternal.class); } @Test diff --git a/services/tests/mockingservicestests/src/com/android/server/deviceidle/BluetoothConstraintTest.java b/services/tests/mockingservicestests/src/com/android/server/deviceidle/BluetoothConstraintTest.java index f74ac1f5317f..a9d1c2d60167 100644 --- a/services/tests/mockingservicestests/src/com/android/server/deviceidle/BluetoothConstraintTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/deviceidle/BluetoothConstraintTest.java @@ -39,7 +39,7 @@ import android.os.Handler; import androidx.test.runner.AndroidJUnit4; -import com.android.server.DeviceIdleController; +import com.android.server.DeviceIdleInternal; import org.junit.After; import org.junit.Before; @@ -71,7 +71,7 @@ public class BluetoothConstraintTest { private BluetoothManager mBluetoothManager; @Mock - private DeviceIdleController.LocalService mDeviceIdleService; + private DeviceIdleInternal mDeviceIdleService; private BluetoothConstraint mConstraint; diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java index 22cd3d39c982..71f7d2c27c86 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java @@ -53,7 +53,7 @@ import android.os.RemoteException; import android.os.SystemClock; import com.android.server.AppStateTracker; -import com.android.server.DeviceIdleController; +import com.android.server.DeviceIdleInternal; import com.android.server.LocalServices; import com.android.server.job.controllers.JobStatus; @@ -114,8 +114,8 @@ public class JobSchedulerServiceTest { when(mContext.getSystemService(NetworkPolicyManager.class)) .thenReturn(mock(NetworkPolicyManager.class)); // Called in DeviceIdleJobsController constructor. - doReturn(mock(DeviceIdleController.LocalService.class)) - .when(() -> LocalServices.getService(DeviceIdleController.LocalService.class)); + doReturn(mock(DeviceIdleInternal.class)) + .when(() -> LocalServices.getService(DeviceIdleInternal.class)); // Used in JobStatus. doReturn(mock(PackageManagerInternal.class)) .when(() -> LocalServices.getService(PackageManagerInternal.class)); diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java index 3614763fecab..5d041b7c5757 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java @@ -71,6 +71,7 @@ public class TimeControllerTest { private static final String SOURCE_PACKAGE = "com.android.frameworks.mockingservicestests"; private static final int SOURCE_USER_ID = 0; + private TimeController.TcConstants mConstants; private TimeController mTimeController; private MockitoSession mMockingSession; @@ -110,6 +111,7 @@ public class TimeControllerTest { // Initialize real objects. mTimeController = new TimeController(mJobSchedulerService); + mConstants = mTimeController.getTcConstants(); spyOn(mTimeController); } @@ -528,6 +530,46 @@ public class TimeControllerTest { } @Test + public void testJobDelayWakeupAlarmToggling() { + final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); + + JobStatus job = createJobStatus( + "testMaybeStartTrackingJobLocked_DeadlineReverseOrder", + createJob().setMinimumLatency(HOUR_IN_MILLIS)); + + doReturn(true).when(mTimeController) + .wouldBeReadyWithConstraintLocked(eq(job), anyInt()); + + // Starting off with using a wakeup alarm. + mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = false; + InOrder inOrder = inOrder(mAlarmManager); + + mTimeController.maybeStartTrackingJobLocked(job, null); + inOrder.verify(mAlarmManager, times(1)) + .set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(now + HOUR_IN_MILLIS), anyLong(), + anyLong(), + eq(TAG_DELAY), any(), any(), any()); + + // Use a non wakeup alarm. + mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = true; + + mTimeController.maybeStartTrackingJobLocked(job, null); + inOrder.verify(mAlarmManager, times(1)) + .set(eq(AlarmManager.ELAPSED_REALTIME), eq(now + HOUR_IN_MILLIS), anyLong(), + anyLong(), eq(TAG_DELAY), + any(), any(), any()); + + // Back off, use a wakeup alarm. + mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = false; + + mTimeController.maybeStartTrackingJobLocked(job, null); + inOrder.verify(mAlarmManager, times(1)) + .set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(now + HOUR_IN_MILLIS), anyLong(), + anyLong(), + eq(TAG_DELAY), any(), any(), any()); + } + + @Test public void testCheckExpiredDeadlinesAndResetAlarm_AllReady() { doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt()); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java index 1084d625f8a3..939aafa813e6 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java @@ -752,7 +752,7 @@ public class AbstractAccessibilityServiceConnectionTest { } @Override - protected boolean isCalledForCurrentUserLocked() { + protected boolean hasRightsToCurrentUserLocked() { return mResolvedUserId == mSystemSupport.getCurrentUserIdLocked(); } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java index 7887d5b76bca..93c16fedcc1b 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java @@ -77,6 +77,8 @@ public class AccessibilityWindowManagerTest { private static final boolean FORCE_SEND = true; private static final boolean SEND_ON_WINDOW_CHANGES = false; private static final int USER_SYSTEM_ID = UserHandle.USER_SYSTEM; + private static final int USER_PROFILE = 11; + private static final int USER_PROFILE_PARENT = 1; // TO-DO [Multi-Display] : change the display count to 2 private static final int DISPLAY_COUNT = 1; private static final int NUM_GLOBAL_WINDOWS = 4; @@ -110,6 +112,8 @@ public class AccessibilityWindowManagerTest { MockitoAnnotations.initMocks(this); when(mMockA11yUserManager.getCurrentUserIdLocked()).thenReturn(USER_SYSTEM_ID); when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked( + USER_PROFILE)).thenReturn(USER_PROFILE_PARENT); + when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked( USER_SYSTEM_ID)).thenReturn(USER_SYSTEM_ID); when(mMockA11ySecurityPolicy.resolveValidReportedPackageLocked( anyString(), anyInt(), anyInt())).thenReturn(PACKAGE_NAME); @@ -247,8 +251,8 @@ public class AccessibilityWindowManagerTest { throws RemoteException { final AccessibilityWindowInfo oldWindow = mA11yWindowManager.getWindowListLocked().get(0); - final IWindow token = - addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, true); + final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, + true, USER_SYSTEM_ID); final WindowInfo windowInfo = WindowInfo.obtain(); windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION; windowInfo.token = token.asBinder(); @@ -605,6 +609,16 @@ public class AccessibilityWindowManagerTest { verify(mockRemoteConnection).notifyOutsideTouch(); } + @Test + public void addAccessibilityInteractionConnection_profileUser_findInParentUser() + throws RemoteException { + final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, + false, USER_PROFILE); + final int windowId = mA11yWindowManager.findWindowIdLocked( + USER_PROFILE_PARENT, token.asBinder()); + assertTrue(windowId >= 0); + } + private void startTrackingPerDisplay(int displayId) throws RemoteException { ArrayList<WindowInfo> windowInfosForDisplay = new ArrayList<>(); // Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy @@ -612,12 +626,14 @@ public class AccessibilityWindowManagerTest { // for the test. int layer = 0; for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) { - final IWindow token = addAccessibilityInteractionConnection(displayId, true); + final IWindow token = addAccessibilityInteractionConnection(displayId, + true, USER_SYSTEM_ID); addWindowInfo(windowInfosForDisplay, token, layer++); } for (int i = 0; i < NUM_APP_WINDOWS; i++) { - final IWindow token = addAccessibilityInteractionConnection(displayId, false); + final IWindow token = addAccessibilityInteractionConnection(displayId, + false, USER_SYSTEM_ID); addWindowInfo(windowInfosForDisplay, token, layer++); } // Setups default focus. @@ -647,8 +663,8 @@ public class AccessibilityWindowManagerTest { return windowsForAccessibilityCallbacksCaptor.getValue(); } - private IWindow addAccessibilityInteractionConnection(int displayId, boolean bGlobal) - throws RemoteException { + private IWindow addAccessibilityInteractionConnection(int displayId, boolean bGlobal, + int userId) throws RemoteException { final IWindow mockWindowToken = Mockito.mock(IWindow.class); final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock( IAccessibilityInteractionConnection.class); @@ -656,13 +672,13 @@ public class AccessibilityWindowManagerTest { final IBinder mockWindowBinder = Mockito.mock(IBinder.class); when(mockA11yConnection.asBinder()).thenReturn(mockConnectionBinder); when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder); - when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(USER_SYSTEM_ID)) + when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(userId)) .thenReturn(bGlobal); when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowToken.asBinder())) .thenReturn(displayId); int windowId = mA11yWindowManager.addAccessibilityInteractionConnection( - mockWindowToken, mockA11yConnection, PACKAGE_NAME, USER_SYSTEM_ID); + mockWindowToken, mockA11yConnection, PACKAGE_NAME, userId); mA11yWindowTokens.put(windowId, mockWindowToken); return mockWindowToken; } diff --git a/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java new file mode 100644 index 000000000000..68b413ff976c --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/backup/BackupManagerServiceTest.java @@ -0,0 +1,621 @@ +/* + * Copyright (C) 2017 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.backup; + +import static com.google.common.truth.Truth.assertThat; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import android.Manifest; +import android.annotation.UserIdInt; +import android.app.backup.BackupManager; +import android.app.backup.IBackupManagerMonitor; +import android.app.backup.IBackupObserver; +import android.app.backup.IFullBackupRestoreObserver; +import android.app.backup.ISelectBackupTransportCallback; +import android.app.job.JobScheduler; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.UserInfo; +import android.os.ConditionVariable; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.os.Process; +import android.os.RemoteException; +import android.os.UserHandle; +import android.os.UserManager; +import android.platform.test.annotations.Presubmit; +import android.util.SparseArray; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.backup.utils.RandomAccessFileUtils; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +@SmallTest +@Presubmit +@RunWith(AndroidJUnit4.class) +public class BackupManagerServiceTest { + private static final String PACKAGE_NAME = "some.package.name"; + private static final String TRANSPORT_NAME = "some.transport.name"; + private static final String CURRENT_PASSWORD = "current_password"; + private static final String NEW_PASSWORD = "new_password"; + private static final String ENCRYPTION_PASSWORD = "encryption_password"; + private static final CharSequence DATA_MANAGEMENT_LABEL = "data_management_label"; + private static final String DESTINATION_STRING = "destination_string"; + private static final String[] PACKAGE_NAMES = + new String[]{"some.package.name._1", "some.package.name._2"}; + private static final String[] TRANSPORTS = + new String[]{"some.transport.name._1", "some.transport.name._2"}; + private static final ComponentName TRANSPORT_COMPONENT_NAME = new ComponentName("package", + "class"); + private static final ComponentName[] TRANSPORT_COMPONENTS = new ComponentName[]{ + new ComponentName("package1", "class1"), + new ComponentName("package2", "class2") + }; + private static final int NON_USER_SYSTEM = UserHandle.USER_SYSTEM + 1; + private static final int UNSTARTED_NON_USER_SYSTEM = UserHandle.USER_SYSTEM + 2; + + @UserIdInt + private int mUserId; + @Mock + private UserBackupManagerService mUserBackupManagerService; + @Mock + private Context mContextMock; + @Mock + private IBinder mAgentMock; + @Mock + private ParcelFileDescriptor mParcelFileDescriptorMock; + @Mock + private IFullBackupRestoreObserver mFullBackupRestoreObserverMock; + @Mock + private IBackupObserver mBackupObserverMock; + @Mock + private IBackupManagerMonitor mBackupManagerMonitorMock; + @Mock + private PrintWriter mPrintWriterMock; + @Mock + private UserManager mUserManagerMock; + @Mock + private UserInfo mUserInfoMock; + + private FileDescriptor mFileDescriptorStub = new FileDescriptor(); + + private BackupManagerServiceTestable mService; + private File mTestDir; + private File mSuppressFile; + private SparseArray<UserBackupManagerService> mUserServices; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mUserId = UserHandle.USER_SYSTEM; + + mUserServices = new SparseArray<>(); + mUserServices.append(UserHandle.USER_SYSTEM, mUserBackupManagerService); + mUserServices.append(NON_USER_SYSTEM, mUserBackupManagerService); + + when(mUserManagerMock.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(mUserInfoMock); + when(mUserManagerMock.getUserInfo(NON_USER_SYSTEM)).thenReturn(mUserInfoMock); + when(mUserManagerMock.getUserInfo(UNSTARTED_NON_USER_SYSTEM)).thenReturn(mUserInfoMock); + + BackupManagerServiceTestable.sCallingUserId = UserHandle.USER_SYSTEM; + BackupManagerServiceTestable.sCallingUid = Process.SYSTEM_UID; + BackupManagerServiceTestable.sBackupDisabled = false; + BackupManagerServiceTestable.sUserManagerMock = mUserManagerMock; + + mTestDir = InstrumentationRegistry.getContext().getFilesDir(); + mTestDir.mkdirs(); + + mSuppressFile = new File(mTestDir, "suppress"); + BackupManagerServiceTestable.sSuppressFile = mSuppressFile; + + setUpStateFilesForNonSystemUser(NON_USER_SYSTEM); + setUpStateFilesForNonSystemUser(UNSTARTED_NON_USER_SYSTEM); + + when(mContextMock.getSystemService(Context.JOB_SCHEDULER_SERVICE)) + .thenReturn(mock(JobScheduler.class)); + mService = new BackupManagerServiceTestable(mContextMock, mUserServices); + } + + private void setUpStateFilesForNonSystemUser(int userId) { + File activatedFile = new File(mTestDir, "activate-" + userId); + BackupManagerServiceTestable.sActivatedFiles.append(userId, activatedFile); + File rememberActivatedFile = new File(mTestDir, "rem-activate-" + userId); + BackupManagerServiceTestable.sRememberActivatedFiles.append(userId, rememberActivatedFile); + } + + @After + public void tearDown() throws Exception { + mSuppressFile.delete(); + deleteFiles(BackupManagerServiceTestable.sActivatedFiles); + deleteFiles(BackupManagerServiceTestable.sRememberActivatedFiles); + } + + private void deleteFiles(SparseArray<File> files) { + int numFiles = files.size(); + for (int i = 0; i < numFiles; i++) { + files.valueAt(i).delete(); + } + } + + @Test + public void testIsBackupServiceActive_whenBackupsNotDisabledAndSuppressFileDoesNotExist() { + assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM)); + } + + @Test + public void testOnUnlockUser_forNonSystemUserWhenBackupsDisabled_doesNotStartUser() { + BackupManagerServiceTestable.sBackupDisabled = true; + BackupManagerServiceTestable service = + new BackupManagerServiceTestable(mContextMock, new SparseArray<>()); + ConditionVariable unlocked = new ConditionVariable(false); + + service.onUnlockUser(NON_USER_SYSTEM); + + service.getBackupHandler().post(unlocked::open); + unlocked.block(); + assertNull(service.getUserService(NON_USER_SYSTEM)); + } + + @Test + public void testOnUnlockUser_forSystemUserWhenBackupsDisabled_doesNotStartUser() { + BackupManagerServiceTestable.sBackupDisabled = true; + BackupManagerServiceTestable service = + new BackupManagerServiceTestable(mContextMock, new SparseArray<>()); + ConditionVariable unlocked = new ConditionVariable(false); + + service.onUnlockUser(UserHandle.USER_SYSTEM); + + service.getBackupHandler().post(unlocked::open); + unlocked.block(); + assertNull(service.getUserService(UserHandle.USER_SYSTEM)); + } + + @Test + public void testOnUnlockUser_whenBackupNotActivated_doesNotStartUser() { + BackupManagerServiceTestable.sBackupDisabled = false; + BackupManagerServiceTestable service = + new BackupManagerServiceTestable(mContextMock, new SparseArray<>()); + service.setBackupServiceActive(NON_USER_SYSTEM, false); + ConditionVariable unlocked = new ConditionVariable(false); + + service.onUnlockUser(NON_USER_SYSTEM); + + service.getBackupHandler().post(unlocked::open); + unlocked.block(); + assertNull(service.getUserService(NON_USER_SYSTEM)); + } + + @Test + public void testIsBackupServiceActive_forSystemUserWhenBackupDisabled_returnsTrue() + throws Exception { + BackupManagerServiceTestable.sBackupDisabled = true; + BackupManagerService backupManagerService = + new BackupManagerServiceTestable(mContextMock, mUserServices); + backupManagerService.setBackupServiceActive(UserHandle.USER_SYSTEM, true); + + assertFalse(backupManagerService.isBackupServiceActive(UserHandle.USER_SYSTEM)); + } + + @Test + public void testIsBackupServiceActive_forNonSystemUserWhenBackupDisabled_returnsTrue() + throws Exception { + BackupManagerServiceTestable.sBackupDisabled = true; + BackupManagerService backupManagerService = + new BackupManagerServiceTestable(mContextMock, mUserServices); + backupManagerService.setBackupServiceActive(NON_USER_SYSTEM, true); + + assertFalse(backupManagerService.isBackupServiceActive(NON_USER_SYSTEM)); + } + + @Test + public void isBackupServiceActive_forSystemUser_returnsTrueWhenActivated() throws Exception { + mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true); + + assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM)); + } + + @Test + public void isBackupServiceActive_forSystemUser_returnsFalseWhenDeactivated() throws Exception { + mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false); + + assertFalse(mService.isBackupServiceActive(UserHandle.USER_SYSTEM)); + } + + @Test + public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenSystemUserDeactivated() + throws Exception { + mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false); + mService.setBackupServiceActive(NON_USER_SYSTEM, true); + + assertFalse(mService.isBackupServiceActive(NON_USER_SYSTEM)); + } + + @Test + public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenNonSystemUserDeactivated() + throws Exception { + mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true); + // Don't activate non-system user. + + assertFalse(mService.isBackupServiceActive(NON_USER_SYSTEM)); + } + + @Test + public void + isBackupServiceActive_forNonSystemUser_returnsTrueWhenSystemAndNonSystemUserActivated() + throws Exception { + mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true); + mService.setBackupServiceActive(NON_USER_SYSTEM, true); + + assertTrue(mService.isBackupServiceActive(NON_USER_SYSTEM)); + } + + @Test + public void + isBackupServiceActive_forUnstartedNonSystemUser_returnsTrueWhenSystemAndUserActivated() + throws Exception { + mService.setBackupServiceActive(UNSTARTED_NON_USER_SYSTEM, true); + + assertTrue(mService.isBackupServiceActive(UNSTARTED_NON_USER_SYSTEM)); + } + + @Test + public void setBackupServiceActive_forSystemUserAndCallerSystemUid_serviceCreated() { + BackupManagerServiceTestable.sCallingUid = Process.SYSTEM_UID; + + mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true); + + assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM)); + } + + @Test + public void setBackupServiceActive_forSystemUserAndCallerRootUid_serviceCreated() { + BackupManagerServiceTestable.sCallingUid = Process.ROOT_UID; + + mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true); + + assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM)); + } + + @Test + public void setBackupServiceActive_forSystemUserAndCallerNonRootNonSystem_throws() { + BackupManagerServiceTestable.sCallingUid = Process.FIRST_APPLICATION_UID; + + try { + mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true); + fail(); + } catch (SecurityException expected) { + } + } + + @Test + public void setBackupServiceActive_forManagedProfileAndCallerSystemUid_serviceCreated() { + when(mUserInfoMock.isManagedProfile()).thenReturn(true); + BackupManagerServiceTestable.sCallingUid = Process.SYSTEM_UID; + + mService.setBackupServiceActive(NON_USER_SYSTEM, true); + + assertTrue(mService.isBackupServiceActive(NON_USER_SYSTEM)); + } + + @Test + public void setBackupServiceActive_forManagedProfileAndCallerRootUid_serviceCreated() { + when(mUserInfoMock.isManagedProfile()).thenReturn(true); + BackupManagerServiceTestable.sCallingUid = Process.ROOT_UID; + + mService.setBackupServiceActive(NON_USER_SYSTEM, true); + + assertTrue(mService.isBackupServiceActive(NON_USER_SYSTEM)); + } + + @Test + public void setBackupServiceActive_forManagedProfileAndCallerNonRootNonSystem_throws() { + when(mUserInfoMock.isManagedProfile()).thenReturn(true); + BackupManagerServiceTestable.sCallingUid = Process.FIRST_APPLICATION_UID; + + try { + mService.setBackupServiceActive(NON_USER_SYSTEM, true); + fail(); + } catch (SecurityException expected) { + } + } + + @Test + public void setBackupServiceActive_forNonSystemUserAndCallerWithoutBackupPermission_throws() { + doThrow(new SecurityException()) + .when(mContextMock) + .enforceCallingOrSelfPermission(eq(Manifest.permission.BACKUP), anyString()); + + try { + mService.setBackupServiceActive(NON_USER_SYSTEM, true); + fail(); + } catch (SecurityException expected) { + } + } + + @Test + public void setBackupServiceActive_forNonSystemUserAndCallerWithoutUserPermission_throws() { + doThrow(new SecurityException()) + .when(mContextMock) + .enforceCallingOrSelfPermission( + eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL), anyString()); + + try { + mService.setBackupServiceActive(NON_USER_SYSTEM, true); + fail(); + } catch (SecurityException expected) { + } + } + + @Test + public void setBackupServiceActive_backupDisabled_ignored() { + BackupManagerServiceTestable.sBackupDisabled = true; + BackupManagerServiceTestable service = + new BackupManagerServiceTestable(mContextMock, mUserServices); + + service.setBackupServiceActive(UserHandle.USER_SYSTEM, true); + + assertFalse(service.isBackupServiceActive(UserHandle.USER_SYSTEM)); + } + + @Test + public void setBackupServiceActive_alreadyActive_ignored() { + mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true); + assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM)); + + mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true); + assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM)); + } + + @Test + public void setBackupServiceActive_makeNonActive_alreadyNonActive_ignored() { + mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false); + mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false); + + assertFalse(mService.isBackupServiceActive(UserHandle.USER_SYSTEM)); + } + + @Test + public void setBackupServiceActive_makeActive_serviceCreatedAndSuppressFileDeleted() { + mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true); + + assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM)); + } + + @Test + public void setBackupServiceActive_makeNonActive_serviceDeletedAndSuppressFileCreated() + throws IOException { + assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM)); + + mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false); + + assertFalse(mService.isBackupServiceActive(UserHandle.USER_SYSTEM)); + } + + @Test + public void setBackupActive_nonSystemUser_disabledForSystemUser_ignored() { + mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false); + mService.setBackupServiceActive(NON_USER_SYSTEM, true); + + assertFalse(mService.isBackupServiceActive(NON_USER_SYSTEM)); + } + + @Test + public void setBackupServiceActive_forOneNonSystemUser_doesNotActivateForAllNonSystemUsers() { + int otherUser = NON_USER_SYSTEM + 1; + File activateFile = new File(mTestDir, "activate-" + otherUser); + BackupManagerServiceTestable.sActivatedFiles.append(otherUser, activateFile); + mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true); + + mService.setBackupServiceActive(NON_USER_SYSTEM, true); + + assertTrue(mService.isBackupServiceActive(NON_USER_SYSTEM)); + assertFalse(mService.isBackupServiceActive(otherUser)); + activateFile.delete(); + } + + @Test + public void setBackupServiceActive_forNonSystemUser_remembersActivated() { + + mService.setBackupServiceActive(NON_USER_SYSTEM, true); + + assertTrue(RandomAccessFileUtils.readBoolean( + BackupManagerServiceTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), false)); + } + + @Test + public void setBackupServiceActiveFalse_forNonSystemUser_remembersActivated() { + + mService.setBackupServiceActive(NON_USER_SYSTEM, false); + + assertFalse(RandomAccessFileUtils.readBoolean( + BackupManagerServiceTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), true)); + } + + @Test + public void setBackupServiceActiveTwice_forNonSystemUser_remembersLastActivated() { + mService.setBackupServiceActive(NON_USER_SYSTEM, true); + mService.setBackupServiceActive(NON_USER_SYSTEM, false); + + assertFalse(RandomAccessFileUtils.readBoolean( + BackupManagerServiceTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), true)); + } + + @Test + public void selectBackupTransportAsyncForUser_beforeUserUnlocked_notifiesBackupNotAllowed() + throws Exception { + mUserServices.clear(); + CompletableFuture<Integer> future = new CompletableFuture<>(); + ISelectBackupTransportCallback listener = + new ISelectBackupTransportCallback.Stub() { + @Override + public void onSuccess(String transportName) { + future.completeExceptionally(new AssertionError()); + } + @Override + public void onFailure(int reason) { + future.complete(reason); + } + }; + + mService.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener); + + assertEquals(BackupManager.ERROR_BACKUP_NOT_ALLOWED, (int) future.get(5, TimeUnit.SECONDS)); + } + + @Test + public void selectBackupTransportAsyncForUser_beforeUserUnlockedWithNullListener_doesNotThrow() + throws Exception { + mService.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null); + + // No crash. + } + + @Test + public void + selectBackupTransportAsyncForUser_beforeUserUnlockedListenerThrowing_doesNotThrow() + throws Exception { + ISelectBackupTransportCallback.Stub listener = + new ISelectBackupTransportCallback.Stub() { + @Override + public void onSuccess(String transportName) {} + @Override + public void onFailure(int reason) throws RemoteException { + throw new RemoteException(); + } + }; + + mService.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener); + + // No crash. + } + + @Test + public void dump_callerDoesNotHavePermission_ignored() { + when(mContextMock.checkCallingOrSelfPermission( + android.Manifest.permission.DUMP)).thenReturn( + PackageManager.PERMISSION_DENIED); + + mService.dump(mFileDescriptorStub, mPrintWriterMock, new String[0]); + + verifyNoMoreInteractions(mUserBackupManagerService); + } + + public void testGetUserForAncestralSerialNumber() { + BackupManagerServiceTestable.sBackupDisabled = false; + BackupManagerService backupManagerService = + new BackupManagerServiceTestable(mContextMock, mUserServices); + when(mUserBackupManagerService.getAncestralSerialNumber()).thenReturn(11L); + + UserHandle user = backupManagerService.getUserForAncestralSerialNumber(11L); + + assertThat(user).isEqualTo(UserHandle.of(1)); + } + + public void testGetUserForAncestralSerialNumber_whenDisabled() { + BackupManagerServiceTestable.sBackupDisabled = true; + BackupManagerService backupManagerService = + new BackupManagerServiceTestable(mContextMock, mUserServices); + when(mUserBackupManagerService.getAncestralSerialNumber()).thenReturn(11L); + + UserHandle user = backupManagerService.getUserForAncestralSerialNumber(11L); + + assertThat(user).isNull(); + } + + private static class BackupManagerServiceTestable extends BackupManagerService { + static boolean sBackupDisabled = false; + static int sCallingUserId = -1; + static int sCallingUid = -1; + static File sSuppressFile = null; + static SparseArray<File> sActivatedFiles = new SparseArray<>(); + static SparseArray<File> sRememberActivatedFiles = new SparseArray<>(); + static UserManager sUserManagerMock = null; + + BackupManagerServiceTestable( + Context context, SparseArray<UserBackupManagerService> userServices) { + super(context, userServices); + } + + @Override + protected UserManager getUserManager() { + return sUserManagerMock; + } + + @Override + protected boolean isBackupDisabled() { + return sBackupDisabled; + } + + @Override + protected File getSuppressFileForSystemUser() { + return sSuppressFile; + } + + @Override + protected File getRememberActivatedFileForNonSystemUser(int userId) { + return sRememberActivatedFiles.get(userId); + } + + @Override + protected File getActivatedFileForNonSystemUser(int userId) { + return sActivatedFiles.get(userId); + } + + protected int binderGetCallingUserId() { + return sCallingUserId; + } + + @Override + protected int binderGetCallingUid() { + return sCallingUid; + } + + @Override + protected void postToHandler(Runnable runnable) { + runnable.run(); + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java deleted file mode 100644 index 8668a3cfa26c..000000000000 --- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java +++ /dev/null @@ -1,1116 +0,0 @@ -/* - * Copyright (C) 2017 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.backup; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; -import static junit.framework.Assert.fail; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import android.Manifest; -import android.annotation.UserIdInt; -import android.app.backup.BackupManager; -import android.app.backup.IBackupManagerMonitor; -import android.app.backup.IBackupObserver; -import android.app.backup.IFullBackupRestoreObserver; -import android.app.backup.ISelectBackupTransportCallback; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.UserInfo; -import android.os.ConditionVariable; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; -import android.os.Process; -import android.os.RemoteException; -import android.os.UserHandle; -import android.os.UserManager; -import android.platform.test.annotations.Presubmit; -import android.util.SparseArray; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import com.android.server.backup.utils.RandomAccessFileUtils; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.io.File; -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; - -@SmallTest -@Presubmit -@RunWith(AndroidJUnit4.class) -public class TrampolineTest { - private static final String PACKAGE_NAME = "some.package.name"; - private static final String TRANSPORT_NAME = "some.transport.name"; - private static final String CURRENT_PASSWORD = "current_password"; - private static final String NEW_PASSWORD = "new_password"; - private static final String ENCRYPTION_PASSWORD = "encryption_password"; - private static final CharSequence DATA_MANAGEMENT_LABEL = "data_management_label"; - private static final String DESTINATION_STRING = "destination_string"; - private static final String[] PACKAGE_NAMES = - new String[]{"some.package.name._1", "some.package.name._2"}; - private static final String[] TRANSPORTS = - new String[]{"some.transport.name._1", "some.transport.name._2"}; - private static final ComponentName TRANSPORT_COMPONENT_NAME = new ComponentName("package", - "class"); - private static final ComponentName[] TRANSPORT_COMPONENTS = new ComponentName[]{ - new ComponentName("package1", "class1"), - new ComponentName("package2", "class2") - }; - private static final int NON_USER_SYSTEM = UserHandle.USER_SYSTEM + 1; - private static final int UNSTARTED_NON_USER_SYSTEM = UserHandle.USER_SYSTEM + 2; - - @UserIdInt - private int mUserId; - @Mock - private BackupManagerService mBackupManagerServiceMock; - @Mock - private UserBackupManagerService mUserBackupManagerService; - @Mock - private Context mContextMock; - @Mock - private IBinder mAgentMock; - @Mock - private ParcelFileDescriptor mParcelFileDescriptorMock; - @Mock - private IFullBackupRestoreObserver mFullBackupRestoreObserverMock; - @Mock - private IBackupObserver mBackupObserverMock; - @Mock - private IBackupManagerMonitor mBackupManagerMonitorMock; - @Mock - private PrintWriter mPrintWriterMock; - @Mock - private UserManager mUserManagerMock; - @Mock - private UserInfo mUserInfoMock; - - private FileDescriptor mFileDescriptorStub = new FileDescriptor(); - - private TrampolineTestable mTrampoline; - private File mTestDir; - private File mSuppressFile; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mUserId = UserHandle.USER_SYSTEM; - - SparseArray<UserBackupManagerService> serviceUsers = new SparseArray<>(); - serviceUsers.append(UserHandle.USER_SYSTEM, mUserBackupManagerService); - serviceUsers.append(NON_USER_SYSTEM, mUserBackupManagerService); - when(mBackupManagerServiceMock.getUserServices()).thenReturn(serviceUsers); - - when(mUserManagerMock.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(mUserInfoMock); - when(mUserManagerMock.getUserInfo(NON_USER_SYSTEM)).thenReturn(mUserInfoMock); - when(mUserManagerMock.getUserInfo(UNSTARTED_NON_USER_SYSTEM)).thenReturn(mUserInfoMock); - - TrampolineTestable.sBackupManagerServiceMock = mBackupManagerServiceMock; - TrampolineTestable.sCallingUserId = UserHandle.USER_SYSTEM; - TrampolineTestable.sCallingUid = Process.SYSTEM_UID; - TrampolineTestable.sBackupDisabled = false; - TrampolineTestable.sUserManagerMock = mUserManagerMock; - - mTestDir = InstrumentationRegistry.getContext().getFilesDir(); - mTestDir.mkdirs(); - - mSuppressFile = new File(mTestDir, "suppress"); - TrampolineTestable.sSuppressFile = mSuppressFile; - - setUpStateFilesForNonSystemUser(NON_USER_SYSTEM); - setUpStateFilesForNonSystemUser(UNSTARTED_NON_USER_SYSTEM); - - mTrampoline = new TrampolineTestable(mContextMock); - } - - private void setUpStateFilesForNonSystemUser(int userId) { - File activatedFile = new File(mTestDir, "activate-" + userId); - TrampolineTestable.sActivatedFiles.append(userId, activatedFile); - File rememberActivatedFile = new File(mTestDir, "rem-activate-" + userId); - TrampolineTestable.sRememberActivatedFiles.append(userId, rememberActivatedFile); - } - - @After - public void tearDown() throws Exception { - mSuppressFile.delete(); - deleteFiles(TrampolineTestable.sActivatedFiles); - deleteFiles(TrampolineTestable.sRememberActivatedFiles); - } - - private void deleteFiles(SparseArray<File> files) { - int numFiles = files.size(); - for (int i = 0; i < numFiles; i++) { - files.valueAt(i).delete(); - } - } - - @Test - public void testIsBackupServiceActive_whenBackupsNotDisabledAndSuppressFileDoesNotExist() { - assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); - } - - @Test - public void testOnUnlockUser_forNonSystemUserWhenBackupsDisabled_doesNotStartUser() { - when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>()); - TrampolineTestable.sBackupDisabled = true; - TrampolineTestable trampoline = new TrampolineTestable(mContextMock); - ConditionVariable unlocked = new ConditionVariable(false); - - trampoline.onUnlockUser(NON_USER_SYSTEM); - - trampoline.getBackupHandler().post(unlocked::open); - unlocked.block(); - assertNull(trampoline.getUserService(NON_USER_SYSTEM)); - } - - @Test - public void testOnUnlockUser_forSystemUserWhenBackupsDisabled_doesNotStartUser() { - when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>()); - TrampolineTestable.sBackupDisabled = true; - TrampolineTestable trampoline = new TrampolineTestable(mContextMock); - ConditionVariable unlocked = new ConditionVariable(false); - - trampoline.onUnlockUser(UserHandle.USER_SYSTEM); - - trampoline.getBackupHandler().post(unlocked::open); - unlocked.block(); - assertNull(trampoline.getUserService(UserHandle.USER_SYSTEM)); - } - - @Test - public void testOnUnlockUser_whenBackupNotActivated_doesNotStartUser() { - when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>()); - TrampolineTestable.sBackupDisabled = false; - TrampolineTestable trampoline = new TrampolineTestable(mContextMock); - trampoline.setBackupServiceActive(NON_USER_SYSTEM, false); - ConditionVariable unlocked = new ConditionVariable(false); - - trampoline.onUnlockUser(NON_USER_SYSTEM); - - trampoline.getBackupHandler().post(unlocked::open); - unlocked.block(); - assertNull(trampoline.getUserService(NON_USER_SYSTEM)); - //noinspection unchecked - verify(mBackupManagerServiceMock, never()).startServiceForUser( - eq(NON_USER_SYSTEM), any(Set.class)); - } - - @Test - public void testIsBackupServiceActive_forSystemUserWhenBackupDisabled_returnsTrue() - throws Exception { - TrampolineTestable.sBackupDisabled = true; - Trampoline trampoline = new TrampolineTestable(mContextMock); - trampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); - - assertFalse(trampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); - } - - @Test - public void testIsBackupServiceActive_forNonSystemUserWhenBackupDisabled_returnsTrue() - throws Exception { - TrampolineTestable.sBackupDisabled = true; - Trampoline trampoline = new TrampolineTestable(mContextMock); - trampoline.setBackupServiceActive(NON_USER_SYSTEM, true); - - assertFalse(trampoline.isBackupServiceActive(NON_USER_SYSTEM)); - } - - @Test - public void isBackupServiceActive_forSystemUser_returnsTrueWhenActivated() throws Exception { - mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); - - assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); - } - - @Test - public void isBackupServiceActive_forSystemUser_returnsFalseWhenDeactivated() throws Exception { - mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false); - - assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); - } - - @Test - public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenSystemUserDeactivated() - throws Exception { - mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false); - mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); - - assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM)); - } - - @Test - public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenNonSystemUserDeactivated() - throws Exception { - mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); - // Don't activate non-system user. - - assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM)); - } - - @Test - public void - isBackupServiceActive_forNonSystemUser_returnsTrueWhenSystemAndNonSystemUserActivated() - throws Exception { - mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); - mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); - - assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM)); - } - - @Test - public void - isBackupServiceActive_forUnstartedNonSystemUser_returnsTrueWhenSystemAndUserActivated() - throws Exception { - mTrampoline.setBackupServiceActive(UNSTARTED_NON_USER_SYSTEM, true); - - assertTrue(mTrampoline.isBackupServiceActive(UNSTARTED_NON_USER_SYSTEM)); - } - - @Test - public void setBackupServiceActive_forSystemUserAndCallerSystemUid_serviceCreated() { - TrampolineTestable.sCallingUid = Process.SYSTEM_UID; - - mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); - - assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); - } - - @Test - public void setBackupServiceActive_forSystemUserAndCallerRootUid_serviceCreated() { - TrampolineTestable.sCallingUid = Process.ROOT_UID; - - mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); - - assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); - } - - @Test - public void setBackupServiceActive_forSystemUserAndCallerNonRootNonSystem_throws() { - TrampolineTestable.sCallingUid = Process.FIRST_APPLICATION_UID; - - try { - mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); - fail(); - } catch (SecurityException expected) { - } - } - - @Test - public void setBackupServiceActive_forManagedProfileAndCallerSystemUid_serviceCreated() { - when(mUserInfoMock.isManagedProfile()).thenReturn(true); - TrampolineTestable.sCallingUid = Process.SYSTEM_UID; - - mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); - - assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM)); - } - - @Test - public void setBackupServiceActive_forManagedProfileAndCallerRootUid_serviceCreated() { - when(mUserInfoMock.isManagedProfile()).thenReturn(true); - TrampolineTestable.sCallingUid = Process.ROOT_UID; - - mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); - - assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM)); - } - - @Test - public void setBackupServiceActive_forManagedProfileAndCallerNonRootNonSystem_throws() { - when(mUserInfoMock.isManagedProfile()).thenReturn(true); - TrampolineTestable.sCallingUid = Process.FIRST_APPLICATION_UID; - - try { - mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); - fail(); - } catch (SecurityException expected) { - } - } - - @Test - public void setBackupServiceActive_forNonSystemUserAndCallerWithoutBackupPermission_throws() { - doThrow(new SecurityException()) - .when(mContextMock) - .enforceCallingOrSelfPermission(eq(Manifest.permission.BACKUP), anyString()); - - try { - mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); - fail(); - } catch (SecurityException expected) { - } - } - - @Test - public void setBackupServiceActive_forNonSystemUserAndCallerWithoutUserPermission_throws() { - doThrow(new SecurityException()) - .when(mContextMock) - .enforceCallingOrSelfPermission( - eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL), anyString()); - - try { - mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); - fail(); - } catch (SecurityException expected) { - } - } - - @Test - public void setBackupServiceActive_backupDisabled_ignored() { - TrampolineTestable.sBackupDisabled = true; - TrampolineTestable trampoline = new TrampolineTestable(mContextMock); - - trampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); - - assertFalse(trampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); - } - - @Test - public void setBackupServiceActive_alreadyActive_ignored() { - mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); - assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); - - mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); - assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); - } - - @Test - public void setBackupServiceActive_makeNonActive_alreadyNonActive_ignored() { - mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false); - mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false); - - assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); - } - - @Test - public void setBackupServiceActive_makeActive_serviceCreatedAndSuppressFileDeleted() { - mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); - - assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); - } - - @Test - public void setBackupServiceActive_makeNonActive_serviceDeletedAndSuppressFileCreated() - throws IOException { - assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); - - mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false); - - assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM)); - } - - @Test - public void setBackupActive_nonSystemUser_disabledForSystemUser_ignored() { - mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false); - mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); - - assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM)); - } - - @Test - public void setBackupServiceActive_forOneNonSystemUser_doesNotActivateForAllNonSystemUsers() { - int otherUser = NON_USER_SYSTEM + 1; - File activateFile = new File(mTestDir, "activate-" + otherUser); - TrampolineTestable.sActivatedFiles.append(otherUser, activateFile); - mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true); - - mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); - - assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM)); - assertFalse(mTrampoline.isBackupServiceActive(otherUser)); - activateFile.delete(); - } - - @Test - public void setBackupServiceActive_forNonSystemUser_remembersActivated() { - - mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); - - assertTrue(RandomAccessFileUtils.readBoolean( - TrampolineTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), false)); - } - - @Test - public void setBackupServiceActiveFalse_forNonSystemUser_remembersActivated() { - - mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, false); - - assertFalse(RandomAccessFileUtils.readBoolean( - TrampolineTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), true)); - } - - @Test - public void setBackupServiceActiveTwice_forNonSystemUser_remembersLastActivated() { - mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true); - mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, false); - - assertFalse(RandomAccessFileUtils.readBoolean( - TrampolineTestable.sRememberActivatedFiles.get(NON_USER_SYSTEM), true)); - } - - @Test - public void dataChangedForUser_forwarded() throws Exception { - mTrampoline.dataChangedForUser(mUserId, PACKAGE_NAME); - - verify(mBackupManagerServiceMock).dataChanged(mUserId, PACKAGE_NAME); - } - - @Test - public void dataChanged_forwarded() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - - mTrampoline.dataChanged(PACKAGE_NAME); - - verify(mBackupManagerServiceMock).dataChanged(mUserId, PACKAGE_NAME); - } - - @Test - public void clearBackupDataForUser_forwarded() throws Exception { - - mTrampoline.clearBackupDataForUser(mUserId, TRANSPORT_NAME, PACKAGE_NAME); - - verify(mBackupManagerServiceMock).clearBackupData(mUserId, TRANSPORT_NAME, PACKAGE_NAME); - } - - @Test - public void clearBackupData_forwarded() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - - mTrampoline.clearBackupData(TRANSPORT_NAME, PACKAGE_NAME); - - verify(mBackupManagerServiceMock).clearBackupData(mUserId, TRANSPORT_NAME, PACKAGE_NAME); - } - - @Test - public void agentConnectedForUser_forwarded() throws Exception { - - mTrampoline.agentConnectedForUser(mUserId, PACKAGE_NAME, mAgentMock); - - verify(mBackupManagerServiceMock).agentConnected(mUserId, PACKAGE_NAME, mAgentMock); - } - - @Test - public void agentConnected_forwarded() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - - mTrampoline.agentConnected(PACKAGE_NAME, mAgentMock); - - verify(mBackupManagerServiceMock).agentConnected(mUserId, PACKAGE_NAME, mAgentMock); - } - - @Test - public void agentDisconnectedForUser_forwarded() throws Exception { - - mTrampoline.agentDisconnectedForUser(mUserId, PACKAGE_NAME); - - verify(mBackupManagerServiceMock).agentDisconnected(mUserId, PACKAGE_NAME); - } - - @Test - public void agentDisconnected_forwarded() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - - mTrampoline.agentDisconnected(PACKAGE_NAME); - - verify(mBackupManagerServiceMock).agentDisconnected(mUserId, PACKAGE_NAME); - } - - @Test - public void restoreAtInstallForUser_forwarded() throws Exception { - - mTrampoline.restoreAtInstallForUser(mUserId, PACKAGE_NAME, 123); - - verify(mBackupManagerServiceMock).restoreAtInstall(mUserId, PACKAGE_NAME, 123); - } - - @Test - public void restoreAtInstall_forwarded() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - - mTrampoline.restoreAtInstall(PACKAGE_NAME, 123); - - verify(mBackupManagerServiceMock).restoreAtInstall(mUserId, PACKAGE_NAME, 123); - } - - @Test - public void setBackupEnabledForUser_forwarded() throws Exception { - - mTrampoline.setBackupEnabledForUser(mUserId, true); - - verify(mBackupManagerServiceMock).setBackupEnabled(mUserId, true); - } - - @Test - public void setBackupEnabled_forwardedToCallingUserId() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - - mTrampoline.setBackupEnabled(true); - - verify(mBackupManagerServiceMock).setBackupEnabled(mUserId, true); - } - - @Test - public void setAutoRestoreForUser_forwarded() throws Exception { - - mTrampoline.setAutoRestoreForUser(mUserId, true); - - verify(mBackupManagerServiceMock).setAutoRestore(mUserId, true); - } - - @Test - public void setAutoRestore_forwarded() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - - mTrampoline.setAutoRestore(true); - - verify(mBackupManagerServiceMock).setAutoRestore(mUserId, true); - } - - @Test - public void isBackupEnabledForUser_forwarded() throws Exception { - - mTrampoline.isBackupEnabledForUser(mUserId); - - verify(mBackupManagerServiceMock).isBackupEnabled(mUserId); - } - - @Test - public void isBackupEnabled_forwardedToCallingUserId() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - - mTrampoline.isBackupEnabled(); - - verify(mBackupManagerServiceMock).isBackupEnabled(mUserId); - } - - @Test - public void setBackupPassword_forwarded() throws Exception { - mTrampoline.setBackupPassword(CURRENT_PASSWORD, NEW_PASSWORD); - verify(mBackupManagerServiceMock).setBackupPassword(CURRENT_PASSWORD, NEW_PASSWORD); - } - - @Test - public void hasBackupPassword_forwarded() throws Exception { - mTrampoline.hasBackupPassword(); - verify(mBackupManagerServiceMock).hasBackupPassword(); - } - - @Test - public void backupNowForUser_forwarded() throws Exception { - - mTrampoline.backupNowForUser(mUserId); - - verify(mBackupManagerServiceMock).backupNow(mUserId); - } - - @Test - public void backupNow_forwardedToCallingUserId() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - - mTrampoline.backupNow(); - - verify(mBackupManagerServiceMock).backupNow(mUserId); - } - - @Test - public void adbBackup_forwarded() throws Exception { - mTrampoline.adbBackup(mUserId, mParcelFileDescriptorMock, true, true, - true, true, true, true, true, true, - PACKAGE_NAMES); - verify(mBackupManagerServiceMock).adbBackup(mUserId, mParcelFileDescriptorMock, true, - true, true, true, true, true, true, true, PACKAGE_NAMES); - } - - @Test - public void fullTransportBackupForUser_forwarded() throws Exception { - - mTrampoline.fullTransportBackupForUser(mUserId, PACKAGE_NAMES); - - verify(mBackupManagerServiceMock).fullTransportBackup(mUserId, PACKAGE_NAMES); - } - - @Test - public void adbRestore_forwarded() throws Exception { - mTrampoline.adbRestore(mUserId, mParcelFileDescriptorMock); - verify(mBackupManagerServiceMock).adbRestore(mUserId, mParcelFileDescriptorMock); - } - - @Test - public void acknowledgeFullBackupOrRestoreForUser_forwarded() throws Exception { - - mTrampoline.acknowledgeFullBackupOrRestoreForUser( - mUserId, - 123, - true, - CURRENT_PASSWORD, - ENCRYPTION_PASSWORD, - mFullBackupRestoreObserverMock); - - verify(mBackupManagerServiceMock) - .acknowledgeAdbBackupOrRestore( - mUserId, - 123, - true, - CURRENT_PASSWORD, - ENCRYPTION_PASSWORD, - mFullBackupRestoreObserverMock); - } - - @Test - public void acknowledgeFullBackupOrRestore_forwarded() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - - mTrampoline.acknowledgeFullBackupOrRestore(123, true, CURRENT_PASSWORD, ENCRYPTION_PASSWORD, - mFullBackupRestoreObserverMock); - - verify(mBackupManagerServiceMock) - .acknowledgeAdbBackupOrRestore( - mUserId, - 123, - true, - CURRENT_PASSWORD, - ENCRYPTION_PASSWORD, - mFullBackupRestoreObserverMock); - } - - @Test - public void getCurrentTransportForUser_forwarded() throws Exception { - when(mBackupManagerServiceMock.getCurrentTransport(mUserId)).thenReturn(TRANSPORT_NAME); - - assertEquals(TRANSPORT_NAME, mTrampoline.getCurrentTransportForUser(mUserId)); - verify(mBackupManagerServiceMock).getCurrentTransport(mUserId); - } - - @Test - public void getCurrentTransport_forwarded() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - when(mBackupManagerServiceMock.getCurrentTransport(mUserId)).thenReturn(TRANSPORT_NAME); - - assertEquals(TRANSPORT_NAME, mTrampoline.getCurrentTransport()); - verify(mBackupManagerServiceMock).getCurrentTransport(mUserId); - } - - @Test - public void listAllTransportsForUser_forwarded() throws Exception { - when(mBackupManagerServiceMock.listAllTransports(mUserId)).thenReturn(TRANSPORTS); - - assertEquals(TRANSPORTS, mTrampoline.listAllTransportsForUser(mUserId)); - verify(mBackupManagerServiceMock).listAllTransports(mUserId); - } - - - @Test - public void listAllTransports_forwarded() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - when(mBackupManagerServiceMock.listAllTransports(mUserId)).thenReturn(TRANSPORTS); - - assertEquals(TRANSPORTS, mTrampoline.listAllTransports()); - verify(mBackupManagerServiceMock).listAllTransports(mUserId); - } - - @Test - public void listAllTransportComponentsForUser_forwarded() throws Exception { - when(mBackupManagerServiceMock.listAllTransportComponents(mUserId)).thenReturn( - TRANSPORT_COMPONENTS); - - assertEquals(TRANSPORT_COMPONENTS, mTrampoline.listAllTransportComponentsForUser(mUserId)); - verify(mBackupManagerServiceMock).listAllTransportComponents(mUserId); - } - - @Test - public void updateTransportAttributesForUser_forwarded() { - mTrampoline.updateTransportAttributesForUser( - mUserId, - TRANSPORT_COMPONENT_NAME, - TRANSPORT_NAME, - null, - "Transport Destination", - null, - "Data Management"); - - verify(mBackupManagerServiceMock) - .updateTransportAttributes( - mUserId, - TRANSPORT_COMPONENT_NAME, - TRANSPORT_NAME, - null, - "Transport Destination", - null, - "Data Management"); - } - - @Test - public void selectBackupTransportForUser_forwarded() throws Exception { - - mTrampoline.selectBackupTransportForUser(mUserId, TRANSPORT_NAME); - - verify(mBackupManagerServiceMock).selectBackupTransport(mUserId, TRANSPORT_NAME); - } - - @Test - public void selectBackupTransport_forwarded() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - - mTrampoline.selectBackupTransport(TRANSPORT_NAME); - - verify(mBackupManagerServiceMock).selectBackupTransport(mUserId, TRANSPORT_NAME); - } - - @Test - public void selectBackupTransportAsyncForUser_beforeUserUnlocked_notifiesBackupNotAllowed() - throws Exception { - when(mBackupManagerServiceMock.getUserServices()).thenReturn(new SparseArray<>()); - CompletableFuture<Integer> future = new CompletableFuture<>(); - ISelectBackupTransportCallback listener = - new ISelectBackupTransportCallback.Stub() { - @Override - public void onSuccess(String transportName) { - future.completeExceptionally(new AssertionError()); - } - @Override - public void onFailure(int reason) { - future.complete(reason); - } - }; - - mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener); - - assertEquals(BackupManager.ERROR_BACKUP_NOT_ALLOWED, (int) future.get(5, TimeUnit.SECONDS)); - } - - @Test - public void selectBackupTransportAsyncForUser_beforeUserUnlockedWithNullListener_doesNotThrow() - throws Exception { - mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null); - - // No crash. - } - - @Test - public void - selectBackupTransportAsyncForUser_beforeUserUnlockedWithThrowingListener_doesNotThrow() - throws Exception { - ISelectBackupTransportCallback.Stub listener = - new ISelectBackupTransportCallback.Stub() { - @Override - public void onSuccess(String transportName) {} - @Override - public void onFailure(int reason) throws RemoteException { - throw new RemoteException(); - } - }; - - mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener); - - // No crash. - } - - @Test - public void selectBackupTransportAsyncForUser_forwarded() throws Exception { - - mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null); - - verify(mBackupManagerServiceMock) - .selectBackupTransportAsync(mUserId, TRANSPORT_COMPONENT_NAME, null); - } - - @Test - public void getConfigurationIntentForUser_forwarded() throws Exception { - Intent configurationIntentStub = new Intent(); - when(mBackupManagerServiceMock.getConfigurationIntent(mUserId, TRANSPORT_NAME)).thenReturn( - configurationIntentStub); - - assertEquals( - configurationIntentStub, - mTrampoline.getConfigurationIntentForUser(mUserId, TRANSPORT_NAME)); - verify(mBackupManagerServiceMock).getConfigurationIntent(mUserId, TRANSPORT_NAME); - } - - @Test - public void getConfigurationIntent_forwarded() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - Intent configurationIntentStub = new Intent(); - when(mBackupManagerServiceMock.getConfigurationIntent(mUserId, TRANSPORT_NAME)).thenReturn( - configurationIntentStub); - - assertEquals(configurationIntentStub, mTrampoline.getConfigurationIntent(TRANSPORT_NAME)); - verify(mBackupManagerServiceMock).getConfigurationIntent(mUserId, TRANSPORT_NAME); - } - - @Test - public void getDestinationStringForUser_forwarded() throws Exception { - when(mBackupManagerServiceMock.getDestinationString(mUserId, TRANSPORT_NAME)).thenReturn( - DESTINATION_STRING); - - assertEquals( - DESTINATION_STRING, - mTrampoline.getDestinationStringForUser(mUserId, TRANSPORT_NAME)); - verify(mBackupManagerServiceMock).getDestinationString(mUserId, TRANSPORT_NAME); - } - - @Test - public void getDestinationString_forwarded() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - when(mBackupManagerServiceMock.getDestinationString(mUserId, TRANSPORT_NAME)).thenReturn( - DESTINATION_STRING); - - assertEquals(DESTINATION_STRING, mTrampoline.getDestinationString(TRANSPORT_NAME)); - verify(mBackupManagerServiceMock).getDestinationString(mUserId, TRANSPORT_NAME); - } - - @Test - public void getDataManagementIntentForUser_forwarded() throws Exception { - Intent dataManagementIntent = new Intent(); - when(mBackupManagerServiceMock.getDataManagementIntent(mUserId, TRANSPORT_NAME)).thenReturn( - dataManagementIntent); - - assertEquals( - dataManagementIntent, - mTrampoline.getDataManagementIntentForUser(mUserId, TRANSPORT_NAME)); - verify(mBackupManagerServiceMock).getDataManagementIntent(mUserId, TRANSPORT_NAME); - } - - @Test - public void getDataManagementIntent_forwarded() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - Intent dataManagementIntent = new Intent(); - when(mBackupManagerServiceMock.getDataManagementIntent(mUserId, TRANSPORT_NAME)).thenReturn( - dataManagementIntent); - - assertEquals(dataManagementIntent, mTrampoline.getDataManagementIntent(TRANSPORT_NAME)); - verify(mBackupManagerServiceMock).getDataManagementIntent(mUserId, TRANSPORT_NAME); - } - - @Test - public void getDataManagementLabelForUser_forwarded() throws Exception { - when(mBackupManagerServiceMock.getDataManagementLabel(mUserId, TRANSPORT_NAME)).thenReturn( - DATA_MANAGEMENT_LABEL); - - assertEquals( - DATA_MANAGEMENT_LABEL, - mTrampoline.getDataManagementLabelForUser(mUserId, TRANSPORT_NAME)); - verify(mBackupManagerServiceMock).getDataManagementLabel(mUserId, TRANSPORT_NAME); - } - - @Test - public void beginRestoreSessionForUser_forwarded() throws Exception { - - mTrampoline.beginRestoreSessionForUser(mUserId, PACKAGE_NAME, TRANSPORT_NAME); - - verify(mBackupManagerServiceMock) - .beginRestoreSession(mUserId, PACKAGE_NAME, TRANSPORT_NAME); - } - - @Test - public void opComplete_forwarded() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - - mTrampoline.opComplete(1, 2); - - verify(mBackupManagerServiceMock).opComplete(mUserId, 1, 2); - } - - @Test - public void getAvailableRestoreTokenForUser_forwarded() { - when(mBackupManagerServiceMock.getAvailableRestoreToken(mUserId, PACKAGE_NAME)) - .thenReturn(123L); - - assertEquals(123, mTrampoline.getAvailableRestoreTokenForUser(mUserId, PACKAGE_NAME)); - verify(mBackupManagerServiceMock).getAvailableRestoreToken(mUserId, PACKAGE_NAME); - } - - @Test - public void isAppEligibleForBackupForUser_forwarded() { - when(mBackupManagerServiceMock.isAppEligibleForBackup(mUserId, PACKAGE_NAME)) - .thenReturn(true); - - assertTrue(mTrampoline.isAppEligibleForBackupForUser(mUserId, PACKAGE_NAME)); - verify(mBackupManagerServiceMock).isAppEligibleForBackup(mUserId, PACKAGE_NAME); - } - - @Test - public void requestBackupForUser_forwarded() throws Exception { - when(mBackupManagerServiceMock.requestBackup(mUserId, PACKAGE_NAMES, - mBackupObserverMock, mBackupManagerMonitorMock, 123)).thenReturn(456); - - assertEquals(456, mTrampoline.requestBackupForUser(mUserId, PACKAGE_NAMES, - mBackupObserverMock, mBackupManagerMonitorMock, 123)); - verify(mBackupManagerServiceMock).requestBackup(mUserId, PACKAGE_NAMES, - mBackupObserverMock, mBackupManagerMonitorMock, 123); - } - - @Test - public void requestBackup_forwardedToCallingUserId() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - when(mBackupManagerServiceMock.requestBackup(mUserId, PACKAGE_NAMES, - mBackupObserverMock, mBackupManagerMonitorMock, 123)).thenReturn(456); - - assertEquals(456, mTrampoline.requestBackup(PACKAGE_NAMES, - mBackupObserverMock, mBackupManagerMonitorMock, 123)); - verify(mBackupManagerServiceMock).requestBackup(mUserId, PACKAGE_NAMES, - mBackupObserverMock, mBackupManagerMonitorMock, 123); - } - - @Test - public void cancelBackupsForUser_forwarded() throws Exception { - - mTrampoline.cancelBackupsForUser(mUserId); - - verify(mBackupManagerServiceMock).cancelBackups(mUserId); - } - - @Test - public void cancelBackups_forwardedToCallingUserId() throws Exception { - TrampolineTestable.sCallingUserId = mUserId; - - mTrampoline.cancelBackups(); - - verify(mBackupManagerServiceMock).cancelBackups(mUserId); - } - - @Test - public void beginFullBackup_forwarded() throws Exception { - FullBackupJob fullBackupJob = new FullBackupJob(); - when(mBackupManagerServiceMock.beginFullBackup(mUserId, fullBackupJob)).thenReturn(true); - - assertTrue(mTrampoline.beginFullBackup(mUserId, fullBackupJob)); - verify(mBackupManagerServiceMock).beginFullBackup(mUserId, fullBackupJob); - } - - @Test - public void endFullBackup_forwarded() { - mTrampoline.endFullBackup(mUserId); - verify(mBackupManagerServiceMock).endFullBackup(mUserId); - } - - @Test - public void dump_callerDoesNotHavePermission_ignored() { - when(mContextMock.checkCallingOrSelfPermission( - android.Manifest.permission.DUMP)).thenReturn( - PackageManager.PERMISSION_DENIED); - - mTrampoline.dump(mFileDescriptorStub, mPrintWriterMock, new String[0]); - - verifyNoMoreInteractions(mBackupManagerServiceMock); - } - - @Test - public void dump_callerHasPermission_forwarded() { - when(mContextMock.checkCallingOrSelfPermission( - android.Manifest.permission.DUMP)).thenReturn( - PackageManager.PERMISSION_GRANTED); - - mTrampoline.dump(mFileDescriptorStub, mPrintWriterMock, null); - - verify(mBackupManagerServiceMock).dump(mFileDescriptorStub, mPrintWriterMock, null); - } - - public void testGetUserForAncestralSerialNumber() { - TrampolineTestable.sBackupDisabled = false; - Trampoline trampoline = new TrampolineTestable(mContextMock); - - trampoline.getUserForAncestralSerialNumber(0L); - verify(mBackupManagerServiceMock).getUserForAncestralSerialNumber(anyInt()); - } - - public void testGetUserForAncestralSerialNumber_whenDisabled() { - TrampolineTestable.sBackupDisabled = true; - Trampoline trampoline = new TrampolineTestable(mContextMock); - - trampoline.getUserForAncestralSerialNumber(0L); - verify(mBackupManagerServiceMock, never()).getUserForAncestralSerialNumber(anyInt()); - } - - private static class TrampolineTestable extends Trampoline { - static boolean sBackupDisabled = false; - static int sCallingUserId = -1; - static int sCallingUid = -1; - static BackupManagerService sBackupManagerServiceMock = null; - static File sSuppressFile = null; - static SparseArray<File> sActivatedFiles = new SparseArray<>(); - static SparseArray<File> sRememberActivatedFiles = new SparseArray<>(); - static UserManager sUserManagerMock = null; - - TrampolineTestable(Context context) { - super(context); - mService = sBackupManagerServiceMock; - } - - @Override - protected UserManager getUserManager() { - return sUserManagerMock; - } - - @Override - protected boolean isBackupDisabled() { - return sBackupDisabled; - } - - @Override - protected File getSuppressFileForSystemUser() { - return sSuppressFile; - } - - @Override - protected File getRememberActivatedFileForNonSystemUser(int userId) { - return sRememberActivatedFiles.get(userId); - } - - @Override - protected File getActivatedFileForNonSystemUser(int userId) { - return sActivatedFiles.get(userId); - } - - protected int binderGetCallingUserId() { - return sCallingUserId; - } - - @Override - protected int binderGetCallingUid() { - return sCallingUid; - } - - @Override - protected void postToHandler(Runnable runnable) { - runnable.run(); - } - } -} diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java new file mode 100644 index 000000000000..ccf3a908364a --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java @@ -0,0 +1,748 @@ +/* + * 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.biometrics; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.TestCase.assertNotNull; + +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; +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.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.AppOpsManager; +import android.app.IActivityManager; +import android.content.ContentResolver; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.hardware.biometrics.BiometricAuthenticator; +import android.hardware.biometrics.BiometricConstants; +import android.hardware.biometrics.BiometricPrompt; +import android.hardware.biometrics.IBiometricService; +import android.hardware.biometrics.IBiometricServiceReceiver; +import android.hardware.biometrics.IBiometricServiceReceiverInternal; +import android.hardware.face.FaceManager; +import android.hardware.face.IFaceService; +import android.hardware.fingerprint.FingerprintManager; +import android.hardware.fingerprint.IFingerprintService; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.security.KeyStore; + +import com.android.internal.R; +import com.android.internal.statusbar.IStatusBarService; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.List; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; + +@SmallTest +public class BiometricServiceTest { + + private static final String TAG = "BiometricServiceTest"; + + private static final String TEST_PACKAGE_NAME = "test_package"; + + private static final String ERROR_HW_UNAVAILABLE = "hw_unavailable"; + private static final String ERROR_NOT_RECOGNIZED = "not_recognized"; + private static final String ERROR_TIMEOUT = "error_timeout"; + private static final String ERROR_CANCELED = "error_canceled"; + private static final String ERROR_UNABLE_TO_PROCESS = "error_unable_to_process"; + private static final String ERROR_USER_CANCELED = "error_user_canceled"; + + private static final String FINGERPRINT_ACQUIRED_SENSOR_DIRTY = "sensor_dirty"; + + private BiometricService mBiometricService; + + @Mock + private Context mContext; + @Mock + private ContentResolver mContentResolver; + @Mock + private Resources mResources; + @Mock + private PackageManager mPackageManager; + @Mock + private AppOpsManager mAppOpsManager; + @Mock + IBiometricServiceReceiver mReceiver1; + @Mock + IBiometricServiceReceiver mReceiver2; + @Mock + FingerprintManager mFingerprintManager; + @Mock + FaceManager mFaceManager; + + private static class MockInjector extends BiometricService.Injector { + @Override + IActivityManager getActivityManagerService() { + return mock(IActivityManager.class); + } + + @Override + IStatusBarService getStatusBarService() { + return mock(IStatusBarService.class); + } + + @Override + IFingerprintService getFingerprintService() { + return mock(IFingerprintService.class); + } + + @Override + IFaceService getFaceService() { + return mock(IFaceService.class); + } + + @Override + BiometricService.SettingObserver getSettingObserver(Context context, Handler handler, + List<BiometricService.EnabledOnKeyguardCallback> callbacks) { + return mock(BiometricService.SettingObserver.class); + } + + @Override + KeyStore getKeyStore() { + return mock(KeyStore.class); + } + + @Override + boolean isDebugEnabled(Context context, int userId) { + return false; + } + + @Override + void publishBinderService(BiometricService service, IBiometricService.Stub impl) { + // no-op for test + } + } + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + when(mContext.getPackageManager()).thenReturn(mPackageManager); + when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager); + when(mContext.getSystemService(Context.FINGERPRINT_SERVICE)) + .thenReturn(mFingerprintManager); + when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mFaceManager); + when(mContext.getContentResolver()).thenReturn(mContentResolver); + when(mContext.getResources()).thenReturn(mResources); + + when(mResources.getString(R.string.biometric_error_hw_unavailable)) + .thenReturn(ERROR_HW_UNAVAILABLE); + when(mResources.getString(R.string.biometric_not_recognized)) + .thenReturn(ERROR_NOT_RECOGNIZED); + when(mResources.getString(R.string.biometric_error_user_canceled)) + .thenReturn(ERROR_USER_CANCELED); + } + + @Test + public void testAuthenticate_withoutHardware_returnsErrorHardwareNotPresent() throws Exception { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) + .thenReturn(false); + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IRIS)).thenReturn(false); + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(false); + + mBiometricService = new BiometricService(mContext, new MockInjector()); + mBiometricService.onStart(); + + invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */); + waitForIdle(); + verify(mReceiver1).onError( + eq(BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT), eq(ERROR_HW_UNAVAILABLE)); + } + + @Test + public void testAuthenticate_withoutEnrolled_returnsErrorNoBiometrics() throws Exception { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + + mBiometricService = new BiometricService(mContext, new MockInjector()); + mBiometricService.onStart(); + + invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */); + waitForIdle(); + verify(mReceiver1).onError( + eq(BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS), any()); + } + + @Test + public void testAuthenticate_whenHalIsDead_returnsErrorHardwareUnavailable() throws Exception { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true); + when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(false); + + mBiometricService = new BiometricService(mContext, new MockInjector()); + mBiometricService.onStart(); + + invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */); + waitForIdle(); + verify(mReceiver1).onError( + eq(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE), eq(ERROR_HW_UNAVAILABLE)); + } + + @Test + public void testAuthenticateFace_respectsUserSetting() + throws Exception { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true); + when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + + mBiometricService = new BiometricService(mContext, new MockInjector()); + mBiometricService.onStart(); + + // Disabled in user settings receives onError + when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(false); + invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */); + waitForIdle(); + verify(mReceiver1).onError( + eq(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE), eq(ERROR_HW_UNAVAILABLE)); + + // Enrolled, not disabled in settings, user requires confirmation in settings + resetReceiver(); + when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true); + when(mBiometricService.mSettingObserver.getFaceAlwaysRequireConfirmation(anyInt())) + .thenReturn(true); + invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */); + waitForIdle(); + verify(mReceiver1, never()).onError(anyInt(), any(String.class)); + verify(mBiometricService.mFaceService).prepareForAuthentication( + eq(true) /* requireConfirmation */, + any(IBinder.class), + anyLong() /* sessionId */, + anyInt() /* userId */, + any(IBiometricServiceReceiverInternal.class), + anyString() /* opPackageName */, + anyInt() /* cookie */, + anyInt() /* callingUid */, + anyInt() /* callingPid */, + anyInt() /* callingUserId */); + + // Enrolled, not disabled in settings, user doesn't require confirmation in settings + resetReceiver(); + when(mBiometricService.mSettingObserver.getFaceAlwaysRequireConfirmation(anyInt())) + .thenReturn(false); + invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */); + waitForIdle(); + verify(mBiometricService.mFaceService).prepareForAuthentication( + eq(false) /* requireConfirmation */, + any(IBinder.class), + anyLong() /* sessionId */, + anyInt() /* userId */, + any(IBiometricServiceReceiverInternal.class), + anyString() /* opPackageName */, + anyInt() /* cookie */, + anyInt() /* callingUid */, + anyInt() /* callingPid */, + anyInt() /* callingUserId */); + } + + @Test + public void testAuthenticate_happyPathWithoutConfirmation() throws Exception { + setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT); + mBiometricService = new BiometricService(mContext, new MockInjector()); + mBiometricService.onStart(); + + // Start testing the happy path + invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */); + waitForIdle(); + + // Creates a pending auth session with the correct initial states + assertEquals(mBiometricService.mPendingAuthSession.mState, + BiometricService.STATE_AUTH_CALLED); + + // Invokes <Modality>Service#prepareForAuthentication + ArgumentCaptor<Integer> cookieCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mReceiver1, never()).onError(anyInt(), any(String.class)); + verify(mBiometricService.mFingerprintService).prepareForAuthentication( + any(IBinder.class), + anyLong() /* sessionId */, + anyInt() /* userId */, + any(IBiometricServiceReceiverInternal.class), + anyString() /* opPackageName */, + cookieCaptor.capture() /* cookie */, + anyInt() /* callingUid */, + anyInt() /* callingPid */, + anyInt() /* callingUserId */); + + // onReadyForAuthentication, mCurrentAuthSession state OK + mBiometricService.mImpl.onReadyForAuthentication(cookieCaptor.getValue(), + anyBoolean() /* requireConfirmation */, anyInt() /* userId */); + waitForIdle(); + assertNull(mBiometricService.mPendingAuthSession); + assertEquals(mBiometricService.mCurrentAuthSession.mState, + BiometricService.STATE_AUTH_STARTED); + + // startPreparedClient invoked + verify(mBiometricService.mFingerprintService) + .startPreparedClient(cookieCaptor.getValue()); + + // StatusBar showBiometricDialog invoked + verify(mBiometricService.mStatusBarService).showBiometricDialog( + eq(mBiometricService.mCurrentAuthSession.mBundle), + any(IBiometricServiceReceiverInternal.class), + eq(BiometricAuthenticator.TYPE_FINGERPRINT), + anyBoolean() /* requireConfirmation */, + anyInt() /* userId */, + eq(TEST_PACKAGE_NAME)); + + // Hardware authenticated + mBiometricService.mInternalReceiver.onAuthenticationSucceeded( + false /* requireConfirmation */, + new byte[69] /* HAT */); + waitForIdle(); + // Waiting for SystemUI to send dismissed callback + assertEquals(mBiometricService.mCurrentAuthSession.mState, + BiometricService.STATE_AUTHENTICATED_PENDING_SYSUI); + // Notify SystemUI hardware authenticated + verify(mBiometricService.mStatusBarService).onBiometricAuthenticated( + eq(true) /* authenticated */, eq(null) /* failureReason */); + + // SystemUI sends callback with dismissed reason + mBiometricService.mInternalReceiver.onDialogDismissed( + BiometricPrompt.DISMISSED_REASON_CONFIRM_NOT_REQUIRED); + waitForIdle(); + // HAT sent to keystore + verify(mBiometricService.mKeyStore).addAuthToken(any(byte[].class)); + // Send onAuthenticated to client + verify(mReceiver1).onAuthenticationSucceeded(); + // Current session becomes null + assertNull(mBiometricService.mCurrentAuthSession); + } + + @Test + public void testAuthenticate_happyPathWithConfirmation() throws Exception { + setupAuthForOnly(BiometricAuthenticator.TYPE_FACE); + invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + true /* requireConfirmation */); + + // Test authentication succeeded goes to PENDING_CONFIRMATION and that the HAT is not + // sent to KeyStore yet + mBiometricService.mInternalReceiver.onAuthenticationSucceeded( + true /* requireConfirmation */, + new byte[69] /* HAT */); + waitForIdle(); + // Waiting for SystemUI to send confirmation callback + assertEquals(mBiometricService.mCurrentAuthSession.mState, + BiometricService.STATE_AUTH_PENDING_CONFIRM); + verify(mBiometricService.mKeyStore, never()).addAuthToken(any(byte[].class)); + + // SystemUI sends confirm, HAT is sent to keystore and client is notified. + mBiometricService.mInternalReceiver.onDialogDismissed( + BiometricPrompt.DISMISSED_REASON_CONFIRMED); + waitForIdle(); + verify(mBiometricService.mKeyStore).addAuthToken(any(byte[].class)); + verify(mReceiver1).onAuthenticationSucceeded(); + } + + @Test + public void testRejectFace_whenAuthenticating_notifiesSystemUIAndClient_thenPaused() + throws Exception { + setupAuthForOnly(BiometricAuthenticator.TYPE_FACE); + invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */); + + mBiometricService.mInternalReceiver.onAuthenticationFailed(); + waitForIdle(); + + verify(mBiometricService.mStatusBarService) + .onBiometricAuthenticated(eq(false), eq(ERROR_NOT_RECOGNIZED)); + verify(mReceiver1).onAuthenticationFailed(); + assertEquals(mBiometricService.mCurrentAuthSession.mState, + BiometricService.STATE_AUTH_PAUSED); + } + + @Test + public void testRejectFingerprint_whenAuthenticating_notifiesAndKeepsAuthenticating() + throws Exception { + setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT); + invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */); + + mBiometricService.mInternalReceiver.onAuthenticationFailed(); + waitForIdle(); + + verify(mBiometricService.mStatusBarService) + .onBiometricAuthenticated(eq(false), eq(ERROR_NOT_RECOGNIZED)); + verify(mReceiver1).onAuthenticationFailed(); + assertEquals(mBiometricService.mCurrentAuthSession.mState, + BiometricService.STATE_AUTH_STARTED); + } + + @Test + public void testErrorCanceled_whenAuthenticating_notifiesSystemUIAndClient() throws Exception { + setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT); + invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */); + + // Create a new pending auth session but don't start it yet. HAL contract is that previous + // one must get ERROR_CANCELED. Simulate that here by creating the pending auth session, + // sending ERROR_CANCELED to the current auth session, and then having the second one + // onReadyForAuthentication. + invokeAuthenticate(mBiometricService.mImpl, mReceiver2, false /* requireConfirmation */); + waitForIdle(); + + assertEquals(mBiometricService.mCurrentAuthSession.mState, + BiometricService.STATE_AUTH_STARTED); + mBiometricService.mInternalReceiver.onError( + getCookieForCurrentSession(mBiometricService.mCurrentAuthSession), + BiometricConstants.BIOMETRIC_ERROR_CANCELED, ERROR_CANCELED); + waitForIdle(); + + // Auth session doesn't become null until SystemUI responds that the animation is completed + assertNotNull(mBiometricService.mCurrentAuthSession); + // ERROR_CANCELED is not sent until SystemUI responded that animation is completed + verify(mReceiver1, never()).onError( + anyInt(), anyString()); + verify(mReceiver2, never()).onError(anyInt(), any(String.class)); + + // SystemUI dialog closed + verify(mBiometricService.mStatusBarService).hideBiometricDialog(); + + // After SystemUI notifies that the animation has completed + mBiometricService.mInternalReceiver + .onDialogDismissed(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED); + waitForIdle(); + verify(mReceiver1).onError( + eq(BiometricConstants.BIOMETRIC_ERROR_CANCELED), + eq(ERROR_CANCELED)); + assertNull(mBiometricService.mCurrentAuthSession); + } + + @Test + public void testErrorHalTimeout_whenAuthenticating_entersPausedState() throws Exception { + setupAuthForOnly(BiometricAuthenticator.TYPE_FACE); + invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */); + + mBiometricService.mInternalReceiver.onError( + getCookieForCurrentSession(mBiometricService.mCurrentAuthSession), + BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, + ERROR_TIMEOUT); + waitForIdle(); + + assertEquals(mBiometricService.mCurrentAuthSession.mState, + BiometricService.STATE_AUTH_PAUSED); + verify(mBiometricService.mStatusBarService) + .onBiometricAuthenticated(eq(false), eq(ERROR_TIMEOUT)); + // Timeout does not count as fail as per BiometricPrompt documentation. + verify(mReceiver1, never()).onAuthenticationFailed(); + + // No pending auth session. Pressing try again will create one. + assertNull(mBiometricService.mPendingAuthSession); + + // Pressing "Try again" on SystemUI starts a new auth session. + mBiometricService.mInternalReceiver.onTryAgainPressed(); + waitForIdle(); + + // The last one is still paused, and a new one has been created. + assertEquals(mBiometricService.mCurrentAuthSession.mState, + BiometricService.STATE_AUTH_PAUSED); + assertEquals(mBiometricService.mPendingAuthSession.mState, + BiometricService.STATE_AUTH_CALLED); + + // Test resuming when hardware becomes ready. SystemUI should not be requested to + // show another dialog since it's already showing. + resetStatusBar(); + startPendingAuthSession(mBiometricService); + waitForIdle(); + verify(mBiometricService.mStatusBarService, never()).showBiometricDialog( + any(Bundle.class), + any(IBiometricServiceReceiverInternal.class), + anyInt(), + anyBoolean() /* requireConfirmation */, + anyInt() /* userId */, + anyString()); + } + + @Test + public void testErrorFromHal_whenPaused_notifiesSystemUIAndClient() throws Exception { + setupAuthForOnly(BiometricAuthenticator.TYPE_FACE); + invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + false /* requireCOnfirmation */); + + mBiometricService.mInternalReceiver.onError( + getCookieForCurrentSession(mBiometricService.mCurrentAuthSession), + BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, + ERROR_TIMEOUT); + mBiometricService.mInternalReceiver.onError( + getCookieForCurrentSession(mBiometricService.mCurrentAuthSession), + BiometricConstants.BIOMETRIC_ERROR_CANCELED, + ERROR_CANCELED); + waitForIdle(); + + // Client receives error immediately + verify(mReceiver1).onError( + eq(BiometricConstants.BIOMETRIC_ERROR_CANCELED), + eq(ERROR_CANCELED)); + // Dialog is hidden immediately + verify(mBiometricService.mStatusBarService).hideBiometricDialog(); + // Auth session is over + assertNull(mBiometricService.mCurrentAuthSession); + } + + @Test + public void testErrorFromHal_whileAuthenticating_waitsForSysUIBeforeNotifyingClient() + throws Exception { + // For errors that show in SystemUI, BiometricService stays in STATE_ERROR_PENDING_SYSUI + // until SystemUI notifies us that the dialog is dismissed at which point the current + // session is done. + setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT); + invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */); + + mBiometricService.mInternalReceiver.onError( + getCookieForCurrentSession(mBiometricService.mCurrentAuthSession), + BiometricConstants.BIOMETRIC_ERROR_UNABLE_TO_PROCESS, + ERROR_UNABLE_TO_PROCESS); + waitForIdle(); + + // Sends error to SystemUI and does not notify client yet + assertEquals(mBiometricService.mCurrentAuthSession.mState, + BiometricService.STATE_ERROR_PENDING_SYSUI); + verify(mBiometricService.mStatusBarService) + .onBiometricError(eq(ERROR_UNABLE_TO_PROCESS)); + verify(mBiometricService.mStatusBarService, never()).hideBiometricDialog(); + verify(mReceiver1, never()).onError(anyInt(), anyString()); + + // SystemUI animation completed, client is notified, auth session is over + mBiometricService.mInternalReceiver + .onDialogDismissed(BiometricPrompt.DISMISSED_REASON_ERROR); + waitForIdle(); + verify(mReceiver1).onError( + eq(BiometricConstants.BIOMETRIC_ERROR_UNABLE_TO_PROCESS), + eq(ERROR_UNABLE_TO_PROCESS)); + assertNull(mBiometricService.mCurrentAuthSession); + } + + @Test + public void testDismissedReasonUserCancel_whileAuthenticating_cancelsHalAuthentication() + throws Exception { + setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT); + invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */); + + mBiometricService.mInternalReceiver + .onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL); + waitForIdle(); + verify(mReceiver1).onError( + eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED), + eq(ERROR_USER_CANCELED)); + verify(mBiometricService.mFingerprintService).cancelAuthenticationFromService( + any(), + any(), + anyInt(), + anyInt(), + anyInt(), + eq(false) /* fromClient */); + assertNull(mBiometricService.mCurrentAuthSession); + } + + @Test + public void testDismissedReasonNegative_whilePaused_doesntInvokeHalCancel() throws Exception { + setupAuthForOnly(BiometricAuthenticator.TYPE_FACE); + invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */); + + mBiometricService.mInternalReceiver.onError( + getCookieForCurrentSession(mBiometricService.mCurrentAuthSession), + BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, + ERROR_TIMEOUT); + mBiometricService.mInternalReceiver.onDialogDismissed( + BiometricPrompt.DISMISSED_REASON_NEGATIVE); + waitForIdle(); + + verify(mBiometricService.mFaceService, never()).cancelAuthenticationFromService( + any(), + any(), + anyInt(), + anyInt(), + anyInt(), + anyBoolean()); + } + + @Test + public void testDismissedReasonUserCancel_whilePaused_doesntInvokeHalCancel() throws Exception { + setupAuthForOnly(BiometricAuthenticator.TYPE_FACE); + invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */); + + mBiometricService.mInternalReceiver.onError( + getCookieForCurrentSession(mBiometricService.mCurrentAuthSession), + BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, + ERROR_TIMEOUT); + mBiometricService.mInternalReceiver.onDialogDismissed( + BiometricPrompt.DISMISSED_REASON_USER_CANCEL); + waitForIdle(); + + verify(mBiometricService.mFaceService, never()).cancelAuthenticationFromService( + any(), + any(), + anyInt(), + anyInt(), + anyInt(), + anyBoolean()); + } + + @Test + public void testDismissedReasonUserCancel_whenPendingConfirmation() throws Exception { + setupAuthForOnly(BiometricAuthenticator.TYPE_FACE); + invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + true /* requireConfirmation */); + + mBiometricService.mInternalReceiver.onAuthenticationSucceeded( + true /* requireConfirmation */, + new byte[69] /* HAT */); + mBiometricService.mInternalReceiver.onDialogDismissed( + BiometricPrompt.DISMISSED_REASON_USER_CANCEL); + waitForIdle(); + + // doesn't send cancel to HAL + verify(mBiometricService.mFaceService, never()).cancelAuthenticationFromService( + any(), + any(), + anyInt(), + anyInt(), + anyInt(), + anyBoolean()); + verify(mReceiver1).onError( + eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED), + eq(ERROR_USER_CANCELED)); + assertNull(mBiometricService.mCurrentAuthSession); + } + + @Test + public void testAcquire_whenAuthenticating_sentToSystemUI() throws Exception { + setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT); + invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, + false /* requireConfirmation */); + + mBiometricService.mInternalReceiver.onAcquired( + FingerprintManager.FINGERPRINT_ACQUIRED_IMAGER_DIRTY, + FINGERPRINT_ACQUIRED_SENSOR_DIRTY); + waitForIdle(); + + // Sends to SysUI and stays in authenticating state + verify(mBiometricService.mStatusBarService) + .onBiometricHelp(eq(FINGERPRINT_ACQUIRED_SENSOR_DIRTY)); + assertEquals(mBiometricService.mCurrentAuthSession.mState, + BiometricService.STATE_AUTH_STARTED); + } + + // Helper methods + + private void setupAuthForOnly(int modality) { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) + .thenReturn(false); + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(false); + + if (modality == BiometricAuthenticator.TYPE_FINGERPRINT) { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) + .thenReturn(true); + when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + } else if (modality == BiometricAuthenticator.TYPE_FACE) { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true); + when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + } else { + fail("Unknown modality: " + modality); + } + + mBiometricService = new BiometricService(mContext, new MockInjector()); + mBiometricService.onStart(); + + when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true); + } + + private void resetReceiver() { + mReceiver1 = mock(IBiometricServiceReceiver.class); + mReceiver2 = mock(IBiometricServiceReceiver.class); + } + + private void resetStatusBar() { + mBiometricService.mStatusBarService = mock(IStatusBarService.class); + } + + private void invokeAuthenticateAndStart(IBiometricService.Stub service, + IBiometricServiceReceiver receiver, boolean requireConfirmation) throws Exception { + // Request auth, creates a pending session + invokeAuthenticate(service, receiver, requireConfirmation); + waitForIdle(); + + startPendingAuthSession(mBiometricService); + waitForIdle(); + } + + private static void startPendingAuthSession(BiometricService service) throws Exception { + // Get the cookie so we can pretend the hardware is ready to authenticate + // Currently we only support single modality per auth + assertEquals(service.mPendingAuthSession.mModalitiesWaiting.values().size(), 1); + final int cookie = service.mPendingAuthSession.mModalitiesWaiting.values() + .iterator().next(); + assertNotEquals(cookie, 0); + + service.mImpl.onReadyForAuthentication(cookie, + anyBoolean() /* requireConfirmation */, anyInt() /* userId */); + } + + private static void invokeAuthenticate(IBiometricService.Stub service, + IBiometricServiceReceiver receiver, boolean requireConfirmation) throws Exception { + service.authenticate( + new Binder() /* token */, + 0 /* sessionId */, + 0 /* userId */, + receiver, + TEST_PACKAGE_NAME /* packageName */, + createTestBiometricPromptBundle(requireConfirmation), + null /* IBiometricConfirmDeviceCredentialCallback */); + } + + private static Bundle createTestBiometricPromptBundle(boolean requireConfirmation) { + final Bundle bundle = new Bundle(); + bundle.putBoolean(BiometricPrompt.KEY_REQUIRE_CONFIRMATION, requireConfirmation); + return bundle; + } + + private static int getCookieForCurrentSession(BiometricService.AuthSession session) { + assertEquals(session.mModalitiesMatched.values().size(), 1); + return session.mModalitiesMatched.values().iterator().next(); + } + + private static void waitForIdle() { + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + } +} diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 09ae3a2628bf..ba12b7393048 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -139,7 +139,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.BroadcastInterceptingContext.FutureIntent; -import com.android.server.DeviceIdleController; +import com.android.server.DeviceIdleInternal; import com.android.server.LocalServices; import com.google.common.util.concurrent.AbstractFuture; @@ -293,7 +293,7 @@ public class NetworkPolicyManagerServiceTest { }; private void registerLocalServices() { - addLocalServiceMock(DeviceIdleController.LocalService.class); + addLocalServiceMock(DeviceIdleInternal.class); final UsageStatsManagerInternal usageStats = addLocalServiceMock(UsageStatsManagerInternal.class); @@ -442,7 +442,7 @@ public class NetworkPolicyManagerServiceTest { // Added in registerLocalServices() LocalServices.removeServiceForTest(ActivityManagerInternal.class); LocalServices.removeServiceForTest(PowerManagerInternal.class); - LocalServices.removeServiceForTest(DeviceIdleController.LocalService.class); + LocalServices.removeServiceForTest(DeviceIdleInternal.class); LocalServices.removeServiceForTest(UsageStatsManagerInternal.class); LocalServices.removeServiceForTest(NetworkStatsManagerInternal.class); } diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java index 75e5847abe90..819091c378b8 100644 --- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java @@ -19,12 +19,12 @@ package com.android.server.pm; import static org.junit.Assert.assertFalse; 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.eq; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.app.AppOpsManager; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; @@ -54,10 +54,7 @@ public class AppsFilterTest { IPermissionManager mPermissionManagerMock; @Mock - AppsFilter.ConfigProvider mConfigProviderMock; - - @Mock - AppOpsManager mAppOpsManager; + AppsFilter.FeatureConfig mFeatureConfigMock; private Map<String, PackageParser.Package> mExisting = new ArrayMap<>(); @@ -108,16 +105,23 @@ public class AppsFilterTest { 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); + when(mFeatureConfigMock.isGloballyEnabled()).thenReturn(true); + when(mFeatureConfigMock.packageIsEnabled(any(PackageParser.Package.class))) + .thenReturn(true); + } + + @Test + public void testSystemReadyPropogates() throws Exception { + final AppsFilter appsFilter = + new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{}, false); + appsFilter.onSystemReady(); + verify(mFeatureConfigMock).onSystemReady(); } @Test public void testQueriesAction_FilterMatches() { final AppsFilter appsFilter = - new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager, - new String[]{}, false); + new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{}, false); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package", new IntentFilter("TEST_ACTION"))).build(); @@ -130,8 +134,7 @@ public class AppsFilterTest { @Test public void testQueriesAction_NoMatchingAction_Filters() { final AppsFilter appsFilter = - new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager, - new String[]{}, false); + new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{}, false); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build(); @@ -144,7 +147,7 @@ public class AppsFilterTest { @Test public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() { final AppsFilter appsFilter = - new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager, + new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{}, false); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build(); @@ -158,7 +161,7 @@ public class AppsFilterTest { @Test public void testNoQueries_Filters() { final AppsFilter appsFilter = - new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager, + new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{}, false); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build(); @@ -171,7 +174,7 @@ public class AppsFilterTest { @Test public void testForceQueryable_DoesntFilter() { final AppsFilter appsFilter = - new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager, + new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{}, false); PackageSetting target = @@ -186,7 +189,7 @@ public class AppsFilterTest { @Test public void testForceQueryableByDevice_SystemCaller_DoesntFilter() { final AppsFilter appsFilter = - new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager, + new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{"com.some.package"}, false); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")) @@ -201,7 +204,7 @@ public class AppsFilterTest { @Test public void testForceQueryableByDevice_NonSystemCaller_Filters() { final AppsFilter appsFilter = - new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager, + new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{"com.some.package"}, false); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build(); @@ -215,7 +218,7 @@ public class AppsFilterTest { @Test public void testSystemQueryable_DoesntFilter() { final AppsFilter appsFilter = - new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager, + new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{}, true /* system force queryable */); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")) @@ -230,7 +233,7 @@ public class AppsFilterTest { @Test public void testQueriesPackage_DoesntFilter() { final AppsFilter appsFilter = - new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager, + new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{}, false); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build(); @@ -241,55 +244,11 @@ public class AppsFilterTest { } @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); + when(mFeatureConfigMock.packageIsEnabled(any(PackageParser.Package.class))) + .thenReturn(false); final AppsFilter appsFilter = - new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager, + new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{}, false); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build(); @@ -302,7 +261,7 @@ public class AppsFilterTest { @Test public void testSystemUid_DoesntFilter() { final AppsFilter appsFilter = - new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager, + new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{}, false); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build(); @@ -315,7 +274,7 @@ public class AppsFilterTest { @Test public void testNonSystemUid_NoCallingSetting_Filters() { final AppsFilter appsFilter = - new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager, + new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{}, false); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build(); @@ -326,7 +285,7 @@ public class AppsFilterTest { @Test public void testNoTargetPackage_filters() { final AppsFilter appsFilter = - new AppsFilter(mConfigProviderMock, mPermissionManagerMock, mAppOpsManager, + new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, new String[]{}, false); PackageSetting target = new PackageSettingBuilder() diff --git a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java index 798605568138..8cb5197f2601 100644 --- a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java @@ -16,6 +16,7 @@ package com.android.server.rollback; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -58,8 +59,8 @@ public class AppDataRollbackHelperTest { // All users are unlocked so we should snapshot data for them. doReturn(true).when(helper).isUserCredentialLocked(eq(10)); doReturn(true).when(helper).isUserCredentialLocked(eq(11)); - PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar", new int[]{10, 11}); - helper.snapshotAppData(5, info); + PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar"); + helper.snapshotAppData(5, info, new int[]{10, 11}); assertEquals(2, info.getPendingBackups().size()); assertEquals(10, info.getPendingBackups().get(0)); @@ -79,8 +80,8 @@ public class AppDataRollbackHelperTest { doReturn(true).when(helper).isUserCredentialLocked(eq(11)); when(installer.snapshotAppData(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(239L); - PackageRollbackInfo info2 = createPackageRollbackInfo("com.foo.bar", new int[]{10, 11}); - helper.snapshotAppData(7, info2); + PackageRollbackInfo info2 = createPackageRollbackInfo("com.foo.bar"); + helper.snapshotAppData(7, info2, new int[]{10, 11}); assertEquals(1, info2.getPendingBackups().size()); assertEquals(11, info2.getPendingBackups().get(0)); @@ -234,22 +235,22 @@ public class AppDataRollbackHelperTest { wasRecentlyRestored.getPendingRestores().add( new RestoreInfo(73 /* userId */, 239 /* appId*/, "seInfo")); - RollbackData dataWithPendingBackup = new RollbackData(101, new File("/does/not/exist"), -1); + Rollback dataWithPendingBackup = new Rollback(101, new File("/does/not/exist"), -1); dataWithPendingBackup.info.getPackages().add(pendingBackup); - RollbackData dataWithRecentRestore = new RollbackData(17239, new File("/does/not/exist"), + Rollback dataWithRecentRestore = new Rollback(17239, new File("/does/not/exist"), -1); dataWithRecentRestore.info.getPackages().add(wasRecentlyRestored); - RollbackData dataForDifferentUser = new RollbackData(17239, new File("/does/not/exist"), + Rollback dataForDifferentUser = new Rollback(17239, new File("/does/not/exist"), -1); dataForDifferentUser.info.getPackages().add(ignoredInfo); - RollbackData dataForRestore = new RollbackData(17239, new File("/does/not/exist"), -1); + Rollback dataForRestore = new Rollback(17239, new File("/does/not/exist"), -1); dataForRestore.info.getPackages().add(pendingRestore); dataForRestore.info.getPackages().add(wasRecentlyRestored); - Set<RollbackData> changed = helper.commitPendingBackupAndRestoreForUser(37, + Set<Rollback> changed = helper.commitPendingBackupAndRestoreForUser(37, Arrays.asList(dataWithPendingBackup, dataWithRecentRestore, dataForDifferentUser, dataForRestore)); InOrder inOrder = Mockito.inOrder(installer); @@ -264,7 +265,7 @@ public class AppDataRollbackHelperTest { assertEquals(-1, pendingBackup.getPendingBackups().indexOf(37)); assertEquals(53, pendingBackup.getCeSnapshotInodes().get(37)); - // Check that changed returns correct RollbackData. + // Check that changed returns correct Rollback. assertEquals(3, changed.size()); assertTrue(changed.contains(dataWithPendingBackup)); assertTrue(changed.contains(dataWithRecentRestore)); @@ -278,4 +279,15 @@ public class AppDataRollbackHelperTest { inOrder.verifyNoMoreInteractions(); } + + @Test + public void snapshotAddDataSavesSnapshottedUsersToInfo() { + Installer installer = mock(Installer.class); + AppDataRollbackHelper helper = new AppDataRollbackHelper(installer); + + PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar"); + helper.snapshotAppData(5, info, new int[]{10, 11}); + + assertArrayEquals(info.getSnapshottedUsers().toArray(), new int[]{10, 11}); + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index c1c0a308e48a..3ac7a79a1630 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -181,12 +181,6 @@ import java.util.function.Consumer; @RunWithLooper public class NotificationManagerServiceTest extends UiServiceTestCase { private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId"; - private static final String CLEAR_DEVICE_CONFIG_KEY_CMD = - "device_config delete " + DeviceConfig.NAMESPACE_SYSTEMUI + " " - + SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE; - private static final String SET_DEFAULT_ASSISTANT_DEVICE_CONFIG_CMD = - "device_config put " + DeviceConfig.NAMESPACE_SYSTEMUI + " " - + SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE; private final int mUid = Binder.getCallingUid(); private TestableNotificationManagerService mService; @@ -2766,6 +2760,18 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testReadPolicyXml_readSnoozedNotificationsFromXml() throws Exception { + final String upgradeXml = "<notification-policy version=\"1\">" + + "<snoozed-notifications>></snoozed-notifications>" + + "</notification-policy>"; + mService.readPolicyXml( + new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())), + false, + UserHandle.USER_ALL); + verify(mSnoozeHelper, times(1)).readXml(any(XmlPullParser.class)); + } + + @Test public void testReadPolicyXml_readApprovedServicesFromSettings() throws Exception { final String preupgradeXml = "<notification-policy version=\"1\">" + "<ranking></ranking>" @@ -4028,6 +4034,41 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testPostFromAndroidForNonExistentPackage() throws Exception { + final String notReal = "NOT REAL"; + when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt())).thenThrow( + PackageManager.NameNotFoundException.class); + ApplicationInfo ai = new ApplicationInfo(); + ai.uid = -1; + when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(ai); + + final StatusBarNotification sbn = generateNotificationRecord(null).sbn; + try { + mInternalService.enqueueNotification(notReal, "android", 0, 0, "tag", + sbn.getId(), sbn.getNotification(), sbn.getUserId()); + fail("can't post notifications for nonexistent packages, even if you exist"); + } catch (SecurityException e) { + // yay + } + } + + @Test + public void testCancelFromAndroidForNonExistentPackage() throws Exception { + final String notReal = "NOT REAL"; + when(mPackageManagerClient.getPackageUidAsUser(eq(notReal), anyInt())).thenThrow( + PackageManager.NameNotFoundException.class); + ApplicationInfo ai = new ApplicationInfo(); + ai.uid = -1; + when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(ai); + + // unlike the post case, ignore instead of throwing + final StatusBarNotification sbn = generateNotificationRecord(null).sbn; + + mInternalService.cancelNotification(notReal, "android", 0, 0, "tag", + sbn.getId(), sbn.getUserId()); + } + + @Test public void testResolveNotificationUid_delegateNotAllowed() throws Exception { when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(123); // no delegate diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java index 2e7277f5af01..36175a93f667 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java @@ -18,6 +18,7 @@ package com.android.server.notification; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.assertNull; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; @@ -37,9 +38,11 @@ import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.test.suitebuilder.annotation.SmallTest; import android.util.IntArray; +import android.util.Xml; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.util.FastXmlSerializer; import com.android.server.UiServiceTestCase; import org.junit.Before; @@ -48,6 +51,15 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; @SmallTest @RunWith(AndroidJUnit4.class) @@ -69,6 +81,117 @@ public class SnoozeHelperTest extends UiServiceTestCase { } @Test + public void testWriteXMLformattedCorrectly_testReadingCorrectTime() + throws XmlPullParserException, IOException { + final String max_time_str = Long.toString(Long.MAX_VALUE); + final String xml_string = "<snoozed-notifications>" + + "<notification version=\"1\" user-id=\"0\" notification=\"notification\" " + + "pkg=\"pkg\" key=\"key\" time=\"" + max_time_str + "\"/>" + + "<notification version=\"1\" user-id=\"0\" notification=\"notification\" " + + "pkg=\"pkg\" key=\"key2\" time=\"" + max_time_str + "\"/>" + + "</snoozed-notifications>"; + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new BufferedInputStream( + new ByteArrayInputStream(xml_string.getBytes())), null); + mSnoozeHelper.readXml(parser); + assertTrue("Should read the notification time from xml and it should be more than zero", + 0 < mSnoozeHelper.getSnoozeTimeForUnpostedNotification( + 0, "pkg", "key").doubleValue()); + } + + @Test + public void testWriteXMLformattedCorrectly_testCorrectContextURI() + throws XmlPullParserException, IOException { + final String max_time_str = Long.toString(Long.MAX_VALUE); + final String xml_string = "<snoozed-notifications>" + + "<context version=\"1\" user-id=\"0\" notification=\"notification\" " + + "pkg=\"pkg\" key=\"key\" id=\"uri\"/>" + + "<context version=\"1\" user-id=\"0\" notification=\"notification\" " + + "pkg=\"pkg\" key=\"key2\" id=\"uri\"/>" + + "</snoozed-notifications>"; + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new BufferedInputStream( + new ByteArrayInputStream(xml_string.getBytes())), null); + mSnoozeHelper.readXml(parser); + assertEquals("Should read the notification context from xml and it should be `uri", + "uri", mSnoozeHelper.getSnoozeContextForUnpostedNotification( + 0, "pkg", "key")); + } + + @Test + public void testReadValidSnoozedFromCorrectly_timeDeadline() + throws XmlPullParserException, IOException { + NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); + mSnoozeHelper.snooze(r, 999999999); + XmlSerializer serializer = new FastXmlSerializer(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); + serializer.startDocument(null, true); + mSnoozeHelper.writeXml(serializer); + serializer.endDocument(); + serializer.flush(); + + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new BufferedInputStream( + new ByteArrayInputStream(baos.toByteArray())), "utf-8"); + mSnoozeHelper.readXml(parser); + assertTrue("Should read the notification time from xml and it should be more than zero", + 0 < mSnoozeHelper.getSnoozeTimeForUnpostedNotification( + 0, "pkg", r.getKey()).doubleValue()); + } + + + @Test + public void testReadExpiredSnoozedNotification() throws + XmlPullParserException, IOException, InterruptedException { + NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); + mSnoozeHelper.snooze(r, 0); + // Thread.sleep(100); + XmlSerializer serializer = new FastXmlSerializer(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); + serializer.startDocument(null, true); + mSnoozeHelper.writeXml(serializer); + serializer.endDocument(); + serializer.flush(); + Thread.sleep(10); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new BufferedInputStream( + new ByteArrayInputStream(baos.toByteArray())), "utf-8"); + mSnoozeHelper.readXml(parser); + int systemUser = UserHandle.SYSTEM.getIdentifier(); + assertTrue("Should see a past time returned", + System.currentTimeMillis() > mSnoozeHelper.getSnoozeTimeForUnpostedNotification( + systemUser, "pkg", r.getKey()).longValue()); + } + + @Test + public void testCleanupContextShouldRemovePersistedRecord() { + NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); + mSnoozeHelper.snooze(r, "context"); + mSnoozeHelper.cleanupPersistedContext(r.sbn.getKey()); + assertNull(mSnoozeHelper.getSnoozeContextForUnpostedNotification( + r.getUser().getIdentifier(), + r.sbn.getPackageName(), + r.sbn.getKey() + )); + } + + @Test + public void testReadNoneSnoozedNotification() throws XmlPullParserException, + IOException, InterruptedException { + NotificationRecord r = getNotificationRecord( + "pkg", 1, "one", UserHandle.SYSTEM); + mSnoozeHelper.snooze(r, 0); + + assertEquals("should see a zero value for unsnoozed notification", + 0L, + mSnoozeHelper.getSnoozeTimeForUnpostedNotification( + UserHandle.SYSTEM.getIdentifier(), + "not_my_package", r.getKey()).longValue()); + } + + @Test public void testSnoozeForTime() throws Exception { NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); mSnoozeHelper.snooze(r, 1000); @@ -84,7 +207,7 @@ public class SnoozeHelperTest extends UiServiceTestCase { @Test public void testSnooze() throws Exception { NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); - mSnoozeHelper.snooze(r); + mSnoozeHelper.snooze(r, (String) null); verify(mAm, never()).setExactAndAllowWhileIdle( anyInt(), anyLong(), any(PendingIntent.class)); assertTrue(mSnoozeHelper.isSnoozed( diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java index 63b9198bda90..6c78f6f0443f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java @@ -28,6 +28,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; @@ -140,7 +141,8 @@ public class ActivityDisplayTests extends ActivityTestsBase { public void testNotResumeHomeStackOnRemovingDisplay() { // Create a display which supports system decoration and allows reparenting stacks to // another display when the display is removed. - final ActivityDisplay display = spy(createNewActivityDisplay()); + final ActivityDisplay display = createNewActivityDisplay(); + spyOn(display); doReturn(false).when(display).shouldDestroyContentOnRemove(); doReturn(true).when(display).supportsSystemDecorations(); mRootActivityContainer.addChild(display, ActivityDisplay.POSITION_TOP); @@ -304,14 +306,18 @@ public class ActivityDisplayTests extends ActivityTestsBase { ACTIVITY_TYPE_STANDARD, ON_TOP); final ActivityStack stack4 = display.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP); - final TaskRecord task1 = new TaskBuilder(mService.mStackSupervisor).setStack( - stack1).setTaskId(1).build(); - final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor).setStack( - stack2).setTaskId(2).build(); - final TaskRecord task3 = new TaskBuilder(mService.mStackSupervisor).setStack( - stack3).setTaskId(3).build(); - final TaskRecord task4 = new TaskBuilder(mService.mStackSupervisor).setStack( - stack4).setTaskId(4).build(); + final TaskRecord task1 = new TaskBuilder(mService.mStackSupervisor) + .setStack(stack1) + .build(); + final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor) + .setStack(stack2) + .build(); + final TaskRecord task3 = new TaskBuilder(mService.mStackSupervisor) + .setStack(stack3) + .build(); + final TaskRecord task4 = new TaskBuilder(mService.mStackSupervisor) + .setStack(stack4) + .build(); // Reordering stacks while removing stacks. doAnswer(invocation -> { diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java index 23bae8881aa1..977dd8e5951e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -61,13 +61,13 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { private ActivityMetricsLaunchObserver mLaunchObserver; private ActivityMetricsLaunchObserverRegistry mLaunchObserverRegistry; - private TestActivityStack mStack; + private ActivityStack mStack; private TaskRecord mTask; private ActivityRecord mActivityRecord; private ActivityRecord mActivityRecordTrampoline; @Before - public void setUpAMLO() throws Exception { + public void setUpAMLO() { mLaunchObserver = mock(ActivityMetricsLaunchObserver.class); // ActivityStackSupervisor always creates its own instance of ActivityMetricsLogger. @@ -78,15 +78,19 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { // Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful. // This seems to be the easiest way to create an ActivityRecord. - mStack = mRootActivityContainer.getDefaultDisplay().createStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - mTask = new TaskBuilder(mSupervisor).setStack(mStack).build(); - mActivityRecord = new ActivityBuilder(mService).setTask(mTask).build(); + mStack = new StackBuilder(mRootActivityContainer) + .setActivityType(ACTIVITY_TYPE_STANDARD) + .setWindowingMode(WINDOWING_MODE_FULLSCREEN) + .setOnTop(true) + .setCreateActivity(true) + .build(); + mTask = mStack.topTask(); + mActivityRecord = mTask.getTopActivity(); mActivityRecordTrampoline = new ActivityBuilder(mService).setTask(mTask).build(); } @After - public void tearDownAMLO() throws Exception { + public void tearDownAMLO() { if (mLaunchObserverRegistry != null) { // Don't NPE if setUp failed. mLaunchObserverRegistry.unregisterLaunchObserver(mLaunchObserver); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 7b252cbfc0b0..642df4311939 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -16,6 +16,12 @@ package com.android.server.wm; +import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; +import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; +import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; +import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.os.Process.NOBODY_UID; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Surface.ROTATION_0; @@ -29,6 +35,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED; @@ -71,6 +78,7 @@ import android.os.PersistableBundle; import android.platform.test.annotations.Presubmit; import android.util.MergedConfiguration; import android.util.MutableBoolean; +import android.view.DisplayInfo; import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner.Stub; import android.view.RemoteAnimationAdapter; @@ -79,7 +87,6 @@ import android.view.RemoteAnimationTarget; import androidx.test.filters.MediumTest; import com.android.internal.R; -import com.android.server.wm.utils.WmDisplayCutout; import org.junit.Before; import org.junit.Test; @@ -96,13 +103,13 @@ import java.util.concurrent.TimeUnit; @MediumTest @Presubmit public class ActivityRecordTests extends ActivityTestsBase { - private TestActivityStack mStack; + private ActivityStack mStack; private TaskRecord mTask; private ActivityRecord mActivity; @Before public void setUp() throws Exception { - mStack = (TestActivityStack) new StackBuilder(mRootActivityContainer).build(); + mStack = new StackBuilder(mRootActivityContainer).build(); mTask = mStack.getChildAt(0); mActivity = mTask.getTopActivity(); @@ -113,13 +120,13 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testStackCleanupOnClearingTask() { mActivity.setTask(null); - assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 1); + verify(mStack, times(1)).onActivityRemovedFromStack(any()); } @Test public void testStackCleanupOnActivityRemoval() { mTask.removeActivity(mActivity); - assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 1); + verify(mStack, times(1)).onActivityRemovedFromStack(any()); } @Test @@ -134,7 +141,7 @@ public class ActivityRecordTests extends ActivityTestsBase { final TaskRecord newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack) .build(); mActivity.reparent(newTask, 0, null /*reason*/); - assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 0); + verify(mStack, times(0)).onActivityRemovedFromStack(any()); } @Test @@ -181,7 +188,7 @@ public class ActivityRecordTests extends ActivityTestsBase { assertTrue(mActivity.isState(STARTED)); mStack.mTranslucentActivityWaiting = null; - topActivity.changeWindowTranslucency(false); + topActivity.setOccludesParent(false); mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind non-opaque"); mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */); assertTrue(mActivity.isState(STARTED)); @@ -261,8 +268,8 @@ public class ActivityRecordTests extends ActivityTestsBase { public void testNewParentConfigurationIncrementsSeq() { final Configuration newConfig = new Configuration( mTask.getRequestedOverrideConfiguration()); - newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT - ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT; + newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT + ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT; final int prevSeq = mActivity.getMergedOverrideConfiguration().seq; mTask.onRequestedOverrideConfigurationChanged(newConfig); @@ -277,7 +284,7 @@ public class ActivityRecordTests extends ActivityTestsBase { .getRequestedOverrideConfiguration(); final Configuration newConfig = new Configuration(); - newConfig.orientation = Configuration.ORIENTATION_PORTRAIT; + newConfig.orientation = ORIENTATION_PORTRAIT; final int prevSeq = mActivity.getMergedOverrideConfiguration().seq; mActivity.onRequestedOverrideConfigurationChanged(newConfig); @@ -293,10 +300,11 @@ public class ActivityRecordTests extends ActivityTestsBase { mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), mActivity.getConfiguration())); - mActivity.info.configChanges &= ~ActivityInfo.CONFIG_ORIENTATION; + mActivity.info.configChanges &= ~CONFIG_ORIENTATION; final Configuration newConfig = new Configuration(mTask.getConfiguration()); - newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT - ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT; + newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT + ? ORIENTATION_LANDSCAPE + : ORIENTATION_PORTRAIT; mTask.onRequestedOverrideConfigurationChanged(newConfig); mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE; @@ -315,13 +323,14 @@ public class ActivityRecordTests extends ActivityTestsBase { mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), mActivity.getConfiguration())); - mActivity.info.configChanges &= ~ActivityInfo.CONFIG_ORIENTATION; + mActivity.info.configChanges &= ~CONFIG_ORIENTATION; final Configuration newConfig = new Configuration(mTask.getConfiguration()); - newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT - ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT; + newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT + ? ORIENTATION_LANDSCAPE + : ORIENTATION_PORTRAIT; mTask.onRequestedOverrideConfigurationChanged(newConfig); - doReturn(true).when(mTask.getTask()).isDragResizing(); + doReturn(true).when(mTask.mTask).isDragResizing(); mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE; @@ -355,30 +364,39 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testSetRequestedOrientationUpdatesConfiguration() throws Exception { + mActivity = new ActivityBuilder(mService) + .setTask(mTask) + .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT) + .build(); mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing"); - mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration()); mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), mActivity.getConfiguration())); - mActivity.info.configChanges |= ActivityInfo.CONFIG_ORIENTATION; final Configuration newConfig = new Configuration(mActivity.getConfiguration()); - newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT - ? Configuration.ORIENTATION_LANDSCAPE - : Configuration.ORIENTATION_PORTRAIT; + final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp); + final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp); + if (newConfig.orientation == ORIENTATION_PORTRAIT) { + newConfig.orientation = ORIENTATION_LANDSCAPE; + newConfig.screenWidthDp = longSide; + newConfig.screenHeightDp = shortSide; + } else { + newConfig.orientation = ORIENTATION_PORTRAIT; + newConfig.screenWidthDp = shortSide; + newConfig.screenHeightDp = longSide; + } // Mimic the behavior that display doesn't handle app's requested orientation. - doAnswer(invocation -> { - mTask.onConfigurationChanged(newConfig); - return null; - }).when(mActivity.mAppWindowToken).setOrientation(anyInt(), any(), any()); + final DisplayContent dc = mTask.mTask.getDisplayContent(); + doReturn(false).when(dc).onDescendantOrientationChanged(any(), any()); + doReturn(false).when(dc).handlesOrientationChangeFromDescendant(); final int requestedOrientation; switch (newConfig.orientation) { - case Configuration.ORIENTATION_LANDSCAPE: - requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; + case ORIENTATION_LANDSCAPE: + requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE; break; - case Configuration.ORIENTATION_PORTRAIT: + case ORIENTATION_PORTRAIT: requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; break; default: @@ -421,24 +439,33 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testPushConfigurationWhenLaunchTaskBehind() throws Exception { + mActivity = new ActivityBuilder(mService) + .setTask(mTask) + .setLaunchTaskBehind(true) + .setConfigChanges(CONFIG_ORIENTATION) + .build(); mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); - final TestActivityStack stack = (TestActivityStack) new StackBuilder(mRootActivityContainer) - .build(); + final ActivityStack stack = new StackBuilder(mRootActivityContainer).build(); try { - stack.setIsTranslucent(false); + doReturn(false).when(stack).isStackTranslucent(any()); assertFalse(mStack.shouldBeVisible(null /* starting */)); - mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration()); mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), mActivity.getConfiguration())); - mActivity.mLaunchTaskBehind = true; - mActivity.info.configChanges |= ActivityInfo.CONFIG_ORIENTATION; final Configuration newConfig = new Configuration(mActivity.getConfiguration()); - newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT - ? Configuration.ORIENTATION_LANDSCAPE - : Configuration.ORIENTATION_PORTRAIT; + final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp); + final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp); + if (newConfig.orientation == ORIENTATION_PORTRAIT) { + newConfig.orientation = ORIENTATION_LANDSCAPE; + newConfig.screenWidthDp = longSide; + newConfig.screenHeightDp = shortSide; + } else { + newConfig.orientation = ORIENTATION_PORTRAIT; + newConfig.screenWidthDp = shortSide; + newConfig.screenHeightDp = longSide; + } mTask.onConfigurationChanged(newConfig); @@ -457,7 +484,7 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testShouldPauseWhenMakeClientVisible() { ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); - topActivity.changeWindowTranslucency(false); + topActivity.setOccludesParent(false); mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); mActivity.makeClientVisible(); assertEquals(STARTED, mActivity.getState()); @@ -468,6 +495,7 @@ public class ActivityRecordTests extends ActivityTestsBase { setupDisplayContentForCompatDisplayInsets(); final int decorHeight = 200; // e.g. The device has cutout. final DisplayPolicy policy = setupDisplayAndParentSize(600, 800).getDisplayPolicy(); + spyOn(policy); doAnswer(invocationOnMock -> { final int rotation = invocationOnMock.<Integer>getArgument(0); final Rect insets = invocationOnMock.<Rect>getArgument(4); @@ -482,7 +510,7 @@ public class ActivityRecordTests extends ActivityTestsBase { doReturn(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) .when(mActivity.mAppWindowToken).getOrientationIgnoreVisibility(); - mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE; + mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = 1; ensureActivityConfiguration(); // The parent configuration doesn't change since the first resolved configuration, so the @@ -506,19 +534,32 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testSizeCompatMode_FixedScreenConfigurationWhenMovingToDisplay() { // Initialize different bounds on a new display. - final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); - newDisplay.getWindowConfiguration().setAppBounds(new Rect(0, 0, 1000, 2000)); - newDisplay.getConfiguration().densityDpi = 300; - - mTask.getConfiguration().densityDpi = 200; - prepareFixedAspectRatioUnresizableActivity(); + final Rect newDisplayBounds = new Rect(0, 0, 1000, 2000); + DisplayInfo info = new DisplayInfo(); + mService.mContext.getDisplay().getDisplayInfo(info); + info.logicalWidth = newDisplayBounds.width(); + info.logicalHeight = newDisplayBounds.height(); + info.logicalDensityDpi = 300; + + final ActivityDisplay newDisplay = + addNewActivityDisplayAt(info, ActivityDisplay.POSITION_TOP); + + final Configuration c = + new Configuration(mStack.getDisplay().getRequestedOverrideConfiguration()); + c.densityDpi = 200; + mStack.getDisplay().onRequestedOverrideConfigurationChanged(c); + mActivity = new ActivityBuilder(mService) + .setTask(mTask) + .setResizeMode(RESIZE_MODE_UNRESIZEABLE) + .setMaxAspectRatio(1.5f) + .build(); + mActivity.visible = true; final Rect originalBounds = new Rect(mActivity.getBounds()); final int originalDpi = mActivity.getConfiguration().densityDpi; // Move the non-resizable activity to the new display. mStack.reparent(newDisplay, true /* onTop */, false /* displayRemoved */); - ensureActivityConfiguration(); assertEquals(originalBounds, mActivity.getBounds()); assertEquals(originalDpi, mActivity.getConfiguration().densityDpi); @@ -531,9 +572,9 @@ public class ActivityRecordTests extends ActivityTestsBase { when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn( ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds()); - mTask.getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT; + mTask.getConfiguration().orientation = ORIENTATION_PORTRAIT; mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; - mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE; + mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; ensureActivityConfiguration(); final Rect originalBounds = new Rect(mActivity.getBounds()); @@ -549,7 +590,7 @@ public class ActivityRecordTests extends ActivityTestsBase { public void testSizeCompatMode_FixedScreenLayoutSizeBits() { final int fixedScreenLayout = Configuration.SCREENLAYOUT_LONG_NO | Configuration.SCREENLAYOUT_SIZE_NORMAL; - mTask.getConfiguration().screenLayout = fixedScreenLayout + mTask.getRequestedOverrideConfiguration().screenLayout = fixedScreenLayout | Configuration.SCREENLAYOUT_LAYOUTDIR_LTR; prepareFixedAspectRatioUnresizableActivity(); @@ -579,7 +620,7 @@ public class ActivityRecordTests extends ActivityTestsBase { mTask.getWindowConfiguration().setAppBounds(new Rect(0, 0, 600, 1200)); // Simulate the display changes orientation. - doReturn(ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION + doReturn(ActivityInfo.CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION | ActivityInfo.CONFIG_WINDOW_CONFIGURATION) .when(display).getLastOverrideConfigurationChanges(); mActivity.onConfigurationChanged(mTask.getConfiguration()); @@ -754,29 +795,27 @@ public class ActivityRecordTests extends ActivityTestsBase { /** Setup {@link #mActivity} as a size-compat-mode-able activity without fixed orientation. */ private void prepareFixedAspectRatioUnresizableActivity() { setupDisplayContentForCompatDisplayInsets(); - when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn( - ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); - mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE; + mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; mActivity.info.maxAspectRatio = 1.5f; + mActivity.visible = true; ensureActivityConfiguration(); } private void setupDisplayContentForCompatDisplayInsets() { final Rect displayBounds = mStack.getDisplay().getBounds(); - final DisplayContent displayContent = setupDisplayAndParentSize( - displayBounds.width(), displayBounds.height()); - doReturn(mock(DisplayPolicy.class)).when(displayContent).getDisplayPolicy(); - doReturn(mock(WmDisplayCutout.class)).when(displayContent) - .calculateDisplayCutoutForRotation(anyInt()); + setupDisplayAndParentSize(displayBounds.width(), displayBounds.height()); } private DisplayContent setupDisplayAndParentSize(int width, int height) { - // The DisplayContent is already a mocked object. final DisplayContent displayContent = mStack.getDisplay().mDisplayContent; displayContent.mBaseDisplayWidth = width; displayContent.mBaseDisplayHeight = height; - mTask.getWindowConfiguration().setAppBounds(0, 0, width, height); - mTask.getWindowConfiguration().setRotation(ROTATION_0); + final Configuration c = + new Configuration(mStack.getDisplay().getRequestedOverrideConfiguration()); + c.windowConfiguration.setBounds(new Rect(0, 0, width, height)); + c.windowConfiguration.setAppBounds(0, 0, width, height); + c.windowConfiguration.setRotation(ROTATION_0); + mStack.getDisplay().onRequestedOverrideConfigurationChanged(c); return displayContent; } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index e5278d81767e..ff7b1fadbaf9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -29,7 +29,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; import static com.android.server.wm.ActivityStack.ActivityState.FINISHING; @@ -44,6 +44,7 @@ import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; +import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; import static com.google.common.truth.Truth.assertThat; @@ -83,8 +84,9 @@ public class ActivityStackTests extends ActivityTestsBase { @Before public void setUp() throws Exception { mDefaultDisplay = mRootActivityContainer.getDefaultDisplay(); - mStack = spy(mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, - true /* onTop */)); + mStack = mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, + true /* onTop */); + spyOn(mStack); mTask = new TaskBuilder(mSupervisor).setStack(mStack).build(); } @@ -140,10 +142,8 @@ public class ActivityStackTests extends ActivityTestsBase { final ActivityStack destStack = mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final TaskRecord destTask = new TaskBuilder(mSupervisor).setStack(destStack).build(); - - mTask.removeActivity(r); - destTask.addActivityToTop(r); + mTask.reparent(destStack, true /*toTop*/, REPARENT_MOVE_STACK_TO_FRONT, false, false, + "testResumedActivityFromActivityReparenting"); assertNull(mStack.getResumedActivity()); assertEquals(r, destStack.getResumedActivity()); @@ -313,45 +313,50 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testShouldBeVisible_Fullscreen() { - final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); + // Add an activity to the pinned stack so it isn't considered empty for visibility check. + final ActivityRecord pinnedActivity = new ActivityBuilder(mService) + .setCreateTask(true) + .setStack(pinnedStack) + .build(); assertTrue(homeStack.shouldBeVisible(null /* starting */)); assertTrue(pinnedStack.shouldBeVisible(null /* starting */)); - final TestActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Home stack shouldn't be visible behind an opaque fullscreen stack, but pinned stack // should be visible since it is always on-top. - fullscreenStack.setIsTranslucent(false); + doReturn(false).when(fullscreenStack).isStackTranslucent(any()); assertFalse(homeStack.shouldBeVisible(null /* starting */)); assertTrue(pinnedStack.shouldBeVisible(null /* starting */)); assertTrue(fullscreenStack.shouldBeVisible(null /* starting */)); // Home stack should be visible behind a translucent fullscreen stack. - fullscreenStack.setIsTranslucent(true); + doReturn(true).when(fullscreenStack).isStackTranslucent(any()); assertTrue(homeStack.shouldBeVisible(null /* starting */)); assertTrue(pinnedStack.shouldBeVisible(null /* starting */)); } @Test public void testShouldBeVisible_SplitScreen() { - final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); // Home stack should always be fullscreen for this test. - homeStack.setSupportsSplitScreen(false); - final TestActivityStack splitScreenPrimary = + doReturn(false).when(homeStack).supportsSplitScreenWindowingMode(); + final ActivityStack splitScreenPrimary = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final TestActivityStack splitScreenSecondary = + final ActivityStack splitScreenSecondary = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Home stack shouldn't be visible if both halves of split-screen are opaque. - splitScreenPrimary.setIsTranslucent(false); - splitScreenSecondary.setIsTranslucent(false); + doReturn(false).when(splitScreenPrimary).isStackTranslucent(any()); + doReturn(false).when(splitScreenSecondary).isStackTranslucent(any()); assertFalse(homeStack.shouldBeVisible(null /* starting */)); assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */)); @@ -362,7 +367,7 @@ public class ActivityStackTests extends ActivityTestsBase { splitScreenSecondary.getVisibility(null /* starting */)); // Home stack should be visible if one of the halves of split-screen is translucent. - splitScreenPrimary.setIsTranslucent(true); + doReturn(true).when(splitScreenPrimary).isStackTranslucent(any()); assertTrue(homeStack.shouldBeVisible(null /* starting */)); assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */)); @@ -373,12 +378,12 @@ public class ActivityStackTests extends ActivityTestsBase { assertEquals(STACK_VISIBILITY_VISIBLE, splitScreenSecondary.getVisibility(null /* starting */)); - final TestActivityStack splitScreenSecondary2 = + final ActivityStack splitScreenSecondary2 = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); // First split-screen secondary shouldn't be visible behind another opaque split-split // secondary. - splitScreenSecondary2.setIsTranslucent(false); + doReturn(false).when(splitScreenSecondary2).isStackTranslucent(any()); assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */)); assertEquals(STACK_VISIBILITY_INVISIBLE, @@ -388,7 +393,7 @@ public class ActivityStackTests extends ActivityTestsBase { // First split-screen secondary should be visible behind another translucent split-screen // secondary. - splitScreenSecondary2.setIsTranslucent(true); + doReturn(true).when(splitScreenSecondary2).isStackTranslucent(any()); assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */)); assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, @@ -396,11 +401,11 @@ public class ActivityStackTests extends ActivityTestsBase { assertEquals(STACK_VISIBILITY_VISIBLE, splitScreenSecondary2.getVisibility(null /* starting */)); - final TestActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */); // Split-screen stacks shouldn't be visible behind an opaque fullscreen stack. - assistantStack.setIsTranslucent(false); + doReturn(false).when(assistantStack).isStackTranslucent(any()); assertTrue(assistantStack.shouldBeVisible(null /* starting */)); assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */)); assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */)); @@ -415,7 +420,7 @@ public class ActivityStackTests extends ActivityTestsBase { splitScreenSecondary2.getVisibility(null /* starting */)); // Split-screen stacks should be visible behind a translucent fullscreen stack. - assistantStack.setIsTranslucent(true); + doReturn(true).when(assistantStack).isStackTranslucent(any()); assertTrue(assistantStack.shouldBeVisible(null /* starting */)); assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */)); @@ -430,9 +435,9 @@ public class ActivityStackTests extends ActivityTestsBase { splitScreenSecondary2.getVisibility(null /* starting */)); // Assistant stack shouldn't be visible behind translucent split-screen stack - assistantStack.setIsTranslucent(false); - splitScreenPrimary.setIsTranslucent(true); - splitScreenSecondary2.setIsTranslucent(true); + doReturn(false).when(assistantStack).isStackTranslucent(any()); + doReturn(true).when(splitScreenPrimary).isStackTranslucent(any()); + doReturn(true).when(splitScreenSecondary2).isStackTranslucent(any()); splitScreenSecondary2.moveToFront("testShouldBeVisible_SplitScreen"); splitScreenPrimary.moveToFront("testShouldBeVisible_SplitScreen"); assertFalse(assistantStack.shouldBeVisible(null /* starting */)); @@ -450,10 +455,10 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testGetVisibility_FullscreenBehindTranslucent() { - final TestActivityStack bottomStack = + final ActivityStack bottomStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, false /* translucent */); - final TestActivityStack translucentStack = + final ActivityStack translucentStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, true /* translucent */); @@ -465,13 +470,13 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testGetVisibility_FullscreenBehindTranslucentAndOpaque() { - final TestActivityStack bottomStack = + final ActivityStack bottomStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, false /* translucent */); - final TestActivityStack translucentStack = + final ActivityStack translucentStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, true /* translucent */); - final TestActivityStack opaqueStack = + final ActivityStack opaqueStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, false /* translucent */); @@ -483,13 +488,13 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testGetVisibility_FullscreenBehindOpaqueAndTranslucent() { - final TestActivityStack bottomStack = + final ActivityStack bottomStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, false /* translucent */); - final TestActivityStack opaqueStack = + final ActivityStack opaqueStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, false /* translucent */); - final TestActivityStack translucentStack = + final ActivityStack translucentStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, true /* translucent */); @@ -502,10 +507,10 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testGetVisibility_FullscreenTranslucentBehindTranslucent() { - final TestActivityStack bottomTranslucentStack = + final ActivityStack bottomTranslucentStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, true /* translucent */); - final TestActivityStack translucentStack = + final ActivityStack translucentStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, true /* translucent */); @@ -517,10 +522,10 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testGetVisibility_FullscreenTranslucentBehindOpaque() { - final TestActivityStack bottomTranslucentStack = + final ActivityStack bottomTranslucentStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, true /* translucent */); - final TestActivityStack opaqueStack = + final ActivityStack opaqueStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, false /* translucent */); @@ -531,10 +536,10 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testGetVisibility_FullscreenBehindTranslucentAndPip() { - final TestActivityStack bottomStack = + final ActivityStack bottomStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, false /* translucent */); - final TestActivityStack translucentStack = + final ActivityStack translucentStack = createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN, true /* translucent */); final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay, @@ -544,22 +549,34 @@ public class ActivityStackTests extends ActivityTestsBase { bottomStack.getVisibility(null /* starting */)); assertEquals(STACK_VISIBILITY_VISIBLE, translucentStack.getVisibility(null /* starting */)); + // Add an activity to the pinned stack so it isn't considered empty for visibility check. + final ActivityRecord pinnedActivity = new ActivityBuilder(mService) + .setCreateTask(true) + .setStack(pinnedStack) + .build(); assertEquals(STACK_VISIBILITY_VISIBLE, pinnedStack.getVisibility(null /* starting */)); } @Test public void testShouldBeVisible_Finishing() { - final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - final TestActivityStack translucentStack = createStackForShouldBeVisibleTest( + ActivityRecord topRunningHomeActivity = homeStack.topRunningActivityLocked(); + if (topRunningHomeActivity == null) { + topRunningHomeActivity = new ActivityBuilder(mService) + .setStack(homeStack) + .setCreateTask(true) + .build(); + } + + final ActivityStack translucentStack = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - translucentStack.setIsTranslucent(true); + doReturn(true).when(translucentStack).isStackTranslucent(any()); assertTrue(homeStack.shouldBeVisible(null /* starting */)); assertTrue(translucentStack.shouldBeVisible(null /* starting */)); - final ActivityRecord topRunningHomeActivity = homeStack.topRunningActivityLocked(); topRunningHomeActivity.finishing = true; final ActivityRecord topRunningTranslucentActivity = translucentStack.topRunningActivityLocked(); @@ -577,13 +594,13 @@ public class ActivityStackTests extends ActivityTestsBase { public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeBehindFullscreen() { mDefaultDisplay.removeChild(mStack); - final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - final TestActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - homeStack.setIsTranslucent(false); - fullscreenStack.setIsTranslucent(false); + doReturn(false).when(homeStack).isStackTranslucent(any()); + doReturn(false).when(fullscreenStack).isStackTranslucent(any()); // Ensure that we don't move the home stack if it is already behind the top fullscreen stack int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack); @@ -596,13 +613,13 @@ public class ActivityStackTests extends ActivityTestsBase { public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeBehindTranslucent() { mDefaultDisplay.removeChild(mStack); - final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - final TestActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - homeStack.setIsTranslucent(false); - fullscreenStack.setIsTranslucent(true); + doReturn(false).when(homeStack).isStackTranslucent(any()); + doReturn(true).when(fullscreenStack).isStackTranslucent(any()); // Ensure that we don't move the home stack if it is already behind the top fullscreen stack int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack); @@ -615,13 +632,13 @@ public class ActivityStackTests extends ActivityTestsBase { public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeOnTop() { mDefaultDisplay.removeChild(mStack); - final TestActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - homeStack.setIsTranslucent(false); - fullscreenStack.setIsTranslucent(false); + doReturn(false).when(homeStack).isStackTranslucent(any()); + doReturn(false).when(fullscreenStack).isStackTranslucent(any()); // Ensure we don't move the home stack if it is already on top int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack); @@ -634,20 +651,20 @@ public class ActivityStackTests extends ActivityTestsBase { public void testMoveHomeStackBehindBottomMostVisibleStack_MoveHomeBehindFullscreen() { mDefaultDisplay.removeChild(mStack); - final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - final TestActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest( + final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest( + final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); - homeStack.setIsTranslucent(false); - fullscreenStack1.setIsTranslucent(false); - fullscreenStack2.setIsTranslucent(false); + doReturn(false).when(homeStack).isStackTranslucent(any()); + doReturn(false).when(fullscreenStack1).isStackTranslucent(any()); + doReturn(false).when(fullscreenStack2).isStackTranslucent(any()); // Ensure that we move the home stack behind the bottom most fullscreen stack, ignoring the // pinned stack @@ -661,18 +678,18 @@ public class ActivityStackTests extends ActivityTestsBase { testMoveHomeStackBehindBottomMostVisibleStack_MoveHomeBehindFullscreenAndTranslucent() { mDefaultDisplay.removeChild(mStack); - final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - final TestActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest( + final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest( + final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - homeStack.setIsTranslucent(false); - fullscreenStack1.setIsTranslucent(false); - fullscreenStack2.setIsTranslucent(true); + doReturn(false).when(homeStack).isStackTranslucent(any()); + doReturn(false).when(fullscreenStack1).isStackTranslucent(any()); + doReturn(true).when(fullscreenStack2).isStackTranslucent(any()); // Ensure that we move the home stack behind the bottom most non-translucent fullscreen // stack @@ -685,18 +702,18 @@ public class ActivityStackTests extends ActivityTestsBase { public void testMoveHomeStackBehindStack_BehindHomeStack() { mDefaultDisplay.removeChild(mStack); - final TestActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest( + final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest( + final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - homeStack.setIsTranslucent(false); - fullscreenStack1.setIsTranslucent(false); - fullscreenStack2.setIsTranslucent(false); + doReturn(false).when(homeStack).isStackTranslucent(any()); + doReturn(false).when(fullscreenStack1).isStackTranslucent(any()); + doReturn(false).when(fullscreenStack2).isStackTranslucent(any()); // Ensure we don't move the home stack behind itself int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack); @@ -708,19 +725,19 @@ public class ActivityStackTests extends ActivityTestsBase { public void testMoveHomeStackBehindStack() { mDefaultDisplay.removeChild(mStack); - final TestActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest( + final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest( + final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final TestActivityStack fullscreenStack3 = createStackForShouldBeVisibleTest( + final ActivityStack fullscreenStack3 = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final TestActivityStack fullscreenStack4 = createStackForShouldBeVisibleTest( + final ActivityStack fullscreenStack4 = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); mDefaultDisplay.moveStackBehindStack(homeStack, fullscreenStack1); @@ -735,13 +752,13 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testSetAlwaysOnTop() { - final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); assertEquals(pinnedStack, mDefaultDisplay.getStackAbove(homeStack)); - final TestActivityStack alwaysOnTopStack = createStackForShouldBeVisibleTest( + final ActivityStack alwaysOnTopStack = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); alwaysOnTopStack.setAlwaysOnTop(true); @@ -749,13 +766,13 @@ public class ActivityStackTests extends ActivityTestsBase { // Ensure (non-pinned) always on top stack is put below pinned stack. assertEquals(pinnedStack, mDefaultDisplay.getStackAbove(alwaysOnTopStack)); - final TestActivityStack nonAlwaysOnTopStack = createStackForShouldBeVisibleTest( + final ActivityStack nonAlwaysOnTopStack = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Ensure non always on top stack is put below always on top stacks. assertEquals(alwaysOnTopStack, mDefaultDisplay.getStackAbove(nonAlwaysOnTopStack)); - final TestActivityStack alwaysOnTopStack2 = createStackForShouldBeVisibleTest( + final ActivityStack alwaysOnTopStack2 = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); alwaysOnTopStack2.setAlwaysOnTop(true); @@ -780,18 +797,18 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testSplitScreenMoveToFront() { - final TestActivityStack splitScreenPrimary = createStackForShouldBeVisibleTest( + final ActivityStack splitScreenPrimary = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final TestActivityStack splitScreenSecondary = createStackForShouldBeVisibleTest( + final ActivityStack splitScreenSecondary = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final TestActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */); - splitScreenPrimary.setIsTranslucent(false); - splitScreenSecondary.setIsTranslucent(false); - assistantStack.setIsTranslucent(false); + doReturn(false).when(splitScreenPrimary).isStackTranslucent(any()); + doReturn(false).when(splitScreenSecondary).isStackTranslucent(any()); + doReturn(false).when(assistantStack).isStackTranslucent(any()); assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */)); assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */)); @@ -804,18 +821,18 @@ public class ActivityStackTests extends ActivityTestsBase { assertFalse(assistantStack.shouldBeVisible(null /* starting */)); } - private TestActivityStack createStandardStackForVisibilityTest(int windowingMode, + private ActivityStack createStandardStackForVisibilityTest(int windowingMode, boolean translucent) { - final TestActivityStack stack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack stack = createStackForShouldBeVisibleTest(mDefaultDisplay, windowingMode, ACTIVITY_TYPE_STANDARD, true /* onTop */); - stack.setIsTranslucent(translucent); + doReturn(translucent).when(stack).isStackTranslucent(any()); return stack; } @SuppressWarnings("TypeParameterUnusedInFormals") private <T extends ActivityStack> T createStackForShouldBeVisibleTest( ActivityDisplay display, int windowingMode, int activityType, boolean onTop) { - final T stack; + final ActivityStack stack; if (activityType == ACTIVITY_TYPE_HOME) { // Home stack and activity are created in ActivityTestsBase#setupActivityManagerService stack = mDefaultDisplay.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); @@ -825,11 +842,15 @@ public class ActivityStackTests extends ActivityTestsBase { mDefaultDisplay.positionChildAtBottom(stack); } } else { - stack = display.createStack(windowingMode, activityType, onTop); - final ActivityRecord r = new ActivityBuilder(mService).setUid(0).setStack(stack) - .setCreateTask(true).build(); + stack = new StackBuilder(mRootActivityContainer) + .setDisplay(display) + .setWindowingMode(windowingMode) + .setActivityType(activityType) + .setOnTop(onTop) + .setCreateActivity(true) + .build(); } - return stack; + return (T) stack; } @Test @@ -961,11 +982,16 @@ public class ActivityStackTests extends ActivityTestsBase { @Test public void testAdjustFocusedStackToHomeWhenNoActivity() { + final ActivityStack homeStask = mDefaultDisplay.getHomeStack(); + TaskRecord homeTask = homeStask.topTask(); + if (homeTask == null) { + // Create home task if there isn't one. + homeTask = new TaskBuilder(mSupervisor).setStack(homeStask).build(); + } + final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); mStack.moveToFront("testAdjustFocusedStack"); - final ActivityStack homeStask = mDefaultDisplay.getHomeStack(); - final TaskRecord homeTask = homeStask.topTask(); // Simulate that home activity has not been started or is force-stopped. homeStask.removeTask(homeTask, "testAdjustFocusedStack", REMOVE_TASK_MODE_DESTROYING); @@ -981,6 +1007,14 @@ public class ActivityStackTests extends ActivityTestsBase { final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); + ActivityRecord activity = homeStack.topRunningActivityLocked(); + if (activity == null) { + activity = new ActivityBuilder(mService) + .setStack(homeStack) + .setCreateTask(true) + .build(); + } + // Home stack should not be destroyed immediately. final ActivityRecord activity1 = finishCurrentActivity(homeStack); assertEquals(FINISHING, activity1.getState()); @@ -1068,7 +1102,7 @@ public class ActivityStackTests extends ActivityTestsBase { public void testStackOrderChangedOnPositionStack() { StackOrderChangedListener listener = new StackOrderChangedListener(); try { - final TestActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest( + final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); mDefaultDisplay.registerStackOrderChangedListener(listener); 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 3d944671ef25..81fbfe4e8641 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -79,6 +79,7 @@ import android.view.Gravity; import androidx.test.filters.SmallTest; import com.android.server.wm.LaunchParamsController.LaunchParamsModifier; +import com.android.server.wm.utils.MockTracker; import org.junit.Before; import org.junit.Test; @@ -186,6 +187,19 @@ public class ActivityStarterTests extends ActivityTestsBase { verifyStartActivityPreconditions(preconditions, 0 /*launchFlags*/, expectedResult); } + private void verifyStartActivityPreconditions(int preconditions, int launchFlags, + int expectedResult) { + // We track mocks created here because this is used in a single test + // (testStartActivityPreconditions) as a specific case, and mocks created inside it won't be + // used for other cases. To avoid extensive memory usage, we clean up all used mocks after + // each case. This is necessary because usually we only clean up mocks after a test + // finishes, but this test creates too many mocks that the intermediate memory usage can be + // ~0.8 GiB and thus very susceptible to OutOfMemoryException. + try (MockTracker tracker = new MockTracker()) { + verifyStartActivityPreconditionsUntracked(preconditions, launchFlags, expectedResult); + } + } + /** * Excercises how the {@link ActivityStarter} reacts to various preconditions. The caller * provides a bitmask of all the set conditions (such as {@link #PRECONDITION_NO_CALLER_APP}) @@ -197,7 +211,7 @@ public class ActivityStarterTests extends ActivityTestsBase { * @param launchFlags The launch flags to be provided by the launch {@link Intent}. * @param expectedResult The expected result from the launch. */ - private void verifyStartActivityPreconditions(int preconditions, int launchFlags, + private void verifyStartActivityPreconditionsUntracked(int preconditions, int launchFlags, int expectedResult) { final ActivityTaskManagerService service = mService; final IPackageManager packageManager = mock(IPackageManager.class); @@ -329,9 +343,6 @@ public class ActivityStarterTests extends ActivityTestsBase { any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), anyBoolean(), anyBoolean(), any(), any(), any()); - // Use factory that only returns spy task. - mockTaskRecordFactory(); - if (mockGetLaunchStack) { // Instrument the stack and task used. final ActivityStack stack = mRootActivityContainer.getDefaultDisplay().createStack( @@ -482,7 +493,7 @@ public class ActivityStarterTests extends ActivityTestsBase { @Test public void testTaskModeViolation() { final ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay(); - ((TestActivityDisplay) display).removeAllTasks(); + display.removeAllTasks(); assertNoTasks(display); final ActivityStarter starter = prepareStarter(0); @@ -676,18 +687,27 @@ public class ActivityStarterTests extends ActivityTestsBase { doReturn(isCallingUidDeviceOwner).when(mService).isDeviceOwner(callingUid); final ActivityOptions options = spy(ActivityOptions.makeBasic()); + ActivityRecord[] outActivity = new ActivityRecord[1]; ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK) .setCallingPackage("com.whatever.dude") .setCaller(caller) .setCallingUid(callingUid) .setRealCallingUid(realCallingUid) - .setActivityOptions(new SafeActivityOptions(options)); + .setActivityOptions(new SafeActivityOptions(options)) + .setOutActivity(outActivity); final int result = starter.setReason("testBackgroundActivityStarts_" + name).execute(); assertEquals(ActivityStarter.getExternalResult( shouldHaveAborted ? START_ABORTED : START_SUCCESS), result); verify(options, times(shouldHaveAborted ? 1 : 0)).abort(); + + final ActivityRecord startedActivity = outActivity[0]; + if (startedActivity != null && startedActivity.getTaskRecord() != null) { + // Remove the activity so it doesn't interfere with with subsequent activity launch + // tests from this method. + startedActivity.getTaskRecord().removeActivity(startedActivity); + } } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java index d8a9bb0d6237..297aa7eab169 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java @@ -45,8 +45,7 @@ public class ActivityTaskManagerServiceTests extends ActivityTestsBase { /** Verify that activity is finished correctly upon request. */ @Test public void testActivityFinish() { - final TestActivityStack stack = - (TestActivityStack) new StackBuilder(mRootActivityContainer).build(); + final ActivityStack stack = new StackBuilder(mRootActivityContainer).build(); final ActivityRecord activity = stack.getChildAt(0).getTopActivity(); assertTrue("Activity must be finished", mService.finishActivity(activity.appToken, 0 /* resultCode */, null /* resultData */, diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index ab2da2ba6c5f..a5dc24111dab 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -16,96 +16,58 @@ package com.android.server.wm; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; -import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod; 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.mock; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; -import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; -import android.app.ActivityManagerInternal; import android.app.ActivityOptions; -import android.app.AppOpsManager; import android.app.IApplicationThread; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManagerInternal; import android.content.res.Configuration; import android.graphics.Rect; -import android.hardware.display.DisplayManager; -import android.hardware.display.DisplayManagerGlobal; -import android.os.Handler; -import android.os.Looper; -import android.os.PowerManager; -import android.os.Process; import android.os.UserHandle; import android.service.voice.IVoiceInteractionSession; import android.testing.DexmakerShareClassLoaderRule; -import android.view.Display; import android.view.DisplayInfo; -import com.android.internal.app.IVoiceInteractor; import com.android.server.AttributeCache; -import com.android.server.ServiceThread; -import com.android.server.am.ActivityManagerService; -import com.android.server.am.PendingIntentController; -import com.android.server.appop.AppOpsService; -import com.android.server.firewall.IntentFirewall; -import com.android.server.policy.PermissionPolicyInternal; -import com.android.server.uri.UriGrantsManagerInternal; -import com.android.server.wm.TaskRecord.TaskRecordFactory; -import com.android.server.wm.utils.MockTracker; - -import org.junit.After; + import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; -import org.mockito.invocation.InvocationOnMock; - -import java.io.File; -import java.util.List; -import java.util.function.Consumer; /** * A base class to handle common operations in activity related unit tests. */ class ActivityTestsBase { - private static int sNextDisplayId = DEFAULT_DISPLAY + 1; @Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = new DexmakerShareClassLoaderRule(); + @Rule + public final SystemServicesTestRule mSystemServicesTestRule = new SystemServicesTestRule(); + final Context mContext = getInstrumentation().getTargetContext(); - final TestInjector mTestInjector = new TestInjector(mContext); ActivityTaskManagerService mService; RootActivityContainer mRootActivityContainer; ActivityStackSupervisor mSupervisor; - private MockTracker mMockTracker; - // Default package name static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo"; @@ -119,37 +81,18 @@ class ActivityTestsBase { @Before public void setUpBase() { - mMockTracker = new MockTracker(); - - mTestInjector.setUp(); - - mService = new TestActivityTaskManagerService(mContext); + mService = mSystemServicesTestRule.getActivityTaskManagerService(); mSupervisor = mService.mStackSupervisor; mRootActivityContainer = mService.mRootActivityContainer; } - @After - public void tearDownBase() { - mTestInjector.tearDown(); - if (mService != null) { - mService.setWindowManager(null); - mService = null; - } - if (sMockWindowManagerService != null) { - reset(sMockWindowManagerService); - } - - mMockTracker.close(); - mMockTracker = null; - } - /** Creates a {@link TestActivityDisplay}. */ TestActivityDisplay createNewActivityDisplay() { - return TestActivityDisplay.create(mSupervisor, sNextDisplayId++); + return TestActivityDisplay.create(mSupervisor); } TestActivityDisplay createNewActivityDisplay(DisplayInfo info) { - return TestActivityDisplay.create(mSupervisor, sNextDisplayId++, info); + return TestActivityDisplay.create(mSupervisor, info); } /** Creates and adds a {@link TestActivityDisplay} to supervisor at the given position. */ @@ -166,25 +109,9 @@ class ActivityTestsBase { return display; } - /** - * Delegates task creation to {@link #TaskBuilder} to avoid the dependency of window hierarchy - * when starting activity in unit tests. - */ - void mockTaskRecordFactory(Consumer<TaskBuilder> taskBuilderSetup) { - final TaskBuilder taskBuilder = new TaskBuilder(mSupervisor).setCreateStack(false); - if (taskBuilderSetup != null) { - taskBuilderSetup.accept(taskBuilder); - } - final TaskRecord task = taskBuilder.build(); - final TaskRecordFactory factory = mock(TaskRecordFactory.class); - TaskRecord.setTaskRecordFactory(factory); - doReturn(task).when(factory).create(any() /* service */, anyInt() /* taskId */, - any() /* info */, any() /* intent */, any() /* voiceSession */, - any() /* voiceInteractor */); - } - - void mockTaskRecordFactory() { - mockTaskRecordFactory(null /* taskBuilderSetup */); + /** Sets the default minimum task size to 1 so that tests can use small task sizes */ + public void removeGlobalMinSizeRestriction() { + mService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp = 1; } /** @@ -204,6 +131,11 @@ class ActivityTestsBase { private ActivityStack mStack; private int mActivityFlags; private int mLaunchMode; + private int mResizeMode = RESIZE_MODE_RESIZEABLE; + private float mMaxAspectRatio; + private int mScreenOrientation = SCREEN_ORIENTATION_UNSPECIFIED; + private boolean mLaunchTaskBehind; + private int mConfigChanges; ActivityBuilder(ActivityTaskManagerService service) { mService = service; @@ -254,6 +186,31 @@ class ActivityTestsBase { return this; } + ActivityBuilder setResizeMode(int resizeMode) { + mResizeMode = resizeMode; + return this; + } + + ActivityBuilder setMaxAspectRatio(float maxAspectRatio) { + mMaxAspectRatio = maxAspectRatio; + return this; + } + + ActivityBuilder setScreenOrientation(int screenOrientation) { + mScreenOrientation = screenOrientation; + return this; + } + + ActivityBuilder setLaunchTaskBehind(boolean launchTaskBehind) { + mLaunchTaskBehind = launchTaskBehind; + return this; + } + + ActivityBuilder setConfigChanges(int configChanges) { + mConfigChanges = configChanges; + return this; + } + ActivityRecord build() { if (mComponent == null) { final int id = sCurrentActivityId++; @@ -279,24 +236,31 @@ class ActivityTestsBase { } aInfo.flags |= mActivityFlags; aInfo.launchMode = mLaunchMode; + aInfo.resizeMode = mResizeMode; + aInfo.maxAspectRatio = mMaxAspectRatio; + aInfo.screenOrientation = mScreenOrientation; + aInfo.configChanges |= mConfigChanges; + + ActivityOptions options = null; + if (mLaunchTaskBehind) { + options = ActivityOptions.makeTaskLaunchBehind(); + } final ActivityRecord activity = new ActivityRecord(mService, null /* caller */, 0 /* launchedFromPid */, 0, null, intent, null, aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */, 0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */, - mService.mStackSupervisor, null /* options */, null /* sourceRecord */); + mService.mStackSupervisor, options, null /* sourceRecord */); spyOn(activity); - activity.mAppWindowToken = mock(AppWindowToken.class); - doCallRealMethod().when(activity.mAppWindowToken).getOrientationIgnoreVisibility(); - doCallRealMethod().when(activity.mAppWindowToken) - .setOrientation(anyInt(), any(), any()); - doCallRealMethod().when(activity.mAppWindowToken).setOrientation(anyInt()); - doNothing().when(activity).removeWindowContainer(); - doReturn(mock(Configuration.class)).when(activity.mAppWindowToken) - .getRequestedOverrideConfiguration(); - if (mTaskRecord != null) { - mTaskRecord.addActivityToTop(activity); + // fullscreen value is normally read from resources in ctor, so for testing we need + // to set it somewhere else since we can't mock resources. + activity.fullscreen = true; + activity.setTask(mTaskRecord); + activity.createAppWindowToken(); + spyOn(activity.mAppWindowToken); + // Make visible by default... + activity.mAppWindowToken.setHidden(false); } final WindowProcessController wpc = new WindowProcessController(mService, @@ -305,6 +269,9 @@ class ActivityTestsBase { mock(WindowProcessListener.class)); wpc.setThread(mock(IApplicationThread.class)); activity.setProcess(wpc); + + // Resume top activities to make sure all other signals in the system are connected. + mService.mRootActivityContainer.resumeFocusedStacksTopActivities(); return activity; } } @@ -313,16 +280,13 @@ class ActivityTestsBase { * Builder for creating new tasks. */ protected static class TaskBuilder { - // Default package name - static final String DEFAULT_PACKAGE = "com.bar"; - private final ActivityStackSupervisor mSupervisor; private ComponentName mComponent; private String mPackage; private int mFlags = 0; // Task id 0 is reserved in ARC for the home app. - private int mTaskId = 1; + private int mTaskId = SystemServicesTestRule.sNextTaskId++; private int mUserId = 0; private IVoiceInteractionSession mVoiceSession; private boolean mCreateStack = true; @@ -381,6 +345,7 @@ class ActivityTestsBase { if (mStack == null && mCreateStack) { mStack = mSupervisor.mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + spyOn(mStack); } final ActivityInfo aInfo = new ActivityInfo(); @@ -396,450 +361,22 @@ class ActivityTestsBase { intent.setComponent(mComponent); intent.setFlags(mFlags); - final TestTaskRecord task = new TestTaskRecord(mSupervisor.mService, mTaskId, aInfo, + final TaskRecord task = new TaskRecord(mSupervisor.mService, mTaskId, aInfo, intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/); + spyOn(task); task.userId = mUserId; if (mStack != null) { mStack.moveToFront("test"); mStack.addTask(task, true, "creating test task"); - task.setStack(mStack); - task.setTask(); - mStack.getTaskStack().addChild(task.mTask, 0); + task.createTask(true, true); + spyOn(task.mTask); } task.touchActiveTime(); return task; } - - private static class TestTaskRecord extends TaskRecord { - TestTaskRecord(ActivityTaskManagerService service, int taskId, ActivityInfo info, - Intent intent, IVoiceInteractionSession voiceSession, - IVoiceInteractor voiceInteractor) { - super(service, taskId, info, intent, voiceSession, voiceInteractor); - } - - @Override - void createTask(boolean onTop, boolean showForAllUsers) { - setTask(); - } - - void setTask() { - Task mockTask = mock(Task.class); - mockTask.mTaskRecord = this; - doCallRealMethod().when(mockTask).onDescendantOrientationChanged(any(), any()); - setTask(mock(Task.class)); - } - } - } - - protected class TestActivityTaskManagerService extends ActivityTaskManagerService { - private PackageManagerInternal mPmInternal; - private PermissionPolicyInternal mPermissionPolicyInternal; - - // ActivityStackSupervisor may be created more than once while setting up AMS and ATMS. - // We keep the reference in order to prevent creating it twice. - ActivityStackSupervisor mTestStackSupervisor; - - ActivityDisplay mDefaultDisplay; - AppOpsService mAppOpsService; - - TestActivityTaskManagerService(Context context) { - super(context); - spyOn(this); - - mUgmInternal = mock(UriGrantsManagerInternal.class); - mAppOpsService = mock(AppOpsService.class); - - // Make sure permission checks aren't overridden. - doReturn(AppOpsManager.MODE_DEFAULT) - .when(mAppOpsService).noteOperation(anyInt(), anyInt(), anyString()); - - mSupportsMultiWindow = true; - mSupportsMultiDisplay = true; - mSupportsSplitScreenMultiWindow = true; - mSupportsFreeformWindowManagement = true; - mSupportsPictureInPicture = true; - - final TestActivityManagerService am = - new TestActivityManagerService(mTestInjector, this); - - spyOn(getLifecycleManager()); - spyOn(getLockTaskController()); - spyOn(getTaskChangeNotificationController()); - doReturn(mock(IPackageManager.class)).when(this).getPackageManager(); - // allow background activity starts by default - doReturn(true).when(this).isBackgroundActivityStartsEnabled(); - doNothing().when(this).updateCpuStats(); - } - - void setup(IntentFirewall intentFirewall, PendingIntentController intentController, - ActivityManagerInternal amInternal, WindowManagerService wm, Looper looper) { - mAmInternal = amInternal; - initialize(intentFirewall, intentController, looper); - initRootActivityContainerMocks(wm); - setWindowManager(wm); - createDefaultDisplay(); - } - - void initRootActivityContainerMocks(WindowManagerService wm) { - spyOn(mRootActivityContainer); - mRootActivityContainer.setWindowContainer(mock(RootWindowContainer.class)); - mRootActivityContainer.mWindowManager = wm; - mRootActivityContainer.mDisplayManager = - (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE); - doNothing().when(mRootActivityContainer).setWindowManager(any()); - // Invoked during {@link ActivityStack} creation. - doNothing().when(mRootActivityContainer).updateUIDsPresentOnDisplay(); - // Always keep things awake. - doReturn(true).when(mRootActivityContainer).hasAwakeDisplay(); - // Called when moving activity to pinned stack. - doNothing().when(mRootActivityContainer).ensureActivitiesVisible(any(), anyInt(), - anyBoolean()); - } - - void createDefaultDisplay() { - // Create a default display and put a home stack on it so that we'll always have - // something focusable. - mDefaultDisplay = TestActivityDisplay.create(mStackSupervisor, DEFAULT_DISPLAY); - spyOn(mDefaultDisplay); - mRootActivityContainer.addChild(mDefaultDisplay, ActivityDisplay.POSITION_TOP); - mDefaultDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); - final TaskRecord task = new TaskBuilder(mStackSupervisor) - .setStack(mDefaultDisplay.getHomeStack()).build(); - new ActivityBuilder(this).setTask(task).build(); - - doReturn(mDefaultDisplay).when(mRootActivityContainer).getDefaultDisplay(); - } - - @Override - int handleIncomingUser(int callingPid, int callingUid, int userId, String name) { - return userId; - } - - @Override - AppOpsService getAppOpsService() { - return mAppOpsService; - } - - @Override - void updateCpuStats() { - } - - @Override - void updateBatteryStats(ActivityRecord component, boolean resumed) { - } - - @Override - void updateActivityUsageStats(ActivityRecord activity, int event) { - } - - @Override - protected ActivityStackSupervisor createStackSupervisor() { - if (mTestStackSupervisor == null) { - mTestStackSupervisor = new TestActivityStackSupervisor(this, mH.getLooper()); - } - return mTestStackSupervisor; - } - - @Override - PackageManagerInternal getPackageManagerInternalLocked() { - if (mPmInternal == null) { - mPmInternal = mock(PackageManagerInternal.class); - doReturn(false) - .when(mPmInternal) - .isPermissionsReviewRequired(anyString(), anyInt()); - } - return mPmInternal; - } - - @Override - PermissionPolicyInternal getPermissionPolicyInternal() { - if (mPermissionPolicyInternal == null) { - mPermissionPolicyInternal = mock(PermissionPolicyInternal.class); - doReturn(true).when(mPermissionPolicyInternal).checkStartActivity(any(), anyInt(), - any()); - } - return mPermissionPolicyInternal; - } - } - - private static class TestInjector extends ActivityManagerService.Injector { - private ServiceThread mHandlerThread; - - TestInjector(Context context) { - super(context); - } - - @Override - public AppOpsService getAppOpsService(File file, Handler handler) { - return null; - } - - @Override - public Handler getUiHandler(ActivityManagerService service) { - return mHandlerThread.getThreadHandler(); - } - - @Override - public boolean isNetworkRestrictedForUid(int uid) { - return false; - } - - void setUp() { - mHandlerThread = new ServiceThread("ActivityTestsThread", - Process.THREAD_PRIORITY_DEFAULT, true /* allowIo */); - mHandlerThread.start(); - } - - void tearDown() { - // Make sure there are no running messages and then quit the thread so the next test - // won't be affected. - mHandlerThread.getThreadHandler().runWithScissors(mHandlerThread::quit, - 0 /* timeout */); - } - } - - // TODO: Replace this with a mock object since we are no longer in AMS package. - /** - * An {@link ActivityManagerService} subclass which provides a test - * {@link ActivityStackSupervisor}. - */ - class TestActivityManagerService extends ActivityManagerService { - - TestActivityManagerService(TestInjector testInjector, TestActivityTaskManagerService atm) { - super(testInjector, testInjector.mHandlerThread); - spyOn(this); - - mWindowManager = prepareMockWindowManager(); - mUgmInternal = mock(UriGrantsManagerInternal.class); - - atm.setup(mIntentFirewall, mPendingIntentController, new LocalService(), mWindowManager, - testInjector.mHandlerThread.getLooper()); - - mActivityTaskManager = atm; - mAtmInternal = atm.mInternal; - - doReturn(mock(IPackageManager.class)).when(this).getPackageManager(); - PackageManagerInternal mockPackageManager = mock(PackageManagerInternal.class); - doReturn(mockPackageManager).when(this).getPackageManagerInternalLocked(); - doReturn(null).when(mockPackageManager).getDefaultHomeActivity(anyInt()); - doNothing().when(this).grantEphemeralAccessLocked(anyInt(), any(), anyInt(), anyInt()); - } - } - - /** - * An {@link ActivityStackSupervisor} which stubs out certain methods that depend on - * setup not available in the test environment. Also specifies an injector for - */ - protected class TestActivityStackSupervisor extends ActivityStackSupervisor { - private KeyguardController mKeyguardController; - - TestActivityStackSupervisor(ActivityTaskManagerService service, Looper looper) { - super(service, looper); - spyOn(this); - mWindowManager = prepareMockWindowManager(); - mKeyguardController = mock(KeyguardController.class); - - // Do not schedule idle that may touch methods outside the scope of the test. - doNothing().when(this).scheduleIdleLocked(); - doNothing().when(this).scheduleIdleTimeoutLocked(any()); - // unit test version does not handle launch wake lock - doNothing().when(this).acquireLaunchWakelock(); - doReturn(mKeyguardController).when(this).getKeyguardController(); - - mLaunchingActivityWakeLock = mock(PowerManager.WakeLock.class); - - initialize(); - } - - @Override - public KeyguardController getKeyguardController() { - return mKeyguardController; - } - - @Override - void setWindowManager(WindowManagerService wm) { - mWindowManager = wm; - } - } - - protected static class TestActivityDisplay extends ActivityDisplay { - private final ActivityStackSupervisor mSupervisor; - - static TestActivityDisplay create(ActivityStackSupervisor supervisor, int displayId) { - return create(supervisor, displayId, new DisplayInfo()); - } - - static TestActivityDisplay create(ActivityStackSupervisor supervisor, int displayId, - DisplayInfo info) { - if (displayId == DEFAULT_DISPLAY) { - return new TestActivityDisplay(supervisor, - supervisor.mRootActivityContainer.mDisplayManager.getDisplay(displayId)); - } - final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId, - info, DEFAULT_DISPLAY_ADJUSTMENTS); - return new TestActivityDisplay(supervisor, display); - } - - TestActivityDisplay(ActivityStackSupervisor supervisor, Display display) { - super(supervisor.mService.mRootActivityContainer, display); - // Normally this comes from display-properties as exposed by WM. Without that, just - // hard-code to FULLSCREEN for tests. - setWindowingMode(WINDOWING_MODE_FULLSCREEN); - mSupervisor = supervisor; - } - - @SuppressWarnings("TypeParameterUnusedInFormals") - @Override - ActivityStack createStackUnchecked(int windowingMode, int activityType, - int stackId, boolean onTop) { - return new StackBuilder(mSupervisor.mRootActivityContainer).setDisplay(this) - .setWindowingMode(windowingMode).setActivityType(activityType) - .setStackId(stackId).setOnTop(onTop).setCreateActivity(false).build(); - } - - @Override - protected DisplayContent createDisplayContent() { - final DisplayContent displayContent = mock(DisplayContent.class); - DockedStackDividerController divider = mock(DockedStackDividerController.class); - doReturn(divider).when(displayContent).getDockedDividerController(); - return displayContent; - } - - void removeAllTasks() { - for (int i = 0; i < getChildCount(); i++) { - final ActivityStack stack = getChildAt(i); - for (TaskRecord task : (List<TaskRecord>) stack.getAllTasks()) { - stack.removeTask(task, "removeAllTasks", REMOVE_TASK_MODE_DESTROYING); - } - } - } - } - - private static WindowManagerService sMockWindowManagerService; - - private static WindowManagerService prepareMockWindowManager() { - if (sMockWindowManagerService == null) { - sMockWindowManagerService = mock(WindowManagerService.class); - } - - sMockWindowManagerService.mRoot = mock(RootWindowContainer.class); - - doAnswer((InvocationOnMock invocationOnMock) -> { - final Runnable runnable = invocationOnMock.<Runnable>getArgument(0); - if (runnable != null) { - runnable.run(); - } - return null; - }).when(sMockWindowManagerService).inSurfaceTransaction(any()); - - return sMockWindowManagerService; - } - - /** - * Overridden {@link ActivityStack} that tracks test metrics, such as the number of times a - * method is called. Note that its functionality depends on the implementations of the - * construction arguments. - */ - protected static class TestActivityStack - extends ActivityStack { - private int mOnActivityRemovedFromStackCount = 0; - - static final int IS_TRANSLUCENT_UNSET = 0; - static final int IS_TRANSLUCENT_FALSE = 1; - static final int IS_TRANSLUCENT_TRUE = 2; - private int mIsTranslucent = IS_TRANSLUCENT_UNSET; - - static final int SUPPORTS_SPLIT_SCREEN_UNSET = 0; - static final int SUPPORTS_SPLIT_SCREEN_FALSE = 1; - static final int SUPPORTS_SPLIT_SCREEN_TRUE = 2; - private int mSupportsSplitScreen = SUPPORTS_SPLIT_SCREEN_UNSET; - - TestActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor, - int windowingMode, int activityType, boolean onTop, boolean createActivity) { - super(display, stackId, supervisor, windowingMode, activityType, onTop); - if (createActivity) { - new ActivityBuilder(mService).setCreateTask(true).setStack(this).build(); - if (onTop) { - // We move the task to front again in order to regain focus after activity - // added to the stack. Or {@link ActivityDisplay#mPreferredTopFocusableStack} - // could be other stacks (e.g. home stack). - moveToFront("createActivityStack"); - } else { - moveToBack("createActivityStack", null); - } - } - } - - @Override - void onActivityRemovedFromStack(ActivityRecord r) { - mOnActivityRemovedFromStackCount++; - super.onActivityRemovedFromStack(r); - } - - // Returns the number of times {@link #onActivityRemovedFromStack} has been called - int onActivityRemovedFromStackInvocationCount() { - return mOnActivityRemovedFromStackCount; - } - - @Override - protected void createTaskStack(int displayId, boolean onTop, Rect outBounds) { - mTaskStack = mock(TaskStack.class); - - // Primary pinned stacks require a non-empty out bounds to be set or else all tasks - // will be moved to the full screen stack. - if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - outBounds.set(0, 0, 100, 100); - } - } - - @Override - TaskStack getTaskStack() { - return mTaskStack; - } - - void setIsTranslucent(boolean isTranslucent) { - mIsTranslucent = isTranslucent ? IS_TRANSLUCENT_TRUE : IS_TRANSLUCENT_FALSE; - } - - @Override - boolean isStackTranslucent(ActivityRecord starting) { - switch (mIsTranslucent) { - case IS_TRANSLUCENT_TRUE: - return true; - case IS_TRANSLUCENT_FALSE: - return false; - case IS_TRANSLUCENT_UNSET: - default: - return super.isStackTranslucent(starting); - } - } - - void setSupportsSplitScreen(boolean supportsSplitScreen) { - mSupportsSplitScreen = supportsSplitScreen - ? SUPPORTS_SPLIT_SCREEN_TRUE : SUPPORTS_SPLIT_SCREEN_FALSE; - } - - @Override - public boolean supportsSplitScreenWindowingMode() { - switch (mSupportsSplitScreen) { - case SUPPORTS_SPLIT_SCREEN_TRUE: - return true; - case SUPPORTS_SPLIT_SCREEN_FALSE: - return false; - case SUPPORTS_SPLIT_SCREEN_UNSET: - default: - return super.supportsSplitScreenWindowingMode(); - } - } - - @Override - void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity, - boolean newTask, boolean keepCurTransition, - ActivityOptions options) { - } } static class StackBuilder { @@ -886,27 +423,45 @@ class ActivityTestsBase { return this; } - @SuppressWarnings("TypeParameterUnusedInFormals") ActivityStack build() { final int stackId = mStackId >= 0 ? mStackId : mDisplay.getNextStackId(); + final ActivityStack stack; + final ActivityStackSupervisor supervisor = mRootActivityContainer.mStackSupervisor; if (mWindowingMode == WINDOWING_MODE_PINNED) { - return new ActivityStack(mDisplay, stackId, mRootActivityContainer.mStackSupervisor, + stack = new ActivityStack(mDisplay, stackId, supervisor, mWindowingMode, ACTIVITY_TYPE_STANDARD, mOnTop) { @Override Rect getDefaultPictureInPictureBounds(float aspectRatio) { return new Rect(50, 50, 100, 100); } - - @Override - void createTaskStack(int displayId, boolean onTop, Rect outBounds) { - mTaskStack = mock(TaskStack.class); - } }; } else { - return new TestActivityStack(mDisplay, stackId, - mRootActivityContainer.mStackSupervisor, mWindowingMode, - mActivityType, mOnTop, mCreateActivity); + stack = new ActivityStack(mDisplay, stackId, supervisor, + mWindowingMode, mActivityType, mOnTop); + + if (mCreateActivity) { + new ActivityBuilder(supervisor.mService) + .setCreateTask(true) + .setStack(stack) + .build(); + if (mOnTop) { + // We move the task to front again in order to regain focus after activity + // added to the stack. + // Or {@link ActivityDisplay#mPreferredTopFocusableStack} could be other + // stacks (e.g. home stack). + stack.moveToFront("createActivityStack"); + } else { + stack.moveToBack("createActivityStack", null); + } + } } + + spyOn(stack); + spyOn(stack.mTaskStack); + doNothing().when(stack).startActivityLocked( + any(), any(), anyBoolean(), anyBoolean(), any()); + + return stack; } } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java index 20379a2427be..e71c8f47a69f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -60,7 +60,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); final AppWindowToken translucentOpening = createAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - translucentOpening.setFillsParent(false); + translucentOpening.setOccludesParent(false); translucentOpening.setHidden(true); mDisplayContent.mOpeningApps.add(behind); mDisplayContent.mOpeningApps.add(translucentOpening); @@ -78,7 +78,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); final AppWindowToken translucentClosing = createAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - translucentClosing.setFillsParent(false); + translucentClosing.setOccludesParent(false); mDisplayContent.mClosingApps.add(translucentClosing); assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE, mAppTransitionController.maybeUpdateTransitToTranslucentAnim( @@ -94,7 +94,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); final AppWindowToken translucentOpening = createAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - translucentOpening.setFillsParent(false); + translucentOpening.setOccludesParent(false); translucentOpening.setHidden(true); mDisplayContent.mOpeningApps.add(behind); mDisplayContent.mOpeningApps.add(translucentOpening); @@ -110,10 +110,10 @@ public class AppTransitionControllerTest extends WindowTestsBase { synchronized (mWm.mGlobalLock) { final AppWindowToken opening = createAppWindowToken(mDisplayContent, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD); - opening.setFillsParent(false); + opening.setOccludesParent(false); final AppWindowToken closing = createAppWindowToken(mDisplayContent, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD); - closing.setFillsParent(false); + closing.setOccludesParent(false); Task task = opening.getTask(); mDisplayContent.mOpeningApps.add(opening); mDisplayContent.mClosingApps.add(closing); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index d1dc38273a28..c162b6a5a289 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -30,12 +30,14 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; 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 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 android.graphics.Rect; import android.os.IBinder; @@ -195,6 +197,7 @@ public class AppTransitionTests extends WindowTestsBase { @Test public void testCancelRemoteAnimationWhenFreeze() { final DisplayContent dc = createNewDisplay(Display.STATE_ON); + doReturn(false).when(dc).onDescendantOrientationChanged(any(), any()); final WindowState exitingAppWindow = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "exiting app"); final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken; diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index d9566a3c871d..e387e186182b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -36,7 +36,7 @@ import static android.view.WindowManager.TRANSIT_UNSET; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE; @@ -152,10 +152,6 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test @FlakyTest(bugId = 131005232) public void testLandscapeSeascapeRotationByApp() { - // Some plumbing to get the service ready for rotation updates. - mWm.mDisplayReady = true; - mWm.mDisplayEnabled = true; - final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( TYPE_BASE_APPLICATION); attrs.setTitle("AppWindow"); @@ -185,25 +181,21 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test public void testLandscapeSeascapeRotationByPolicy() { - // Some plumbing to get the service ready for rotation updates. - mWm.mDisplayReady = true; - mWm.mDisplayEnabled = true; - - final DisplayRotation spiedRotation = spy(mDisplayContent.getDisplayRotation()); - mDisplayContent.setDisplayRotation(spiedRotation); + final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation(); + spyOn(displayRotation); final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( TYPE_BASE_APPLICATION); - attrs.setTitle("AppWindow"); + attrs.setTitle("RotationByPolicy"); final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, mToken); mToken.addWindow(appWindow); // Set initial orientation and update. - performRotation(spiedRotation, Surface.ROTATION_90); + performRotation(displayRotation, Surface.ROTATION_90); appWindow.mResizeReported = false; // Update the rotation to perform 180 degree rotation and check that resize was reported. - performRotation(spiedRotation, Surface.ROTATION_270); + performRotation(displayRotation, Surface.ROTATION_270); assertTrue(appWindow.mResizeReported); appWindow.removeImmediately(); @@ -211,14 +203,7 @@ public class AppWindowTokenTests extends WindowTestsBase { private void performRotation(DisplayRotation spiedRotation, int rotationToReport) { doReturn(rotationToReport).when(spiedRotation).rotationForOrientation(anyInt(), anyInt()); - int oldRotation = mDisplayContent.getRotation(); mWm.updateRotation(false, false); - // Must manually apply here since ATM doesn't know about the display during this test - // (meaning it can't perform the normal sendNewConfiguration flow). - mDisplayContent.applyRotationLocked(oldRotation, mDisplayContent.getRotation()); - // Prevent the next rotation from being deferred by animation. - mWm.mAnimator.setScreenRotationAnimationLocked(mDisplayContent.getDisplayId(), null); - mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */); } @Test @@ -266,14 +251,14 @@ public class AppWindowTokenTests extends WindowTestsBase { public void testGetOrientation() { mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); - mToken.setFillsParent(false); - // Can specify orientation if app doesn't fill parent. + mToken.setOccludesParent(false); + // Can specify orientation if app doesn't occludes parent. assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mToken.getOrientation()); - mToken.setFillsParent(true); + mToken.setOccludesParent(true); mToken.setHidden(true); mToken.sendingToBottom = true; - // Can not specify orientation if app isn't visible even though it fills parent. + // Can not specify orientation if app isn't visible even though it occludes parent. assertEquals(SCREEN_ORIENTATION_UNSET, mToken.getOrientation()); // Can specify orientation if the current orientation candidate is orientation behind. assertEquals(SCREEN_ORIENTATION_LANDSCAPE, diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 388658dfac88..62897687b8ad 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -83,7 +83,6 @@ import android.view.test.InsetsModeSession; import androidx.test.filters.SmallTest; -import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.server.wm.utils.WmDisplayCutout; @@ -653,25 +652,27 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testOnDescendantOrientationRequestChanged() { final DisplayContent dc = createNewDisplay(); - mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class); + dc.getDisplayRotation().setFixedToUserRotation( + DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED); final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE; - final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w"); - window.getTask().mTaskRecord = mock(TaskRecord.class, ExtendedMockito.RETURNS_DEEP_STUBS); - window.mAppToken.setOrientation(newOrientation); - - ActivityRecord activityRecord = mock(ActivityRecord.class); + final ActivityStack stack = + new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootActivityContainer) + .setDisplay(dc.mAcitvityDisplay).build(); + final ActivityRecord activity = stack.topTask().getTopActivity(); - assertTrue("Display should rotate to handle orientation request by default.", - dc.onDescendantOrientationChanged(window.mToken.token, activityRecord)); + activity.setRequestedOrientation(newOrientation); final ArgumentCaptor<Configuration> captor = ArgumentCaptor.forClass(Configuration.class); verify(dc.mAcitvityDisplay).updateDisplayOverrideConfigurationLocked(captor.capture(), - same(activityRecord), anyBoolean(), same(null)); + same(activity), anyBoolean(), same(null)); final Configuration newDisplayConfig = captor.getValue(); - assertEquals(Configuration.ORIENTATION_PORTRAIT, newDisplayConfig.orientation); + final int expectedOrientation = newOrientation == SCREEN_ORIENTATION_PORTRAIT + ? Configuration.ORIENTATION_PORTRAIT + : Configuration.ORIENTATION_LANDSCAPE; + assertEquals(expectedOrientation, newDisplayConfig.orientation); } @Test @@ -679,22 +680,20 @@ public class DisplayContentTests extends WindowTestsBase { final DisplayContent dc = createNewDisplay(); dc.getDisplayRotation().setFixedToUserRotation( DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED); - mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class); final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE; - final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w"); - window.getTask().mTaskRecord = mock(TaskRecord.class, ExtendedMockito.RETURNS_DEEP_STUBS); - window.mAppToken.setOrientation(newOrientation); + final ActivityStack stack = + new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootActivityContainer) + .setDisplay(dc.mAcitvityDisplay).build(); + final ActivityRecord activity = stack.topTask().getTopActivity(); - ActivityRecord activityRecord = mock(ActivityRecord.class); + activity.setRequestedOrientation(newOrientation); - assertFalse("Display shouldn't rotate to handle orientation request if fixed to" - + " user rotation.", - dc.onDescendantOrientationChanged(window.mToken.token, activityRecord)); verify(dc.mAcitvityDisplay, never()).updateDisplayOverrideConfigurationLocked(any(), - eq(activityRecord), anyBoolean(), same(null)); + eq(activity), anyBoolean(), same(null)); + assertEquals(dc.getDisplayRotation().getUserRotation(), dc.getRotation()); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java index bfede51f5a3c..f6f8811f2317 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java @@ -95,7 +95,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase { public void setUp() throws Exception { deleteRecursively(TEST_FOLDER); - mWm.setSupportsFreeformWindowManagement(false); + mWm.mAtmService.mSupportsFreeformWindowManagement = false; mWm.setIsPc(false); mWm.setForceDesktopModeOnExternalDisplays(false); @@ -134,7 +134,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase { @Test public void testPrimaryDisplayDefaultToFullscreen_HasFreeformSupport_NonPc_NoDesktopMode() { - mWm.setSupportsFreeformWindowManagement(true); + mWm.mAtmService.mSupportsFreeformWindowManagement = true; mTarget.applySettingsToDisplayLocked(mPrimaryDisplay); @@ -144,7 +144,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase { @Test public void testPrimaryDisplayDefaultToFullscreen_HasFreeformSupport_NonPc_HasDesktopMode() { - mWm.setSupportsFreeformWindowManagement(true); + mWm.mAtmService.mSupportsFreeformWindowManagement = true; mWm.setForceDesktopModeOnExternalDisplays(true); mTarget.applySettingsToDisplayLocked(mPrimaryDisplay); @@ -155,7 +155,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase { @Test public void testPrimaryDisplayDefaultToFreeform_HasFreeformSupport_IsPc() { - mWm.setSupportsFreeformWindowManagement(true); + mWm.mAtmService.mSupportsFreeformWindowManagement = true; mWm.setIsPc(true); mTarget.applySettingsToDisplayLocked(mPrimaryDisplay); @@ -168,7 +168,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase { public void testPrimaryDisplayUpdateToFreeform_HasFreeformSupport_IsPc() { mTarget.applySettingsToDisplayLocked(mPrimaryDisplay); - mWm.setSupportsFreeformWindowManagement(true); + mWm.mAtmService.mSupportsFreeformWindowManagement = true; mWm.setIsPc(true); mTarget.updateSettingsForDisplay(mPrimaryDisplay); @@ -187,7 +187,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase { @Test public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_NonPc_NoDesktopMode() { - mWm.setSupportsFreeformWindowManagement(true); + mWm.mAtmService.mSupportsFreeformWindowManagement = true; mTarget.applySettingsToDisplayLocked(mSecondaryDisplay); @@ -197,7 +197,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase { @Test public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_NonPc_HasDesktopMode() { - mWm.setSupportsFreeformWindowManagement(true); + mWm.mAtmService.mSupportsFreeformWindowManagement = true; mWm.setForceDesktopModeOnExternalDisplays(true); mTarget.applySettingsToDisplayLocked(mSecondaryDisplay); @@ -208,7 +208,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase { @Test public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_IsPc() { - mWm.setSupportsFreeformWindowManagement(true); + mWm.mAtmService.mSupportsFreeformWindowManagement = true; mWm.setIsPc(true); mTarget.applySettingsToDisplayLocked(mSecondaryDisplay); diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java index b28ae40d5056..be2ee2909a22 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java @@ -331,7 +331,9 @@ public class LaunchParamsControllerTests extends ActivityTestsBase { mController.layoutTask(task, null /* windowLayout */); - assertEquals(expected, task.getBounds()); + // TaskRecord will make adjustments to requested bounds. We only need to guarantee that the + // reuqested bounds are expected. + assertEquals(expected, task.getRequestedOverrideBounds()); } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java index e4d3770de54c..49d778f023e5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java @@ -104,6 +104,7 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase { mDisplayUniqueId = "test:" + Integer.toString(sNextUniqueId++); final DisplayInfo info = new DisplayInfo(); + mService.mContext.getDisplay().getDisplayInfo(info); info.uniqueId = mDisplayUniqueId; mTestDisplay = createNewActivityDisplay(info); mRootActivityContainer.addChild(mTestDisplay, ActivityDisplay.POSITION_TOP); diff --git a/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java index 63d9fb9c17e9..efd468f1f77a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/PinnedStackControllerTest.java @@ -61,7 +61,7 @@ public class PinnedStackControllerTest extends WindowTestsBase { @Test public void setShelfHeight_shelfVisibilityChangedTriggered() throws RemoteException { - mWm.mSupportsPictureInPicture = true; + mWm.mAtmService.mSupportsPictureInPicture = true; mWm.registerPinnedStackListener(DEFAULT_DISPLAY, mIPinnedStackListener); verify(mIPinnedStackListener).onImeVisibilityChanged(false, 0); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index b7a85d7bb5b7..fb4e330f06ed 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -32,7 +32,7 @@ import static android.view.Display.DEFAULT_DISPLAY; 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.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; @@ -53,14 +53,12 @@ import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityTaskManager; import android.app.WindowConfiguration; import android.content.ComponentName; -import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.UserInfo; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; -import android.os.Looper; import android.os.RemoteException; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; @@ -93,11 +91,8 @@ public class RecentTasksTest extends ActivityTestsBase { private static final int TEST_QUIET_USER_ID = 20; private static final UserInfo DEFAULT_USER_INFO = new UserInfo(); private static final UserInfo QUIET_USER_INFO = new UserInfo(); - private static int sLastTaskId = 1; - private static int sLastStackId = 1; private static final int INVALID_STACK_ID = 999; - private TestActivityTaskManagerService mTestService; private ActivityDisplay mDisplay; private ActivityDisplay mOtherDisplay; private ActivityDisplay mSingleTaskDisplay; @@ -115,13 +110,29 @@ public class RecentTasksTest extends ActivityTestsBase { @Before public void setUp() throws Exception { mTaskPersister = new TestTaskPersister(mContext.getFilesDir()); - mTestService = new MyTestActivityTaskManagerService(mContext); - mRecentTasks = (TestRecentTasks) mTestService.getRecentTasks(); + + // Set testing displays + mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY); + mOtherDisplay = createNewActivityDisplay(); + mSingleTaskDisplay = createNewActivityDisplay(); + mSingleTaskDisplay.setDisplayToSingleTaskInstance(); + mRootActivityContainer.addChild(mOtherDisplay, ActivityDisplay.POSITION_TOP); + mRootActivityContainer.addChild(mDisplay, ActivityDisplay.POSITION_TOP); + mRootActivityContainer.addChild(mSingleTaskDisplay, ActivityDisplay.POSITION_TOP); + + // Set the recent tasks we should use for testing in this class. + mRecentTasks = new TestRecentTasks(mService, mTaskPersister); + spyOn(mRecentTasks); + mService.setRecentTasks(mRecentTasks); mRecentTasks.loadParametersFromResources(mContext.getResources()); - mRunningTasks = (TestRunningTasks) mTestService.mStackSupervisor.mRunningTasks; - mHomeStack = mTestService.mRootActivityContainer.getDefaultDisplay().getOrCreateStack( + + // Set the running tasks we should use for testing in this class. + mRunningTasks = new TestRunningTasks(); + mService.mStackSupervisor.setRunningTasks(mRunningTasks); + + mHomeStack = mDisplay.getOrCreateStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - mStack = mTestService.mRootActivityContainer.getDefaultDisplay().createStack( + mStack = mDisplay.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); mCallbacksRecorder = new CallbacksRecorder(); mRecentTasks.registerCallback(mCallbacksRecorder); @@ -723,7 +734,7 @@ public class RecentTasksTest extends ActivityTestsBase { ActivityStack stack = mTasks.get(2).getStack(); stack.moveToFront("", mTasks.get(2)); - doReturn(stack).when(mTestService.mRootActivityContainer).getTopDisplayFocusedStack(); + doReturn(stack).when(mService.mRootActivityContainer).getTopDisplayFocusedStack(); // Simulate the reset from the timeout mRecentTasks.resetFreezeTaskListReorderingOnTimeout(); @@ -742,10 +753,9 @@ public class RecentTasksTest extends ActivityTestsBase { public void testBackStackTasks_expectNoTrim() { mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */); - final MyTestActivityStackSupervisor supervisor = - (MyTestActivityStackSupervisor) mTestService.mStackSupervisor; final ActivityStack homeStack = mDisplay.getHomeStack(); - final ActivityStack aboveHomeStack = new MyTestActivityStack(mDisplay, supervisor); + final ActivityStack aboveHomeStack = mDisplay.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Add a number of tasks (beyond the max) but ensure that nothing is trimmed because all // the tasks belong in stacks above the home stack @@ -761,11 +771,11 @@ public class RecentTasksTest extends ActivityTestsBase { public void testBehindHomeStackTasks_expectTaskTrimmed() { mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */); - final MyTestActivityStackSupervisor supervisor = - (MyTestActivityStackSupervisor) mTestService.mStackSupervisor; - final ActivityStack behindHomeStack = new MyTestActivityStack(mDisplay, supervisor); + final ActivityStack behindHomeStack = mDisplay.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); final ActivityStack homeStack = mDisplay.getHomeStack(); - final ActivityStack aboveHomeStack = new MyTestActivityStack(mDisplay, supervisor); + final ActivityStack aboveHomeStack = mDisplay.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Add a number of tasks (beyond the max) but ensure that only the task in the stack behind // the home stack is trimmed once a new task is added @@ -783,10 +793,9 @@ public class RecentTasksTest extends ActivityTestsBase { public void testOtherDisplayTasks_expectNoTrim() { mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */); - final MyTestActivityStackSupervisor supervisor = - (MyTestActivityStackSupervisor) mTestService.mStackSupervisor; final ActivityStack homeStack = mDisplay.getHomeStack(); - final ActivityStack otherDisplayStack = new MyTestActivityStack(mOtherDisplay, supervisor); + final ActivityStack otherDisplayStack = mOtherDisplay.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Add a number of tasks (beyond the max) on each display, ensure that the tasks are not // removed @@ -887,16 +896,16 @@ public class RecentTasksTest extends ActivityTestsBase { mStack.remove(); // The following APIs should not restore task from recents to the active list. - assertNotRestoreTask(() -> mTestService.setFocusedTask(taskId)); - assertNotRestoreTask(() -> mTestService.startSystemLockTaskMode(taskId)); - assertNotRestoreTask(() -> mTestService.cancelTaskWindowTransition(taskId)); + assertNotRestoreTask(() -> mService.setFocusedTask(taskId)); + assertNotRestoreTask(() -> mService.startSystemLockTaskMode(taskId)); + assertNotRestoreTask(() -> mService.cancelTaskWindowTransition(taskId)); assertNotRestoreTask( - () -> mTestService.resizeTask(taskId, null /* bounds */, 0 /* resizeMode */)); + () -> mService.resizeTask(taskId, null /* bounds */, 0 /* resizeMode */)); assertNotRestoreTask( - () -> mTestService.setTaskWindowingMode(taskId, WINDOWING_MODE_FULLSCREEN, + () -> mService.setTaskWindowingMode(taskId, WINDOWING_MODE_FULLSCREEN, false/* toTop */)); assertNotRestoreTask( - () -> mTestService.setTaskWindowingModeSplitScreenPrimary(taskId, + () -> mService.setTaskWindowingModeSplitScreenPrimary(taskId, SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, false /* toTop */, false /* animate */, null /* initialBounds */, true /* showRecents */)); @@ -910,7 +919,7 @@ public class RecentTasksTest extends ActivityTestsBase { mRecentTasks.remove(task); TaskChangeNotificationController controller = - mTestService.getTaskChangeNotificationController(); + mService.getTaskChangeNotificationController(); verify(controller, times(2)).notifyTaskListUpdated(); } @@ -923,7 +932,7 @@ public class RecentTasksTest extends ActivityTestsBase { // 2 calls - Once for add and once for remove TaskChangeNotificationController controller = - mTestService.getTaskChangeNotificationController(); + mService.getTaskChangeNotificationController(); verify(controller, times(2)).notifyTaskListUpdated(); } @@ -938,7 +947,7 @@ public class RecentTasksTest extends ActivityTestsBase { // 4 calls - Twice for add and twice for remove TaskChangeNotificationController controller = - mTestService.getTaskChangeNotificationController(); + mService.getTaskChangeNotificationController(); verify(controller, times(4)).notifyTaskListUpdated(); } @@ -980,7 +989,7 @@ public class RecentTasksTest extends ActivityTestsBase { @Test public void testNotRecentsComponent_denyApiAccess() throws Exception { - doReturn(PackageManager.PERMISSION_DENIED).when(mTestService) + doReturn(PackageManager.PERMISSION_DENIED).when(mService) .checkGetTasksPermission(anyString(), anyInt(), anyInt()); // Expect the following methods to fail due to recents component not being set mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.DENY_THROW_SECURITY_EXCEPTION); @@ -992,7 +1001,7 @@ public class RecentTasksTest extends ActivityTestsBase { @Test public void testRecentsComponent_allowApiAccessWithoutPermissions() { - doReturn(PackageManager.PERMISSION_DENIED).when(mTestService) + doReturn(PackageManager.PERMISSION_DENIED).when(mService) .checkGetTasksPermission(anyString(), anyInt(), anyInt()); // Set the recents component and ensure that the following calls do not fail @@ -1002,62 +1011,62 @@ public class RecentTasksTest extends ActivityTestsBase { } private void doTestRecentTasksApis(boolean expectCallable) { - assertSecurityException(expectCallable, () -> mTestService.removeStack(INVALID_STACK_ID)); + assertSecurityException(expectCallable, () -> mService.removeStack(INVALID_STACK_ID)); assertSecurityException(expectCallable, - () -> mTestService.removeStacksInWindowingModes( + () -> mService.removeStacksInWindowingModes( new int[]{WINDOWING_MODE_UNDEFINED})); assertSecurityException(expectCallable, - () -> mTestService.removeStacksWithActivityTypes( + () -> mService.removeStacksWithActivityTypes( new int[]{ACTIVITY_TYPE_UNDEFINED})); - assertSecurityException(expectCallable, () -> mTestService.removeTask(0)); + assertSecurityException(expectCallable, () -> mService.removeTask(0)); assertSecurityException(expectCallable, - () -> mTestService.setTaskWindowingMode(0, WINDOWING_MODE_UNDEFINED, true)); + () -> mService.setTaskWindowingMode(0, WINDOWING_MODE_UNDEFINED, true)); assertSecurityException(expectCallable, - () -> mTestService.moveTaskToStack(0, INVALID_STACK_ID, true)); + () -> mService.moveTaskToStack(0, INVALID_STACK_ID, true)); assertSecurityException(expectCallable, - () -> mTestService.setTaskWindowingModeSplitScreenPrimary(0, + () -> mService.setTaskWindowingModeSplitScreenPrimary(0, SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, true, true, new Rect(), true)); - assertSecurityException(expectCallable, () -> mTestService.dismissSplitScreenMode(true)); - assertSecurityException(expectCallable, () -> mTestService.dismissPip(true, 0)); + assertSecurityException(expectCallable, () -> mService.dismissSplitScreenMode(true)); + assertSecurityException(expectCallable, () -> mService.dismissPip(true, 0)); assertSecurityException(expectCallable, - () -> mTestService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect())); + () -> mService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect())); assertSecurityException(expectCallable, - () -> mTestService.resizeStack(INVALID_STACK_ID, new Rect(), true, true, true, 0)); + () -> mService.resizeStack(INVALID_STACK_ID, new Rect(), true, true, true, 0)); assertSecurityException(expectCallable, - () -> mTestService.resizeDockedStack(new Rect(), new Rect(), new Rect(), new Rect(), + () -> mService.resizeDockedStack(new Rect(), new Rect(), new Rect(), new Rect(), new Rect())); assertSecurityException(expectCallable, - () -> mTestService.resizePinnedStack(new Rect(), new Rect())); - assertSecurityException(expectCallable, () -> mTestService.getAllStackInfos()); + () -> mService.resizePinnedStack(new Rect(), new Rect())); + assertSecurityException(expectCallable, () -> mService.getAllStackInfos()); assertSecurityException(expectCallable, - () -> mTestService.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED)); + () -> mService.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED)); assertSecurityException(expectCallable, () -> { try { - mTestService.getFocusedStackInfo(); + mService.getFocusedStackInfo(); } catch (RemoteException e) { // Ignore } }); assertSecurityException(expectCallable, - () -> mTestService.moveTasksToFullscreenStack(INVALID_STACK_ID, true)); + () -> mService.moveTasksToFullscreenStack(INVALID_STACK_ID, true)); assertSecurityException(expectCallable, - () -> mTestService.startActivityFromRecents(0, new Bundle())); - assertSecurityException(expectCallable, () -> mTestService.getTaskSnapshot(0, true)); - assertSecurityException(expectCallable, () -> mTestService.registerTaskStackListener(null)); + () -> mService.startActivityFromRecents(0, new Bundle())); + assertSecurityException(expectCallable, () -> mService.getTaskSnapshot(0, true)); + assertSecurityException(expectCallable, () -> mService.registerTaskStackListener(null)); assertSecurityException(expectCallable, - () -> mTestService.unregisterTaskStackListener(null)); - assertSecurityException(expectCallable, () -> mTestService.getTaskDescription(0)); - assertSecurityException(expectCallable, () -> mTestService.cancelTaskWindowTransition(0)); - assertSecurityException(expectCallable, () -> mTestService.startRecentsActivity(null, null, + () -> mService.unregisterTaskStackListener(null)); + assertSecurityException(expectCallable, () -> mService.getTaskDescription(0)); + assertSecurityException(expectCallable, () -> mService.cancelTaskWindowTransition(0)); + assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null, null)); - assertSecurityException(expectCallable, () -> mTestService.cancelRecentsAnimation(true)); - assertSecurityException(expectCallable, () -> mTestService.stopAppSwitches()); - assertSecurityException(expectCallable, () -> mTestService.resumeAppSwitches()); + assertSecurityException(expectCallable, () -> mService.cancelRecentsAnimation(true)); + assertSecurityException(expectCallable, () -> mService.stopAppSwitches()); + assertSecurityException(expectCallable, () -> mService.resumeAppSwitches()); } private void testGetTasksApis(boolean expectCallable) { - mTestService.getRecentTasks(MAX_VALUE, 0, TEST_USER_0_ID); - mTestService.getTasks(MAX_VALUE); + mService.getRecentTasks(MAX_VALUE, 0, TEST_USER_0_ID); + mService.getTasks(MAX_VALUE); if (expectCallable) { assertTrue(mRecentTasks.mLastAllowed); assertTrue(mRunningTasks.mLastAllowed); @@ -1072,10 +1081,9 @@ public class RecentTasksTest extends ActivityTestsBase { } private TaskBuilder createTaskBuilder(String packageName, String className) { - return new TaskBuilder(mTestService.mStackSupervisor) + return new TaskBuilder(mService.mStackSupervisor) .setComponent(new ComponentName(packageName, className)) .setStack(mStack) - .setTaskId(sLastTaskId++) .setUserId(TEST_USER_0_ID); } @@ -1140,68 +1148,6 @@ public class RecentTasksTest extends ActivityTestsBase { } } - private class MyTestActivityTaskManagerService extends TestActivityTaskManagerService { - MyTestActivityTaskManagerService(Context context) { - super(context); - } - - @Override - protected RecentTasks createRecentTasks() { - return spy(new TestRecentTasks(this, mTaskPersister)); - } - - @Override - protected ActivityStackSupervisor createStackSupervisor() { - if (mTestStackSupervisor == null) { - mTestStackSupervisor = new MyTestActivityStackSupervisor(this, mH.getLooper()); - } - return mTestStackSupervisor; - } - - @Override - void createDefaultDisplay() { - super.createDefaultDisplay(); - mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY); - mOtherDisplay = TestActivityDisplay.create(mTestStackSupervisor, DEFAULT_DISPLAY + 1); - mSingleTaskDisplay = TestActivityDisplay.create(mTestStackSupervisor, - DEFAULT_DISPLAY + 2); - mSingleTaskDisplay.setDisplayToSingleTaskInstance(); - mRootActivityContainer.addChild(mOtherDisplay, ActivityDisplay.POSITION_TOP); - mRootActivityContainer.addChild(mDisplay, ActivityDisplay.POSITION_TOP); - mRootActivityContainer.addChild(mSingleTaskDisplay, ActivityDisplay.POSITION_TOP); - } - } - - private class MyTestActivityStackSupervisor extends TestActivityStackSupervisor { - MyTestActivityStackSupervisor(ActivityTaskManagerService service, Looper looper) { - super(service, looper); - } - - @Override - RunningTasks createRunningTasks() { - mRunningTasks = new TestRunningTasks(); - return mRunningTasks; - } - } - - private static class MyTestActivityStack extends TestActivityStack { - private ActivityDisplay mDisplay = null; - - MyTestActivityStack(ActivityDisplay display, ActivityStackSupervisor supervisor) { - super(display, sLastStackId++, supervisor, WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_STANDARD, true /* onTop */, false /* createActivity */); - mDisplay = display; - } - - @Override - ActivityDisplay getDisplay() { - if (mDisplay != null) { - return mDisplay; - } - return super.getDisplay(); - } - } - private static class CallbacksRecorder implements Callbacks { public final ArrayList<TaskRecord> mAdded = new ArrayList<>(); public final ArrayList<TaskRecord> mTrimmed = new ArrayList<>(); 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 f5a1d752590e..9ca0180e507d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -30,6 +30,7 @@ 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; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; +import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION; @@ -132,8 +133,14 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { @Test public void testIncludedApps_expectTargetAndVisible() { mWm.setRecentsAnimationController(mController); - final AppWindowToken homeAppWindow = createAppWindowToken(mDisplayContent, - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); + final ActivityStack homStack = mDisplayContent.mAcitvityDisplay.getOrCreateStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); + final AppWindowToken homeAppWindow = + new ActivityTestsBase.ActivityBuilder(mWm.mAtmService) + .setStack(homStack) + .setCreateTask(true) + .build() + .mAppWindowToken; final AppWindowToken appWindow = createAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); final AppWindowToken hiddenAppWindow = createAppWindowToken(mDisplayContent, @@ -169,7 +176,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { // Simulate the app transition finishing mController.mAppTransitionListener.onAppTransitionStartingLocked(0, 0, 0, 0); - verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false); + verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, false); } @Test @@ -201,7 +208,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { spyOn(mController.mRecentScreenshotAnimator.mAnimatable); mController.mRecentScreenshotAnimator.cancelAnimation(); verify(mController.mRecentScreenshotAnimator.mAnimatable).onAnimationLeashLost(any()); - verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false); + verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, false); } @Test 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 0e119e3cc375..dcc295c4aab3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java @@ -74,8 +74,9 @@ public class RecentsAnimationTest extends ActivityTestsBase { @Before public void setUp() throws Exception { mRecentsAnimationController = mock(RecentsAnimationController.class); - doReturn(mRecentsAnimationController).when( - mService.mWindowManager).getRecentsAnimationController(); + mService.mWindowManager.setRecentsAnimationController(mRecentsAnimationController); + doNothing().when(mService.mWindowManager).initializeRecentsAnimation( + anyInt(), any(), any(), anyInt(), any()); doReturn(true).when(mService.mWindowManager).canStartRecentsAnimation(); final RecentTasks recentTasks = mService.getRecentTasks(); @@ -107,16 +108,25 @@ public class RecentsAnimationTest extends ActivityTestsBase { assertTrue(recentActivity.visible); // Simulate the animation is cancelled without changing the stack order. - recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, true /* runSychronously */, - false /* sendUserLeaveHint */); + recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, false /* sendUserLeaveHint */); // The non-top recents activity should be invisible by the restored launch-behind state. assertFalse(recentActivity.visible); } @Test public void testPreloadRecentsActivity() { - // Ensure that the fake recent component can be resolved by the recents intent. - mockTaskRecordFactory(builder -> builder.setComponent(mRecentsComponent)); + final ActivityDisplay defaultDisplay = mRootActivityContainer.getDefaultDisplay(); + final ActivityStack homeStack = + defaultDisplay.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); + defaultDisplay.positionChildAtTop(homeStack, false /* includingParents */); + ActivityRecord topRunningHomeActivity = homeStack.topRunningActivityLocked(); + if (topRunningHomeActivity == null) { + topRunningHomeActivity = new ActivityBuilder(mService) + .setStack(homeStack) + .setCreateTask(true) + .build(); + } + ActivityInfo aInfo = new ActivityInfo(); aInfo.applicationInfo = new ApplicationInfo(); aInfo.applicationInfo.uid = 10001; @@ -204,6 +214,13 @@ public class RecentsAnimationTest extends ActivityTestsBase { ActivityStack homeStack = display.getHomeStack(); // Assume the home activity support recents. ActivityRecord targetActivity = homeStack.getTopActivity(); + if (targetActivity == null) { + targetActivity = new ActivityBuilder(mService) + .setCreateTask(true) + .setStack(homeStack) + .build(); + } + // Put another home activity in home stack. ActivityRecord anotherHomeActivity = new ActivityBuilder(mService) .setComponent(new ComponentName(mContext.getPackageName(), "Home2")) @@ -226,13 +243,12 @@ public class RecentsAnimationTest extends ActivityTestsBase { anotherHomeActivity.moveFocusableActivityToTop("launchAnotherHome"); // The current top activity is not the recents so the animation should be canceled. - verify(mService.mWindowManager, times(1)).cancelRecentsAnimationSynchronously( + verify(mService.mWindowManager, times(1)).cancelRecentsAnimation( eq(REORDER_KEEP_IN_PLACE), any() /* reason */); // The test uses mocked RecentsAnimationController so we have to invoke the callback // manually to simulate the flow. - recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, true /* runSychronously */, - false /* sendUserLeaveHint */); + recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, false /* sendUserLeaveHint */); // We should restore the launch-behind of the original target activity. assertFalse(targetActivity.mLaunchTaskBehind); } @@ -269,7 +285,7 @@ public class RecentsAnimationTest extends ActivityTestsBase { fullscreenStack.moveToFront("Activity start"); // Ensure that the recents animation was canceled by cancelAnimationSynchronously(). - verify(mService.mWindowManager, times(1)).cancelRecentsAnimationSynchronously( + verify(mService.mWindowManager, times(1)).cancelRecentsAnimation( eq(REORDER_KEEP_IN_PLACE), any()); // Assume recents animation already started, set a state that cancel recents animation @@ -314,7 +330,7 @@ public class RecentsAnimationTest extends ActivityTestsBase { fullscreenStack.remove(); // Ensure that the recents animation was NOT canceled - verify(mService.mWindowManager, times(0)).cancelRecentsAnimationSynchronously( + verify(mService.mWindowManager, times(0)).cancelRecentsAnimation( eq(REORDER_KEEP_IN_PLACE), any()); verify(mRecentsAnimationController, times(0)).setCancelOnNextTransitionStart(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index d4f24f9b5717..539a79ccd783 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -97,7 +97,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { */ @Test public void testRestoringInvalidTask() { - ((TestActivityDisplay) mRootActivityContainer.getDefaultDisplay()).removeAllTasks(); + mRootActivityContainer.getDefaultDisplay().removeAllTasks(); TaskRecord task = mRootActivityContainer.anyTaskForId(0 /*taskId*/, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */); assertNull(task); @@ -304,21 +304,23 @@ public class RootActivityContainerTests extends ActivityTestsBase { */ @Test public void testResizeDockedStackForSplitScreenPrimary() { - final Rect taskSize = new Rect(0, 0, 600, 600); + final Rect taskSize = new Rect(0, 0, 1000, 1000); final Rect stackSize = new Rect(0, 0, 300, 300); // Create primary split-screen stack with a task. - final ActivityStack primaryStack = mRootActivityContainer.getDefaultDisplay() - .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, - true /* onTop */); - final TaskRecord task = new TaskBuilder(mSupervisor).setStack(primaryStack).build(); + final ActivityStack primaryStack = new StackBuilder(mRootActivityContainer) + .setActivityType(ACTIVITY_TYPE_STANDARD) + .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) + .setOnTop(true) + .build(); + final TaskRecord task = primaryStack.topTask(); // Resize dock stack. mService.resizeDockedStack(stackSize, taskSize, null, null, null); // Verify dock stack & its task bounds if is equal as resized result. - assertEquals(primaryStack.getBounds(), stackSize); - assertEquals(task.getBounds(), taskSize); + assertEquals(stackSize, primaryStack.getBounds()); + assertEquals(taskSize, task.getBounds()); } /** @@ -328,8 +330,9 @@ public class RootActivityContainerTests extends ActivityTestsBase { public void testFindTaskToMoveToFrontWhenRecentsOnTop() { // Create stack/task on default display. final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay(); - final TestActivityStack targetStack = (TestActivityStack) new StackBuilder( - mRootActivityContainer).setOnTop(false).build(); + final ActivityStack targetStack = new StackBuilder(mRootActivityContainer) + .setOnTop(false) + .build(); final TaskRecord targetTask = targetStack.getChildAt(0); // Create Recents on top of the display. @@ -505,12 +508,10 @@ public class RootActivityContainerTests extends ActivityTestsBase { mockResolveSecondaryHomeActivity(); // Create secondary displays. - final TestActivityDisplay secondDisplay = spy(createNewActivityDisplay()); + final TestActivityDisplay secondDisplay = createNewActivityDisplay(); mRootActivityContainer.addChild(secondDisplay, POSITION_TOP); doReturn(true).when(secondDisplay).supportsSystemDecorations(); - // Create mock tasks and other necessary mocks. - mockTaskRecordFactory(); doReturn(true).when(mRootActivityContainer) .ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean()); doReturn(true).when(mRootActivityContainer).canStartHomeOnDisplay( @@ -621,7 +622,6 @@ public class RootActivityContainerTests extends ActivityTestsBase { info.applicationInfo.packageName = "android"; info.name = ResolverActivity.class.getName(); doReturn(info).when(mRootActivityContainer).resolveHomeActivity(anyInt(), any()); - mockTaskRecordFactory(); mRootActivityContainer.startHomeOnDisplay(0 /* userId */, "test", DEFAULT_DISPLAY); final ActivityRecord resolverActivity = mRootActivityContainer.topRunningActivity(); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index f51ce131b7bc..db105ddc956d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -96,7 +96,7 @@ public class RootWindowContainerTests extends WindowTestsBase { mWm.getDefaultDisplayContentLocked().getWindowingMode()); mWm.mIsPc = true; - mWm.mSupportsFreeformWindowManagement = true; + mWm.mAtmService.mSupportsFreeformWindowManagement = true; mWm.mRoot.onSettingsRetrieved(); diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index df7c9a44dd12..1ad0e00bbd48 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -16,6 +16,9 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.os.Process.THREAD_PRIORITY_DEFAULT; import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader; import static android.view.Display.DEFAULT_DISPLAY; @@ -25,67 +28,91 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; 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.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.nullable; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.app.ActivityManagerInternal; import android.app.AppOpsManager; +import android.app.usage.UsageStatsManagerInternal; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.IntentFilter; +import android.content.pm.IPackageManager; +import android.content.pm.PackageManagerInternal; import android.database.ContentObserver; +import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerInternal; import android.net.Uri; import android.os.Handler; +import android.os.Looper; +import android.os.PowerManager; import android.os.PowerManagerInternal; import android.os.PowerSaveState; import android.os.UserHandle; -import android.view.Display; +import android.provider.DeviceConfig; import android.view.InputChannel; +import android.view.Surface; +import android.view.SurfaceControl; import com.android.dx.mockito.inline.extended.StaticMockitoSession; +import com.android.server.AnimationThread; +import com.android.server.DisplayThread; import com.android.server.LocalServices; import com.android.server.LockGuard; +import com.android.server.ServiceThread; import com.android.server.Watchdog; +import com.android.server.am.ActivityManagerService; +import com.android.server.appop.AppOpsService; +import com.android.server.display.color.ColorDisplayService; import com.android.server.input.InputManagerService; +import com.android.server.policy.PermissionPolicyInternal; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.wm.utils.MockTracker; +import com.android.server.statusbar.StatusBarManagerInternal; +import com.android.server.uri.UriGrantsManagerInternal; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; -import org.mockito.invocation.InvocationOnMock; +import org.mockito.Mockito; import org.mockito.quality.Strictness; +import java.io.File; import java.util.concurrent.atomic.AtomicBoolean; /** - * JUnit test rule to create a mock {@link WindowManagerService} instance for tests. + * JUnit test rule to correctly setting up system services like {@link WindowManagerService} + * and {@link ActivityTaskManagerService} for tests. */ public class SystemServicesTestRule implements TestRule { private static final String TAG = SystemServicesTestRule.class.getSimpleName(); + static int sNextDisplayId = DEFAULT_DISPLAY + 100; + static int sNextTaskId = 100; + private final AtomicBoolean mCurrentMessagesProcessed = new AtomicBoolean(false); - private MockTracker mMockTracker; + private Context mContext; private StaticMockitoSession mMockitoSession; - private WindowManagerService mWindowManagerService; - private TestWindowManagerPolicy mWindowManagerPolicy; - - /** {@link MockTracker} to track mocks created by {@link SystemServicesTestRule}. */ - private static class Tracker extends MockTracker { - // This empty extended class is necessary since Mockito distinguishes a listener by it - // class. - } + ServiceThread mHandlerThread; + private ActivityManagerService mAmService; + private ActivityTaskManagerService mAtmService; + private WindowManagerService mWmService; + private TestWindowManagerPolicy mWMPolicy; + private WindowState.PowerManagerWrapper mPowerManagerWrapper; + private InputManagerService mImService; + /** + * Spied {@link SurfaceControl.Transaction} class than can be used to verify calls. + */ + SurfaceControl.Transaction mTransaction; @Override public Statement apply(Statement base, Description description) { @@ -103,8 +130,6 @@ public class SystemServicesTestRule implements TestRule { } private void setUp() { - mMockTracker = new Tracker(); - mMockitoSession = mockitoSession() .spyStatic(LocalServices.class) .mockStatic(LockGuard.class) @@ -112,101 +137,220 @@ public class SystemServicesTestRule implements TestRule { .strictness(Strictness.LENIENT) .startMocking(); + setUpSystemCore(); + setUpLocalServices(); + setUpActivityTaskManagerService(); + setUpWindowManagerService(); + } + + private void setUpSystemCore() { + mHandlerThread = new ServiceThread( + "WmTestsThread", THREAD_PRIORITY_DEFAULT, true /* allowIo */); + mHandlerThread.start(); + doReturn(mock(Watchdog.class)).when(Watchdog::getInstance); - final Context context = getInstrumentation().getTargetContext(); - spyOn(context); + mContext = getInstrumentation().getTargetContext(); + spyOn(mContext); - doReturn(null).when(context) + doReturn(null).when(mContext) .registerReceiver(nullable(BroadcastReceiver.class), any(IntentFilter.class)); - doReturn(null).when(context) + doReturn(null).when(mContext) .registerReceiverAsUser(any(BroadcastReceiver.class), any(UserHandle.class), any(IntentFilter.class), nullable(String.class), nullable(Handler.class)); - final ContentResolver contentResolver = context.getContentResolver(); + final ContentResolver contentResolver = mContext.getContentResolver(); spyOn(contentResolver); doNothing().when(contentResolver) .registerContentObserver(any(Uri.class), anyBoolean(), any(ContentObserver.class), anyInt()); + } + + private void setUpLocalServices() { + // Tear down any local services just in case. + tearDownLocalServices(); - final AppOpsManager appOpsManager = mock(AppOpsManager.class); - doReturn(appOpsManager).when(context) - .getSystemService(eq(Context.APP_OPS_SERVICE)); + // UriGrantsManagerInternal + final UriGrantsManagerInternal ugmi = mock(UriGrantsManagerInternal.class); + LocalServices.addService(UriGrantsManagerInternal.class, ugmi); + // AppOpsManager + final AppOpsManager aom = mock(AppOpsManager.class); + doReturn(aom).when(mContext).getSystemService(eq(Context.APP_OPS_SERVICE)); + + // DisplayManagerInternal final DisplayManagerInternal dmi = mock(DisplayManagerInternal.class); doReturn(dmi).when(() -> LocalServices.getService(eq(DisplayManagerInternal.class))); + // ColorDisplayServiceInternal + final ColorDisplayService.ColorDisplayServiceInternal cds = + mock(ColorDisplayService.ColorDisplayServiceInternal.class); + doReturn(cds).when(() -> LocalServices.getService( + eq(ColorDisplayService.ColorDisplayServiceInternal.class))); + + final UsageStatsManagerInternal usmi = mock(UsageStatsManagerInternal.class); + LocalServices.addService(UsageStatsManagerInternal.class, usmi); + + // PackageManagerInternal + final PackageManagerInternal packageManagerInternal = mock(PackageManagerInternal.class); + LocalServices.addService(PackageManagerInternal.class, packageManagerInternal); + doReturn(false).when(packageManagerInternal).isPermissionsReviewRequired( + anyString(), anyInt()); + doReturn(null).when(packageManagerInternal).getDefaultHomeActivity(anyInt()); + + // PowerManagerInternal final PowerManagerInternal pmi = mock(PowerManagerInternal.class); final PowerSaveState state = new PowerSaveState.Builder().build(); doReturn(state).when(pmi).getLowPowerState(anyInt()); doReturn(pmi).when(() -> LocalServices.getService(eq(PowerManagerInternal.class))); - final ActivityManagerInternal ami = mock(ActivityManagerInternal.class); - doReturn(ami).when(() -> LocalServices.getService(eq(ActivityManagerInternal.class))); - - final ActivityTaskManagerInternal atmi = mock(ActivityTaskManagerInternal.class); - doAnswer((InvocationOnMock invocationOnMock) -> { - final Runnable runnable = invocationOnMock.getArgument(0); - if (runnable != null) { - runnable.run(); - } - return null; - }).when(atmi).notifyKeyguardFlagsChanged(nullable(Runnable.class), anyInt()); - doReturn(atmi).when(() -> LocalServices.getService(eq(ActivityTaskManagerInternal.class))); + // PermissionPolicyInternal + final PermissionPolicyInternal ppi = mock(PermissionPolicyInternal.class); + LocalServices.addService(PermissionPolicyInternal.class, ppi); + doReturn(true).when(ppi).checkStartActivity(any(), anyInt(), any()); - final InputManagerService ims = mock(InputManagerService.class); + // InputManagerService + mImService = mock(InputManagerService.class); // InputChannel is final and can't be mocked. final InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM); if (input != null && input.length > 1) { - doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt()); + doReturn(input[1]).when(mImService).monitorInput(anyString(), anyInt()); } - final ActivityTaskManagerService atms = mock(ActivityTaskManagerService.class); - final TaskChangeNotificationController taskChangeNotificationController = mock( - TaskChangeNotificationController.class); - doReturn(taskChangeNotificationController).when(atms).getTaskChangeNotificationController(); - final WindowManagerGlobalLock wmLock = new WindowManagerGlobalLock(); - doReturn(wmLock).when(atms).getGlobalLock(); - - mWindowManagerPolicy = new TestWindowManagerPolicy(this::getWindowManagerService); - mWindowManagerService = WindowManagerService.main( - context, ims, false, false, mWindowManagerPolicy, atms, StubTransaction::new); - - mWindowManagerService.onInitReady(); + // StatusBarManagerInternal + final StatusBarManagerInternal sbmi = mock(StatusBarManagerInternal.class); + doReturn(sbmi).when(() -> LocalServices.getService(eq(StatusBarManagerInternal.class))); + } - final Display display = mWindowManagerService.mDisplayManager.getDisplay(DEFAULT_DISPLAY); - // Display creation is driven by the ActivityManagerService via - // ActivityStackSupervisor. We emulate those steps here. - DisplayContent displayContent = mWindowManagerService.mRoot - .createDisplayContent(display, mock(ActivityDisplay.class)); - displayContent.reconfigureDisplayLocked(); + private void setUpActivityTaskManagerService() { + // ActivityManagerService + mAmService = new ActivityManagerService( + new AMTestInjector(mContext, mHandlerThread), mHandlerThread); + spyOn(mAmService); + doReturn(mock(IPackageManager.class)).when(mAmService).getPackageManager(); + doNothing().when(mAmService).grantEphemeralAccessLocked( + anyInt(), any(), anyInt(), anyInt()); + + // ActivityManagerInternal + final ActivityManagerInternal amInternal = mAmService.mInternal; + spyOn(amInternal); + doNothing().when(amInternal).trimApplications(); + doNothing().when(amInternal).updateCpuStats(); + doNothing().when(amInternal).updateOomAdj(); + doNothing().when(amInternal).updateBatteryStats(any(), anyInt(), anyInt(), anyBoolean()); + doNothing().when(amInternal).updateActivityUsageStats( + any(), anyInt(), anyInt(), any(), any()); + doNothing().when(amInternal).startProcess( + any(), any(), anyBoolean(), anyBoolean(), any(), any()); + doNothing().when(amInternal).updateOomLevelsForDisplay(anyInt()); + LocalServices.addService(ActivityManagerInternal.class, amInternal); + + mAtmService = new TestActivityTaskManagerService(mContext, mAmService); + LocalServices.addService(ActivityTaskManagerInternal.class, mAtmService.getAtmInternal()); + } - mMockTracker.stopTracking(); + private void setUpWindowManagerService() { + mPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class); + mWMPolicy = new TestWindowManagerPolicy(this::getWindowManagerService, + mPowerManagerWrapper); + mWmService = WindowManagerService.main( + mContext, mImService, false, false, mWMPolicy, mAtmService, StubTransaction::new); + spyOn(mWmService); + + // Setup factory classes to prevent calls to native code. + mTransaction = spy(StubTransaction.class); + // Return a spied Transaction class than can be used to verify calls. + mWmService.mTransactionFactory = () -> mTransaction; + // Return a SurfaceControl.Builder class that creates mocked SurfaceControl instances. + mWmService.mSurfaceBuilderFactory = (unused) -> new MockSurfaceControlBuilder(); + // Return mocked Surface instances. + mWmService.mSurfaceFactory = () -> mock(Surface.class); + mWmService.mSurfaceAnimationRunner = new SurfaceAnimationRunner( + null, null, mTransaction, mWmService.mPowerManagerInternal); + + mWmService.onInitReady(); + mAmService.setWindowManager(mWmService); + mWmService.mDisplayEnabled = true; + mWmService.mDisplayReady = true; + // Set configuration for default display + mWmService.getDefaultDisplayContentLocked().reconfigureDisplayLocked(); + + // Mock root, some default display, and home stack. + spyOn(mWmService.mRoot); + final ActivityDisplay display = mAtmService.mRootActivityContainer.getDefaultDisplay(); + spyOn(display); + spyOn(display.mDisplayContent); + final ActivityStack homeStack = display.getStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); + spyOn(homeStack); + spyOn(homeStack.mTaskStack); } private void tearDown() { waitUntilWindowManagerHandlersIdle(); - removeLocalServices(); - mWindowManagerService = null; - mWindowManagerPolicy = null; + // Unregister display listener from root to avoid issues with subsequent tests. + mContext.getSystemService(DisplayManager.class) + .unregisterDisplayListener(mAtmService.mRootActivityContainer); + // ProptertiesChangesListener is registered in the constructor of WindowManagerService to + // a static object, so we need to clean it up in tearDown(), even though we didn't set up + // in tests. + DeviceConfig.removeOnPropertiesChangedListener(mWmService.mPropertiesChangedListener); + mWmService = null; + mWMPolicy = null; + mPowerManagerWrapper = null; + + tearDownLocalServices(); + tearDownSystemCore(); + + // Needs to explicitly dispose current static threads because there could be messages + // scheduled at a later time, and all mocks are invalid when it's executed. + DisplayThread.dispose(); + AnimationThread.dispose(); + // Reset priority booster because animation thread has been changed. + WindowManagerService.sThreadPriorityBooster = new WindowManagerThreadPriorityBooster(); + + Mockito.framework().clearInlineMocks(); + } + + private void tearDownSystemCore() { if (mMockitoSession != null) { mMockitoSession.finishMocking(); mMockitoSession = null; } - if (mMockTracker != null) { - mMockTracker.close(); - mMockTracker = null; + if (mHandlerThread != null) { + // Make sure there are no running messages and then quit the thread so the next test + // won't be affected. + mHandlerThread.getThreadHandler().runWithScissors(mHandlerThread::quit, + 0 /* timeout */); } } - private static void removeLocalServices() { + private static void tearDownLocalServices() { + LocalServices.removeServiceForTest(DisplayManagerInternal.class); + LocalServices.removeServiceForTest(PowerManagerInternal.class); + LocalServices.removeServiceForTest(ActivityManagerInternal.class); + LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class); LocalServices.removeServiceForTest(WindowManagerInternal.class); LocalServices.removeServiceForTest(WindowManagerPolicy.class); + LocalServices.removeServiceForTest(PackageManagerInternal.class); + LocalServices.removeServiceForTest(UriGrantsManagerInternal.class); + LocalServices.removeServiceForTest(PermissionPolicyInternal.class); + LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class); + LocalServices.removeServiceForTest(UsageStatsManagerInternal.class); + LocalServices.removeServiceForTest(StatusBarManagerInternal.class); } WindowManagerService getWindowManagerService() { - return mWindowManagerService; + return mWmService; + } + + ActivityTaskManagerService getActivityTaskManagerService() { + return mAtmService; + } + + WindowState.PowerManagerWrapper getPowerManagerWrapper() { + return mPowerManagerWrapper; } void cleanupWindowManagerHandlers() { @@ -229,6 +373,7 @@ public class SystemServicesTestRule implements TestRule { waitHandlerIdle(wm.mH); waitHandlerIdle(wm.mAnimationHandler); waitHandlerIdle(SurfaceAnimationThread.getHandler()); + waitHandlerIdle(mHandlerThread.getThreadHandler()); } private void waitHandlerIdle(Handler handler) { @@ -251,4 +396,121 @@ public class SystemServicesTestRule implements TestRule { } } } + + protected class TestActivityTaskManagerService extends ActivityTaskManagerService { + // ActivityStackSupervisor may be created more than once while setting up AMS and ATMS. + // We keep the reference in order to prevent creating it twice. + ActivityStackSupervisor mTestStackSupervisor; + + TestActivityTaskManagerService(Context context, ActivityManagerService ams) { + super(context); + spyOn(this); + + mSupportsMultiWindow = true; + mSupportsMultiDisplay = true; + mSupportsSplitScreenMultiWindow = true; + mSupportsFreeformWindowManagement = true; + mSupportsPictureInPicture = true; + + doReturn(mock(IPackageManager.class)).when(this).getPackageManager(); + // allow background activity starts by default + doReturn(true).when(this).isBackgroundActivityStartsEnabled(); + doNothing().when(this).updateCpuStats(); + + // AppOpsService + final AppOpsService aos = mock(AppOpsService.class); + doReturn(aos).when(this).getAppOpsService(); + // Make sure permission checks aren't overridden. + doReturn(AppOpsManager.MODE_DEFAULT) + .when(aos).noteOperation(anyInt(), anyInt(), anyString()); + + setUsageStatsManager(LocalServices.getService(UsageStatsManagerInternal.class)); + ams.mActivityTaskManager = this; + ams.mAtmInternal = mInternal; + onActivityManagerInternalAdded(); + initialize( + ams.mIntentFirewall, ams.mPendingIntentController, mHandlerThread.getLooper()); + spyOn(getLifecycleManager()); + spyOn(getLockTaskController()); + spyOn(getTaskChangeNotificationController()); + initRootActivityContainerMocks(); + } + + void initRootActivityContainerMocks() { + spyOn(mRootActivityContainer); + // Invoked during {@link ActivityStack} creation. + doNothing().when(mRootActivityContainer).updateUIDsPresentOnDisplay(); + // Always keep things awake. + doReturn(true).when(mRootActivityContainer).hasAwakeDisplay(); + // Called when moving activity to pinned stack. + doNothing().when(mRootActivityContainer).ensureActivitiesVisible(any(), anyInt(), + anyBoolean()); + } + + @Override + int handleIncomingUser(int callingPid, int callingUid, int userId, String name) { + return userId; + } + + @Override + protected ActivityStackSupervisor createStackSupervisor() { + if (mTestStackSupervisor == null) { + mTestStackSupervisor = new TestActivityStackSupervisor(this, mH.getLooper()); + } + return mTestStackSupervisor; + } + } + + /** + * An {@link ActivityStackSupervisor} which stubs out certain methods that depend on + * setup not available in the test environment. Also specifies an injector for + */ + protected class TestActivityStackSupervisor extends ActivityStackSupervisor { + + TestActivityStackSupervisor(ActivityTaskManagerService service, Looper looper) { + super(service, looper); + spyOn(this); + + // Do not schedule idle that may touch methods outside the scope of the test. + doNothing().when(this).scheduleIdleLocked(); + doNothing().when(this).scheduleIdleTimeoutLocked(any()); + // unit test version does not handle launch wake lock + doNothing().when(this).acquireLaunchWakelock(); + doReturn(mock(KeyguardController.class)).when(this).getKeyguardController(); + + mLaunchingActivityWakeLock = mock(PowerManager.WakeLock.class); + + initialize(); + } + } + + // TODO: Can we just mock this? + private static class AMTestInjector extends ActivityManagerService.Injector { + private ServiceThread mHandlerThread; + + AMTestInjector(Context context, ServiceThread handlerThread) { + super(context); + mHandlerThread = handlerThread; + } + + @Override + public Context getContext() { + return getInstrumentation().getTargetContext(); + } + + @Override + public AppOpsService getAppOpsService(File file, Handler handler) { + return null; + } + + @Override + public Handler getUiHandler(ActivityManagerService service) { + return mHandlerThread.getThreadHandler(); + } + + @Override + public boolean isNetworkRestrictedForUid(int uid) { + return false; + } + } } 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 2cebebfc292e..bcff70426c87 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -1277,17 +1277,18 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { } private ActivityRecord createSourceActivity(TestActivityDisplay display) { - final TestActivityStack stack = display.createStack(display.getWindowingMode(), + final ActivityStack stack = display.createStack(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true); return new ActivityBuilder(mService).setStack(stack).setCreateTask(true).build(); } private void addFreeformTaskTo(TestActivityDisplay display, Rect bounds) { - final TestActivityStack stack = display.createStack(display.getWindowingMode(), + final ActivityStack stack = display.createStack(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true); stack.setWindowingMode(WINDOWING_MODE_FREEFORM); final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build(); - task.setBounds(bounds); + // Just work around the unnecessary adjustments for bounds. + task.getWindowConfiguration().setBounds(bounds); } private void assertEquivalentWindowingMode(int expected, int actual, int parentWindowingMode) { diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java index a0302f69029b..c83401b2eb65 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java @@ -28,14 +28,19 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.util.DisplayMetrics.DENSITY_DEFAULT; import static android.view.Surface.ROTATION_0; +import static android.view.Surface.ROTATION_90; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE; +import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED; import static com.android.server.wm.WindowContainer.POSITION_TOP; +import static com.google.common.truth.Truth.assertThat; + import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.sameInstance; import static org.junit.Assert.assertEquals; @@ -64,6 +69,7 @@ import android.util.DisplayMetrics; import android.util.Xml; import android.view.DisplayInfo; +import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import com.android.internal.app.IVoiceInteractor; @@ -102,6 +108,7 @@ public class TaskRecordTests extends ActivityTestsBase { public void setUp() throws Exception { TaskRecord.setTaskRecordFactory(null); mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/); + removeGlobalMinSizeRestriction(); } @Test @@ -165,6 +172,7 @@ public class TaskRecordTests extends ActivityTestsBase { /** Ensures that bounds on freeform stacks are not clipped. */ @Test + @FlakyTest(bugId = 137879065) public void testAppBounds_FreeFormBounds() { final Rect freeFormBounds = new Rect(mParentBounds); freeFormBounds.offset(10, 10); @@ -174,6 +182,7 @@ public class TaskRecordTests extends ActivityTestsBase { /** Ensures that fully contained bounds are not clipped. */ @Test + @FlakyTest(bugId = 137879065) public void testAppBounds_ContainedBounds() { final Rect insetBounds = new Rect(mParentBounds); insetBounds.inset(5, 5, 5, 5); @@ -182,6 +191,7 @@ public class TaskRecordTests extends ActivityTestsBase { } @Test + @FlakyTest(bugId = 137879065) public void testFitWithinBounds() { final Rect parentBounds = new Rect(10, 10, 200, 200); ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay(); @@ -221,6 +231,7 @@ public class TaskRecordTests extends ActivityTestsBase { /** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */ @Test + @FlakyTest(bugId = 137879065) public void testBoundsOnModeChangeFreeformToFullscreen() { ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay(); ActivityStack stack = new StackBuilder(mRootActivityContainer).setDisplay(display) @@ -248,18 +259,6 @@ public class TaskRecordTests extends ActivityTestsBase { } /** - * This is a temporary hack to trigger an onConfigurationChange at the task level after an - * orientation is requested. Normally this is done by the onDescendentOrientationChanged call - * up the WM hierarchy, but since the WM hierarchy is mocked out, it doesn't happen here. - * TODO: remove this when we either get a WM hierarchy or when hierarchies are merged. - */ - private void setActivityRequestedOrientation(ActivityRecord activity, int orientation) { - activity.setRequestedOrientation(orientation); - ConfigurationContainer taskRecord = activity.getParent(); - taskRecord.onConfigurationChanged(taskRecord.getParent().getConfiguration()); - } - - /** * Tests that a task with forced orientation has orientation-consistent bounds within the * parent. */ @@ -268,49 +267,48 @@ public class TaskRecordTests extends ActivityTestsBase { final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080); final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920); DisplayInfo info = new DisplayInfo(); + mService.mContext.getDisplay().getDisplayInfo(info); info.logicalWidth = fullScreenBounds.width(); info.logicalHeight = fullScreenBounds.height(); ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP); assertTrue(mRootActivityContainer.getActivityDisplay(display.mDisplayId) != null); - // Override display orientation. Normally this is available via DisplayContent, but DC - // is mocked-out. - display.getRequestedOverrideConfiguration().orientation = - Configuration.ORIENTATION_LANDSCAPE; - display.onRequestedOverrideConfigurationChanged( - display.getRequestedOverrideConfiguration()); + // Fix the display orientation to landscape which is the natural rotation (0) for the test + // display. + final DisplayRotation dr = display.mDisplayContent.getDisplayRotation(); + dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED); + dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0); + ActivityStack stack = new StackBuilder(mRootActivityContainer) .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build(); TaskRecord task = stack.getChildAt(0); ActivityRecord root = task.getTopActivity(); - assertEquals(root, task.getTopActivity()); assertEquals(fullScreenBounds, task.getBounds()); // Setting app to fixed portrait fits within parent - setActivityRequestedOrientation(root, SCREEN_ORIENTATION_PORTRAIT); + root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT); assertEquals(root, task.getRootActivity()); assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation()); - assertTrue(task.getBounds().width() < task.getBounds().height()); + assertThat(task.getBounds().width()).isLessThan(task.getBounds().height()); assertEquals(fullScreenBounds.height(), task.getBounds().height()); // Top activity gets used ActivityRecord top = new ActivityBuilder(mService).setTask(task).setStack(stack).build(); assertEquals(top, task.getTopActivity()); - setActivityRequestedOrientation(top, SCREEN_ORIENTATION_LANDSCAPE); - assertTrue(task.getBounds().width() > task.getBounds().height()); + top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); + assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height()); assertEquals(task.getBounds().width(), fullScreenBounds.width()); // Setting app to unspecified restores - setActivityRequestedOrientation(top, SCREEN_ORIENTATION_UNSPECIFIED); + top.setRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED); assertEquals(fullScreenBounds, task.getBounds()); // Setting app to fixed landscape and changing display - setActivityRequestedOrientation(top, SCREEN_ORIENTATION_LANDSCAPE); - // simulate display orientation changing (normally done via DisplayContent) - display.getRequestedOverrideConfiguration().orientation = - Configuration.ORIENTATION_PORTRAIT; - display.setBounds(fullScreenBoundsPort); - assertTrue(task.getBounds().width() > task.getBounds().height()); + top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); + // Fix the display orientation to portrait which is 90 degrees for the test display. + dr.setUserRotation(USER_ROTATION_FREE, ROTATION_90); + + assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height()); assertEquals(fullScreenBoundsPort.width(), task.getBounds().width()); // in FREEFORM, no constraint @@ -323,7 +321,7 @@ public class TaskRecordTests extends ActivityTestsBase { // FULLSCREEN letterboxes bounds stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN); - assertTrue(task.getBounds().width() > task.getBounds().height()); + assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height()); assertEquals(fullScreenBoundsPort.width(), task.getBounds().width()); // FREEFORM restores bounds as before @@ -335,6 +333,7 @@ public class TaskRecordTests extends ActivityTestsBase { public void testIgnoresForcedOrientationWhenParentHandles() { final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080); DisplayInfo info = new DisplayInfo(); + mService.mContext.getDisplay().getDisplayInfo(info); info.logicalWidth = fullScreenBounds.width(); info.logicalHeight = fullScreenBounds.height(); ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP); @@ -355,7 +354,7 @@ public class TaskRecordTests extends ActivityTestsBase { // Setting app to fixed portrait fits within parent, but TaskRecord shouldn't adjust the // bounds because its parent says it will handle it at a later time. - setActivityRequestedOrientation(root, SCREEN_ORIENTATION_PORTRAIT); + root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT); assertEquals(root, task.getRootActivity()); assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation()); assertEquals(fullScreenBounds, task.getBounds()); @@ -646,7 +645,7 @@ public class TaskRecordTests extends ActivityTestsBase { final ActivityRecord activity0 = task0.getChildAt(0); final TaskRecord task1 = getTestTask(); - final ActivityRecord activity1 = task0.getChildAt(0); + final ActivityRecord activity1 = task1.getChildAt(0); assertEquals(task0.taskId, ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */)); diff --git a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java b/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java new file mode 100644 index 000000000000..c14396933143 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java @@ -0,0 +1,101 @@ +/* + * 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.wm; + +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; + +import android.hardware.display.DisplayManagerGlobal; +import android.view.Display; +import android.view.DisplayInfo; + +class TestActivityDisplay extends ActivityDisplay { + private final ActivityStackSupervisor mSupervisor; + + static TestActivityDisplay create(ActivityStackSupervisor supervisor) { + return create(supervisor, SystemServicesTestRule.sNextDisplayId++); + } + + static TestActivityDisplay create(ActivityStackSupervisor supervisor, DisplayInfo info) { + return create(supervisor, SystemServicesTestRule.sNextDisplayId++, info); + } + + static TestActivityDisplay create(ActivityStackSupervisor supervisor, int displayId) { + final DisplayInfo info = new DisplayInfo(); + supervisor.mService.mContext.getDisplay().getDisplayInfo(info); + return create(supervisor, displayId, info); + } + + static TestActivityDisplay create(ActivityStackSupervisor supervisor, int displayId, + DisplayInfo info) { + if (displayId == DEFAULT_DISPLAY) { + synchronized (supervisor.mService.mGlobalLock) { + return new TestActivityDisplay(supervisor, + supervisor.mRootActivityContainer.mDisplayManager.getDisplay(displayId)); + } + } + final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId, + info, DEFAULT_DISPLAY_ADJUSTMENTS); + + synchronized (supervisor.mService.mGlobalLock) { + return new TestActivityDisplay(supervisor, display); + } + } + + private TestActivityDisplay(ActivityStackSupervisor supervisor, Display display) { + super(supervisor.mService.mRootActivityContainer, display); + // Normally this comes from display-properties as exposed by WM. Without that, just + // hard-code to FULLSCREEN for tests. + setWindowingMode(WINDOWING_MODE_FULLSCREEN); + mSupervisor = supervisor; + spyOn(this); + spyOn(mDisplayContent); + doAnswer(invocation -> { + // Bypass all the rotation animation and display freezing stuff for testing and just + // set the rotation we want for the display + final DisplayContent dc = mDisplayContent; + final int oldRotation = dc.getRotation(); + final int rotation = dc.getDisplayRotation().rotationForOrientation( + dc.getLastOrientation(), oldRotation); + if (oldRotation == rotation) { + return false; + } + dc.setLayoutNeeded(); + dc.setRotation(rotation); + return true; + }).when(mDisplayContent).updateRotationUnchecked(anyBoolean()); + } + + @SuppressWarnings("TypeParameterUnusedInFormals") + @Override + ActivityStack createStackUnchecked(int windowingMode, int activityType, + int stackId, boolean onTop) { + return new ActivityTestsBase.StackBuilder(mSupervisor.mRootActivityContainer) + .setDisplay(this) + .setWindowingMode(windowingMode) + .setActivityType(activityType) + .setStackId(stackId) + .setOnTop(onTop) + .setCreateActivity(false) + .build(); + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index 2e5ce69a8564..bb89446dd6e6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -40,12 +40,14 @@ import android.view.animation.Animation; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IShortcutService; import com.android.server.policy.WindowManagerPolicy; +import com.android.server.wm.WindowState.PowerManagerWrapper; import java.io.PrintWriter; import java.util.function.Supplier; class TestWindowManagerPolicy implements WindowManagerPolicy { private final Supplier<WindowManagerService> mWmSupplier; + private final PowerManagerWrapper mPowerManagerWrapper; int mRotationToReport = 0; boolean mKeyguardShowingAndNotOccluded = false; @@ -53,8 +55,10 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { private Runnable mRunnableWhenAddingSplashScreen; - TestWindowManagerPolicy(Supplier<WindowManagerService> wmSupplier) { + TestWindowManagerPolicy(Supplier<WindowManagerService> wmSupplier, + PowerManagerWrapper powerManagerWrapper) { mWmSupplier = wmSupplier; + mPowerManagerWrapper = powerManagerWrapper; } @Override @@ -121,7 +125,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { doReturn(mock(IBinder.class)).when(iWindow).asBinder(); window = WindowTestsBase.createWindow(null, TYPE_APPLICATION_STARTING, atoken, "Starting window", 0 /* ownerId */, false /* internalWindows */, wm, - mock(Session.class), iWindow); + mock(Session.class), iWindow, mPowerManagerWrapper); atoken.startingWindow = window; } if (mRunnableWhenAddingSplashScreen != null) { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index acfc2ea3d402..921f105d1d25 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -27,6 +27,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyFloat; import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; @@ -113,6 +114,7 @@ public class WindowContainerTests extends WindowTestsBase { @Test public void testAddChildSetsSurfacePosition() { + reset(mTransaction); try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) { WindowContainer child = new WindowContainer(mWm); child.setBounds(1, 1, 10, 10); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java index 06bcdf8fcadf..60cefe858c54 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java @@ -57,6 +57,7 @@ public class WindowFrameTests extends WindowTestsBase { private final IWindow mIWindow = new TestIWindow(); private final Rect mEmptyRect = new Rect(); + private DisplayContent mTestDisplayContent; static class FrameTestWindowState extends WindowState { boolean mDockedResizingForTest = false; @@ -77,6 +78,9 @@ public class WindowFrameTests extends WindowTestsBase { @Before public void setUp() throws Exception { mStubStack = mock(TaskStack.class); + DisplayInfo testDisplayInfo = new DisplayInfo(mDisplayInfo); + testDisplayInfo.displayCutout = null; + mTestDisplayContent = createNewDisplay(testDisplayInfo); } // Do not use this function directly in the tests below. Instead, use more explicit function @@ -100,6 +104,10 @@ public class WindowFrameTests extends WindowTestsBase { assertRect(w.getStableInsets(), left, top, right, bottom); } + private void assertFrame(WindowState w, Rect frame) { + assertEquals(w.getFrameLw(), frame); + } + private void assertFrame(WindowState w, int left, int top, int right, int bottom) { assertRect(w.getFrameLw(), left, top, right, bottom); } @@ -380,9 +388,10 @@ public class WindowFrameTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 137879065) public void testLayoutLetterboxedWindow() { // First verify task behavior in multi-window mode. - final DisplayInfo displayInfo = mWm.getDefaultDisplayContentLocked().getDisplayInfo(); + final DisplayInfo displayInfo = mTestDisplayContent.getDisplayInfo(); final int logicalWidth = displayInfo.logicalWidth; final int logicalHeight = displayInfo.logicalHeight; @@ -413,13 +422,14 @@ public class WindowFrameTests extends WindowTestsBase { final Rect cf = new Rect(xInset, 0, logicalWidth - xInset, logicalHeight); Configuration config = new Configuration(w.mAppToken.getRequestedOverrideConfiguration()); config.windowConfiguration.setBounds(cf); + config.windowConfiguration.setAppBounds(cf); w.mAppToken.onRequestedOverrideConfigurationChanged(config); pf.set(0, 0, logicalWidth, logicalHeight); task.setWindowingMode(WINDOWING_MODE_FULLSCREEN); task.setBounds(null); windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect); w.computeFrameLw(); - assertFrame(w, cf.left, cf.top, cf.right, cf.bottom); + assertFrame(w, cf); assertContentFrame(w, cf); assertContentInset(w, 0, 0, 0, 0); } @@ -483,7 +493,7 @@ public class WindowFrameTests extends WindowTestsBase { w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; task.setWindowingMode(WINDOWING_MODE_FREEFORM); - DisplayContent dc = mWm.getDefaultDisplayContentLocked(); + DisplayContent dc = mTestDisplayContent; dc.mInputMethodTarget = w; WindowState mockIme = mock(WindowState.class); Mockito.doReturn(true).when(mockIme).isVisibleNow(); @@ -537,7 +547,7 @@ public class WindowFrameTests extends WindowTestsBase { attrs.width = width; attrs.height = height; - AppWindowToken token = createAppWindowToken(mWm.getDefaultDisplayContentLocked(), + AppWindowToken token = createAppWindowToken(mTestDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); FrameTestWindowState ws = new FrameTestWindowState(mWm, mIWindow, token, attrs); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 36698eae274c..b73162834a52 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -346,24 +346,28 @@ public class WindowStateTests extends WindowTestsBase { firstWindow.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; secondWindow.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; - reset(sPowerManagerWrapper); + final WindowState.PowerManagerWrapper powerManagerWrapper = + mSystemServicesTestRule.getPowerManagerWrapper(); + reset(powerManagerWrapper); firstWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/); - verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString()); + verify(powerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString()); - reset(sPowerManagerWrapper); + reset(powerManagerWrapper); secondWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/); - verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString()); + verify(powerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString()); } private void testPrepareWindowToDisplayDuringRelayout(WindowState appWindow, boolean expectedWakeupCalled, boolean expectedCurrentLaunchCanTurnScreenOn) { - reset(sPowerManagerWrapper); + final WindowState.PowerManagerWrapper powerManagerWrapper = + mSystemServicesTestRule.getPowerManagerWrapper(); + reset(powerManagerWrapper); appWindow.prepareWindowToDisplayDuringRelayout(false /* wasVisible */); if (expectedWakeupCalled) { - verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString()); + verify(powerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString()); } else { - verify(sPowerManagerWrapper, never()).wakeUp(anyLong(), anyInt(), anyString()); + verify(powerManagerWrapper, never()).wakeUp(anyLong(), anyInt(), anyString()); } // If wakeup is expected to be called, the currentLaunchCanTurnScreenOn should be false // because the state will be consumed. @@ -517,13 +521,19 @@ public class WindowStateTests extends WindowTestsBase { @Test public void testGetTransformationMatrix() { + final int PARENT_WINDOW_OFFSET = 1; + final int DISPLAY_IN_PARENT_WINDOW_OFFSET = 2; + final int WINDOW_OFFSET = 3; + final float OFFSET_SUM = + PARENT_WINDOW_OFFSET + DISPLAY_IN_PARENT_WINDOW_OFFSET + WINDOW_OFFSET; + synchronized (mWm.mGlobalLock) { final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0"); - win0.getFrameLw().offsetTo(1, 0); final DisplayContent dc = createNewDisplay(); + win0.getFrameLw().offsetTo(PARENT_WINDOW_OFFSET, 0); dc.reparentDisplayContent(win0, win0.getSurfaceControl()); - dc.updateLocation(win0, 2, 0); + dc.updateLocation(win0, DISPLAY_IN_PARENT_WINDOW_OFFSET, 0); final float[] values = new float[9]; final Matrix matrix = new Matrix(); @@ -531,12 +541,12 @@ public class WindowStateTests extends WindowTestsBase { final WindowState win1 = createWindow(null, TYPE_APPLICATION, dc, "win1"); win1.mHasSurface = true; win1.mSurfaceControl = mock(SurfaceControl.class); - win1.getFrameLw().offsetTo(3, 0); + win1.getFrameLw().offsetTo(WINDOW_OFFSET, 0); win1.updateSurfacePosition(t); win1.getTransformationMatrix(values, matrix); matrix.getValues(values); - assertEquals(6f, values[Matrix.MTRANS_X], 0f); + assertEquals(OFFSET_SUM, values[Matrix.MTRANS_X], 0f); assertEquals(0f, values[Matrix.MTRANS_Y], 0f); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index dc461d149cee..d1cf1c3e2f01 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -20,8 +20,6 @@ import static android.app.AppOpsManager.OP_NONE; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.os.Process.SYSTEM_UID; -import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; import static android.view.View.VISIBLE; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; @@ -38,33 +36,27 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.server.wm.ActivityDisplay.POSITION_TOP; import static org.mockito.Mockito.mock; - import android.content.Context; import android.content.res.Configuration; -import android.hardware.display.DisplayManagerGlobal; import android.testing.DexmakerShareClassLoaderRule; import android.util.Log; import android.view.Display; import android.view.DisplayInfo; import android.view.IWindow; -import android.view.Surface; import android.view.SurfaceControl.Transaction; import android.view.WindowManager; import com.android.server.AttributeCache; -import com.android.server.wm.utils.MockTracker; import org.junit.After; -import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; -import java.io.IOException; import java.util.HashSet; import java.util.LinkedList; @@ -79,10 +71,6 @@ class WindowTestsBase { WindowManagerService mWm; private final IWindow mIWindow = new TestIWindow(); private Session mMockSession; - // The default display is removed in {@link #setUp} and then we iterate over all displays to - // make sure we don't collide with any existing display. If we run into no other display, the - // added display should be treated as default. This cannot be the default display - private static int sNextDisplayId = DEFAULT_DISPLAY + 1; static int sNextStackId = 1000; /** Non-default display. */ @@ -99,8 +87,6 @@ class WindowTestsBase { WindowState mChildAppWindowBelow; HashSet<WindowState> mCommonWindows; - private MockTracker mMockTracker; - /** * Spied {@link Transaction} class than can be used to verify calls. */ @@ -112,49 +98,27 @@ class WindowTestsBase { @Rule public final SystemServicesTestRule mSystemServicesTestRule = new SystemServicesTestRule(); - static WindowState.PowerManagerWrapper sPowerManagerWrapper; - @BeforeClass public static void setUpOnceBase() { AttributeCache.init(getInstrumentation().getTargetContext()); - - sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class); - } - - @AfterClass - public static void tearDownOnceBase() throws IOException { - sPowerManagerWrapper = null; } @Before public void setUpBase() { - mMockTracker = new MockTracker(); - // If @Before throws an exception, the error isn't logged. This will make sure any failures // in the set up are clear. This can be removed when b/37850063 is fixed. try { mMockSession = mock(Session.class); - mTransaction = spy(StubTransaction.class); final Context context = getInstrumentation().getTargetContext(); mWm = mSystemServicesTestRule.getWindowManagerService(); - - // Setup factory classes to prevent calls to native code. - - // Return a spied Transaction class than can be used to verify calls. - mWm.mTransactionFactory = () -> mTransaction; - // Return a SurfaceControl.Builder class that creates mocked SurfaceControl instances. - mWm.mSurfaceBuilderFactory = (unused) -> new MockSurfaceControlBuilder(); - // Return mocked Surface instances. - mWm.mSurfaceFactory = () -> mock(Surface.class); + mTransaction = mSystemServicesTestRule.mTransaction; beforeCreateDisplay(); context.getDisplay().getDisplayInfo(mDisplayInfo); mDisplayContent = createNewDisplay(); - mWm.mDisplayEnabled = true; - mWm.mDisplayReady = true; // Set-up some common windows. mCommonWindows = new HashSet<>(); @@ -211,12 +175,6 @@ class WindowTestsBase { nonCommonWindows.pollLast().removeImmediately(); } - for (int i = mWm.mRoot.mChildren.size() - 1; i >= 0; --i) { - final DisplayContent displayContent = mWm.mRoot.mChildren.get(i); - if (!displayContent.isDefaultDisplay) { - displayContent.removeImmediately(); - } - } // Remove app transition & window freeze timeout callbacks to prevent unnecessary // actions after test. mWm.getDefaultDisplayContentLocked().mAppTransition @@ -230,11 +188,7 @@ class WindowTestsBase { } catch (Exception e) { Log.e(TAG, "Failed to tear down test", e); throw e; - } finally { - mMockTracker.close(); - mMockTracker = null; } - } private WindowState createCommonWindow(WindowState parent, int type, String name) { @@ -356,12 +310,13 @@ class WindowTestsBase { WindowState createWindow(WindowState parent, int type, WindowToken token, String name, int ownerId, boolean ownerCanAddInternalSystemWindow) { return createWindow(parent, type, token, name, ownerId, ownerCanAddInternalSystemWindow, - mWm, mMockSession, mIWindow); + mWm, mMockSession, mIWindow, mSystemServicesTestRule.getPowerManagerWrapper()); } static WindowState createWindow(WindowState parent, int type, WindowToken token, String name, int ownerId, boolean ownerCanAddInternalSystemWindow, - WindowManagerService service, Session session, IWindow iWindow) { + WindowManagerService service, Session session, IWindow iWindow, + WindowState.PowerManagerWrapper powerManagerWrapper) { synchronized (service.mGlobalLock) { final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type); attrs.setTitle(name); @@ -369,7 +324,7 @@ class WindowTestsBase { final WindowState w = new WindowState(service, session, iWindow, token, parent, OP_NONE, 0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow, - sPowerManagerWrapper); + powerManagerWrapper); // TODO: Probably better to make this call in the WindowState ctor to avoid errors with // adding it to the token... token.addWindow(w); @@ -408,13 +363,11 @@ class WindowTestsBase { } /** Creates a {@link DisplayContent} and adds it to the system. */ - DisplayContent createNewDisplay(DisplayInfo displayInfo) { - final int displayId = sNextDisplayId++; - final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId, - displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS); - synchronized (mWm.mGlobalLock) { - return new DisplayContent(display, mWm, mock(ActivityDisplay.class)); - } + DisplayContent createNewDisplay(DisplayInfo info) { + final ActivityDisplay display = + TestActivityDisplay.create(mWm.mAtmService.mStackSupervisor, info); + mWm.mAtmService.mRootActivityContainer.addChild(display, POSITION_TOP); + return display.mDisplayContent; } /** @@ -428,17 +381,7 @@ class WindowTestsBase { DisplayInfo displayInfo = new DisplayInfo(); displayInfo.copyFrom(mDisplayInfo); displayInfo.state = displayState; - final int displayId = sNextDisplayId++; - final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId, - displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS); - synchronized (mWm.mGlobalLock) { - // Display creation is driven by DisplayWindowController via ActivityStackSupervisor. - // We skip those steps here. - final ActivityDisplay mockAd = mock(ActivityDisplay.class); - final DisplayContent displayContent = mWm.mRoot.createDisplayContent(display, mockAd); - displayContent.reconfigureDisplayLocked(); - return displayContent; - } + return createNewDisplay(displayInfo); } /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */ diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java index a6e675ab5f7e..7f0948288799 100644 --- a/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java +++ b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java @@ -89,7 +89,7 @@ public class MockTracker implements MockCreationListener, AutoCloseable { for (final Object mock : mMocks.keySet()) { if (MockUtil.isMock(mock)) { - Mockito.reset(mock); + mMockitoFramework.clearInlineMock(mock); } } mMocks.clear(); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index b2fde548e506..b2ac5490440d 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -20,6 +20,7 @@ import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AppGlobals; @@ -36,6 +37,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.ShortcutServiceInternal; +import android.content.pm.UserInfo; import android.content.res.Resources; import android.database.ContentObserver; import android.hardware.soundtrigger.IRecognitionStatusCallback; @@ -80,6 +82,7 @@ import com.android.server.SystemService; import com.android.server.UiThread; import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.soundtrigger.SoundTriggerInternal; +import com.android.server.utils.TimingsTraceAndSlog; import com.android.server.wm.ActivityTaskManagerInternal; import java.io.FileDescriptor; @@ -92,7 +95,7 @@ import java.util.concurrent.Executor; */ public class VoiceInteractionManagerService extends SystemService { static final String TAG = "VoiceInteractionManagerService"; - static final boolean DEBUG = false; + static final boolean DEBUG = true; // TODO(b/133242016) STOPSHIP: change to false before R ships final Context mContext; final ContentResolver mResolver; @@ -154,19 +157,37 @@ public class VoiceInteractionManagerService extends SystemService { } @Override - public void onStartUser(int userHandle) { - mServiceStub.initForUser(userHandle); + public void onStartUser(@NonNull UserInfo userInfo) { + if (DEBUG) Slog.d(TAG, "onStartUser(" + userInfo + ")"); + + if (!userInfo.isFull()) { + if (DEBUG) Slog.d(TAG, "***** skipping on non-full user " + userInfo); + return; + } + mServiceStub.initForUser(userInfo.id); } @Override - public void onUnlockUser(int userHandle) { - mServiceStub.initForUser(userHandle); + public void onUnlockUser(@NonNull UserInfo userInfo) { + if (DEBUG) Slog.d(TAG, "onUnlockUser(" + userInfo + ")"); + + if (!userInfo.isFull()) { + if (DEBUG) Slog.d(TAG, "***** skipping on non-full user " + userInfo); + return; + } + mServiceStub.initForUser(userInfo.id); mServiceStub.switchImplementationIfNeeded(false); } @Override - public void onSwitchUser(int userHandle) { - mServiceStub.switchUser(userHandle); + public void onSwitchUser(@NonNull UserInfo userInfo) { + if (DEBUG) Slog.d(TAG, "onSwitchUser(" + userInfo + ")"); + + if (!userInfo.isFull()) { + if (DEBUG) Slog.d(TAG, "***** skipping on non-full user " + userInfo); + return; + } + mServiceStub.switchUser(userInfo.id); } class LocalService extends VoiceInteractionManagerInternal { @@ -270,6 +291,20 @@ public class VoiceInteractionManagerService extends SystemService { } public void initForUser(int userHandle) { + final TimingsTraceAndSlog t; + if (DEBUG) { + t = TimingsTraceAndSlog.newAsyncLog(); + t.traceBegin("VoiceInteractionSvc.initForUser(" + userHandle + ")"); + } else { + t = null; + } + initForUserNoTracing(userHandle); + if (t != null) { + t.traceEnd(); + } + } + + private void initForUserNoTracing(@UserIdInt int userHandle) { if (DEBUG) Slog.d(TAG, "**************** initForUser user=" + userHandle); String curInteractorStr = Settings.Secure.getStringForUser( mContext.getContentResolver(), @@ -426,6 +461,20 @@ public class VoiceInteractionManagerService extends SystemService { } void switchImplementationIfNeededLocked(boolean force) { + final TimingsTraceAndSlog t; + if (DEBUG) { + t = TimingsTraceAndSlog.newAsyncLog(); + t.traceBegin("VoiceInteractionSvc.switchImplementation(" + mCurUser + ")"); + } else { + t = null; + } + switchImplementationIfNeededNoTracingLocked(force); + if (t != null) { + t.traceEnd(); + } + } + + void switchImplementationIfNeededNoTracingLocked(boolean force) { if (!mSafeMode) { String curService = Settings.Secure.getStringForUser( mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser); diff --git a/services/wifi/Android.bp b/services/wifi/Android.bp new file mode 100644 index 000000000000..3c916a6d00cd --- /dev/null +++ b/services/wifi/Android.bp @@ -0,0 +1,11 @@ +// Interfaces between the core system and the wifi mainline module. +java_library_static { + name: "services.wifi", + srcs: [ + "java/**/*.java", + "java/**/*.aidl", + ], + libs: [ + "services.net", + ], +} diff --git a/services/wifi/java/android/net/wifi/IWifiStackConnector.aidl b/services/wifi/java/android/net/wifi/IWifiStackConnector.aidl new file mode 100644 index 000000000000..eadc7260e81b --- /dev/null +++ b/services/wifi/java/android/net/wifi/IWifiStackConnector.aidl @@ -0,0 +1,22 @@ +/** + * 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 perNmissions and + * limitations under the License. + */ +package android.net.wifi; + +/** @hide */ +interface IWifiStackConnector { + IBinder retrieveApiServiceImpl(String serviceName); + boolean startApiService(String serviceName); +} diff --git a/services/wifi/java/android/net/wifi/WifiStackClient.java b/services/wifi/java/android/net/wifi/WifiStackClient.java new file mode 100644 index 000000000000..fa66e4c5eeea --- /dev/null +++ b/services/wifi/java/android/net/wifi/WifiStackClient.java @@ -0,0 +1,115 @@ +/* + * 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.net.wifi; + +import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH; +import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; + +import android.annotation.NonNull; +import android.content.Context; +import android.net.ConnectivityModuleConnector; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; + +/** + * Service used to communicate with the wifi stack, which could be running in a separate + * module. + * @hide + */ +public class WifiStackClient { + public static final String PERMISSION_MAINLINE_WIFI_STACK = + "android.permission.MAINLINE_WIFI_STACK"; + + private static final String TAG = WifiStackClient.class.getSimpleName(); + private static WifiStackClient sInstance; + + private WifiStackClient() { } + + /** + * Get the WifiStackClient singleton instance. + */ + public static synchronized WifiStackClient getInstance() { + if (sInstance == null) { + sInstance = new WifiStackClient(); + } + return sInstance; + } + + private class WifiStackConnection implements + ConnectivityModuleConnector.ModuleServiceCallback { + @Override + public void onModuleServiceConnected(IBinder service) { + Log.i(TAG, "Wifi stack connected"); + + registerWifiStackService(service); + IWifiStackConnector connector = IWifiStackConnector.Stub.asInterface(service); + registerApiServiceAndStart(connector, Context.WIFI_SERVICE); + registerApiServiceAndStart(connector, Context.WIFI_SCANNING_SERVICE); + registerApiServiceAndStart(connector, Context.WIFI_P2P_SERVICE); + registerApiServiceAndStart(connector, Context.WIFI_AWARE_SERVICE); + registerApiServiceAndStart(connector, Context.WIFI_RTT_RANGING_SERVICE); + } + } + + private void registerWifiStackService(@NonNull IBinder service) { + ServiceManager.addService(Context.WIFI_STACK_SERVICE, service, + false /* allowIsolated */, + DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL); + Log.i(TAG, "Wifi stack service registered"); + } + + private void registerApiServiceAndStart( + IWifiStackConnector stackConnector, String serviceName) { + IBinder service = null; + try { + service = stackConnector.retrieveApiServiceImpl(serviceName); + } catch (RemoteException e) { + throw new RuntimeException("Failed to retrieve service impl " + serviceName, e); + } + if (service == null) { + Log.i(TAG, "Service " + serviceName + " not available"); + return; + } + Log.i(TAG, "Registering " + serviceName); + ServiceManager.addService(serviceName, service); + + boolean success = false; + try { + success = stackConnector.startApiService(serviceName); + } catch (RemoteException e) { + throw new RuntimeException("Failed to start service " + serviceName, e); + } + if (!success) { + throw new RuntimeException("Service " + serviceName + " start failed"); + } + } + + /** + * Start the wifi stack. Should be called only once on device startup. + * + * <p>This method will start the wifi stack either in the wifi stack + * process, or inside the system server on devices that do not support the wifi stack + * module. + */ + public void start() { + Log.i(TAG, "Starting wifi stack"); + ConnectivityModuleConnector.getInstance().startModuleService( + IWifiStackConnector.class.getName(), PERMISSION_MAINLINE_WIFI_STACK, + new WifiStackConnection()); + } +} diff --git a/telecomm/java/android/telecom/Logging/Session.java b/telecomm/java/android/telecom/Logging/Session.java index 50c3cd97d77a..95a47e131272 100644 --- a/telecomm/java/android/telecom/Logging/Session.java +++ b/telecomm/java/android/telecom/Logging/Session.java @@ -33,6 +33,8 @@ import java.util.ArrayList; */ public class Session { + public static final String LOG_TAG = "Session"; + public static final String START_SESSION = "START_SESSION"; public static final String START_EXTERNAL_SESSION = "START_EXTERNAL_SESSION"; public static final String CREATE_SUBSESSION = "CREATE_SUBSESSION"; @@ -45,6 +47,9 @@ public class Session { public static final String EXTERNAL_INDICATOR = "E-"; public static final String TRUNCATE_STRING = "..."; + // Prevent infinite recursion by setting a reasonable limit. + private static final int SESSION_RECURSION_LIMIT = 25; + /** * Initial value of mExecutionEndTimeMs and the final value of {@link #getLocalExecutionTime()} * if the Session is canceled. @@ -226,6 +231,15 @@ public class Session { // Builds full session id recursively private String getFullSessionId() { + return getFullSessionId(0); + } + + // keep track of calls and bail if we hit the recursion limit + private String getFullSessionId(int parentCount) { + if (parentCount >= SESSION_RECURSION_LIMIT) { + Log.w(LOG_TAG, "getFullSessionId: Hit recursion limit!"); + return TRUNCATE_STRING + mSessionId; + } // Cache mParentSession locally to prevent a concurrency problem where // Log.endParentSessions() is called while a logging statement is running (Log.i, for // example) and setting mParentSession to null in a different thread after the null check @@ -235,42 +249,57 @@ public class Session { return mSessionId; } else { if (Log.VERBOSE) { - return parentSession.getFullSessionId() + + return parentSession.getFullSessionId(parentCount + 1) // Append "_X" to subsession to show subsession designation. - SESSION_SEPARATION_CHAR_CHILD + mSessionId; + + SESSION_SEPARATION_CHAR_CHILD + mSessionId; } else { // Only worry about the base ID at the top of the tree. - return parentSession.getFullSessionId(); + return parentSession.getFullSessionId(parentCount + 1); } } } - // Print out the full Session tree from any subsession node - public String printFullSessionTree() { - // Get to the top of the tree + private Session getRootSession(String callingMethod) { + int currParentCount = 0; Session topNode = this; while (topNode.getParentSession() != null) { + if (currParentCount >= SESSION_RECURSION_LIMIT) { + Log.w(LOG_TAG, "getRootSession: Hit recursion limit from " + callingMethod); + break; + } topNode = topNode.getParentSession(); + currParentCount++; } - return topNode.printSessionTree(); + return topNode; + } + + // Print out the full Session tree from any subsession node + public String printFullSessionTree() { + return getRootSession("printFullSessionTree").printSessionTree(); } // Recursively move down session tree using DFS, but print out each node when it is reached. - public String printSessionTree() { + private String printSessionTree() { StringBuilder sb = new StringBuilder(); - printSessionTree(0, sb); + printSessionTree(0, sb, 0); return sb.toString(); } - private void printSessionTree(int tabI, StringBuilder sb) { + private void printSessionTree(int tabI, StringBuilder sb, int currChildCount) { + // Prevent infinite recursion. + if (currChildCount >= SESSION_RECURSION_LIMIT) { + Log.w(LOG_TAG, "printSessionTree: Hit recursion limit!"); + sb.append(TRUNCATE_STRING); + return; + } sb.append(toString()); for (Session child : mChildSessions) { sb.append("\n"); for (int i = 0; i <= tabI; i++) { sb.append("\t"); } - child.printSessionTree(tabI + 1, sb); + child.printSessionTree(tabI + 1, sb, currChildCount + 1); } } @@ -279,11 +308,17 @@ public class Session { // recent) will be truncated to "..." public String getFullMethodPath(boolean truncatePath) { StringBuilder sb = new StringBuilder(); - getFullMethodPath(sb, truncatePath); + getFullMethodPath(sb, truncatePath, 0); return sb.toString(); } - private synchronized void getFullMethodPath(StringBuilder sb, boolean truncatePath) { + private synchronized void getFullMethodPath(StringBuilder sb, boolean truncatePath, + int parentCount) { + if (parentCount >= SESSION_RECURSION_LIMIT) { + Log.w(LOG_TAG, "getFullMethodPath: Hit recursion limit!"); + sb.append(TRUNCATE_STRING); + return; + } // Return cached value for method path. When returning the truncated path, recalculate the // full path without using the cached value. if (!TextUtils.isEmpty(mFullMethodPathCache) && !truncatePath) { @@ -296,7 +331,7 @@ public class Session { // Check to see if the session has been renamed yet. If it has not, then the session // has not been continued. isSessionStarted = !mShortMethodName.equals(parentSession.mShortMethodName); - parentSession.getFullMethodPath(sb, truncatePath); + parentSession.getFullMethodPath(sb, truncatePath, parentCount + 1); sb.append(SUBSESSION_SEPARATION_CHAR); } // Encapsulate the external session's method name so it is obvious what part of the session @@ -319,13 +354,10 @@ public class Session { mFullMethodPathCache = sb.toString(); } } + // Recursively move to the top of the tree to see if the parent session is external. private boolean isSessionExternal() { - if (getParentSession() == null) { - return isExternal(); - } else { - return getParentSession().isSessionExternal(); - } + return getRootSession("isSessionExternal").isExternal(); } @Override diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java index c4a9ee957ab0..42a5501cc229 100644 --- a/telephony/java/android/provider/Telephony.java +++ b/telephony/java/android/provider/Telephony.java @@ -692,7 +692,7 @@ public final class Telephony { } /** - * Contains all sent text-based SMS messages in the SMS app. + * Contains all draft text-based SMS messages in the SMS app. */ public static final class Draft implements BaseColumns, TextBasedSmsColumns { @@ -808,7 +808,15 @@ public final class Telephony { } /** - * Contains all sent text-based SMS messages in the SMS app. + * Contains a view of SMS conversations (also referred to as threads). This is similar to + * {@link Threads}, but only includes SMS messages and columns relevant to SMS + * conversations. + * <p> + * Note that this view ignores any information about MMS messages, it is a + * view of conversations as if MMS messages did not exist at all. This means that all + * relevant information, such as snippets and message count, will ignore any MMS messages + * that might be in the same thread through other views and present only data based on the + * SMS messages in that thread. */ public static final class Conversations implements BaseColumns, TextBasedSmsColumns { @@ -3230,6 +3238,8 @@ public final class Telephony { /** * The {@code content://} style URL for locked messages in this table. + * <P>This {@link Uri} is used to check at most one locked message found in the union of MMS + * and SMS messages. Also this will return only _id column in response.</P> */ public static final Uri CONTENT_LOCKED_URI = Uri.parse( "content://mms-sms/locked"); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 66cc6ebd019b..10d4b8dbf33e 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1421,6 +1421,13 @@ public class CarrierConfigManager { "show_4g_for_lte_data_icon_bool"; /** + * Boolean indicating if default data account should show 4G icon when in 3G. + * @hide + */ + public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = + "show_4g_for_3g_data_icon_bool"; + + /** * Boolean indicating if lte+ icon should be shown if available * @hide */ @@ -2649,25 +2656,32 @@ public class CarrierConfigManager { "call_waiting_service_class_int"; /** - * This configuration allow the system UI to display different 5G icon for different 5G status. + * This configuration allow the system UI to display different 5G icon for different 5G + * scenario. * - * There are four 5G status: + * There are five 5G scenarios: * 1. connected_mmwave: device currently connected to 5G cell as the secondary cell and using * millimeter wave. * 2. connected: device currently connected to 5G cell as the secondary cell but not using * millimeter wave. - * 3. not_restricted: device camped on a network that has 5G capability(not necessary to connect - * a 5G cell as a secondary cell) and the use of 5G is not restricted. - * 4. restricted: device camped on a network that has 5G capability(not necessary to connect a + * 3. not_restricted_rrc_idle: device camped on a network that has 5G capability(not necessary + * to connect a 5G cell as a secondary cell) and the use of 5G is not restricted and RRC + * currently in IDLE state. + * 4. not_restricted_rrc_con: device camped on a network that has 5G capability(not necessary + * to connect a 5G cell as a secondary cell) and the use of 5G is not restricted and RRC + * currently in CONNECTED state. + * 5. restricted: device camped on a network that has 5G capability(not necessary to connect a * 5G cell as a secondary cell) but the use of 5G is restricted. * * The configured string contains multiple key-value pairs separated by comma. For each pair, * the key and value is separated by a colon. The key is corresponded to a 5G status above and * the value is the icon name. Use "None" as the icon name if no icon should be shown in a - * specific 5G status. + * specific 5G scenario. If the scenario is "None", config can skip this key and value. * - * Here is an example of the configuration: - * "connected_mmwave:5GPlus,connected:5G,not_restricted:None,restricted:None" + * Here is an example: + * UE want to display 5GPlus icon for scenario#1, and 5G icon for scenario#2; otherwise no + * define. + * The configuration is: "connected_mmwave:5GPlus,connected:5G" * * @hide */ @@ -2675,6 +2689,22 @@ public class CarrierConfigManager { "5g_icon_configuration_string"; /** + * Timeout in second for displaying 5G icon, default value is 0 which means the timer is + * disabled. + * + * System UI will show the 5G icon and start a timer with the timeout from this config when the + * device connects to a 5G cell. System UI stops displaying 5G icon when both the device + * disconnects from 5G cell and the timer is expired. + * + * If 5G is reacquired during this timer, the timer is canceled and restarted when 5G is next + * lost. Allows us to momentarily lose 5G without blinking the icon. + * + * @hide + */ + public static final String KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT = + "5g_icon_display_grace_period_sec_int"; + + /** * Support ASCII 7-BIT encoding for long SMS. This carrier config is used to enable * this feature. * @hide @@ -3108,6 +3138,13 @@ public class CarrierConfigManager { public static final String KEY_SUPPORT_WPS_OVER_IMS_BOOL = "support_wps_over_ims_bool"; + /** + * Holds the list of carrier certificate hashes. Note that each carrier has its own certificates + * @hide + */ + public static final String KEY_CARRIER_CERTIFICATE_STRING_ARRAY = + "carrier_certificate_string_array"; + /** The default value for every variable. */ private final static PersistableBundle sDefaults; @@ -3447,6 +3484,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL, false); sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false); sDefaults.putBoolean(KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, false); + sDefaults.putBoolean(KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL, false); sDefaults.putString(KEY_OPERATOR_NAME_FILTER_PATTERN_STRING, ""); sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, ""); sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true); @@ -3485,7 +3523,8 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_USE_CALLER_ID_USSD_BOOL, false); sDefaults.putInt(KEY_CALL_WAITING_SERVICE_CLASS_INT, 1 /* SERVICE_CLASS_VOICE */); sDefaults.putString(KEY_5G_ICON_CONFIGURATION_STRING, - "connected_mmwave:None,connected:5G,not_restricted:None,restricted:None"); + "connected_mmwave:5G,connected:5G"); + sDefaults.putInt(KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT, 0); sDefaults.putBoolean(KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL, false); /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -108); @@ -3527,6 +3566,7 @@ public class CarrierConfigManager { }); sDefaults.putBoolean(KEY_SUPPORT_WPS_OVER_IMS_BOOL, true); sDefaults.putAll(Ims.getDefaults()); + sDefaults.putStringArray(KEY_CARRIER_CERTIFICATE_STRING_ARRAY, null); } /** diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java index 258a873c3ac5..432978d1c866 100644 --- a/telephony/java/android/telephony/CellIdentity.java +++ b/telephony/java/android/telephony/CellIdentity.java @@ -17,6 +17,7 @@ package android.telephony; import android.annotation.CallSuper; +import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; @@ -61,7 +62,7 @@ public abstract class CellIdentity implements Parcelable { mType = type; // Only allow INT_MAX if unknown string mcc/mnc - if (mcc == null || mcc.matches("^[0-9]{3}$")) { + if (mcc == null || isMcc(mcc)) { mMccStr = mcc; } else if (mcc.isEmpty() || mcc.equals(String.valueOf(Integer.MAX_VALUE))) { // If the mccStr is empty or unknown, set it as null. @@ -73,7 +74,7 @@ public abstract class CellIdentity implements Parcelable { log("invalid MCC format: " + mcc); } - if (mnc == null || mnc.matches("^[0-9]{2,3}$")) { + if (mnc == null || isMnc(mnc)) { mMncStr = mnc; } else if (mnc.isEmpty() || mnc.equals(String.valueOf(Integer.MAX_VALUE))) { // If the mncStr is empty or unknown, set it as null. @@ -262,4 +263,30 @@ public abstract class CellIdentity implements Parcelable { if ((value < rangeMin || value > rangeMax) && value != special) return CellInfo.UNAVAILABLE; return value; } + + /** @hide */ + private static boolean isMcc(@NonNull String mcc) { + // ensure no out of bounds indexing + if (mcc.length() != 3) return false; + + // Character.isDigit allows all unicode digits, not just [0-9] + for (int i = 0; i < 3; i++) { + if (mcc.charAt(i) < '0' || mcc.charAt(i) > '9') return false; + } + + return true; + } + + /** @hide */ + private static boolean isMnc(@NonNull String mnc) { + // ensure no out of bounds indexing + if (mnc.length() < 2 || mnc.length() > 3) return false; + + // Character.isDigit allows all unicode digits, not just [0-9] + for (int i = 0; i < mnc.length(); i++) { + if (mnc.charAt(i) < '0' || mnc.charAt(i) > '9') return false; + } + + return true; + } } diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index a8491d3f4d04..36e81232100c 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -38,6 +38,7 @@ import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Log; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -147,7 +148,14 @@ public class SubscriptionInfo implements Parcelable { * The access rules for this subscription, if it is embedded and defines any. */ @Nullable - private UiccAccessRule[] mAccessRules; + private UiccAccessRule[] mNativeAccessRules; + + /** + * The carrier certificates for this subscription that are saved in carrier configs. + * The other carrier certificates are embedded on Uicc and stored as part of mNativeAccessRules. + */ + @Nullable + private UiccAccessRule[] mCarrierConfigAccessRules; /** * The string ID of the SIM card. It is the ICCID of the active profile for a UICC card and the @@ -206,12 +214,12 @@ public class SubscriptionInfo implements Parcelable { public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded, - @Nullable UiccAccessRule[] accessRules, String cardString) { + @Nullable UiccAccessRule[] nativeAccessRules, String cardString) { this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number, - roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString, -1, + roaming, icon, mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString, -1, false, null, false, TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null); + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null); } /** @@ -220,12 +228,12 @@ public class SubscriptionInfo implements Parcelable { public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded, - @Nullable UiccAccessRule[] accessRules, String cardString, boolean isOpportunistic, - @Nullable String groupUUID, int carrierId, int profileClass) { + @Nullable UiccAccessRule[] nativeAccessRules, String cardString, + boolean isOpportunistic, @Nullable String groupUUID, int carrierId, int profileClass) { this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number, - roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString, -1, + roaming, icon, mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString, -1, isOpportunistic, groupUUID, false, carrierId, profileClass, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null); + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null); } /** @@ -234,9 +242,10 @@ public class SubscriptionInfo implements Parcelable { public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded, - @Nullable UiccAccessRule[] accessRules, String cardString, int cardId, + @Nullable UiccAccessRule[] nativeAccessRules, String cardString, int cardId, boolean isOpportunistic, @Nullable String groupUUID, boolean isGroupDisabled, - int carrierId, int profileClass, int subType, @Nullable String groupOwner) { + int carrierId, int profileClass, int subType, @Nullable String groupOwner, + @Nullable UiccAccessRule[] carrierConfigAccessRules) { this.mId = id; this.mIccId = iccId; this.mSimSlotIndex = simSlotIndex; @@ -251,7 +260,7 @@ public class SubscriptionInfo implements Parcelable { this.mMnc = mnc; this.mCountryIso = countryIso; this.mIsEmbedded = isEmbedded; - this.mAccessRules = accessRules; + this.mNativeAccessRules = nativeAccessRules; this.mCardString = cardString; this.mCardId = cardId; this.mIsOpportunistic = isOpportunistic; @@ -261,6 +270,7 @@ public class SubscriptionInfo implements Parcelable { this.mProfileClass = profileClass; this.mSubscriptionType = subType; this.mGroupOwner = groupOwner; + this.mCarrierConfigAccessRules = carrierConfigAccessRules; } /** @@ -566,7 +576,8 @@ public class SubscriptionInfo implements Parcelable { if (!isEmbedded()) { throw new UnsupportedOperationException("Not an embedded subscription"); } - if (mAccessRules == null) { + List<UiccAccessRule> allAccessRules = getAllAccessRules(); + if (allAccessRules == null) { return false; } PackageManager packageManager = context.getPackageManager(); @@ -576,7 +587,7 @@ public class SubscriptionInfo implements Parcelable { } catch (PackageManager.NameNotFoundException e) { throw new IllegalArgumentException("Unknown package: " + packageName, e); } - for (UiccAccessRule rule : mAccessRules) { + for (UiccAccessRule rule : allAccessRules) { if (rule.getCarrierPrivilegeStatus(packageInfo) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { return true; @@ -586,7 +597,10 @@ public class SubscriptionInfo implements Parcelable { } /** - * @return the {@link UiccAccessRule}s dictating who is authorized to manage this subscription. + * @return the {@link UiccAccessRule}s that are stored in Uicc, dictating who + * is authorized to manage this subscription. + * TODO and fix it properly in R / master: either deprecate this and have 3 APIs + * native + carrier + all, or have this return all by default. * @throws UnsupportedOperationException if this subscription is not embedded. * @hide */ @@ -595,8 +609,25 @@ public class SubscriptionInfo implements Parcelable { if (!isEmbedded()) { throw new UnsupportedOperationException("Not an embedded subscription"); } - if (mAccessRules == null) return null; - return Arrays.asList(mAccessRules); + if (mNativeAccessRules == null) return null; + return Arrays.asList(mNativeAccessRules); + } + + /** + * @return the {@link UiccAccessRule}s that are both stored on Uicc and in carrierConfigs + * dictating who is authorized to manage this subscription. + * @hide + */ + public @Nullable List<UiccAccessRule> getAllAccessRules() { + if (!isEmbedded()) { + throw new UnsupportedOperationException("Not an embedded subscription"); + } + List<UiccAccessRule> merged = new ArrayList<>(); + if (mNativeAccessRules != null) merged.addAll(getAccessRules()); + if (mCarrierConfigAccessRules != null) { + merged.addAll(Arrays.asList(mCarrierConfigAccessRules)); + } + return merged.isEmpty() ? null : merged; } /** @@ -651,7 +682,7 @@ public class SubscriptionInfo implements Parcelable { String countryIso = source.readString(); Bitmap iconBitmap = source.readParcelable(Bitmap.class.getClassLoader()); boolean isEmbedded = source.readBoolean(); - UiccAccessRule[] accessRules = source.createTypedArray(UiccAccessRule.CREATOR); + UiccAccessRule[] nativeAccessRules = source.createTypedArray(UiccAccessRule.CREATOR); String cardString = source.readString(); int cardId = source.readInt(); boolean isOpportunistic = source.readBoolean(); @@ -663,11 +694,14 @@ public class SubscriptionInfo implements Parcelable { String[] ehplmns = source.readStringArray(); String[] hplmns = source.readStringArray(); String groupOwner = source.readString(); + UiccAccessRule[] carrierConfigAccessRules = source.createTypedArray( + UiccAccessRule.CREATOR); SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, - countryIso, isEmbedded, accessRules, cardString, cardId, isOpportunistic, - groupUUID, isGroupDisabled, carrierid, profileClass, subType, groupOwner); + countryIso, isEmbedded, nativeAccessRules, cardString, cardId, isOpportunistic, + groupUUID, isGroupDisabled, carrierid, profileClass, subType, groupOwner, + carrierConfigAccessRules); info.setAssociatedPlmns(ehplmns, hplmns); return info; } @@ -694,7 +728,7 @@ public class SubscriptionInfo implements Parcelable { dest.writeString(mCountryIso); dest.writeParcelable(mIconBitmap, flags); dest.writeBoolean(mIsEmbedded); - dest.writeTypedArray(mAccessRules, flags); + dest.writeTypedArray(mNativeAccessRules, flags); dest.writeString(mCardString); dest.writeInt(mCardId); dest.writeBoolean(mIsOpportunistic); @@ -706,6 +740,7 @@ public class SubscriptionInfo implements Parcelable { dest.writeStringArray(mEhplmns); dest.writeStringArray(mHplmns); dest.writeString(mGroupOwner); + dest.writeTypedArray(mCarrierConfigAccessRules, flags); } @Override @@ -736,9 +771,9 @@ public class SubscriptionInfo implements Parcelable { + " carrierId=" + mCarrierId + " displayName=" + mDisplayName + " carrierName=" + mCarrierName + " nameSource=" + mNameSource + " iconTint=" + mIconTint + " mNumber=" + Rlog.pii(Build.IS_DEBUGGABLE, mNumber) - + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc=" + mMcc - + " mnc=" + mMnc + " mCountryIso=" + mCountryIso + " isEmbedded=" + mIsEmbedded - + " accessRules=" + Arrays.toString(mAccessRules) + + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc + + " mnc " + mMnc + "mCountryIso=" + mCountryIso + " isEmbedded " + mIsEmbedded + + " nativeAccessRules " + Arrays.toString(mNativeAccessRules) + " cardString=" + cardStringToPrint + " cardId=" + mCardId + " isOpportunistic=" + mIsOpportunistic + " mGroupUUID=" + mGroupUUID + " mIsGroupDisabled=" + mIsGroupDisabled @@ -746,14 +781,15 @@ public class SubscriptionInfo implements Parcelable { + " ehplmns=" + Arrays.toString(mEhplmns) + " hplmns=" + Arrays.toString(mHplmns) + " subscriptionType=" + mSubscriptionType - + " mGroupOwner=" + mGroupOwner + "}"; + + " mGroupOwner=" + mGroupOwner + + " carrierConfigAccessRules=" + mCarrierConfigAccessRules + "}"; } @Override public int hashCode() { return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded, mIsOpportunistic, mGroupUUID, mIccId, mNumber, mMcc, mMnc, - mCountryIso, mCardString, mCardId, mDisplayName, mCarrierName, mAccessRules, + mCountryIso, mCardString, mCardId, mDisplayName, mCarrierName, mNativeAccessRules, mIsGroupDisabled, mCarrierId, mProfileClass, mGroupOwner); } @@ -789,7 +825,7 @@ public class SubscriptionInfo implements Parcelable { && Objects.equals(mGroupOwner, toCompare.mGroupOwner) && TextUtils.equals(mDisplayName, toCompare.mDisplayName) && TextUtils.equals(mCarrierName, toCompare.mCarrierName) - && Arrays.equals(mAccessRules, toCompare.mAccessRules) + && Arrays.equals(mNativeAccessRules, toCompare.mNativeAccessRules) && mProfileClass == toCompare.mProfileClass && Arrays.equals(mEhplmns, toCompare.mEhplmns) && Arrays.equals(mHplmns, toCompare.mHplmns); diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 8c53c5125b8d..a84c916dde34 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -571,6 +571,16 @@ public class SubscriptionManager { public static final String ACCESS_RULES = "access_rules"; /** + * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from + * {@link UiccAccessRule#encodeRules} but for the rules that come from CarrierConfigs. + * Only present if there are access rules in CarrierConfigs + * <p>TYPE: BLOB + * @hide + */ + public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS = + "access_rules_from_carrier_configs"; + + /** * TelephonyProvider column name identifying whether an embedded subscription is on a removable * card. Such subscriptions are marked inaccessible as soon as the current card is removed. * Otherwise, they will remain accessible unless explicitly deleted. Only present if @@ -2601,7 +2611,7 @@ public class SubscriptionManager { if (!info.isEmbedded()) { throw new IllegalArgumentException("Not an embedded subscription"); } - if (info.getAccessRules() == null) { + if (info.getAllAccessRules() == null) { return false; } PackageManager packageManager = mContext.getPackageManager(); @@ -2611,7 +2621,7 @@ public class SubscriptionManager { } catch (PackageManager.NameNotFoundException e) { throw new IllegalArgumentException("Unknown package: " + packageName, e); } - for (UiccAccessRule rule : info.getAccessRules()) { + for (UiccAccessRule rule : info.getAllAccessRules()) { if (rule.getCarrierPrivilegeStatus(packageInfo) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { return true; diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 35b435d8dfb7..553bff26f78f 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -11047,6 +11047,8 @@ public class TelephonyManager { * The {@link #EXTRA_NETWORK_COUNTRY} extra indicates the country code of the current * network returned by {@link #getNetworkCountryIso()}. * + * <p>There may be a delay of several minutes before reporting that no country is detected. + * * @see #EXTRA_NETWORK_COUNTRY * @see #getNetworkCountryIso() */ diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java index 5d8d79367ba4..89d30c0d4373 100644 --- a/telephony/java/android/telephony/data/DataServiceCallback.java +++ b/telephony/java/android/telephony/data/DataServiceCallback.java @@ -42,6 +42,8 @@ public class DataServiceCallback { private static final String TAG = DataServiceCallback.class.getSimpleName(); + private static final boolean DBG = true; + /** * Result of data requests * @hide @@ -81,6 +83,7 @@ public class DataServiceCallback { IDataServiceCallback callback = mCallback.get(); if (callback != null) { try { + if (DBG) Rlog.d(TAG, "onSetupDataCallComplete"); callback.onSetupDataCallComplete(result, response); } catch (RemoteException e) { Rlog.e(TAG, "Failed to onSetupDataCallComplete on the remote"); @@ -98,6 +101,7 @@ public class DataServiceCallback { IDataServiceCallback callback = mCallback.get(); if (callback != null) { try { + if (DBG) Rlog.d(TAG, "onDeactivateDataCallComplete"); callback.onDeactivateDataCallComplete(result); } catch (RemoteException e) { Rlog.e(TAG, "Failed to onDeactivateDataCallComplete on the remote"); @@ -169,6 +173,7 @@ public class DataServiceCallback { IDataServiceCallback callback = mCallback.get(); if (callback != null) { try { + if (DBG) Rlog.d(TAG, "onDataCallListChanged"); callback.onDataCallListChanged(dataCallList); } catch (RemoteException e) { Rlog.e(TAG, "Failed to onDataCallListChanged on the remote"); diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java index 8e1324b3be0b..6187e67a6acb 100644 --- a/telephony/java/android/telephony/ims/ImsException.java +++ b/telephony/java/android/telephony/ims/ImsException.java @@ -39,11 +39,11 @@ public final class ImsException extends Exception { */ public static final int CODE_ERROR_UNSPECIFIED = 0; /** - * The operation has failed because there is no {@link ImsService} available to service it. This - * may be due to an {@link ImsService} crash or other illegal state. + * The operation has failed because there is no remote process available to service it. This + * may be due to a process crash or other illegal state. * <p> * This is a temporary error and the operation may be retried until the connection to the - * {@link ImsService} is restored. + * remote process is restored. */ public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1; diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl index 691cfba9a28c..4b98b79f1095 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl @@ -16,10 +16,38 @@ package android.telephony.ims.aidl; +import android.net.Uri; +import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.aidl.IImsCapabilityCallback; +import android.telephony.ims.aidl.IRcsFeatureListener; +import android.telephony.ims.feature.CapabilityChangeRequest; + +import java.util.List; + /** * See RcsFeature for more information. * {@hide} */ interface IImsRcsFeature { - //Empty Default Implementation + // Not oneway because we need to verify this completes before doing anything else. + void setListener(IRcsFeatureListener listener); + int queryCapabilityStatus(); + // Inherited from ImsFeature + int getFeatureState(); + oneway void addCapabilityCallback(IImsCapabilityCallback c); + oneway void removeCapabilityCallback(IImsCapabilityCallback c); + oneway void changeCapabilitiesConfiguration(in CapabilityChangeRequest r, + IImsCapabilityCallback c); + oneway void queryCapabilityConfiguration(int capability, int radioTech, + IImsCapabilityCallback c); + // RcsPresenceExchangeImplBase specific api + oneway void requestCapabilities(in List<Uri> uris, int operationToken); + oneway void updateCapabilities(in RcsContactUceCapability capabilities, int operationToken); + // RcsSipOptionsImplBase specific api + oneway void sendCapabilityRequest(in Uri contactUri, + in RcsContactUceCapability capabilities, int operationToken); + oneway void respondToCapabilityRequest(in String contactUri, + in RcsContactUceCapability ownCapabilities, int operationToken); + oneway void respondToCapabilityRequestWithError(in Uri contactUri, int code, in String reason, + int operationToken); }
\ No newline at end of file diff --git a/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl b/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl new file mode 100644 index 000000000000..881b4776b25b --- /dev/null +++ b/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl @@ -0,0 +1,42 @@ +/* + * 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.aidl; + +import android.net.Uri; +import android.telephony.ims.RcsContactUceCapability; + +import java.util.List; + +/** + * Listener interface for updates from the RcsFeature back to the framework. + * {@hide} + */ +interface IRcsFeatureListener { + //RcsCapabilityExchange specific + oneway void onCommandUpdate(int commandCode, int operationToken); + // RcsPresenceExchangeImplBase Specific + oneway void onNetworkResponse(int code, in String reason, int operationToken); + oneway void onCapabilityRequestResponsePresence(in List<RcsContactUceCapability> infos, + int operationToken); + oneway void onNotifyUpdateCapabilities(); + oneway void onUnpublish(); + // RcsSipOptionsImplBase specific + oneway void onCapabilityRequestResponseOptions(int code, in String reason, + in RcsContactUceCapability info, int operationToken); + oneway void onRemoteCapabilityRequest(in Uri contactUri, in RcsContactUceCapability remoteInfo, + int operationToken); +}
\ No newline at end of file diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java index 8f8989909f9f..3a9979d78a55 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -33,12 +33,8 @@ import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; -import java.util.Set; -import java.util.WeakHashMap; /** * Base class for all IMS features that are supported by the framework. Use a concrete subclass @@ -52,35 +48,6 @@ public abstract class ImsFeature { private static final String LOG_TAG = "ImsFeature"; /** - * Action to broadcast when ImsService is up. - * Internal use only. - * Only defined here separately for compatibility purposes with the old ImsService. - * - * @hide - */ - public static final String ACTION_IMS_SERVICE_UP = - "com.android.ims.IMS_SERVICE_UP"; - - /** - * Action to broadcast when ImsService is down. - * Internal use only. - * Only defined here separately for compatibility purposes with the old ImsService. - * - * @hide - */ - public static final String ACTION_IMS_SERVICE_DOWN = - "com.android.ims.IMS_SERVICE_DOWN"; - - /** - * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents. - * A long value; the phone ID corresponding to the IMS service coming up or down. - * Only defined here separately for compatibility purposes with the old ImsService. - * - * @hide - */ - public static final String EXTRA_PHONE_ID = "android:phone_id"; - - /** * Invalid feature value * @hide */ @@ -335,8 +302,8 @@ public abstract class ImsFeature { /** @hide */ protected final Object mLock = new Object(); - private final Set<IImsFeatureStatusCallback> mStatusCallbacks = - Collections.newSetFromMap(new WeakHashMap<>()); + private final RemoteCallbackList<IImsFeatureStatusCallback> mStatusCallbacks = + new RemoteCallbackList<>(); private @ImsState int mState = STATE_UNAVAILABLE; private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; private final RemoteCallbackList<IImsCapabilityCallback> mCapabilityCallbacks = @@ -397,9 +364,7 @@ public abstract class ImsFeature { // If we have just connected, send queued status. c.notifyImsFeatureStatus(getFeatureState()); // Add the callback if the callback completes successfully without a RemoteException. - synchronized (mLock) { - mStatusCallbacks.add(c); - } + mStatusCallbacks.register(c); } catch (RemoteException e) { Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage()); } @@ -411,29 +376,21 @@ public abstract class ImsFeature { */ @VisibleForTesting public void removeImsFeatureStatusCallback(@NonNull IImsFeatureStatusCallback c) { - synchronized (mLock) { - mStatusCallbacks.remove(c); - } + mStatusCallbacks.unregister(c); } /** * Internal method called by ImsFeature when setFeatureState has changed. */ private void notifyFeatureState(@ImsState int state) { - synchronized (mLock) { - for (Iterator<IImsFeatureStatusCallback> iter = mStatusCallbacks.iterator(); - iter.hasNext(); ) { - IImsFeatureStatusCallback callback = iter.next(); - try { - Log.i(LOG_TAG, "notifying ImsFeatureState=" + state); - callback.notifyImsFeatureStatus(state); - } catch (RemoteException e) { - // remove if the callback is no longer alive. - iter.remove(); - Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage()); - } + mStatusCallbacks.broadcast((c) -> { + try { + c.notifyImsFeatureStatus(state); + } catch (RemoteException e) { + Log.w(LOG_TAG, e + " notifyFeatureState() - Skipping " + + "callback."); } - } + }); } /** @@ -452,10 +409,23 @@ public abstract class ImsFeature { /** * @hide */ - public final void removeCapabilityCallback(IImsCapabilityCallback c) { + final void removeCapabilityCallback(IImsCapabilityCallback c) { mCapabilityCallbacks.unregister(c); } + /**@hide*/ + final void queryCapabilityConfigurationInternal(int capability, int radioTech, + IImsCapabilityCallback c) { + boolean enabled = queryCapabilityConfiguration(capability, radioTech); + try { + if (c != null) { + c.onQueryCapabilityConfiguration(capability, radioTech, enabled); + } + } catch (RemoteException e) { + Log.e(LOG_TAG, "queryCapabilityConfigurationInternal called on dead binder!"); + } + } + /** * @return the cached capabilities status for this feature. * @hide @@ -484,31 +454,36 @@ public abstract class ImsFeature { /** * Called by the ImsFeature when the capabilities status has changed. * - * @param c A {@link Capabilities} containing the new Capabilities status. + * @param caps the new {@link Capabilities} status of the {@link ImsFeature}. * * @hide */ - protected final void notifyCapabilitiesStatusChanged(Capabilities c) { + protected final void notifyCapabilitiesStatusChanged(Capabilities caps) { synchronized (mLock) { - mCapabilityStatus = c.copy(); + mCapabilityStatus = caps.copy(); } - int count = mCapabilityCallbacks.beginBroadcast(); - try { - for (int i = 0; i < count; i++) { - try { - mCapabilityCallbacks.getBroadcastItem(i).onCapabilitiesStatusChanged( - c.mCapabilities); - } catch (RemoteException e) { - Log.w(LOG_TAG, e + " " + "notifyCapabilitiesStatusChanged() - Skipping " + - "callback."); - } + mCapabilityCallbacks.broadcast((callback) -> { + try { + callback.onCapabilitiesStatusChanged(caps.mCapabilities); + } catch (RemoteException e) { + Log.w(LOG_TAG, e + " notifyCapabilitiesStatusChanged() - Skipping " + + "callback."); } - } finally { - mCapabilityCallbacks.finishBroadcast(); - } + }); } /** + * Provides the ImsFeature with the ability to return the framework Capability Configuration + * for a provided Capability. If the framework calls {@link #changeEnabledCapabilities} and + * includes a capability A to enable or disable, this method should return the correct enabled + * status for capability A. + * @param capability The capability that we are querying the configuration for. + * @return true if the capability is enabled, false otherwise. + * @hide + */ + public abstract boolean queryCapabilityConfiguration(int capability, int radioTech); + + /** * Features should override this method to receive Capability preference change requests from * the framework using the provided {@link CapabilityChangeRequest}. If any of the capabilities * in the {@link CapabilityChangeRequest} are not able to be completed due to an error, diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java index 898ca48cd1df..056a0abe7a29 100644 --- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java +++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java @@ -37,7 +37,6 @@ import android.telephony.ims.stub.ImsMultiEndpointImplBase; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.telephony.ims.stub.ImsSmsImplBase; import android.telephony.ims.stub.ImsUtImplBase; -import android.util.Log; import com.android.ims.internal.IImsCallSession; import com.android.ims.internal.IImsEcbm; @@ -154,17 +153,13 @@ public class MmTelFeature extends ImsFeature { @Override public void changeCapabilitiesConfiguration(CapabilityChangeRequest request, IImsCapabilityCallback c) { - synchronized (mLock) { - MmTelFeature.this.requestChangeEnabledCapabilities(request, c); - } + MmTelFeature.this.requestChangeEnabledCapabilities(request, c); } @Override public void queryCapabilityConfiguration(int capability, int radioTech, IImsCapabilityCallback c) { - synchronized (mLock) { - queryCapabilityConfigurationInternal(capability, radioTech, c); - } + queryCapabilityConfigurationInternal(capability, radioTech, c); } @Override @@ -381,18 +376,6 @@ public class MmTelFeature extends ImsFeature { } } - private void queryCapabilityConfigurationInternal(int capability, int radioTech, - IImsCapabilityCallback c) { - boolean enabled = queryCapabilityConfiguration(capability, radioTech); - try { - if (c != null) { - c.onQueryCapabilityConfiguration(capability, radioTech, enabled); - } - } catch (RemoteException e) { - Log.e(LOG_TAG, "queryCapabilityConfigurationInternal called on dead binder!"); - } - } - /** * The current capability status that this MmTelFeature has defined is available. This * configuration will be used by the platform to figure out which capabilities are CURRENTLY @@ -512,6 +495,7 @@ public class MmTelFeature extends ImsFeature { * @param capability The capability that we are querying the configuration for. * @return true if the capability is enabled, false otherwise. */ + @Override public boolean queryCapabilityConfiguration(@MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) { // Base implementation - Override to provide functionality diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java index 5fae3eebbfc6..f69b434eb120 100644 --- a/telephony/java/android/telephony/ims/feature/RcsFeature.java +++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java @@ -16,14 +16,32 @@ package android.telephony.ims.feature; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.SystemApi; +import android.net.Uri; +import android.os.Binder; +import android.os.RemoteException; +import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.aidl.IImsCapabilityCallback; import android.telephony.ims.aidl.IImsRcsFeature; +import android.telephony.ims.aidl.IRcsFeatureListener; +import android.telephony.ims.stub.ImsRegistrationImplBase; import android.telephony.ims.stub.RcsPresenceExchangeImplBase; import android.telephony.ims.stub.RcsSipOptionsImplBase; +import android.util.Log; + +import com.android.internal.util.FunctionalUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.List; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; /** * Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend @@ -33,10 +51,132 @@ import java.lang.annotation.RetentionPolicy; @SystemApi public class RcsFeature extends ImsFeature { - /**{@inheritDoc}*/ - private final IImsRcsFeature mImsRcsBinder = new IImsRcsFeature.Stub() { - // Empty Default Implementation. - }; + private static final String LOG_TAG = "RcsFeature"; + + private static final class RcsFeatureBinder extends IImsRcsFeature.Stub { + // Reference the outer class in order to have better test coverage metrics instead of + // creating a inner class referencing the outer class directly. + private final RcsFeature mReference; + private final Executor mExecutor; + + RcsFeatureBinder(RcsFeature classRef, @CallbackExecutor Executor executor) { + mReference = classRef; + mExecutor = executor; + } + + @Override + public void setListener(IRcsFeatureListener listener) { + mReference.setListener(listener); + } + + @Override + public int queryCapabilityStatus() throws RemoteException { + return executeMethodAsyncForResult( + () -> mReference.queryCapabilityStatus().mCapabilities, + "queryCapabilityStatus"); + } + + @Override + public void addCapabilityCallback(IImsCapabilityCallback c) throws RemoteException { + executeMethodAsync(() -> mReference.addCapabilityCallback(c), "addCapabilityCallback"); + } + + @Override + public void removeCapabilityCallback(IImsCapabilityCallback c) throws RemoteException { + executeMethodAsync(() -> mReference.removeCapabilityCallback(c), + "removeCapabilityCallback"); + } + + @Override + public void changeCapabilitiesConfiguration(CapabilityChangeRequest r, + IImsCapabilityCallback c) throws RemoteException { + executeMethodAsync(() -> mReference.requestChangeEnabledCapabilities(r, c), + "changeCapabilitiesConfiguration"); + } + + @Override + public void queryCapabilityConfiguration(int capability, int radioTech, + IImsCapabilityCallback c) throws RemoteException { + executeMethodAsync(() -> mReference.queryCapabilityConfigurationInternal(capability, + radioTech, c), "queryCapabilityConfiguration"); + } + + @Override + public int getFeatureState() throws RemoteException { + return executeMethodAsyncForResult(mReference::getFeatureState, "getFeatureState"); + } + + // RcsPresenceExchangeImplBase specific APIS + @Override + public void requestCapabilities(List<Uri> uris, int operationToken) throws RemoteException { + executeMethodAsync(() -> mReference.getPresenceExchangeInternal() + .requestCapabilities(uris, operationToken), "requestCapabilities"); + } + @Override + public void updateCapabilities(RcsContactUceCapability capabilities, int operationToken) + throws RemoteException { + executeMethodAsync(() -> mReference.getPresenceExchangeInternal() + .updateCapabilities(capabilities, operationToken), + "updateCapabilities"); + + } + // RcsSipOptionsImplBase specific APIS + @Override + public void sendCapabilityRequest(Uri contactUri, RcsContactUceCapability capabilities, + int operationToken) throws RemoteException { + executeMethodAsync(() -> mReference.getOptionsExchangeInternal() + .sendCapabilityRequest(contactUri, capabilities, operationToken), + "sendCapabilityRequest"); + + } + @Override + public void respondToCapabilityRequest(String contactUri, + RcsContactUceCapability ownCapabilities, int operationToken) + throws RemoteException { + executeMethodAsync(() -> mReference.getOptionsExchangeInternal() + .respondToCapabilityRequest(contactUri, ownCapabilities, + operationToken), "respondToCapabilityRequest"); + + } + @Override + public void respondToCapabilityRequestWithError(Uri contactUri, int code, String reason, + int operationToken) throws RemoteException { + executeMethodAsync(() -> mReference.getOptionsExchangeInternal() + .respondToCapabilityRequestWithError(contactUri, code, reason, + operationToken), "respondToCapabilityRequestWithError"); + } + + // Call the methods with a clean calling identity on the executor and wait indefinitely for + // the future to return. + private void executeMethodAsync(FunctionalUtils.ThrowingRunnable r, String errorLogName) + throws RemoteException { + // call with a clean calling identity on the executor and wait indefinitely for the + // future to return. + try { + CompletableFuture.runAsync( + () -> Binder.withCleanCallingIdentity(r), mExecutor).join(); + } catch (CancellationException | CompletionException e) { + Log.w(LOG_TAG, "RcsFeatureBinder - " + errorLogName + " exception: " + + e.getMessage()); + throw new RemoteException(e.getMessage()); + } + } + + private <T> T executeMethodAsyncForResult(FunctionalUtils.ThrowingSupplier<T> r, + String errorLogName) throws RemoteException { + // call with a clean calling identity on the executor and wait indefinitely for the + // future to return. + CompletableFuture<T> future = CompletableFuture.supplyAsync( + () -> Binder.withCleanCallingIdentity(r), mExecutor); + try { + return future.get(); + } catch (ExecutionException | InterruptedException e) { + Log.w(LOG_TAG, "RcsFeatureBinder - " + errorLogName + " exception: " + + e.getMessage()); + throw new RemoteException(e.getMessage()); + } + } + } /** * Contains the capabilities defined and supported by a {@link RcsFeature} in the @@ -81,27 +221,66 @@ public class RcsFeature extends ImsFeature { /**@hide*/ public RcsImsCapabilities(@RcsImsCapabilityFlag int capabilities) { + super(capabilities); + } + /**@hide*/ + private RcsImsCapabilities(Capabilities c) { + super(c.getMask()); } /**@hide*/ @Override public void addCapabilities(@RcsImsCapabilityFlag int capabilities) { - + super.addCapabilities(capabilities); } /**@hide*/ @Override public void removeCapabilities(@RcsImsCapabilityFlag int capabilities) { - + super.removeCapabilities(capabilities); } /**@hide*/ @Override public boolean isCapable(@RcsImsCapabilityFlag int capabilities) { - return false; + return super.isCapable(capabilities); + } + } + + private final RcsFeatureBinder mImsRcsBinder; + private IRcsFeatureListener mListenerBinder; + private RcsPresenceExchangeImplBase mPresExchange; + private RcsSipOptionsImplBase mSipOptions; + + /** + * Create a new RcsFeature. + * <p> + * Method stubs called from the framework will be called asynchronously. To specify the + * {@link Executor} that the methods stubs will be called, use + * {@link RcsFeature#RcsFeature(Executor)} instead. + */ + public RcsFeature() { + super(); + // Run on the Binder threads that call them. + mImsRcsBinder = new RcsFeatureBinder(this, Runnable::run); + } + + /** + * Create a new RcsFeature using the Executor specified for methods being called by the + * framework. + * @param executor The executor for the framework to use when making calls to this service. + * @hide + */ + public RcsFeature(@NonNull Executor executor) { + super(); + if (executor == null) { + throw new IllegalArgumentException("executor can not be null."); } + // Run on the Binder thread by default. + mImsRcsBinder = new RcsFeatureBinder(this, executor); } + /** * 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 @@ -111,7 +290,7 @@ public class RcsFeature extends ImsFeature { */ @Override public final RcsImsCapabilities queryCapabilityStatus() { - throw new UnsupportedOperationException(); + return new RcsImsCapabilities(super.queryCapabilityStatus()); } /** @@ -120,8 +299,11 @@ public class RcsFeature extends ImsFeature { * Call {@link #queryCapabilityStatus()} to return the current capability status. * @hide */ - public final void notifyCapabilitiesStatusChanged(RcsImsCapabilities c) { - throw new UnsupportedOperationException(); + public final void notifyCapabilitiesStatusChanged(@NonNull RcsImsCapabilities c) { + if (c == null) { + throw new IllegalArgumentException("RcsImsCapabilities must be non-null!"); + } + super.notifyCapabilitiesStatusChanged(c); } /** @@ -133,8 +315,10 @@ public class RcsFeature extends ImsFeature { * @hide */ public boolean queryCapabilityConfiguration( - @RcsImsCapabilities.RcsImsCapabilityFlag int capability) { - throw new UnsupportedOperationException(); + @RcsImsCapabilities.RcsImsCapabilityFlag int capability, + @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) { + // Base Implementation - Override to provide functionality + return false; } /** * Called from the framework when the {@link RcsImsCapabilities} that have been configured for @@ -155,7 +339,7 @@ public class RcsFeature extends ImsFeature { @Override public void changeEnabledCapabilities(CapabilityChangeRequest request, CapabilityCallbackProxy c) { - throw new UnsupportedOperationException(); + // Base Implementation - Override to provide functionality } /** @@ -192,13 +376,6 @@ public class RcsFeature extends ImsFeature { return new RcsPresenceExchangeImplBase(); } - /** - * Construct a new {@link RcsFeature} instance. - */ - public RcsFeature() { - super(); - } - /**{@inheritDoc}*/ @Override public void onFeatureRemoved() { @@ -218,4 +395,40 @@ public class RcsFeature extends ImsFeature { public final IImsRcsFeature getBinder() { return mImsRcsBinder; } + + /**@hide*/ + public IRcsFeatureListener getListener() { + synchronized (mLock) { + return mListenerBinder; + } + } + + private void setListener(IRcsFeatureListener listener) { + synchronized (mLock) { + mListenerBinder = listener; + if (mListenerBinder != null) { + onFeatureReady(); + } + } + } + + private RcsPresenceExchangeImplBase getPresenceExchangeInternal() { + synchronized (mLock) { + if (mPresExchange == null) { + mPresExchange = getPresenceExchangeImpl(); + mPresExchange.initialize(this); + } + return mPresExchange; + } + } + + private RcsSipOptionsImplBase getOptionsExchangeInternal() { + synchronized (mLock) { + if (mSipOptions == null) { + mSipOptions = getOptionsExchangeImpl(); + mSipOptions.initialize(this); + } + return mSipOptions; + } + } } diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java index 289fd4c8a134..fda295a27111 100644 --- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java +++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java @@ -17,6 +17,11 @@ package android.telephony.ims.stub; import android.annotation.IntDef; +import android.os.RemoteException; +import android.telephony.ims.ImsException; +import android.telephony.ims.aidl.IRcsFeatureListener; +import android.telephony.ims.feature.ImsFeature; +import android.telephony.ims.feature.RcsFeature; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -72,6 +77,24 @@ public class RcsCapabilityExchange { }) public @interface CommandCode {} + + private RcsFeature mFeature; + + /** @hide */ + public final void initialize(RcsFeature feature) { + mFeature = feature; + } + + /** @hide */ + protected final IRcsFeatureListener getListener() throws ImsException { + IRcsFeatureListener listener = mFeature.getListener(); + if (listener == null) { + throw new ImsException("Connection to Framework has not been established, wait for " + + "onFeatureReady().", ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } + return mFeature.getListener(); + } + /** * 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 @@ -82,8 +105,18 @@ public class RcsCapabilityExchange { * @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. + * @throws ImsException If this {@link RcsCapabilityExchange} instance is not currently + * connected to the framework. This can happen if the {@link RcsFeature} is not + * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the + * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the + * Telephony stack has crashed. */ - public final void onCommandUpdate(@CommandCode int code, int operationToken) { - throw new UnsupportedOperationException(); + public final void onCommandUpdate(@CommandCode int code, int operationToken) + throws ImsException { + try { + getListener().onCommandUpdate(code, operationToken); + } catch (RemoteException e) { + throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } } } diff --git a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java index 44024703042d..055fca57a628 100644 --- a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java +++ b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java @@ -19,7 +19,11 @@ package android.telephony.ims.stub; import android.annotation.IntDef; import android.annotation.NonNull; import android.net.Uri; +import android.os.RemoteException; +import android.telephony.ims.ImsException; import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.feature.ImsFeature; +import android.telephony.ims.feature.RcsFeature; import android.util.Log; import java.lang.annotation.Retention; @@ -113,54 +117,95 @@ public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange { * 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. + * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently + * connected to the framework. This can happen if the {@link RcsFeature} is not + * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the + * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the + * Telephony stack has crashed. */ public final void onNetworkResponse(@PresenceResponseCode int code, @NonNull String reason, - int operationToken) { - throw new UnsupportedOperationException(); + int operationToken) throws ImsException { + try { + getListener().onNetworkResponse(code, reason, operationToken); + } catch (RemoteException e) { + throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } } /** * Provides the framework with the requested contacts’ capabilities requested by the framework - * using {@link #requestCapabilities(List, int)} . + * using {@link #requestCapabilities(List, int)}. + * + * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently + * connected to the framework. This can happen if the {@link RcsFeature} is not + * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the + * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the + * Telephony stack has crashed. */ public final void onCapabilityRequestResponse(@NonNull List<RcsContactUceCapability> infos, - int operationToken) { - throw new UnsupportedOperationException(); + int operationToken) throws ImsException { + try { + getListener().onCapabilityRequestResponsePresence(infos, operationToken); + } catch (RemoteException e) { + throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } } /** * 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. + * {@link #updateCapabilities(RcsContactUceCapability, int)}. * <p> - * The device will cache all presence publications after boot until this method is called once. - */ - public final void onNotifyUpdateCapabilites() { - throw new UnsupportedOperationException(); + * This is typically used when trying to generate an initial PUBLISH for a new subscription to + * the network. The device will cache all presence publications after boot until this method is + * called once. + * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently + * connected to the framework. This can happen if the {@link RcsFeature} is not + * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the + * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the + * Telephony stack has crashed. + */ + public final void onNotifyUpdateCapabilites() throws ImsException { + try { + getListener().onNotifyUpdateCapabilities(); + } catch (RemoteException e) { + throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } } /** * Notify the framework that the device’s capabilities have been unpublished from the network. - */ - public final void onUnpublish() { - throw new UnsupportedOperationException(); + * + * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently + * connected to the framework. This can happen if the {@link RcsFeature} is not + * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the + * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the + * Telephony stack has crashed. + */ + public final void onUnpublish() throws ImsException { + try { + getListener().onUnpublish(); + } catch (RemoteException e) { + throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } } /** - * The user capabilities of one or multiple contacts have been requested. + * The user capabilities of one or multiple contacts have been requested by the framework. * <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. + * The implementer must follow up this call with an {@link #onCommandUpdate(int, int)} call to + * indicate whether or not this operation succeeded. If this operation succeeds, network + * response updates should be sent to the framework 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 {@link Uri}s 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 @@ -169,14 +214,20 @@ public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange { 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); + try { + getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken); + } catch (RemoteException | ImsException e) { + // Do not do anything, this is a stub implementation. + } } /** - * 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)}. + * The capabilities of this device have been updated and should be published to the network. + * <p> + * The implementer must follow up this call with an {@link #onCommandUpdate(int, int)} call to + * indicate whether or not this operation succeeded. If this operation succeeds, network + * response updates should be sent to the framework 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)} @@ -186,6 +237,10 @@ public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange { int operationToken) { // Stub - to be implemented by service Log.w(LOG_TAG, "updateCapabilities called with no implementation."); - onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken); + try { + getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken); + } catch (RemoteException | ImsException e) { + // Do not do anything, this is a stub implementation. + } } } diff --git a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java index 3343074ea52c..1c68fc08529e 100644 --- a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java +++ b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java @@ -20,7 +20,11 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.Uri; +import android.os.RemoteException; +import android.telephony.ims.ImsException; import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.feature.ImsFeature; +import android.telephony.ims.feature.RcsFeature; import android.util.Log; import java.lang.annotation.Retention; @@ -87,10 +91,19 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange { * @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)}. + * @throws ImsException If this {@link RcsSipOptionsImplBase} instance is not currently + * connected to the framework. This can happen if the {@link RcsFeature} is not + * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the + * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the + * Telephony stack has crashed. */ public final void onCapabilityRequestResponse(@SipResponseCode int code, @NonNull String reason, - @Nullable RcsContactUceCapability info, int operationToken) { - throw new UnsupportedOperationException(); + @Nullable RcsContactUceCapability info, int operationToken) throws ImsException { + try { + getListener().onCapabilityRequestResponseOptions(code, reason, info, operationToken); + } catch (RemoteException e) { + throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } } /** @@ -104,10 +117,19 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange { * @param operationToken An unique operation token that you have generated that will be returned * by the framework in * {@link #respondToCapabilityRequest(String, RcsContactUceCapability, int)}. + * @throws ImsException If this {@link RcsSipOptionsImplBase} instance is not currently + * connected to the framework. This can happen if the {@link RcsFeature} is not + * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the + * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the + * Telephony stack has crashed. */ public final void onRemoteCapabilityRequest(@NonNull Uri contactUri, - @NonNull RcsContactUceCapability remoteInfo, int operationToken) { - throw new UnsupportedOperationException(); + @NonNull RcsContactUceCapability remoteInfo, int operationToken) throws ImsException { + try { + getListener().onRemoteCapabilityRequest(contactUri, remoteInfo, operationToken); + } catch (RemoteException e) { + throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } } /** @@ -127,7 +149,11 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange { @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); + try { + getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken); + } catch (RemoteException | ImsException e) { + // Do not do anything, this is a stub implementation. + } } /** @@ -145,7 +171,11 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange { @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); + try { + getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken); + } catch (RemoteException | ImsException e) { + // Do not do anything, this is a stub implementation. + } } /** @@ -164,6 +194,10 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange { @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); + try { + getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken); + } catch (RemoteException | ImsException e) { + // Do not do anything, this is a stub implementation. + } } } diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java index e9a177defd26..4e1ff8f5b7cd 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java +++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java @@ -32,9 +32,11 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.ContactsContract.PhoneLookup; import android.telephony.PhoneNumberUtils; -import android.text.TextUtils; import android.telephony.Rlog; import android.telephony.SubscriptionManager; +import android.text.TextUtils; + +import dalvik.annotation.compat.UnsupportedAppUsage; import java.util.ArrayList; import java.util.List; @@ -80,6 +82,10 @@ public class CallerInfoAsyncQuery { * classes. */ private static final class CookieWrapper { + @UnsupportedAppUsage + private CookieWrapper() { + } + public OnQueryCompleteListener listener; public Object cookie; public int event; @@ -527,6 +533,7 @@ public class CallerInfoAsyncQuery { /** * Releases the relevant data. */ + @UnsupportedAppUsage private void release() { mHandler.mContext = null; mHandler.mQueryUri = null; diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java index cde6db4888fa..e1113eba006f 100644 --- a/telephony/java/com/android/internal/telephony/DctConstants.java +++ b/telephony/java/com/android/internal/telephony/DctConstants.java @@ -17,6 +17,8 @@ package com.android.internal.telephony; import com.android.internal.util.Protocol; +import dalvik.annotation.compat.UnsupportedAppUsage; + /** * @hide */ @@ -37,20 +39,34 @@ public class DctConstants { * RETRYING or CONNECTING: CONNECTING * CONNECTED : CONNECTED or DISCONNECTING */ + @UnsupportedAppUsage(implicitMember = + "values()[Lcom/android/internal/telephony/DctConstants$State;") public enum State { + @UnsupportedAppUsage IDLE, + @UnsupportedAppUsage CONNECTING, + @UnsupportedAppUsage RETRYING, + @UnsupportedAppUsage CONNECTED, + @UnsupportedAppUsage DISCONNECTING, + @UnsupportedAppUsage FAILED, } + @UnsupportedAppUsage(implicitMember = + "values()[Lcom/android/internal/telephony/DctConstants$Activity;") public enum Activity { NONE, + @UnsupportedAppUsage DATAIN, + @UnsupportedAppUsage DATAOUT, + @UnsupportedAppUsage DATAINANDOUT, + @UnsupportedAppUsage DORMANT } diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java index a75096f2c082..5fb4e90b9666 100644 --- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java +++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java @@ -16,19 +16,17 @@ package com.android.internal.telephony; +import android.annotation.UnsupportedAppUsage; import android.content.res.Resources; +import android.os.Build; +import android.telephony.Rlog; import android.text.TextUtils; import android.util.SparseIntArray; -import android.annotation.UnsupportedAppUsage; -import android.os.Build; -import android.telephony.Rlog; +import com.android.internal.R; import java.nio.ByteBuffer; import java.nio.charset.Charset; -import com.android.internal.telephony.SmsConstants; -import com.android.internal.R; - import java.util.ArrayList; import java.util.List; @@ -83,6 +81,11 @@ public class GsmAlphabet { * data. */ public static class TextEncodingDetails { + + @UnsupportedAppUsage + public TextEncodingDetails() { + } + /** *The number of SMS's required to encode the text. */ diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl index 5b509b7260ba..15e7fc26ed47 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl @@ -27,6 +27,7 @@ interface IPhoneSubInfo { /** * Retrieves the unique device ID, e.g., IMEI for GSM phones. */ + @UnsupportedAppUsage String getDeviceId(String callingPackage); /** diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index a65acac737d9..9f1a2f765eee 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -94,6 +94,7 @@ interface ITelephony { * @param callingPackage the name of the package making the call. * @return returns true if the radio is on. */ + @UnsupportedAppUsage boolean isRadioOn(String callingPackage); /** @@ -1254,6 +1255,7 @@ interface ITelephony { * <p>Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ + @UnsupportedAppUsage String getDeviceId(String callingPackage); /** diff --git a/telephony/java/com/android/internal/telephony/IccCardConstants.java b/telephony/java/com/android/internal/telephony/IccCardConstants.java index d57f9afa01e9..6ff27b1152c8 100644 --- a/telephony/java/com/android/internal/telephony/IccCardConstants.java +++ b/telephony/java/com/android/internal/telephony/IccCardConstants.java @@ -17,6 +17,8 @@ package com.android.internal.telephony; import android.telephony.TelephonyManager; +import dalvik.annotation.compat.UnsupportedAppUsage; + /** * {@hide} */ @@ -65,15 +67,26 @@ public class IccCardConstants { * * The ordinal values much match {@link TelephonyManager#SIM_STATE_UNKNOWN} ... */ + @UnsupportedAppUsage(implicitMember = + "values()[Lcom/android/internal/telephony/IccCardConstants$State;") public enum State { + @UnsupportedAppUsage UNKNOWN, /** ordinal(0) == {@See TelephonyManager#SIM_STATE_UNKNOWN} */ + @UnsupportedAppUsage ABSENT, /** ordinal(1) == {@See TelephonyManager#SIM_STATE_ABSENT} */ + @UnsupportedAppUsage PIN_REQUIRED, /** ordinal(2) == {@See TelephonyManager#SIM_STATE_PIN_REQUIRED} */ + @UnsupportedAppUsage PUK_REQUIRED, /** ordinal(3) == {@See TelephonyManager#SIM_STATE_PUK_REQUIRED} */ + @UnsupportedAppUsage NETWORK_LOCKED, /** ordinal(4) == {@See TelephonyManager#SIM_STATE_NETWORK_LOCKED} */ + @UnsupportedAppUsage READY, /** ordinal(5) == {@See TelephonyManager#SIM_STATE_READY} */ + @UnsupportedAppUsage NOT_READY, /** ordinal(6) == {@See TelephonyManager#SIM_STATE_NOT_READY} */ + @UnsupportedAppUsage PERM_DISABLED, /** ordinal(7) == {@See TelephonyManager#SIM_STATE_PERM_DISABLED} */ + @UnsupportedAppUsage CARD_IO_ERROR, /** ordinal(8) == {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR} */ CARD_RESTRICTED,/** ordinal(9) == {@See TelephonyManager#SIM_STATE_CARD_RESTRICTED} */ LOADED; /** ordinal(9) == {@See TelephonyManager#SIM_STATE_LOADED} */ diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java index d5061a32ba6d..ee1a4766bf68 100644 --- a/telephony/java/com/android/internal/telephony/PhoneConstants.java +++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java @@ -15,6 +15,8 @@ */ package com.android.internal.telephony; +import dalvik.annotation.compat.UnsupportedAppUsage; + /** * @hide */ @@ -31,8 +33,12 @@ public class PhoneConstants { * ringing or waiting.</li> * </ul> */ + @UnsupportedAppUsage(implicitMember = + "values()[Lcom/android/internal/telephony/PhoneConstants$State;") public enum State { - IDLE, RINGING, OFFHOOK; + @UnsupportedAppUsage IDLE, + @UnsupportedAppUsage RINGING, + @UnsupportedAppUsage OFFHOOK; }; /** @@ -46,8 +52,13 @@ public class PhoneConstants { * in 2G network</li> * </ul> */ + @UnsupportedAppUsage(implicitMember = + "values()[Lcom/android/internal/telephony/PhoneConstants$DataState;") public enum DataState { - CONNECTED, CONNECTING, DISCONNECTED, SUSPENDED; + @UnsupportedAppUsage CONNECTED, + @UnsupportedAppUsage CONNECTING, + @UnsupportedAppUsage DISCONNECTED, + @UnsupportedAppUsage SUSPENDED; }; public static final String STATE_KEY = "state"; @@ -69,9 +80,13 @@ public class PhoneConstants { public static final int LTE_ON_CDMA_TRUE = RILConstants.LTE_ON_CDMA_TRUE; // Number presentation type for caller id display (From internal/Connection.java) + @UnsupportedAppUsage public static final int PRESENTATION_ALLOWED = 1; // normal + @UnsupportedAppUsage public static final int PRESENTATION_RESTRICTED = 2; // block by user + @UnsupportedAppUsage public static final int PRESENTATION_UNKNOWN = 3; // no specified or unknown by network + @UnsupportedAppUsage public static final int PRESENTATION_PAYPHONE = 4; // show pay phone info // Sim activation type diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index 5205973669ac..03ea9208d064 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -18,6 +18,8 @@ package com.android.internal.telephony; import android.telephony.TelephonyManager; +import dalvik.annotation.compat.UnsupportedAppUsage; + /** * {@hide} */ @@ -230,6 +232,7 @@ public interface RILConstants { /** NR 5G, LTE, TD-SCDMA, CDMA, EVDO, GSM and WCDMA */ int NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 33; + @UnsupportedAppUsage int PREFERRED_NETWORK_MODE = Integer.parseInt(TelephonyManager.getTelephonyProperty(0, "ro.telephony.default_network", Integer.toString(NETWORK_MODE_WCDMA_PREF))); diff --git a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java index 49c737fc3440..2cdf2f63e02f 100644 --- a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java +++ b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java @@ -16,27 +16,28 @@ package com.android.internal.telephony; -import android.telephony.Rlog; -import android.os.Build; -import android.util.SparseIntArray; import android.content.res.Resources; import android.content.res.XmlResourceParser; -import android.telephony.SmsManager; -import android.telephony.TelephonyManager; +import android.os.Build; +import android.telephony.Rlog; +import android.util.SparseIntArray; -import com.android.internal.util.XmlUtils; import com.android.internal.telephony.cdma.sms.UserData; +import com.android.internal.util.XmlUtils; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; +import dalvik.annotation.compat.UnsupportedAppUsage; public class Sms7BitEncodingTranslator { private static final String TAG = "Sms7BitEncodingTranslator"; + @UnsupportedAppUsage private static final boolean DBG = Build.IS_DEBUGGABLE ; private static boolean mIs7BitTranslationTableLoaded = false; private static SparseIntArray mTranslationTable = null; + @UnsupportedAppUsage private static SparseIntArray mTranslationTableCommon = null; + @UnsupportedAppUsage private static SparseIntArray mTranslationTableGSM = null; + @UnsupportedAppUsage private static SparseIntArray mTranslationTableCDMA = null; // Parser variables diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java index 62d3536763d6..f10398f09603 100644 --- a/telephony/java/com/android/internal/telephony/SmsApplication.java +++ b/telephony/java/com/android/internal/telephony/SmsApplication.java @@ -48,6 +48,8 @@ import com.android.internal.content.PackageMonitor; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import dalvik.annotation.compat.UnsupportedAppUsage; + import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -91,6 +93,7 @@ public final class SmsApplication { /** * Name of this SMS app for display. */ + @UnsupportedAppUsage private String mApplicationName; /** @@ -191,7 +194,7 @@ public final class SmsApplication { * @return */ private static int getIncomingUserId(Context context) { - int contextUserId = context.getUserId(); + int contextUserId = UserHandle.myUserId(); final int callingUid = Binder.getCallingUid(); if (DEBUG_MULTIUSER) { Log.i(LOG_TAG, "getIncomingUserHandle caller=" + callingUid + ", myuid=" @@ -224,6 +227,7 @@ public final class SmsApplication { * Implement ACTION_SENDTO intent. * Support smsto Uri scheme. */ + @UnsupportedAppUsage public static Collection<SmsApplicationData> getApplicationCollection(Context context) { return getApplicationCollectionAsUser(context, getIncomingUserId(context)); } @@ -425,9 +429,6 @@ public final class SmsApplication { final SmsApplicationData smsApplicationData = receivers.get(packageName); if (smsApplicationData != null) { if (!smsApplicationData.isComplete()) { - Log.w(LOG_TAG, "Package " + packageName - + " lacks required manifest declarations to be a default sms app: " - + smsApplicationData); receivers.remove(packageName); } } @@ -579,6 +580,7 @@ public final class SmsApplication { * Sets the specified package as the default SMS/MMS application. The caller of this method * needs to have permission to set AppOps and write to secure settings. */ + @UnsupportedAppUsage public static void setDefaultApplication(String packageName, Context context) { setDefaultApplicationAsUser(packageName, context, getIncomingUserId(context)); } @@ -826,6 +828,7 @@ public final class SmsApplication { sSmsPackageMonitor.register(context, context.getMainLooper(), UserHandle.ALL, false); } + @UnsupportedAppUsage private static void configurePreferredActivity(PackageManager packageManager, ComponentName componentName, int userId) { // Add the four activity preferences we want to direct to this app. @@ -868,6 +871,7 @@ public final class SmsApplication { * Returns SmsApplicationData for this package if this package is capable of being set as the * default SMS application. */ + @UnsupportedAppUsage public static SmsApplicationData getSmsApplicationData(String packageName, Context context) { Collection<SmsApplicationData> applications = getApplicationCollection(context); return getApplicationForPackage(applications, packageName); @@ -879,6 +883,7 @@ public final class SmsApplication { * @param updateIfNeeded update the default app if there is no valid default app configured. * @return component name of the app and class to deliver SMS messages to */ + @UnsupportedAppUsage public static ComponentName getDefaultSmsApplication(Context context, boolean updateIfNeeded) { return getDefaultSmsApplicationAsUser(context, updateIfNeeded, getIncomingUserId(context)); } @@ -913,6 +918,7 @@ public final class SmsApplication { * @param updateIfNeeded update the default app if there is no valid default app configured. * @return component name of the app and class to deliver MMS messages to */ + @UnsupportedAppUsage public static ComponentName getDefaultMmsApplication(Context context, boolean updateIfNeeded) { int userId = getIncomingUserId(context); final long token = Binder.clearCallingIdentity(); @@ -936,6 +942,7 @@ public final class SmsApplication { * @param updateIfNeeded update the default app if there is no valid default app configured. * @return component name of the app and class to direct Respond Via Message intent to */ + @UnsupportedAppUsage public static ComponentName getDefaultRespondViaMessageApplication(Context context, boolean updateIfNeeded) { int userId = getIncomingUserId(context); @@ -1036,6 +1043,7 @@ public final class SmsApplication { * <p> * Caller must pass in the correct user context if calling from a singleton service. */ + @UnsupportedAppUsage public static boolean shouldWriteMessageForPackage(String packageName, Context context) { if (SmsManager.getDefault().getAutoPersisting()) { return true; @@ -1050,6 +1058,7 @@ public final class SmsApplication { * @param packageName the name of the package to be checked * @return true if the package is default sms app or bluetooth */ + @UnsupportedAppUsage public static boolean isDefaultSmsApplication(Context context, String packageName) { if (packageName == null) { return false; diff --git a/telephony/java/com/android/internal/telephony/SmsHeader.java b/telephony/java/com/android/internal/telephony/SmsHeader.java index 9fe1718df6b6..dd77b0179487 100644 --- a/telephony/java/com/android/internal/telephony/SmsHeader.java +++ b/telephony/java/com/android/internal/telephony/SmsHeader.java @@ -16,13 +16,12 @@ package com.android.internal.telephony; -import com.android.internal.telephony.SmsConstants; +import android.annotation.UnsupportedAppUsage; + import com.android.internal.util.HexDump; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; - -import android.annotation.UnsupportedAppUsage; import java.util.ArrayList; /** @@ -74,6 +73,10 @@ public class SmsHeader { public static class PortAddrs { @UnsupportedAppUsage + public PortAddrs() { + } + + @UnsupportedAppUsage public int destPort; @UnsupportedAppUsage public int origPort; @@ -82,6 +85,10 @@ public class SmsHeader { public static class ConcatRef { @UnsupportedAppUsage + public ConcatRef() { + } + + @UnsupportedAppUsage public int refNumber; @UnsupportedAppUsage public int seqNumber; diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java index ffdc4b676f90..f0687b4ae7be 100644 --- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java +++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java @@ -16,18 +16,17 @@ package com.android.internal.telephony; -import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; -import com.android.internal.telephony.SmsConstants; -import com.android.internal.telephony.SmsHeader; -import java.text.BreakIterator; -import java.util.Arrays; - import android.annotation.UnsupportedAppUsage; import android.os.Build; import android.provider.Telephony; import android.telephony.SmsMessage; import android.text.Emoji; +import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; + +import java.text.BreakIterator; +import java.util.Arrays; + /** * Base class declaring the specific methods and members for SmsMessage. * {@hide} @@ -102,6 +101,10 @@ public abstract class SmsMessageBase { @UnsupportedAppUsage public int mMessageRef; + @UnsupportedAppUsage + public SmsMessageBase() { + } + // TODO(): This class is duplicated in SmsMessage.java. Refactor accordingly. public static abstract class SubmitPduBase { @UnsupportedAppUsage diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java index dd9b2421a333..ef4850716701 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java +++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import dalvik.annotation.compat.UnsupportedAppUsage; + /** * Contains a list of string constants used to get or set telephone properties * in the system. You can use {@link android.os.SystemProperties os.SystemProperties} @@ -101,6 +103,7 @@ public interface TelephonyProperties * provider of the SIM. 5 or 6 decimal digits. * Availability: SIM state must be "READY" */ + @UnsupportedAppUsage static String PROPERTY_ICC_OPERATOR_NUMERIC = "gsm.sim.operator.numeric"; /** PROPERTY_ICC_OPERATOR_ALPHA is also known as the SPN, or Service Provider Name. diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java index e2a8913b91e6..6b3126dd8f1c 100644 --- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java @@ -19,17 +19,17 @@ package com.android.internal.telephony.cdma; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_IDP_STRING; import android.content.res.Resources; -import android.os.Parcel; import android.os.SystemProperties; import android.telephony.PhoneNumberUtils; +import android.telephony.Rlog; import android.telephony.SmsCbLocation; import android.telephony.SmsCbMessage; import android.telephony.cdma.CdmaSmsCbProgramData; -import android.telephony.Rlog; import android.text.TextUtils; import android.util.Log; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; +import com.android.internal.telephony.Sms7BitEncodingTranslator; import com.android.internal.telephony.SmsAddress; import com.android.internal.telephony.SmsConstants; import com.android.internal.telephony.SmsHeader; @@ -43,7 +43,8 @@ import com.android.internal.telephony.cdma.sms.UserData; import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.util.BitwiseInputStream; import com.android.internal.util.HexDump; -import com.android.internal.telephony.Sms7BitEncodingTranslator; + +import dalvik.annotation.compat.UnsupportedAppUsage; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; @@ -109,7 +110,9 @@ public class SmsMessage extends SmsMessageBase { private static final int PRIORITY_URGENT = 0x2; private static final int PRIORITY_EMERGENCY = 0x3; + @UnsupportedAppUsage private SmsEnvelope mEnvelope; + @UnsupportedAppUsage private BearerData mBearerData; /** @hide */ @@ -119,15 +122,20 @@ public class SmsMessage extends SmsMessageBase { createPdu(); } + @UnsupportedAppUsage public SmsMessage() {} public static class SubmitPdu extends SubmitPduBase { + @UnsupportedAppUsage + public SubmitPdu() { + } } /** * Create an SmsMessage from a raw PDU. * Note: In CDMA the PDU is just a byte representation of the received Sms. */ + @UnsupportedAppUsage public static SmsMessage createFromPdu(byte[] pdu) { SmsMessage msg = new SmsMessage(); @@ -153,6 +161,7 @@ public class SmsMessage extends SmsMessageBase { * * @hide */ + @UnsupportedAppUsage public static SmsMessage createFromEfRecord(int index, byte[] data) { try { SmsMessage msg = new SmsMessage(); @@ -219,6 +228,7 @@ public class SmsMessage extends SmsMessageBase { * Returns null on encode error. * @hide */ + @UnsupportedAppUsage public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, String message, boolean statusReportRequested, SmsHeader smsHeader) { return getSubmitPdu(scAddr, destAddr, message, statusReportRequested, smsHeader, -1); @@ -239,6 +249,7 @@ public class SmsMessage extends SmsMessageBase { * Returns null on encode error. * @hide */ + @UnsupportedAppUsage public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, String message, boolean statusReportRequested, SmsHeader smsHeader, int priority) { @@ -269,6 +280,7 @@ public class SmsMessage extends SmsMessageBase { * address, if applicable, and the encoded message. * Returns null on encode error. */ + @UnsupportedAppUsage public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, int destPort, byte[] data, boolean statusReportRequested) { @@ -306,6 +318,7 @@ public class SmsMessage extends SmsMessageBase { * address, if applicable, and the encoded message. * Returns null on encode error. */ + @UnsupportedAppUsage public static SubmitPdu getSubmitPdu(String destAddr, UserData userData, boolean statusReportRequested) { return privateGetSubmitPdu(destAddr, statusReportRequested, userData); @@ -322,6 +335,7 @@ public class SmsMessage extends SmsMessageBase { * address, if applicable, and the encoded message. * Returns null on encode error. */ + @UnsupportedAppUsage public static SubmitPdu getSubmitPdu(String destAddr, UserData userData, boolean statusReportRequested, int priority) { return privateGetSubmitPdu(destAddr, statusReportRequested, userData, priority); @@ -393,6 +407,7 @@ public class SmsMessage extends SmsMessageBase { } /** Return true iff the bearer data message type is DELIVERY_ACK. */ + @UnsupportedAppUsage @Override public boolean isStatusReportMessage() { return (mBearerData.messageType == BearerData.MESSAGE_TYPE_DELIVERY_ACK); @@ -415,6 +430,7 @@ public class SmsMessage extends SmsMessageBase { * @param isEntireMsg indicates if this is entire msg or a segment in multipart msg * @return TextEncodingDetails */ + @UnsupportedAppUsage public static TextEncodingDetails calculateLength(CharSequence messageBody, boolean use7bitOnly, boolean isEntireMsg) { CharSequence newMsgBody = null; @@ -437,6 +453,7 @@ public class SmsMessage extends SmsMessageBase { * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_VMN}, * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WAP} */ + @UnsupportedAppUsage public int getTeleService() { return mEnvelope.teleService; } @@ -448,6 +465,7 @@ public class SmsMessage extends SmsMessageBase { * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#MESSAGE_TYPE_BROADCAST}, * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#MESSAGE_TYPE_ACKNOWLEDGE}, */ + @UnsupportedAppUsage public int getMessageType() { // NOTE: mEnvelope.messageType is not set correctly for cell broadcasts with some RILs. // Use the service category parameter to detect CMAS and other cell broadcast messages. @@ -680,6 +698,7 @@ public class SmsMessage extends SmsMessageBase { /** * Parses a SMS message from its BearerData stream. */ + @UnsupportedAppUsage public void parseSms() { // Message Waiting Info Record defined in 3GPP2 C.S-0005, 3.7.5.6 // It contains only an 8-bit number with the number of messages waiting @@ -816,6 +835,7 @@ public class SmsMessage extends SmsMessageBase { * binder-call, and hence should be thread-safe, it has been * synchronized. */ + @UnsupportedAppUsage public synchronized static int getNextMessageId() { // Testing and dialog with partners has indicated that // msgId==0 is (sometimes?) treated specially by lower levels. @@ -840,6 +860,7 @@ public class SmsMessage extends SmsMessageBase { * Creates BearerData and Envelope from parameters for a Submit SMS. * @return byte stream for SubmitPdu. */ + @UnsupportedAppUsage private static SubmitPdu privateGetSubmitPdu(String destAddrStr, boolean statusReportRequested, UserData userData) { return privateGetSubmitPdu(destAddrStr, statusReportRequested, userData, -1); @@ -1025,6 +1046,7 @@ public class SmsMessage extends SmsMessageBase { /** This function shall be called to get the number of voicemails. * @hide */ + @UnsupportedAppUsage public int getNumOfVoicemails() { return mBearerData.numberOfMessages; } @@ -1036,6 +1058,7 @@ public class SmsMessage extends SmsMessageBase { * @return byte array uniquely identifying the message. * @hide */ + @UnsupportedAppUsage public byte[] getIncomingSmsFingerprint() { ByteArrayOutputStream output = new ByteArrayOutputStream(); diff --git a/telephony/java/com/android/internal/telephony/cdma/UserData.java b/telephony/java/com/android/internal/telephony/cdma/UserData.java index f87956098e5c..7187ae4f990c 100644 --- a/telephony/java/com/android/internal/telephony/cdma/UserData.java +++ b/telephony/java/com/android/internal/telephony/cdma/UserData.java @@ -21,6 +21,8 @@ import android.util.SparseIntArray; import com.android.internal.telephony.SmsHeader; import com.android.internal.util.HexDump; +import dalvik.annotation.compat.UnsupportedAppUsage; + public class UserData { /** @@ -92,6 +94,7 @@ public class UserData { public static final int PRINTABLE_ASCII_MIN_INDEX = 0x20; public static final int ASCII_NL_INDEX = 0x0A; public static final int ASCII_CR_INDEX = 0x0D; + @UnsupportedAppUsage public static final SparseIntArray charToAscii = new SparseIntArray(); static { for (int i = 0; i < ASCII_MAP.length; i++) { @@ -101,6 +104,10 @@ public class UserData { charToAscii.put('\r', ASCII_CR_INDEX); } + @UnsupportedAppUsage + public UserData() { + } + /* * TODO(cleanup): Move this very generic functionality somewhere * more general. @@ -131,12 +138,15 @@ public class UserData { /** * Contains the data header of the user data */ + @UnsupportedAppUsage public SmsHeader userDataHeader; /** * Contains the data encoding type for the SMS message */ + @UnsupportedAppUsage public int msgEncoding; + @UnsupportedAppUsage public boolean msgEncodingSet = false; public int msgType; @@ -146,13 +156,16 @@ public class UserData { */ public int paddingBits; + @UnsupportedAppUsage public int numFields; /** * Contains the user data of a SMS message * (See 3GPP2 C.S0015-B, v2, 4.5.2) */ + @UnsupportedAppUsage public byte[] payload; + @UnsupportedAppUsage public String payloadStr; @Override diff --git a/telephony/java/com/android/internal/telephony/cdma/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java index 9e6f19f9243d..2181bc425a78 100644 --- a/telephony/java/com/android/internal/telephony/cdma/BearerData.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java @@ -17,10 +17,10 @@ package com.android.internal.telephony.cdma.sms; import android.content.res.Resources; +import android.telephony.Rlog; import android.telephony.SmsCbCmasInfo; import android.telephony.cdma.CdmaSmsCbProgramData; import android.telephony.cdma.CdmaSmsCbProgramResults; -import android.telephony.Rlog; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; @@ -31,6 +31,8 @@ import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.util.BitwiseInputStream; import com.android.internal.util.BitwiseOutputStream; +import dalvik.annotation.compat.UnsupportedAppUsage; + import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; @@ -95,6 +97,7 @@ public final class BearerData { * (Special rules apply for WAP-messages.) * (See 3GPP2 C.S0015-B, v2, 4.5.1) */ + @UnsupportedAppUsage public int messageId; /** @@ -106,7 +109,9 @@ public final class BearerData { public static final int PRIORITY_URGENT = 0x2; public static final int PRIORITY_EMERGENCY = 0x3; + @UnsupportedAppUsage public boolean priorityIndicatorSet = false; + @UnsupportedAppUsage public int priority = PRIORITY_NORMAL; /** @@ -144,6 +149,7 @@ public final class BearerData { public static final int DISPLAY_MODE_USER = 0x2; public boolean displayModeSet = false; + @UnsupportedAppUsage public int displayMode = DISPLAY_MODE_DEFAULT; /** @@ -207,6 +213,7 @@ public final class BearerData { * presence of a UDH in the structured data, any existing setting * will be overwritten. */ + @UnsupportedAppUsage public boolean hasUserDataHeader; /** @@ -214,6 +221,7 @@ public final class BearerData { * (e.g. padding bits, user data, user data header, etc) * (See 3GPP2 C.S.0015-B, v2, 4.5.2) */ + @UnsupportedAppUsage public UserData userData; /** @@ -226,6 +234,10 @@ public final class BearerData { public boolean userResponseCodeSet = false; public int userResponseCode; + @UnsupportedAppUsage + public BearerData() { + } + /** * 6-byte-field, see 3GPP2 C.S0015-B, v2, 4.5.4 */ @@ -244,6 +256,7 @@ public final class BearerData { private ZoneId mZoneId; + @UnsupportedAppUsage public TimeStamp() { mZoneId = ZoneId.systemDefault(); // 3GPP2 timestamps use the local timezone } @@ -295,6 +308,7 @@ public final class BearerData { } } + @UnsupportedAppUsage public TimeStamp msgCenterTimeStamp; public TimeStamp validityPeriodAbsolute; public TimeStamp deferredDeliveryTimeAbsolute; @@ -383,6 +397,7 @@ public final class BearerData { private static class CodingException extends Exception { + @UnsupportedAppUsage public CodingException(String s) { super(s); } @@ -476,6 +491,7 @@ public final class BearerData { outStream.skip(3); } + @UnsupportedAppUsage private static int countAsciiSeptets(CharSequence msg, boolean force) { int msgLen = msg.length(); if (force) return msgLen; @@ -518,6 +534,7 @@ public final class BearerData { return ted; } + @UnsupportedAppUsage private static byte[] encode7bitAscii(String msg, boolean force) throws CodingException { @@ -949,6 +966,7 @@ public final class BearerData { * * @return byte array of raw encoded SMS bearer data. */ + @UnsupportedAppUsage public static byte[] encode(BearerData bData) { bData.hasUserDataHeader = ((bData.userData != null) && (bData.userData.userDataHeader != null)); @@ -1200,6 +1218,7 @@ public final class BearerData { } } + @UnsupportedAppUsage private static void decodeUserDataPayload(UserData userData, boolean hasUserDataHeader) throws CodingException { @@ -1845,6 +1864,7 @@ public final class BearerData { * @return the number of bits to read from the stream * @throws CodingException if the specified encoding is not supported */ + @UnsupportedAppUsage private static int getBitsForNumFields(int msgEncoding, int numFields) throws CodingException { switch (msgEncoding) { diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java index d27a75815980..a82b9755045f 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java @@ -16,11 +16,11 @@ package com.android.internal.telephony.cdma.sms; +import android.annotation.UnsupportedAppUsage; import android.util.SparseBooleanArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.SmsAddress; -import com.android.internal.telephony.cdma.sms.UserData; import com.android.internal.util.HexDump; public class CdmaSmsAddress extends SmsAddress { @@ -33,6 +33,7 @@ public class CdmaSmsAddress extends SmsAddress { static public final int DIGIT_MODE_4BIT_DTMF = 0x00; static public final int DIGIT_MODE_8BIT_CHAR = 0x01; + @UnsupportedAppUsage public int digitMode; /** @@ -43,6 +44,7 @@ public class CdmaSmsAddress extends SmsAddress { static public final int NUMBER_MODE_NOT_DATA_NETWORK = 0x00; static public final int NUMBER_MODE_DATA_NETWORK = 0x01; + @UnsupportedAppUsage public int numberMode; /** @@ -70,6 +72,7 @@ public class CdmaSmsAddress extends SmsAddress { * This field shall be set to the number of address digits * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) */ + @UnsupportedAppUsage public int numberOfDigits; /** @@ -83,6 +86,7 @@ public class CdmaSmsAddress extends SmsAddress { //static protected final int NUMBERING_PLAN_TELEX = 0x4; //static protected final int NUMBERING_PLAN_PRIVATE = 0x9; + @UnsupportedAppUsage public int numberPlan; /** @@ -91,6 +95,7 @@ public class CdmaSmsAddress extends SmsAddress { * respectively. */ + @UnsupportedAppUsage public CdmaSmsAddress(){ } @@ -194,6 +199,7 @@ public class CdmaSmsAddress extends SmsAddress { * common punctuation. For alpha addresses, the string is cleaned * up by removing whitespace. */ + @UnsupportedAppUsage public static CdmaSmsAddress parse(String address) { CdmaSmsAddress addr = new CdmaSmsAddress(); addr.address = address; diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSmsSubaddress.java b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsSubaddress.java index 0d5b502b9102..0d5b502b9102 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaSmsSubaddress.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsSubaddress.java diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsEnvelope.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java index de93b573f215..6af174c851cc 100644 --- a/telephony/java/com/android/internal/telephony/cdma/SmsEnvelope.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java @@ -17,7 +17,7 @@ package com.android.internal.telephony.cdma.sms; -import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress; +import android.annotation.UnsupportedAppUsage; public final class SmsEnvelope { /** @@ -69,6 +69,7 @@ public final class SmsEnvelope { * or receiving the message. * (See 3GPP2 C.S0015-B, v2, 3.4.3.1) */ + @UnsupportedAppUsage public int teleService = TELESERVICE_NOT_SET; /** @@ -76,6 +77,7 @@ public final class SmsEnvelope { * by the SMS message. * (See 3GPP2 C.S0015-B, v2, 3.4.3.2) */ + @UnsupportedAppUsage public int serviceCategory; /** @@ -126,8 +128,10 @@ public final class SmsEnvelope { * encoded bearer data * (See 3GPP2 C.S0015-B, v2, 3.4.3.7) */ + @UnsupportedAppUsage public byte[] bearerData; + @UnsupportedAppUsage public SmsEnvelope() { // nothing to see here } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java index bd8c83e63055..17f69b3ef9d9 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java @@ -18,10 +18,13 @@ package com.android.internal.telephony.gsm; import android.telephony.PhoneNumberUtils; -import java.text.ParseException; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.SmsAddress; +import dalvik.annotation.compat.UnsupportedAppUsage; + +import java.text.ParseException; + public class GsmSmsAddress extends SmsAddress { static final int OFFSET_ADDRESS_LENGTH = 0; @@ -38,7 +41,7 @@ public class GsmSmsAddress extends SmsAddress { * (addressLength + 1) / 2" * @throws ParseException */ - + @UnsupportedAppUsage public GsmSmsAddress(byte[] data, int offset, int length) throws ParseException { origBytes = new byte[length]; System.arraycopy(data, offset, origBytes, 0, length); @@ -136,6 +139,7 @@ public class GsmSmsAddress extends SmsAddress { * address indicating a "set" of "indicator 1" of type "voice message * waiting" */ + @UnsupportedAppUsage public boolean isCphsVoiceMessageSet() { // 0x11 means "set" "voice message waiting" "indicator 1" return isCphsVoiceMessageIndicatorAddress() @@ -148,6 +152,7 @@ public class GsmSmsAddress extends SmsAddress { * address indicating a "clear" of "indicator 1" of type "voice message * waiting" */ + @UnsupportedAppUsage public boolean isCphsVoiceMessageClear() { // 0x10 means "clear" "voice message waiting" "indicator 1" return isCphsVoiceMessageIndicatorAddress() diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java b/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java index 0dbc186ef2cf..996edfc18eee 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java @@ -19,6 +19,8 @@ package com.android.internal.telephony.gsm; import android.telephony.SmsCbCmasInfo; import android.telephony.SmsCbEtwsInfo; +import dalvik.annotation.compat.UnsupportedAppUsage; + import java.util.Arrays; /** @@ -74,6 +76,7 @@ public class SmsCbHeader { private final int mSerialNumber; /** The Message Identifier in 3GPP is the same as the Service Category in CDMA. */ + @UnsupportedAppUsage private final int mMessageIdentifier; private final int mDataCodingScheme; @@ -90,6 +93,7 @@ public class SmsCbHeader { /** CMAS warning notification info. */ private final SmsCbCmasInfo mCmasInfo; + @UnsupportedAppUsage public SmsCbHeader(byte[] pdu) throws IllegalArgumentException { if (pdu == null || pdu.length < PDU_HEADER_LENGTH) { throw new IllegalArgumentException("Illegal PDU"); @@ -183,14 +187,17 @@ public class SmsCbHeader { } } + @UnsupportedAppUsage int getGeographicalScope() { return mGeographicalScope; } + @UnsupportedAppUsage int getSerialNumber() { return mSerialNumber; } + @UnsupportedAppUsage int getServiceCategory() { return mMessageIdentifier; } @@ -199,10 +206,12 @@ public class SmsCbHeader { return mDataCodingScheme; } + @UnsupportedAppUsage int getPageIndex() { return mPageIndex; } + @UnsupportedAppUsage int getNumberOfPages() { return mNrOfPages; } diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java index 5667387bdc1b..5bb818bd3286 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java @@ -16,18 +16,29 @@ package com.android.internal.telephony.gsm; +import static com.android.internal.telephony.SmsConstants.ENCODING_16BIT; +import static com.android.internal.telephony.SmsConstants.ENCODING_7BIT; +import static com.android.internal.telephony.SmsConstants.ENCODING_8BIT; +import static com.android.internal.telephony.SmsConstants.ENCODING_KSC5601; +import static com.android.internal.telephony.SmsConstants.ENCODING_UNKNOWN; +import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_BYTES; +import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_SEPTETS; +import static com.android.internal.telephony.SmsConstants.MessageClass; + +import android.content.res.Resources; import android.telephony.PhoneNumberUtils; import android.telephony.Rlog; -import android.content.res.Resources; import android.text.TextUtils; import com.android.internal.telephony.EncodeException; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; -import com.android.internal.telephony.uicc.IccUtils; +import com.android.internal.telephony.Sms7BitEncodingTranslator; import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; -import com.android.internal.telephony.Sms7BitEncodingTranslator; +import com.android.internal.telephony.uicc.IccUtils; + +import dalvik.annotation.compat.UnsupportedAppUsage; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; @@ -35,16 +46,6 @@ import java.text.ParseException; import java.time.LocalDateTime; import java.time.ZoneOffset; -import static com.android.internal.telephony.SmsConstants.MessageClass; -import static com.android.internal.telephony.SmsConstants.ENCODING_UNKNOWN; -import static com.android.internal.telephony.SmsConstants.ENCODING_7BIT; -import static com.android.internal.telephony.SmsConstants.ENCODING_8BIT; -import static com.android.internal.telephony.SmsConstants.ENCODING_16BIT; -import static com.android.internal.telephony.SmsConstants.ENCODING_KSC5601; -import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_SEPTETS; -import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_BYTES; -import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER; - /** * A Short Message Service message. * @@ -100,11 +101,18 @@ public class SmsMessage extends SmsMessageBase { private static final int INVALID_VALIDITY_PERIOD = -1; public static class SubmitPdu extends SubmitPduBase { + @UnsupportedAppUsage + public SubmitPdu() {} + } + + @UnsupportedAppUsage + public SmsMessage() { } /** * Create an SmsMessage from a raw PDU. */ + @UnsupportedAppUsage public static SmsMessage createFromPdu(byte[] pdu) { try { SmsMessage msg = new SmsMessage(); @@ -169,6 +177,7 @@ public class SmsMessage extends SmsMessageBase { * * @hide */ + @UnsupportedAppUsage public static SmsMessage createFromEfRecord(int index, byte[] data) { try { SmsMessage msg = new SmsMessage(); @@ -259,6 +268,7 @@ public class SmsMessage extends SmsMessageBase { * Returns null on encode error. * @hide */ + @UnsupportedAppUsage public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, String message, boolean statusReportRequested, byte[] header) { @@ -281,6 +291,7 @@ public class SmsMessage extends SmsMessageBase { * Returns null on encode error. * @hide */ + @UnsupportedAppUsage public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, String message, boolean statusReportRequested, byte[] header, int encoding, @@ -304,6 +315,7 @@ public class SmsMessage extends SmsMessageBase { * Returns null on encode error. * @hide */ + @UnsupportedAppUsage public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, String message, boolean statusReportRequested, byte[] header, int encoding, @@ -444,6 +456,7 @@ public class SmsMessage extends SmsMessageBase { * @throws UnsupportedEncodingException * @throws EncodeException if String is too large to encode */ + @UnsupportedAppUsage private static byte[] encodeUCS2(String message, byte[] header) throws UnsupportedEncodingException, EncodeException { byte[] userData, textPart; @@ -478,6 +491,7 @@ public class SmsMessage extends SmsMessageBase { * address, if applicable, and the encoded message. * Returns null on encode error. */ + @UnsupportedAppUsage public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, String message, boolean statusReportRequested) { @@ -496,6 +510,7 @@ public class SmsMessage extends SmsMessageBase { * address, if applicable, and the encoded message. * Returns null on encode error. */ + @UnsupportedAppUsage public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, String message, boolean statusReportRequested, int validityPeriod) { @@ -576,6 +591,7 @@ public class SmsMessage extends SmsMessageBase { * @param ret <code>SubmitPdu</code> containing the encoded SC * address, if applicable, and the encoded message. Returns null on encode error. */ + @UnsupportedAppUsage private static ByteArrayOutputStream getSubmitPduHead( String scAddress, String destinationAddress, byte mtiByte, boolean statusReportRequested, SubmitPdu ret) { @@ -622,12 +638,16 @@ public class SmsMessage extends SmsMessageBase { } private static class PduParser { + @UnsupportedAppUsage byte mPdu[]; + @UnsupportedAppUsage int mCur; SmsHeader mUserDataHeader; byte[] mUserData; + @UnsupportedAppUsage int mUserDataSeptetPadding; + @UnsupportedAppUsage PduParser(byte[] pdu) { mPdu = pdu; mCur = 0; @@ -667,6 +687,7 @@ public class SmsMessage extends SmsMessageBase { /** * returns non-sign-extended byte value */ + @UnsupportedAppUsage int getByte() { return mPdu[mCur++] & 0xff; } @@ -808,6 +829,7 @@ public class SmsMessage extends SmsMessageBase { * * @return the user data payload, not including the headers */ + @UnsupportedAppUsage byte[] getUserData() { return mUserData; } @@ -864,6 +886,7 @@ public class SmsMessage extends SmsMessageBase { * @param byteCount the number of bytes in the user data payload * @return a String with the decoded characters */ + @UnsupportedAppUsage String getUserDataUCS2(int byteCount) { String ret; @@ -912,6 +935,7 @@ public class SmsMessage extends SmsMessageBase { * @param use7bitOnly ignore (but still count) illegal characters if true * @return TextEncodingDetails */ + @UnsupportedAppUsage public static TextEncodingDetails calculateLength(CharSequence msgBody, boolean use7bitOnly) { CharSequence newMsgBody = null; @@ -959,6 +983,7 @@ public class SmsMessage extends SmsMessageBase { } /** {@inheritDoc} */ + @UnsupportedAppUsage @Override public boolean isMWIClearMessage() { if (mIsMwi && !mMwiSense) { @@ -970,6 +995,7 @@ public class SmsMessage extends SmsMessageBase { } /** {@inheritDoc} */ + @UnsupportedAppUsage @Override public boolean isMWISetMessage() { if (mIsMwi && mMwiSense) { @@ -981,6 +1007,7 @@ public class SmsMessage extends SmsMessageBase { } /** {@inheritDoc} */ + @UnsupportedAppUsage @Override public boolean isMwiDontStore() { if (mIsMwi && mMwiDontStore) { @@ -1000,12 +1027,14 @@ public class SmsMessage extends SmsMessageBase { } /** {@inheritDoc} */ + @UnsupportedAppUsage @Override public int getStatus() { return mStatus; } /** {@inheritDoc} */ + @UnsupportedAppUsage @Override public boolean isStatusReportMessage() { return mIsStatusReportMessage; diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java index 6b3df94063bf..9c69e2d6e08f 100644 --- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java +++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java @@ -24,6 +24,8 @@ import android.telephony.Rlog; import com.android.internal.telephony.GsmAlphabet; +import dalvik.annotation.compat.UnsupportedAppUsage; + import java.io.UnsupportedEncodingException; /** @@ -46,6 +48,7 @@ public class IccUtils { * * Stops on invalid BCD value, returning string so far */ + @UnsupportedAppUsage public static String bcdToString(byte[] data, int offset, int length) { StringBuilder ret = new StringBuilder(length*2); @@ -173,6 +176,7 @@ public class IccUtils { /** * Decode cdma byte into String. */ + @UnsupportedAppUsage public static String cdmaBcdToString(byte[] data, int offset, int length) { StringBuilder ret = new StringBuilder(length); @@ -208,6 +212,7 @@ public class IccUtils { * assume the digit is set to 0 but shall store the entire field * exactly as received" */ + @UnsupportedAppUsage public static int gsmBcdByteToInt(byte b) { int ret = 0; @@ -230,6 +235,7 @@ public class IccUtils { * is in the least significant nibble and the most significant * is in the most significant nibble. */ + @UnsupportedAppUsage public static int cdmaBcdByteToInt(byte b) { int ret = 0; @@ -281,6 +287,7 @@ public class IccUtils { * contain a 16 bit number which defines the complete 16 bit * base pointer to a "half page" in the UCS2 code space... */ + @UnsupportedAppUsage public static String adnStringFieldToString(byte[] data, int offset, int length) { if (length == 0) { @@ -372,6 +379,7 @@ public class IccUtils { return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length, defaultCharset.trim()); } + @UnsupportedAppUsage public static int hexCharToInt(char c) { if (c >= '0' && c <= '9') return (c - '0'); @@ -391,6 +399,7 @@ public class IccUtils { * * @throws RuntimeException on invalid format */ + @UnsupportedAppUsage public static byte[] hexStringToBytes(String s) { byte[] ret; @@ -417,6 +426,7 @@ public class IccUtils { * * @return hex string representation of bytes array */ + @UnsupportedAppUsage public static String bytesToHexString(byte[] bytes) { if (bytes == null) return null; @@ -444,6 +454,7 @@ public class IccUtils { * "offset" points to "octet 3", the coding scheme byte * empty string returned on decode error */ + @UnsupportedAppUsage public static String networkNameToString(byte[] data, int offset, int length) { String ret; @@ -494,6 +505,7 @@ public class IccUtils { * @param length The length of image body * @return The bitmap */ + @UnsupportedAppUsage public static Bitmap parseToBnW(byte[] data, int length){ int valueIndex = 0; int width = data[valueIndex++] & 0xFF; @@ -536,6 +548,7 @@ public class IccUtils { * @param transparency with or without transparency * @return The color bitmap */ + @UnsupportedAppUsage public static Bitmap parseToRGB(byte[] data, int length, boolean transparency) { int valueIndex = 0; diff --git a/test-mock/Android.bp b/test-mock/Android.bp index a5cd1751151f..0129c4ca5bc1 100644 --- a/test-mock/Android.bp +++ b/test-mock/Android.bp @@ -25,7 +25,7 @@ java_sdk_library { "android.test.mock", ], - srcs_lib: "framework", + srcs_lib: "framework-minus-apex", srcs_lib_whitelist_dirs: ["core/java"], srcs_lib_whitelist_pkgs: ["android"], compile_dex: true, diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java index 232b5cb17023..c42201fa0d3e 100644 --- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java +++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java @@ -35,8 +35,8 @@ import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.VersionedPackage; -import android.net.NetworkStackClient; -import android.net.NetworkStackClient.NetworkStackHealthListener; +import android.net.ConnectivityModuleConnector; +import android.net.ConnectivityModuleConnector.ConnectivityModuleHealthListener; import android.os.Handler; import android.os.test.TestLooper; import android.provider.DeviceConfig; @@ -86,11 +86,11 @@ public class PackageWatchdogTest { private TestLooper mTestLooper; private Context mSpyContext; @Mock - private NetworkStackClient mMockNetworkStackClient; + private ConnectivityModuleConnector mConnectivityModuleConnector; @Mock private PackageManager mMockPackageManager; @Captor - private ArgumentCaptor<NetworkStackHealthListener> mNetworkStackCallbackCaptor; + private ArgumentCaptor<ConnectivityModuleHealthListener> mConnectivityModuleCallbackCaptor; @Before public void setUp() throws Exception { @@ -736,7 +736,7 @@ public class PackageWatchdogTest { wd.startObservingHealth(observer, Collections.singletonList(APP_A), SHORT_DURATION); // Notify of NetworkStack failure - mNetworkStackCallbackCaptor.getValue().onNetworkStackFailure(APP_A); + mConnectivityModuleCallbackCaptor.getValue().onNetworkStackFailure(APP_A); // Run handler so package failures are dispatched to observers mTestLooper.dispatchAll(); @@ -782,18 +782,18 @@ public class PackageWatchdogTest { Handler handler = new Handler(mTestLooper.getLooper()); PackageWatchdog watchdog = new PackageWatchdog(mSpyContext, policyFile, handler, handler, controller, - mMockNetworkStackClient); + mConnectivityModuleConnector); // Verify controller is not automatically started assertFalse(controller.mIsEnabled); if (withPackagesReady) { // Only capture the NetworkStack callback for the latest registered watchdog - reset(mMockNetworkStackClient); + reset(mConnectivityModuleConnector); watchdog.onPackagesReady(); // Verify controller by default is started when packages are ready assertTrue(controller.mIsEnabled); - verify(mMockNetworkStackClient).registerHealthListener( - mNetworkStackCallbackCaptor.capture()); + verify(mConnectivityModuleConnector).registerHealthListener( + mConnectivityModuleCallbackCaptor.capture()); } return watchdog; } diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java index 2c0432aeed50..720c1af906ff 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java @@ -929,7 +929,6 @@ public class RollbackTest { */ @Test public void testBadUpdateRollback() throws Exception { - BroadcastReceiver crashCountReceiver = null; Context context = InstrumentationRegistry.getContext(); try { InstallUtils.adoptShellPermissionIdentity( @@ -937,7 +936,7 @@ public class RollbackTest { Manifest.permission.DELETE_PACKAGES, Manifest.permission.MANAGE_ROLLBACKS, Manifest.permission.TEST_MANAGE_ROLLBACKS, - Manifest.permission.KILL_BACKGROUND_PROCESSES, + Manifest.permission.FORCE_STOP_PACKAGES, Manifest.permission.RESTART_PACKAGES); RollbackManager rm = RollbackUtils.getRollbackManager(); @@ -967,7 +966,7 @@ public class RollbackTest { RollbackBroadcastReceiver rollbackReceiver = new RollbackBroadcastReceiver(); // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback - crashCountReceiver = RollbackUtils.sendCrashBroadcast(context, TestApp.A, 5); + RollbackUtils.sendCrashBroadcast(TestApp.A, 5); // Verify we received a broadcast for the rollback. rollbackReceiver.take(); @@ -981,9 +980,6 @@ public class RollbackTest { assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2); } finally { InstallUtils.dropShellPermissionIdentity(); - if (crashCountReceiver != null) { - context.unregisterReceiver(crashCountReceiver); - } } } diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java index db8183124f59..9e6ac8ef679b 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java @@ -25,7 +25,6 @@ import static org.junit.Assert.fail; import android.Manifest; import android.annotation.Nullable; -import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -77,7 +76,7 @@ public class StagedRollbackTest { Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS, - Manifest.permission.KILL_BACKGROUND_PROCESSES); + Manifest.permission.FORCE_STOP_PACKAGES); } /** @@ -135,17 +134,8 @@ public class StagedRollbackTest { */ @Test public void testBadApkOnlyTriggerRollback() throws Exception { - BroadcastReceiver crashCountReceiver = null; - Context context = InstrumentationRegistry.getContext(); - - try { - // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback - crashCountReceiver = RollbackUtils.sendCrashBroadcast(context, TestApp.A, 5); - } finally { - if (crashCountReceiver != null) { - context.unregisterReceiver(crashCountReceiver); - } - } + // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback + RollbackUtils.sendCrashBroadcast(TestApp.A, 5); // We expect the device to be rebooted automatically. Wait for that to // happen. At that point, the host test driver will wait for the diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index 8c522f48cfd2..c030c3e9ac86 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -469,6 +469,8 @@ public class TetheringTest { if (emulateInterfaceStatusChanged) { assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); + verify(mWifiManager).updateInterfaceIpState( + TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); } verifyNoMoreInteractions(mNMService); verifyNoMoreInteractions(mWifiManager); @@ -534,6 +536,8 @@ public class TetheringTest { verify(mNMService, times(1)).startTethering(any(String[].class)); verifyNoMoreInteractions(mNMService); verify(mWifiManager).updateInterfaceIpState( + TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); + verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY); verifyNoMoreInteractions(mWifiManager); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY); @@ -554,6 +558,8 @@ public class TetheringTest { .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class)); verify(mNMService, times(1)).stopTethering(); verify(mNMService, times(1)).setIpForwardingEnabled(false); + verify(mWifiManager, times(3)).updateInterfaceIpState( + TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); verifyNoMoreInteractions(mNMService); verifyNoMoreInteractions(mWifiManager); // Asking for the last error after the per-interface state machine @@ -739,6 +745,8 @@ public class TetheringTest { assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); + verify(mWifiManager).updateInterfaceIpState( + TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); verifyNoMoreInteractions(mNMService); verifyNoMoreInteractions(mWifiManager); } @@ -768,6 +776,8 @@ public class TetheringTest { verify(mNMService, times(1)).startTethering(any(String[].class)); verifyNoMoreInteractions(mNMService); verify(mWifiManager).updateInterfaceIpState( + TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); + verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED); verifyNoMoreInteractions(mWifiManager); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_TETHER); @@ -805,6 +815,8 @@ public class TetheringTest { .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class)); verify(mNMService, times(1)).stopTethering(); verify(mNMService, times(1)).setIpForwardingEnabled(false); + verify(mWifiManager, times(3)).updateInterfaceIpState( + TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); verifyNoMoreInteractions(mNMService); verifyNoMoreInteractions(mWifiManager); // Asking for the last error after the per-interface state machine @@ -842,6 +854,8 @@ public class TetheringTest { verify(mNetd, times(1)).interfaceSetCfg(argThat(p -> TEST_WLAN_IFNAME.equals(p.ifName))); verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME); verify(mWifiManager).updateInterfaceIpState( + TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); + verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED); // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast(). assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls); diff --git a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java index 2b2e8a72ab04..5217e26a40ef 100644 --- a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java +++ b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java @@ -406,6 +406,13 @@ public final class EntitlementManagerTest { } @Test + public void verifyPermissionWhenProvisioningNotStarted() { + assertTrue(mEnMgr.isCellularUpstreamPermitted()); + setupForRequiredProvisioning(); + assertFalse(mEnMgr.isCellularUpstreamPermitted()); + } + + @Test public void testRunTetherProvisioning() { setupForRequiredProvisioning(); // 1. start ui provisioning, upstream is mobile diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index bbf71e70c396..99a686be1390 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -1084,7 +1084,8 @@ class Linker { case OutputFormat::kProto: { pb::ResourceTable pb_table; - SerializeTableToPb(*table, &pb_table, context_->GetDiagnostics()); + SerializeTableToPb(*table, &pb_table, context_->GetDiagnostics(), + options_.proto_table_flattener_options); return io::CopyProtoToArchive(context_, &pb_table, kProtoResourceTablePath, ArchiveEntry::kCompress, writer); } break; diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h index 324807c55215..56bff8fe0fe8 100644 --- a/tools/aapt2/cmd/Link.h +++ b/tools/aapt2/cmd/Link.h @@ -24,6 +24,7 @@ #include "Resource.h" #include "split/TableSplitter.h" #include "format/binary/TableFlattener.h" +#include "format/proto/ProtoSerialize.h" #include "link/ManifestFixer.h" #include "trace/TraceBuffer.h" @@ -81,6 +82,7 @@ struct LinkOptions { // Flattening options. TableFlattenerOptions table_flattener_options; + SerializeTableOptions proto_table_flattener_options; bool keep_raw_values = false; // Split APK options. @@ -245,9 +247,9 @@ class LinkCommand : public Command { "<add-resource> tags.", &options_.auto_add_overlay); AddOptionalSwitch("--override-styles-instead-of-overlaying", - "Causes styles defined in -R resources to replace previous definitions\n" - "instead of merging into them\n", - &options_.override_styles_instead_of_overlaying); + "Causes styles defined in -R resources to replace previous definitions\n" + "instead of merging into them\n", + &options_.override_styles_instead_of_overlaying); AddOptionalFlag("--rename-manifest-package", "Renames the package in AndroidManifest.xml.", &options_.manifest_fixer_options.rename_manifest_package); AddOptionalFlag("--rename-instrumentation-target-package", @@ -283,13 +285,18 @@ class LinkCommand : public Command { AddOptionalSwitch("--strict-visibility", "Do not allow overlays with different visibility levels.", &options_.strict_visibility); - AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); - AddOptionalFlag("--trace-folder", "Generate systrace json trace fragment to specified folder.", - &trace_folder_); + AddOptionalSwitch("--exclude-sources", + "Do not serialize source file information when generating resources in\n" + "Protobuf format.", + &options_.proto_table_flattener_options.exclude_sources); + AddOptionalFlag("--trace-folder", + "Generate systrace json trace fragment to specified folder.", + &trace_folder_); AddOptionalSwitch("--merge-only", - "Only merge the resources, without verifying resource references. This flag\n" - "should only be used together with the --static-lib flag.", - &options_.merge_only); + "Only merge the resources, without verifying resource references. This flag\n" + "should only be used together with the --static-lib flag.", + &options_.merge_only); + AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); } int Action(const std::vector<std::string>& args) override; diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index aa6547e81624..e4b3fce52166 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -290,8 +290,10 @@ static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item pb::Overlayable* pb_overlayable = pb_table->add_overlayable(); pb_overlayable->set_name(overlayable_item.overlayable->name); pb_overlayable->set_actor(overlayable_item.overlayable->actor); - SerializeSourceToPb(overlayable_item.overlayable->source, source_pool, - pb_overlayable->mutable_source()); + if (source_pool != nullptr) { + SerializeSourceToPb(overlayable_item.overlayable->source, source_pool, + pb_overlayable->mutable_source()); + } } pb::OverlayableItem* pb_overlayable_item = pb_entry->mutable_overlayable_item(); @@ -319,14 +321,17 @@ static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item pb_overlayable_item->add_policy(pb::OverlayableItem::OEM); } - SerializeSourceToPb(overlayable_item.source, source_pool, - pb_overlayable_item->mutable_source()); + if (source_pool != nullptr) { + SerializeSourceToPb(overlayable_item.source, source_pool, + pb_overlayable_item->mutable_source()); + } pb_overlayable_item->set_comment(overlayable_item.comment); } void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table, - IDiagnostics* diag) { - StringPool source_pool; + IDiagnostics* diag, SerializeTableOptions options) { + auto source_pool = (options.exclude_sources) ? nullptr : util::make_unique<StringPool>(); + pb::ToolFingerprint* pb_fingerprint = out_table->add_tool_fingerprint(); pb_fingerprint->set_tool(util::GetToolName()); pb_fingerprint->set_version(util::GetToolFingerprint()); @@ -356,32 +361,40 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table // Write the Visibility struct. pb::Visibility* pb_visibility = pb_entry->mutable_visibility(); pb_visibility->set_level(SerializeVisibilityToPb(entry->visibility.level)); - SerializeSourceToPb(entry->visibility.source, &source_pool, - pb_visibility->mutable_source()); + if (source_pool != nullptr) { + SerializeSourceToPb(entry->visibility.source, source_pool.get(), + pb_visibility->mutable_source()); + } pb_visibility->set_comment(entry->visibility.comment); if (entry->allow_new) { pb::AllowNew* pb_allow_new = pb_entry->mutable_allow_new(); - SerializeSourceToPb(entry->allow_new.value().source, &source_pool, - pb_allow_new->mutable_source()); + if (source_pool != nullptr) { + SerializeSourceToPb(entry->allow_new.value().source, source_pool.get(), + pb_allow_new->mutable_source()); + } pb_allow_new->set_comment(entry->allow_new.value().comment); } if (entry->overlayable_item) { - SerializeOverlayableItemToPb(entry->overlayable_item.value(), overlayables, &source_pool, - pb_entry, out_table); + SerializeOverlayableItemToPb(entry->overlayable_item.value(), overlayables, + source_pool.get(), pb_entry, out_table); } for (const std::unique_ptr<ResourceConfigValue>& config_value : entry->values) { pb::ConfigValue* pb_config_value = pb_entry->add_config_value(); SerializeConfig(config_value->config, pb_config_value->mutable_config()); pb_config_value->mutable_config()->set_product(config_value->product); - SerializeValueToPb(*config_value->value, pb_config_value->mutable_value(), &source_pool); + SerializeValueToPb(*config_value->value, pb_config_value->mutable_value(), + source_pool.get()); } } } } - SerializeStringPoolToPb(source_pool, out_table->mutable_source_pool(), diag); + + if (source_pool != nullptr) { + SerializeStringPoolToPb(*source_pool, out_table->mutable_source_pool(), diag); + } } static pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type) { diff --git a/tools/aapt2/format/proto/ProtoSerialize.h b/tools/aapt2/format/proto/ProtoSerialize.h index 33ffd182435b..7a3ea9903732 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.h +++ b/tools/aapt2/format/proto/ProtoSerialize.h @@ -35,6 +35,11 @@ struct SerializeXmlOptions { bool remove_empty_text_nodes = false; }; +struct SerializeTableOptions { + /** Prevent serializing the source pool and source protos. */ + bool exclude_sources = false; +}; + // Serializes a Value to its protobuf representation. An optional StringPool will hold the // source path string. void SerializeValueToPb(const Value& value, pb::Value* out_value, StringPool* src_pool = nullptr); @@ -59,7 +64,8 @@ void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool void SerializeConfig(const android::ConfigDescription& config, pb::Configuration* out_pb_config); // Serializes a ResourceTable into its protobuf representation. -void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table, IDiagnostics* diag); +void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table, + IDiagnostics* diag, SerializeTableOptions options = {}); // Serializes a ResourceFile into its protobuf representation. void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file); diff --git a/tools/aapt2/optimize/ResourceDeduper.cpp b/tools/aapt2/optimize/ResourceDeduper.cpp index 78ebcb97b811..0278b439cfae 100644 --- a/tools/aapt2/optimize/ResourceDeduper.cpp +++ b/tools/aapt2/optimize/ResourceDeduper.cpp @@ -63,13 +63,14 @@ class DominatedKeyValueRemover : public DominatorTree::BottomUpVisitor { // Compare compatible configs for this entry and ensure the values are // equivalent. const ConfigDescription& node_configuration = node_value->config; - for (const auto& sibling : entry_->values) { - if (!sibling->value) { + for (const auto& sibling : parent->children()) { + ResourceConfigValue* sibling_value = sibling->value(); + if (!sibling_value->value) { // Sibling was already removed. continue; } - if (node_configuration.IsCompatibleWith(sibling->config) && - !node_value->value->Equals(sibling->value.get())) { + if (node_configuration.IsCompatibleWith(sibling_value->config) && + !node_value->value->Equals(sibling_value->value.get())) { // The configurations are compatible, but the value is // different, so we can't remove this value. return; diff --git a/tools/aapt2/optimize/ResourceDeduper_test.cpp b/tools/aapt2/optimize/ResourceDeduper_test.cpp index 2e098aec4f8d..048e318d2802 100644 --- a/tools/aapt2/optimize/ResourceDeduper_test.cpp +++ b/tools/aapt2/optimize/ResourceDeduper_test.cpp @@ -80,11 +80,58 @@ TEST(ResourceDeduperTest, DifferentValuesAreKept) { .Build(); ASSERT_TRUE(ResourceDeduper().Consume(context.get(), table.get())); + EXPECT_THAT(table, HasValue("android:string/keep", default_config)); EXPECT_THAT(table, HasValue("android:string/keep", ldrtl_config)); EXPECT_THAT(table, HasValue("android:string/keep", ldrtl_v21_config)); EXPECT_THAT(table, HasValue("android:string/keep", land_config)); } +TEST(ResourceDeduperTest, SameValuesAreDedupedIncompatibleSiblings) { + std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); + const ConfigDescription default_config = {}; + const ConfigDescription ldrtl_config = test::ParseConfigOrDie("ldrtl"); + const ConfigDescription ldrtl_night_config = test::ParseConfigOrDie("ldrtl-night"); + // Chosen because this configuration is not compatible with ldrtl-night. + const ConfigDescription ldrtl_notnight_config = test::ParseConfigOrDie("ldrtl-notnight"); + + std::unique_ptr<ResourceTable> table = + test::ResourceTableBuilder() + .AddString("android:string/keep", ResourceId{}, default_config, "keep") + .AddString("android:string/keep", ResourceId{}, ldrtl_config, "dedupe") + .AddString("android:string/keep", ResourceId{}, ldrtl_night_config, "dedupe") + .AddString("android:string/keep", ResourceId{}, ldrtl_notnight_config, "keep2") + .Build(); + + ASSERT_TRUE(ResourceDeduper().Consume(context.get(), table.get())); + EXPECT_THAT(table, HasValue("android:string/keep", default_config)); + EXPECT_THAT(table, HasValue("android:string/keep", ldrtl_config)); + EXPECT_THAT(table, Not(HasValue("android:string/keep", ldrtl_night_config))); + EXPECT_THAT(table, HasValue("android:string/keep", ldrtl_notnight_config)); +} + +TEST(ResourceDeduperTest, SameValuesAreDedupedCompatibleNonSiblings) { + std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); + const ConfigDescription default_config = {}; + const ConfigDescription ldrtl_config = test::ParseConfigOrDie("ldrtl"); + const ConfigDescription ldrtl_night_config = test::ParseConfigOrDie("ldrtl-night"); + // Chosen because this configuration is compatible with ldrtl. + const ConfigDescription land_config = test::ParseConfigOrDie("land"); + + std::unique_ptr<ResourceTable> table = + test::ResourceTableBuilder() + .AddString("android:string/keep", ResourceId{}, default_config, "keep") + .AddString("android:string/keep", ResourceId{}, ldrtl_config, "dedupe") + .AddString("android:string/keep", ResourceId{}, ldrtl_night_config, "dedupe") + .AddString("android:string/keep", ResourceId{}, land_config, "keep2") + .Build(); + + ASSERT_TRUE(ResourceDeduper().Consume(context.get(), table.get())); + EXPECT_THAT(table, HasValue("android:string/keep", default_config)); + EXPECT_THAT(table, HasValue("android:string/keep", ldrtl_config)); + EXPECT_THAT(table, Not(HasValue("android:string/keep", ldrtl_night_config))); + EXPECT_THAT(table, HasValue("android:string/keep", land_config)); +} + TEST(ResourceDeduperTest, LocalesValuesAreKept) { std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); const ConfigDescription default_config = {}; diff --git a/tools/processors/staledataclass/Android.bp b/tools/processors/staledataclass/Android.bp index c81d410c5e4b..58a7d346ce1f 100644 --- a/tools/processors/staledataclass/Android.bp +++ b/tools/processors/staledataclass/Android.bp @@ -13,6 +13,8 @@ java_plugin { static_libs: [ "codegen-version-info", ], + // The --add-modules/exports flags below don't work for kotlinc yet, so pin this module to Java language level 8 (see b/139342589): + java_version: "1.8", openjdk9: { javacflags: [ "--add-modules=jdk.compiler", diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 20d772c8fb11..ca65736d8ec2 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -50,6 +50,7 @@ import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.WorkSource; import android.util.Log; import android.util.Pair; @@ -1149,18 +1150,40 @@ public class WifiManager { * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}. * @param context the application context - * @param service the Binder interface * @hide - hide this because it takes in a parameter of type IWifiManager, which * is a system private class. */ - public WifiManager(Context context, IWifiManager service, Looper looper) { + public WifiManager(Context context, Looper looper) { mContext = context; - mService = service; mLooper = looper; mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; + } + + /** + * This is used only for unit testing. + * @hide + */ + @VisibleForTesting + public WifiManager(Context context, IWifiManager service, Looper looper) { + this(context, looper); + mService = service; updateVerboseLoggingEnabledFromService(); } + private IWifiManager getIWifiManager() throws RemoteException { + if (mService == null) { + synchronized (this) { + mService = IWifiManager.Stub.asInterface( + ServiceManager.getService(Context.WIFI_SERVICE)); + if (mService == null) { + throw new RemoteException("Wifi Service not running"); + } + updateVerboseLoggingEnabledFromService(); + } + } + return mService; + } + /** * Return a list of all the networks configured for the current foreground * user. @@ -1201,7 +1224,7 @@ public class WifiManager { public List<WifiConfiguration> getConfiguredNetworks() { try { ParceledListSlice<WifiConfiguration> parceledList = - mService.getConfiguredNetworks(mContext.getOpPackageName()); + getIWifiManager().getConfiguredNetworks(mContext.getOpPackageName()); if (parceledList == null) { return Collections.emptyList(); } @@ -1217,7 +1240,7 @@ public class WifiManager { public List<WifiConfiguration> getPrivilegedConfiguredNetworks() { try { ParceledListSlice<WifiConfiguration> parceledList = - mService.getPrivilegedConfiguredNetworks(mContext.getOpPackageName()); + getIWifiManager().getPrivilegedConfiguredNetworks(mContext.getOpPackageName()); if (parceledList == null) { return Collections.emptyList(); } @@ -1249,13 +1272,13 @@ public class WifiManager { List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>(); try { Map<String, Map<Integer, List<ScanResult>>> results = - mService.getAllMatchingFqdnsForScanResults( + getIWifiManager().getAllMatchingFqdnsForScanResults( scanResults); if (results.isEmpty()) { return configs; } List<WifiConfiguration> wifiConfigurations = - mService.getWifiConfigsForPasspointProfiles( + getIWifiManager().getWifiConfigsForPasspointProfiles( new ArrayList<>(results.keySet())); for (WifiConfiguration configuration : wifiConfigurations) { Map<Integer, List<ScanResult>> scanResultsPerNetworkType = results.get( @@ -1293,7 +1316,7 @@ public class WifiManager { return new HashMap<>(); } try { - return mService.getMatchingOsuProviders(scanResults); + return getIWifiManager().getMatchingOsuProviders(scanResults); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1320,7 +1343,7 @@ public class WifiManager { public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders( @NonNull Set<OsuProvider> osuProviders) { try { - return mService.getMatchingPasspointConfigsForOsuProviders( + return getIWifiManager().getMatchingPasspointConfigsForOsuProviders( new ArrayList<>(osuProviders)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1405,7 +1428,7 @@ public class WifiManager { */ private int addOrUpdateNetwork(WifiConfiguration config) { try { - return mService.addOrUpdateNetwork(config, mContext.getOpPackageName()); + return getIWifiManager().addOrUpdateNetwork(config, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1631,7 +1654,7 @@ public class WifiManager { Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper(); Binder binder = new Binder(); try { - mService.registerNetworkRequestMatchCallback( + getIWifiManager().registerNetworkRequestMatchCallback( binder, new NetworkRequestMatchCallbackProxy(looper, callback), callback.hashCode()); } catch (RemoteException e) { @@ -1657,7 +1680,7 @@ public class WifiManager { Log.v(TAG, "unregisterNetworkRequestMatchCallback: callback=" + callback); try { - mService.unregisterNetworkRequestMatchCallback(callback.hashCode()); + getIWifiManager().unregisterNetworkRequestMatchCallback(callback.hashCode()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1691,7 +1714,8 @@ public class WifiManager { public @NetworkSuggestionsStatusCode int addNetworkSuggestions( @NonNull List<WifiNetworkSuggestion> networkSuggestions) { try { - return mService.addNetworkSuggestions(networkSuggestions, mContext.getOpPackageName()); + return getIWifiManager().addNetworkSuggestions( + networkSuggestions, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1714,7 +1738,7 @@ public class WifiManager { public @NetworkSuggestionsStatusCode int removeNetworkSuggestions( @NonNull List<WifiNetworkSuggestion> networkSuggestions) { try { - return mService.removeNetworkSuggestions( + return getIWifiManager().removeNetworkSuggestions( networkSuggestions, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1760,7 +1784,8 @@ public class WifiManager { */ public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) { try { - if (!mService.addOrUpdatePasspointConfiguration(config, mContext.getOpPackageName())) { + if (!getIWifiManager().addOrUpdatePasspointConfiguration( + config, mContext.getOpPackageName())) { throw new IllegalArgumentException(); } } catch (RemoteException e) { @@ -1783,7 +1808,8 @@ public class WifiManager { }) public void removePasspointConfiguration(String fqdn) { try { - if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) { + if (!getIWifiManager().removePasspointConfiguration( + fqdn, mContext.getOpPackageName())) { throw new IllegalArgumentException(); } } catch (RemoteException e) { @@ -1806,7 +1832,7 @@ public class WifiManager { }) public List<PasspointConfiguration> getPasspointConfigurations() { try { - return mService.getPasspointConfigurations(mContext.getOpPackageName()); + return getIWifiManager().getPasspointConfigurations(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1826,7 +1852,7 @@ public class WifiManager { */ public void queryPasspointIcon(long bssid, String fileName) { try { - mService.queryPasspointIcon(bssid, fileName); + getIWifiManager().queryPasspointIcon(bssid, fileName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1840,7 +1866,7 @@ public class WifiManager { */ public int matchProviderWithCurrentNetwork(String fqdn) { try { - return mService.matchProviderWithCurrentNetwork(fqdn); + return getIWifiManager().matchProviderWithCurrentNetwork(fqdn); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1854,7 +1880,7 @@ public class WifiManager { */ public void deauthenticateNetwork(long holdoff, boolean ess) { try { - mService.deauthenticateNetwork(holdoff, ess); + getIWifiManager().deauthenticateNetwork(holdoff, ess); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1884,7 +1910,7 @@ public class WifiManager { @Deprecated public boolean removeNetwork(int netId) { try { - return mService.removeNetwork(netId, mContext.getOpPackageName()); + return getIWifiManager().removeNetwork(netId, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1939,7 +1965,8 @@ public class WifiManager { boolean success; try { - success = mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName()); + success = getIWifiManager().enableNetwork( + netId, attemptConnect, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1975,7 +2002,7 @@ public class WifiManager { @Deprecated public boolean disableNetwork(int netId) { try { - return mService.disableNetwork(netId, mContext.getOpPackageName()); + return getIWifiManager().disableNetwork(netId, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1998,7 +2025,7 @@ public class WifiManager { @Deprecated public boolean disconnect() { try { - return mService.disconnect(mContext.getOpPackageName()); + return getIWifiManager().disconnect(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2022,7 +2049,7 @@ public class WifiManager { @Deprecated public boolean reconnect() { try { - return mService.reconnect(mContext.getOpPackageName()); + return getIWifiManager().reconnect(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2046,7 +2073,7 @@ public class WifiManager { @Deprecated public boolean reassociate() { try { - return mService.reassociate(mContext.getOpPackageName()); + return getIWifiManager().reassociate(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2132,7 +2159,7 @@ public class WifiManager { private long getSupportedFeatures() { try { - return mService.getSupportedFeatures(); + return getIWifiManager().getSupportedFeatures(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2261,10 +2288,9 @@ public class WifiManager { * @hide */ public WifiActivityEnergyInfo getControllerActivityEnergyInfo() { - if (mService == null) return null; try { synchronized(this) { - return mService.reportActivityInfo(); + return getIWifiManager().reportActivityInfo(); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -2304,7 +2330,7 @@ public class WifiManager { public boolean startScan(WorkSource workSource) { try { String packageName = mContext.getOpPackageName(); - return mService.startScan(packageName); + return getIWifiManager().startScan(packageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2333,7 +2359,7 @@ public class WifiManager { */ public WifiInfo getConnectionInfo() { try { - return mService.getConnectionInfo(mContext.getOpPackageName()); + return getIWifiManager().getConnectionInfo(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2347,7 +2373,7 @@ public class WifiManager { */ public List<ScanResult> getScanResults() { try { - return mService.getScanResults(mContext.getOpPackageName()); + return getIWifiManager().getScanResults(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2366,7 +2392,7 @@ public class WifiManager { @Deprecated public boolean isScanAlwaysAvailable() { try { - return mService.isScanAlwaysAvailable(); + return getIWifiManager().isScanAlwaysAvailable(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2397,7 +2423,7 @@ public class WifiManager { */ public void setCountryCode(@NonNull String country) { try { - mService.setCountryCode(country); + getIWifiManager().setCountryCode(country); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2411,12 +2437,12 @@ public class WifiManager { */ @UnsupportedAppUsage public String getCountryCode() { - try { - String country = mService.getCountryCode(); - return country; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + try { + String country = getIWifiManager().getCountryCode(); + return country; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** @@ -2427,7 +2453,7 @@ public class WifiManager { @UnsupportedAppUsage public boolean isDualBandSupported() { try { - return mService.isDualBandSupported(); + return getIWifiManager().isDualBandSupported(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2440,7 +2466,7 @@ public class WifiManager { */ public boolean isDualModeSupported() { try { - return mService.needs5GHzToAnyApBandConversion(); + return getIWifiManager().needs5GHzToAnyApBandConversion(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2453,7 +2479,7 @@ public class WifiManager { */ public DhcpInfo getDhcpInfo() { try { - return mService.getDhcpInfo(); + return getIWifiManager().getDhcpInfo(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2480,7 +2506,7 @@ public class WifiManager { @Deprecated public boolean setWifiEnabled(boolean enabled) { try { - return mService.setWifiEnabled(mContext.getOpPackageName(), enabled); + return getIWifiManager().setWifiEnabled(mContext.getOpPackageName(), enabled); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2495,7 +2521,7 @@ public class WifiManager { */ public int getWifiState() { try { - return mService.getWifiEnabledState(); + return getIWifiManager().getWifiEnabledState(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2569,7 +2595,7 @@ public class WifiManager { */ public void updateInterfaceIpState(String ifaceName, int mode) { try { - mService.updateInterfaceIpState(ifaceName, mode); + getIWifiManager().updateInterfaceIpState(ifaceName, mode); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2587,7 +2613,7 @@ public class WifiManager { */ public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) { try { - return mService.startSoftAp(wifiConfig); + return getIWifiManager().startSoftAp(wifiConfig); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2602,7 +2628,7 @@ public class WifiManager { */ public boolean stopSoftAp() { try { - return mService.stopSoftAp(); + return getIWifiManager().stopSoftAp(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2671,7 +2697,7 @@ public class WifiManager { new LocalOnlyHotspotCallbackProxy(this, looper, callback); try { String packageName = mContext.getOpPackageName(); - int returnCode = mService.startLocalOnlyHotspot( + int returnCode = getIWifiManager().startLocalOnlyHotspot( proxy.getMessenger(), new Binder(), packageName); if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) { // Send message to the proxy to make sure we call back on the correct thread @@ -2723,7 +2749,7 @@ public class WifiManager { } mLOHSCallbackProxy = null; try { - mService.stopLocalOnlyHotspot(); + getIWifiManager().stopLocalOnlyHotspot(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2753,7 +2779,7 @@ public class WifiManager { Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper(); mLOHSObserverProxy = new LocalOnlyHotspotObserverProxy(this, looper, observer); try { - mService.startWatchLocalOnlyHotspot( + getIWifiManager().startWatchLocalOnlyHotspot( mLOHSObserverProxy.getMessenger(), new Binder()); mLOHSObserverProxy.registered(); } catch (RemoteException e) { @@ -2777,7 +2803,7 @@ public class WifiManager { } mLOHSObserverProxy = null; try { - mService.stopWatchLocalOnlyHotspot(); + getIWifiManager().stopWatchLocalOnlyHotspot(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2797,7 +2823,7 @@ public class WifiManager { @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState() { try { - return mService.getWifiApEnabledState(); + return getIWifiManager().getWifiApEnabledState(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2826,7 +2852,7 @@ public class WifiManager { @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public WifiConfiguration getWifiApConfiguration() { try { - return mService.getWifiApConfiguration(); + return getIWifiManager().getWifiApConfiguration(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2843,7 +2869,8 @@ public class WifiManager { @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) { try { - return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName()); + return getIWifiManager().setWifiApConfiguration( + wifiConfig, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2858,7 +2885,7 @@ public class WifiManager { public void notifyUserOfApBandConversion() { Log.d(TAG, "apBand was converted, notify the user"); try { - mService.notifyUserOfApBandConversion(mContext.getOpPackageName()); + getIWifiManager().notifyUserOfApBandConversion(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2886,7 +2913,7 @@ public class WifiManager { */ public void setTdlsEnabled(InetAddress remoteIPAddress, boolean enable) { try { - mService.enableTdls(remoteIPAddress.getHostAddress(), enable); + getIWifiManager().enableTdls(remoteIPAddress.getHostAddress(), enable); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2900,7 +2927,7 @@ public class WifiManager { */ public void setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable) { try { - mService.enableTdlsWithMacAddress(remoteMacAddress, enable); + getIWifiManager().enableTdlsWithMacAddress(remoteMacAddress, enable); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3189,8 +3216,8 @@ public class WifiManager { Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper(); Binder binder = new Binder(); try { - mService.registerSoftApCallback(binder, new SoftApCallbackProxy(looper, callback), - callback.hashCode()); + getIWifiManager().registerSoftApCallback( + binder, new SoftApCallbackProxy(looper, callback), callback.hashCode()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3210,7 +3237,7 @@ public class WifiManager { Log.v(TAG, "unregisterSoftApCallback: callback=" + callback); try { - mService.unregisterSoftApCallback(callback.hashCode()); + getIWifiManager().unregisterSoftApCallback(callback.hashCode()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3780,7 +3807,7 @@ public class WifiManager { public void disableEphemeralNetwork(String SSID) { if (SSID == null) throw new IllegalArgumentException("SSID cannot be null"); try { - mService.disableEphemeralNetwork(SSID, mContext.getOpPackageName()); + getIWifiManager().disableEphemeralNetwork(SSID, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3824,7 +3851,7 @@ public class WifiManager { @UnsupportedAppUsage private Messenger getWifiServiceMessenger() { try { - return mService.getWifiServiceMessenger(mContext.getOpPackageName()); + return getIWifiManager().getWifiServiceMessenger(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3884,10 +3911,10 @@ public class WifiManager { synchronized (mBinder) { if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) { try { - mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource); + getIWifiManager().acquireWifiLock(mBinder, mLockType, mTag, mWorkSource); synchronized (WifiManager.this) { if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { - mService.releaseWifiLock(mBinder); + getIWifiManager().releaseWifiLock(mBinder); throw new UnsupportedOperationException( "Exceeded maximum number of wifi locks"); } @@ -3917,7 +3944,7 @@ public class WifiManager { synchronized (mBinder) { if (mRefCounted ? (--mRefCount == 0) : (mHeld)) { try { - mService.releaseWifiLock(mBinder); + getIWifiManager().releaseWifiLock(mBinder); synchronized (WifiManager.this) { mActiveLockCount--; } @@ -3980,7 +4007,7 @@ public class WifiManager { } if (changed && mHeld) { try { - mService.updateWifiLockWorkSource(mBinder, mWorkSource); + getIWifiManager().updateWifiLockWorkSource(mBinder, mWorkSource); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4008,7 +4035,7 @@ public class WifiManager { synchronized (mBinder) { if (mHeld) { try { - mService.releaseWifiLock(mBinder); + getIWifiManager().releaseWifiLock(mBinder); synchronized (WifiManager.this) { mActiveLockCount--; } @@ -4121,10 +4148,10 @@ public class WifiManager { synchronized (mBinder) { if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) { try { - mService.acquireMulticastLock(mBinder, mTag); + getIWifiManager().acquireMulticastLock(mBinder, mTag); synchronized (WifiManager.this) { if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { - mService.releaseMulticastLock(mTag); + getIWifiManager().releaseMulticastLock(mTag); throw new UnsupportedOperationException( "Exceeded maximum number of wifi locks"); } @@ -4166,7 +4193,7 @@ public class WifiManager { synchronized (mBinder) { if (mRefCounted ? (--mRefCount == 0) : (mHeld)) { try { - mService.releaseMulticastLock(mTag); + getIWifiManager().releaseMulticastLock(mTag); synchronized (WifiManager.this) { mActiveLockCount--; } @@ -4243,7 +4270,7 @@ public class WifiManager { */ public boolean isMulticastEnabled() { try { - return mService.isMulticastEnabled(); + return getIWifiManager().isMulticastEnabled(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4256,7 +4283,7 @@ public class WifiManager { @UnsupportedAppUsage public boolean initializeMulticastFiltering() { try { - mService.initializeMulticastFiltering(); + getIWifiManager().initializeMulticastFiltering(); return true; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -4281,7 +4308,7 @@ public class WifiManager { @UnsupportedAppUsage public void enableVerboseLogging (int verbose) { try { - mService.enableVerboseLogging(verbose); + getIWifiManager().enableVerboseLogging(verbose); } catch (Exception e) { //ignore any failure here Log.e(TAG, "enableVerboseLogging " + e.toString()); @@ -4296,7 +4323,7 @@ public class WifiManager { @UnsupportedAppUsage public int getVerboseLoggingLevel() { try { - return mService.getVerboseLoggingLevel(); + return getIWifiManager().getVerboseLoggingLevel(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4309,7 +4336,7 @@ public class WifiManager { */ public void factoryReset() { try { - mService.factoryReset(mContext.getOpPackageName()); + getIWifiManager().factoryReset(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4323,7 +4350,7 @@ public class WifiManager { @UnsupportedAppUsage public Network getCurrentNetwork() { try { - return mService.getCurrentNetwork(); + return getIWifiManager().getCurrentNetwork(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4355,7 +4382,7 @@ public class WifiManager { */ public void enableWifiConnectivityManager(boolean enabled) { try { - mService.enableWifiConnectivityManager(enabled); + getIWifiManager().enableWifiConnectivityManager(enabled); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4367,7 +4394,7 @@ public class WifiManager { */ public byte[] retrieveBackupData() { try { - return mService.retrieveBackupData(); + return getIWifiManager().retrieveBackupData(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4379,7 +4406,7 @@ public class WifiManager { */ public void restoreBackupData(byte[] data) { try { - mService.restoreBackupData(data); + getIWifiManager().restoreBackupData(data); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4395,7 +4422,7 @@ public class WifiManager { @Deprecated public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) { try { - mService.restoreSupplicantBackupData(supplicantData, ipConfigData); + getIWifiManager().restoreSupplicantBackupData(supplicantData, ipConfigData); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4424,7 +4451,7 @@ public class WifiManager { throw new IllegalArgumentException("callback must not be null"); } try { - mService.startSubscriptionProvisioning(provider, + getIWifiManager().startSubscriptionProvisioning(provider, new ProvisioningCallbackProxy(executor, callback)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -4538,7 +4565,7 @@ public class WifiManager { Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper(); Binder binder = new Binder(); try { - mService.registerTrafficStateCallback( + getIWifiManager().registerTrafficStateCallback( binder, new TrafficStateCallbackProxy(looper, callback), callback.hashCode()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -4558,7 +4585,7 @@ public class WifiManager { Log.v(TAG, "unregisterTrafficStateCallback: callback=" + callback); try { - mService.unregisterTrafficStateCallback(callback.hashCode()); + getIWifiManager().unregisterTrafficStateCallback(callback.hashCode()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4614,7 +4641,7 @@ public class WifiManager { @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String[] getFactoryMacAddresses() { try { - return mService.getFactoryMacAddresses(); + return getIWifiManager().getFactoryMacAddresses(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4683,7 +4710,7 @@ public class WifiManager { @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(@DeviceMobilityState int state) { try { - mService.setDeviceMobilityState(state); + getIWifiManager().setDeviceMobilityState(state); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4738,8 +4765,9 @@ public class WifiManager { @NonNull EasyConnectStatusCallback callback) { Binder binder = new Binder(); try { - mService.startDppAsConfiguratorInitiator(binder, enrolleeUri, selectedNetworkId, - enrolleeNetworkRole, new EasyConnectCallbackProxy(executor, callback)); + getIWifiManager().startDppAsConfiguratorInitiator( + binder, enrolleeUri, selectedNetworkId, enrolleeNetworkRole, + new EasyConnectCallbackProxy(executor, callback)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4764,7 +4792,7 @@ public class WifiManager { @NonNull EasyConnectStatusCallback callback) { Binder binder = new Binder(); try { - mService.startDppAsEnrolleeInitiator(binder, configuratorUri, + getIWifiManager().startDppAsEnrolleeInitiator(binder, configuratorUri, new EasyConnectCallbackProxy(executor, callback)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -4786,7 +4814,7 @@ public class WifiManager { public void stopEasyConnectSession() { try { /* Request lower layers to stop/abort and clear resources */ - mService.stopDppSession(); + getIWifiManager().stopDppSession(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4885,7 +4913,7 @@ public class WifiManager { Log.v(TAG, "addOnWifiUsabilityStatsListener: listener=" + listener); } try { - mService.addOnWifiUsabilityStatsListener(new Binder(), + getIWifiManager().addOnWifiUsabilityStatsListener(new Binder(), new IOnWifiUsabilityStatsListener.Stub() { @Override public void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq, @@ -4922,7 +4950,7 @@ public class WifiManager { Log.v(TAG, "removeOnWifiUsabilityStatsListener: listener=" + listener); } try { - mService.removeOnWifiUsabilityStatsListener(listener.hashCode()); + getIWifiManager().removeOnWifiUsabilityStatsListener(listener.hashCode()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4945,7 +4973,7 @@ public class WifiManager { @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) { try { - mService.updateWifiUsabilityScore(seqNum, score, predictionHorizonSec); + getIWifiManager().updateWifiUsabilityScore(seqNum, score, predictionHorizonSec); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/wifi/java/android/net/wifi/rtt/ResponderLocation.java b/wifi/java/android/net/wifi/rtt/ResponderLocation.java index e1d82f8d3a09..970a75d7c418 100644 --- a/wifi/java/android/net/wifi/rtt/ResponderLocation.java +++ b/wifi/java/android/net/wifi/rtt/ResponderLocation.java @@ -605,11 +605,11 @@ public final class ResponderLocation implements Parcelable { // Negative 2's complement value // Note: The Math.pow(...) method cannot return a NaN value because the bitFieldSize // for Lat or Lng is limited to exactly 34 bits. - angle = Math.scalb(fields[offset] - Math.pow(2, bitFieldSizes[offset]), + angle = Math.scalb((double) fields[offset] - Math.pow(2, bitFieldSizes[offset]), -LATLNG_FRACTION_BITS); } else { // Positive 2's complement value - angle = Math.scalb(fields[offset], -LATLNG_FRACTION_BITS); + angle = Math.scalb((double) fields[offset], -LATLNG_FRACTION_BITS); } if (angle > limit) { angle = limit; @@ -732,10 +732,11 @@ public final class ResponderLocation implements Parcelable { int maxBssidIndicator = (int) buffer[SUBELEMENT_BSSID_MAX_INDICATOR_INDEX] & BYTE_MASK; int bssidListLength = (buffer.length - 1) / BYTES_IN_A_BSSID; - // Check the max number of BSSIDs agrees with the list length. - if (maxBssidIndicator != bssidListLength) { - return false; - } + // The maxBSSIDIndicator is ignored. Its use is still being clarified in 802.11REVmd, + // which is not published at this time. This field will be used in a future + // release of Android after 802.11REVmd is public. Here, we interpret the following + // params as an explicit list of BSSIDs. + int bssidOffset = SUBELEMENT_BSSID_LIST_INDEX; for (int i = 0; i < bssidListLength; i++) { diff --git a/wifi/tests/src/android/net/wifi/rtt/ResponderLocationTest.java b/wifi/tests/src/android/net/wifi/rtt/ResponderLocationTest.java index 47c304097372..b02eebbe9a01 100644 --- a/wifi/tests/src/android/net/wifi/rtt/ResponderLocationTest.java +++ b/wifi/tests/src/android/net/wifi/rtt/ResponderLocationTest.java @@ -37,7 +37,7 @@ import java.util.List; */ @RunWith(JUnit4.class) public class ResponderLocationTest { - private static final double LATLNG_TOLERANCE_DEGREES = 0.00001; + private static final double LATLNG_TOLERANCE_DEGREES = 0.000_000_05D; // 5E-8 = 6mm of meridian private static final double ALT_TOLERANCE_METERS = 0.01; private static final double HEIGHT_TOLERANCE_METERS = 0.01; private static final int INDEX_ELEMENT_TYPE = 2; @@ -103,7 +103,7 @@ public class ResponderLocationTest { private static final byte[] sTestBssidListSE = { (byte) 0x07, // Subelement BSSID list (byte) 13, // length dependent on number of BSSIDs in list - (byte) 0x02, // Number of BSSIDs in list + (byte) 0x00, // List is explicit; no expansion of list required (byte) 0x01, // BSSID #1 (MSB) (byte) 0x02, (byte) 0x03, @@ -266,11 +266,11 @@ public class ResponderLocationTest { assertTrue(valid); assertTrue(lciValid); assertFalse(zValid); - assertEquals(0.0009765625, responderLocation.getLatitudeUncertainty()); - assertEquals(-33.857009, responderLocation.getLatitude(), + assertEquals(0.0009765625D, responderLocation.getLatitudeUncertainty()); + assertEquals(-33.8570095D, responderLocation.getLatitude(), LATLNG_TOLERANCE_DEGREES); - assertEquals(0.0009765625, responderLocation.getLongitudeUncertainty()); - assertEquals(151.215200, responderLocation.getLongitude(), + assertEquals(0.0009765625D, responderLocation.getLongitudeUncertainty()); + assertEquals(151.2152005D, responderLocation.getLongitude(), LATLNG_TOLERANCE_DEGREES); assertEquals(1, responderLocation.getAltitudeType()); assertEquals(64.0, responderLocation.getAltitudeUncertainty()); @@ -282,11 +282,11 @@ public class ResponderLocationTest { assertEquals(1, responderLocation.getLciVersion()); // Testing Location Object - assertEquals(-33.857009, location.getLatitude(), + assertEquals(-33.8570095D, location.getLatitude(), LATLNG_TOLERANCE_DEGREES); - assertEquals(151.215200, location.getLongitude(), + assertEquals(151.2152005D, location.getLongitude(), LATLNG_TOLERANCE_DEGREES); - assertEquals((0.0009765625 + 0.0009765625) / 2, location.getAccuracy(), + assertEquals((0.0009765625D + 0.0009765625D) / 2, location.getAccuracy(), LATLNG_TOLERANCE_DEGREES); assertEquals(11.2, location.getAltitude(), ALT_TOLERANCE_METERS); assertEquals(64.0, location.getVerticalAccuracyMeters(), ALT_TOLERANCE_METERS); |