Merge "Add @UnsupportedAppUsage annotations to telephony-common."
diff --git a/Android.bp b/Android.bp
index ecf567c..b80ef88 100644
--- a/Android.bp
+++ b/Android.bp
@@ -25,30 +25,105 @@
 //
 // READ ME: ########################################################
 
+// 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 = [
+    // 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",
+    "opengl/java/**/*.java",
+    "rs/java/**/*.java",
+    "sax/java/**/*.java",
+    "telecomm/java/**/*.java",
+    "telephony/java/**/*.java",
+    "wifi/java/**/*.java",
+
+    // 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",
-        ],
+        export_include_dirs: framework_aidl_local_include_dirs,
     },
 }
 
@@ -57,691 +132,11 @@
     defaults: ["framework-aidl-export-defaults"],
     installable: true,
 
-    srcs: [
-        // From build/make/core/pathmap.mk FRAMEWORK_BASE_SUBDIRS
-        "core/java/**/*.java",
-        "graphics/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",
-        "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/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/ims/aidl/IRcsFeatureListener.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",
-
-        ":framework-statslog-gen",
-    ],
+    srcs: framework_srcs,
 
     aidl: {
-        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",
-        ],
-
+        local_include_dirs: framework_aidl_local_include_dirs,
+        include_dirs: framework_aidl_external_include_dirs,
         generate_get_transaction_name: true,
     },
 
@@ -1828,6 +1223,7 @@
         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,
@@ -1853,6 +1249,7 @@
         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,
@@ -1907,7 +1304,9 @@
 // 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/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 5ba563c..4e424c3 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.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 @@
     PackageManagerInternal mLocalPM;
     ActivityManagerInternal mActivityManagerInternal;
     IBatteryStats mBatteryStats;
-    DeviceIdleController.LocalService mLocalDeviceIdleController;
+    DeviceIdleInternal mLocalDeviceIdleController;
     AppStateTracker mAppStateTracker;
     final UsageStatsManagerInternal mUsageStats;
 
@@ -1399,8 +1399,8 @@
                 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(
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 0b67971..01f5fa6 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 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 @@
     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 @@
         // 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/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 3bb9929..d4d5871 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -18,6 +18,7 @@
     tidy_checks: [
         "modernize-*",
         "-modernize-avoid-c-arrays",
+        "-modernize-use-trailing-return-type",
         "android-*",
         "misc-*",
         "readability-*",
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 663cd55..96522f7 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -6875,6 +6875,9 @@
 
     // 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;
 }
 
 /**
@@ -6912,6 +6915,9 @@
 
     // Time spent on generating links in ms.
     optional int64 latency_millis = 10;
+
+    // Name of source package.
+    optional string package_name = 11;
 }
 
 /**
@@ -6943,6 +6949,9 @@
 
     // The score of the first entity type.
     optional float score = 8;
+
+    // Name of source package.
+    optional string package_name = 9;
 }
 
 /**
@@ -6971,6 +6980,9 @@
 
     // Position of this action.
     optional int32 action_index = 7;
+
+    // Name of source package.
+    optional string package_name = 8;
 }
 
 /**
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 553ef69..a6784780 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -191,6 +191,8 @@
 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;
@@ -6435,6 +6437,26 @@
         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/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index c58972e..635b9b0 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -112,7 +112,6 @@
 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 @@
         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 @@
             @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/services/core/java/com/android/server/compat/IPlatformCompat.aidl b/core/java/android/compat/IPlatformCompat.aidl
similarity index 90%
rename from services/core/java/com/android/server/compat/IPlatformCompat.aidl
rename to core/java/android/compat/IPlatformCompat.aidl
index 8ab08f9..3d8a9d5 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/Context.java b/core/java/android/content/Context.java
index 73bc908..bb5ced56 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3735,6 +3735,14 @@
     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 +4117,9 @@
     /**
      * 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)
      */
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 2f198ac..f50502e 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -675,12 +675,6 @@
             "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/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index 2014751..c89796d 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -76,10 +76,10 @@
     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 @@
     }
 
     /** @hide */
-    public IntArray getInstalledUsers() {
-        return mInstalledUsers;
+    public IntArray getSnapshottedUsers() {
+        return mSnapshottedUsers;
     }
 
     /** @hide */
@@ -179,14 +179,14 @@
     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 @@
         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/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 099ae29..e78fb7f 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -339,6 +339,8 @@
      * 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 @@
      * 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/net/util/MultinetworkPolicyTracker.java b/core/java/android/net/util/MultinetworkPolicyTracker.java
index 30c5cd9..f7e494d 100644
--- a/core/java/android/net/util/MultinetworkPolicyTracker.java
+++ b/core/java/android/net/util/MultinetworkPolicyTracker.java
@@ -16,29 +16,32 @@
 
 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 com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.Arrays;
 import java.util.List;
 
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.R;
-
-import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
-import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
-
 /**
  * A class to encapsulate management of the "Smart Networking" capability of
  * avoiding bad Wi-Fi when, for example upstream connectivity is lost or
@@ -69,6 +72,7 @@
 
     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 @@
             }
         };
 
+        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 @@
      * 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/service/gatekeeper/GateKeeperResponse.java b/core/java/android/service/gatekeeper/GateKeeperResponse.java
index 66fee1e..7ed733c 100644
--- a/core/java/android/service/gatekeeper/GateKeeperResponse.java
+++ b/core/java/android/service/gatekeeper/GateKeeperResponse.java
@@ -31,6 +31,8 @@
     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/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index c73de8f..1bb2ba2 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -775,17 +775,54 @@
         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 @@
 
         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 @@
             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/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 78e8e13..18a1b43 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -237,10 +237,6 @@
 }
 
 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 @@
         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/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index e43b6a0..e62af74 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -20,6 +20,7 @@
 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 @@
 
     // 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 0000000..cc24196
--- /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/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 4025a08..4187c80 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -24,6 +24,7 @@
         <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">
@@ -350,4 +351,19 @@
         <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/libs/hostgraphics/Android.bp b/libs/hostgraphics/Android.bp
index aedb752..e713b98 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 0000000..9e54816
--- /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 0000000..ec30437
--- /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 0000000..af6d273
--- /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 0000000..01409e1
--- /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 0000000..707b313
--- /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 0000000..aa3e726
--- /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 0000000..9002953
--- /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 0000000..9eb67b2
--- /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 0042213..a1efd0b 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 0000000..04d535c
--- /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 0000000..ac88e44
--- /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/location/lib/Android.bp b/location/lib/Android.bp
index ab01ddb..db63889 100644
--- a/location/lib/Android.bp
+++ b/location/lib/Android.bp
@@ -22,6 +22,8 @@
     ],
     api_packages: ["com.android.location.provider"],
     srcs_lib: "framework-minus-apex",
-    srcs_lib_whitelist_dirs: ["location/java"],
-    srcs_lib_whitelist_pkgs: ["com.android.internal.location"],
+    // 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/Metadata.java b/media/java/android/media/Metadata.java
index 792a2ba..be0d966 100644
--- a/media/java/android/media/Metadata.java
+++ b/media/java/android/media/Metadata.java
@@ -272,6 +272,15 @@
     @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 @@
             parcel.setDataPosition(pin);
             return false;
         }
+
+        if (mParcel != null) {
+            mParcel.recycle();
+        }
         mParcel = parcel;
         return true;
     }
diff --git a/packages/CarSystemUI/AndroidManifest.xml b/packages/CarSystemUI/AndroidManifest.xml
index 195d4fe..261b9f5 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 0000000..bec6ba7
--- /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 0000000..2d9901c
--- /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 69ab3f3..0a3f7aa 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 42a7649..9cb09c9 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 be2cb0d8..862ba75 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 83e91c5..717692e 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 371bebd..a9423bf 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 b1f9797..97fbea6 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -26,6 +26,7 @@
 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;
@@ -957,8 +958,12 @@
         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 0000000..78bb1bc
--- /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 0a167d9..7cd6adb 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 @@
 
 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 @@
         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 @@
     }
 
     /**
-     * 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.
      *
-     * We dismiss the entire keyguard if user clicked on the foreground user (user we're already
-     * logged in as).
+     * 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 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 @@
                 });
 
     }
+
+    private boolean hasTrustedDevice(int uid) {
+        return !mEnrollmentManager.getEnrolledDeviceInfoForUser(uid).isEmpty();
+    }
 }
diff --git a/packages/SettingsLib/res/values/styles_support_preference.xml b/packages/SettingsLib/res/values/styles_support_preference.xml
index 5d787f8..6e61196 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 3e359d2..d3bab5f 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 @@
         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/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 6adb305..a3b0e6b 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 @@
 
 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.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
@@ -1599,6 +1656,33 @@
         // 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/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index c732584..08996c3 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 @@
         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/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 0ee9bff..59270a0 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.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 @@
 
     @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 @@
         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 @@
         // 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/assist/ui/InvocationLightsView.java b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
index bc782a7..bb3bd78 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 @@
 
         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/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
new file mode 100644
index 0000000..f0e8c16
--- /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 0000000..d44b63e
--- /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/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 991d9fa..0403a05 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 @@
         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/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 001e094..16a3975 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 @@
         if (listening) {
             refreshState();
         }
+        mHotspotController.handleSetListening(listening);
     }
 
     @Override
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 830b50e..8b06a9f 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.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 db2be0e..1c6d12f 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 @@
     private int mHotspotState;
     private int mNumConnectedDevices;
     private boolean mWaitingForTerminalState;
+    private boolean mListening;
 
     /**
      */
@@ -105,14 +106,18 @@
             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 @@
         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/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 1c24bb9..04f96a4 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 @@
         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 @@
                     recalculateEmergency();
                 }
                 break;
+            case Intent.ACTION_BOOT_COMPLETED:
+                mWifiSignalController.handleBootCompleted();
+                break;
             case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
                 mConfig = Config.readConfig(mContext);
                 mReceiverHandler.post(this::handleConfigurationChanged);
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 6f63544..a441f66 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 @@
 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 @@
                 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 @@
         notifyListenersIfNecessary();
     }
 
+    public void handleBootCompleted() {
+        mWifiManager.registerTrafficStateCallback(new WifiTrafficStateCallback(), null);
+    }
+
     /**
      * Handler to receive the data activity on wifi.
      */
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 0000000..2bff548
--- /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 0000000..011c2cd
--- /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/statusbar/policy/HotspotControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
index 3e4c4d6..556ed5c 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 @@
                 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/utils/leaks/FakeHotspotController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java
index 016160a..c9681ac 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 @@
     }
 
     @Override
+    public void handleSetListening(boolean listening) {
+    }
+
+    @Override
     public boolean isHotspotEnabled() {
         return false;
     }
diff --git a/services/Android.bp b/services/Android.bp
index b08d1a8..54157d0 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -35,6 +35,7 @@
         "services.usage",
         "services.usb",
         "services.voiceinteraction",
+        "services.wifi",
         "android.hidl.base-V1.0-java",
     ],
 
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index fffdba7..695fccc 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -18,29 +18,21 @@
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 
-import android.Manifest;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
-import android.app.ActivityManager;
 import android.app.backup.BackupManager;
 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.app.job.JobParameters;
 import android.app.job.JobScheduler;
 import android.app.job.JobService;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.os.Binder;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -82,42 +74,6 @@
     }
 
     /**
-     * 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.
-     */
-    private void enforceCallingPermissionOnUserId(@UserIdInt int userId, String message) {
-        if (Binder.getCallingUserHandle().getIdentifier() != userId) {
-            mContext.enforceCallingOrSelfPermission(
-                    Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
-        }
-    }
-
-    // ---------------------------------------------
-    // USER LIFECYCLE CALLBACKS
-    // ---------------------------------------------
-
-    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.
-     *
-     *  Warning: Do NOT modify returned object as it's used inside.
-     *
-     *  TODO: Return a copy or only expose read-only information through other means.
-     */
-    @VisibleForTesting
-    public SparseArray<UserBackupManagerService> getUserServices() {
-        return mServiceUsers;
-    }
-
-    /**
      * 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}.
@@ -132,12 +88,7 @@
     @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);
-        }
-        return userBackupManagerService;
+        return mTrampoline.getServiceForUserIfCallerHasPermission(userId, caller);
     }
 
     /*
@@ -148,326 +99,6 @@
     // TODO (b/118520567): Stop hardcoding system user when we pass in user id as a parameter
 
     // ---------------------------------------------
-    // BACKUP AGENT OPERATIONS
-    // ---------------------------------------------
-
-    /**
-     * An app's backup agent calls this method to let the service know that there's new data to
-     * backup for their app {@code packageName}. Only used for apps participating in key-value
-     * backup.
-     */
-    public void dataChanged(@UserIdInt int userId, String packageName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "dataChanged()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.dataChanged(packageName);
-        }
-    }
-
-    /**
-     * Callback: a requested backup agent has been instantiated. This should only be called from the
-     * {@link ActivityManager}.
-     */
-    public void agentConnected(@UserIdInt int userId, String packageName, IBinder agentBinder) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "agentConnected()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.agentConnected(packageName, agentBinder);
-        }
-    }
-
-    /**
-     * Callback: a backup agent has failed to come up, or has unexpectedly quit. This should only be
-     * called from the {@link ActivityManager}.
-     */
-    public void agentDisconnected(@UserIdInt int userId, String packageName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "agentDisconnected()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.agentDisconnected(packageName);
-        }
-    }
-
-    /**
-     * 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, "opComplete()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.opComplete(token, result);
-        }
-    }
-
-    // ---------------------------------------------
-    // TRANSPORT OPERATIONS
-    // ---------------------------------------------
-
-    /** 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);
-        }
-    }
-
-    /**
-     * 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);
-        }
-    }
-
-    /** Return the name of the currently active transport. */
-    @Nullable
-    public String getCurrentTransport(@UserIdInt int userId) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "getCurrentTransport()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.getCurrentTransport();
-    }
-
-    /**
-     * 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.
-     */
-    @Nullable
-    public ComponentName getCurrentTransportComponent(@UserIdInt int userId) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "getCurrentTransportComponent()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.getCurrentTransportComponent();
-    }
-
-    /** Report all known, available backup transports by name. */
-    @Nullable
-    public String[] listAllTransports(@UserIdInt int userId) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "listAllTransports()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.listAllTransports();
-    }
-
-    /** Report all known, available backup transports by {@link ComponentName}. */
-    @Nullable
-    public ComponentName[] listAllTransportComponents(@UserIdInt int userId) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "listAllTransportComponents()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.listAllTransportComponents();
-    }
-
-    /**
-     * 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
-     * ignored. Only the host process of the transport can change its description, otherwise a
-     * {@link SecurityException} will be thrown.
-     *
-     * @param transportComponent The identity of the transport being described.
-     * @param name A {@link String} with the new name for the transport. This is NOT for
-     *     identification. MUST NOT be {@code null}.
-     * @param configurationIntent An {@link Intent} that can be passed to {@link
-     *     Context#startActivity} in order to launch the transport's configuration UI. It may be
-     *     {@code null} if the transport does not offer any user-facing configuration UI.
-     * @param currentDestinationString A {@link String} describing the destination to which the
-     *     transport is currently sending data. MUST NOT be {@code null}.
-     * @param dataManagementIntent An {@link Intent} that can be passed to {@link
-     *     Context#startActivity} in order to launch the transport's data-management UI. It may be
-     *     {@code null} if the transport does not offer any user-facing data management UI.
-     * @param dataManagementLabel A {@link CharSequence} to be used as the label for the transport's
-     *     data management affordance. This MUST be {@code null} when dataManagementIntent is {@code
-     *     null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
-     * @throws SecurityException If the UID of the calling process differs from the package UID of
-     *     {@code transportComponent} or if the caller does NOT have BACKUP permission.
-     */
-    public void updateTransportAttributes(
-            @UserIdInt int userId,
-            ComponentName transportComponent,
-            String name,
-            @Nullable Intent configurationIntent,
-            String currentDestinationString,
-            @Nullable Intent dataManagementIntent,
-            CharSequence dataManagementLabel) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "updateTransportAttributes()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.updateTransportAttributes(
-                    transportComponent,
-                    name,
-                    configurationIntent,
-                    currentDestinationString,
-                    dataManagementIntent,
-                    dataManagementLabel);
-        }
-    }
-
-    /**
-     * Selects transport {@code transportName} and returns the previously selected transport.
-     *
-     * @deprecated Use {@link #selectBackupTransportAsync(ComponentName,
-     *     ISelectBackupTransportCallback)} instead.
-     */
-    @Deprecated
-    @Nullable
-    public String selectBackupTransport(@UserIdInt int userId, String transportName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "selectBackupTransport()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.selectBackupTransport(transportName);
-    }
-
-    /**
-     * Selects transport {@code transportComponent} asynchronously and notifies {@code listener}
-     * with the result upon completion.
-     */
-    public void selectBackupTransportAsync(
-            @UserIdInt int userId,
-            ComponentName transportComponent,
-            ISelectBackupTransportCallback listener) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "selectBackupTransportAsync()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.selectBackupTransportAsync(transportComponent, listener);
-        }
-    }
-
-    /**
-     * 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
-     * returns {@code null}.
-     */
-    @Nullable
-    public Intent getConfigurationIntent(@UserIdInt int userId, String transportName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "getConfigurationIntent()");
-
-        return userBackupManagerService == null
-            ? 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);
-        }
-    }
-
-    /**
-     * 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 = mServiceUsers.get(userId);
-            if (userBackupManagerService != null) {
-                if (userBackupManagerService.getAncestralSerialNumber() == ancestralSerialNumber) {
-                    return UserHandle.of(userId);
-                }
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * Supply the current destination string for the given transport. If the name is not one of the
-     * registered transports the method will return null.
-     *
-     * <p>This string is used VERBATIM as the summary text of the relevant Settings item.
-     *
-     * @param transportName The name of the registered transport.
-     * @return The current destination string or null if the transport is not registered.
-     */
-    @Nullable
-    public String getDestinationString(@UserIdInt int userId, String transportName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "getDestinationString()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.getDestinationString(transportName);
-    }
-
-    /** Supply the manage-data intent for the given transport. */
-    @Nullable
-    public Intent getDataManagementIntent(@UserIdInt int userId, String transportName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "getDataManagementIntent()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.getDataManagementIntent(transportName);
-    }
-
-    /**
-     * Supply the menu label for affordances that fire the manage-data intent for the given
-     * transport.
-     */
-    @Nullable
-    public CharSequence getDataManagementLabel(@UserIdInt int userId, String transportName) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(userId, "getDataManagementLabel()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.getDataManagementLabel(transportName);
-    }
-
-    // ---------------------------------------------
     // SETTINGS OPERATIONS
     // ---------------------------------------------
 
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index cd2fb03..b522c87 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -24,6 +24,7 @@
 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;
@@ -269,7 +270,8 @@
     // 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);
+        return mUserServices.get(UserHandle.USER_SYSTEM) != null
+                && mUserServices.get(userId) != null;
     }
 
     /**
@@ -501,7 +503,7 @@
     @Override
     public void dataChangedForUser(int userId, String packageName) throws RemoteException {
         if (isUserReadyForBackup(userId)) {
-            mService.dataChanged(userId, packageName);
+            dataChanged(userId, packageName);
         }
     }
 
@@ -510,11 +512,40 @@
         dataChangedForUser(binderGetCallingUserId(), packageName);
     }
 
+    /**
+     * An app's backup agent calls this method to let the service know that there's new data to
+     * backup for their app {@code packageName}. Only used for apps participating in key-value
+     * backup.
+     */
+    public void dataChanged(@UserIdInt int userId, String packageName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "dataChanged()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.dataChanged(packageName);
+        }
+    }
+
+    // ---------------------------------------------
+    // TRANSPORT OPERATIONS
+    // ---------------------------------------------
+
     @Override
     public void initializeTransportsForUser(
             int userId, String[] transportNames, IBackupObserver observer) throws RemoteException {
         if (isUserReadyForBackup(userId)) {
-            mService.initializeTransports(userId, transportNames, observer);
+            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);
         }
     }
 
@@ -522,7 +553,20 @@
     public void clearBackupDataForUser(int userId, String transportName, String packageName)
             throws RemoteException {
         if (isUserReadyForBackup(userId)) {
-            mService.clearBackupData(userId, transportName, packageName);
+            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);
         }
     }
 
@@ -536,7 +580,7 @@
     public void agentConnectedForUser(int userId, String packageName, IBinder agent)
             throws RemoteException {
         if (isUserReadyForBackup(userId)) {
-            mService.agentConnected(userId, packageName, agent);
+            agentConnected(userId, packageName, agent);
         }
     }
 
@@ -545,10 +589,23 @@
         agentConnectedForUser(binderGetCallingUserId(), packageName, agent);
     }
 
+    /**
+     * Callback: a requested backup agent has been instantiated. This should only be called from the
+     * {@link ActivityManager}.
+     */
+    public void agentConnected(@UserIdInt int userId, String packageName, IBinder agentBinder) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "agentConnected()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.agentConnected(packageName, agentBinder);
+        }
+    }
+
     @Override
     public void agentDisconnectedForUser(int userId, String packageName) throws RemoteException {
         if (isUserReadyForBackup(userId)) {
-            mService.agentDisconnected(userId, packageName);
+            agentDisconnected(userId, packageName);
         }
     }
 
@@ -557,6 +614,19 @@
         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}.
+     */
+    public void agentDisconnected(@UserIdInt int userId, String packageName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "agentDisconnected()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.agentDisconnected(packageName);
+        }
+    }
+
     @Override
     public void restoreAtInstallForUser(int userId, String packageName, int token)
             throws RemoteException {
@@ -680,7 +750,7 @@
 
     @Override
     public String getCurrentTransportForUser(int userId) throws RemoteException {
-        return (isUserReadyForBackup(userId)) ? mService.getCurrentTransport(userId) : null;
+        return (isUserReadyForBackup(userId)) ? getCurrentTransport(userId) : null;
     }
 
     @Override
@@ -688,6 +758,17 @@
         return getCurrentTransportForUser(binderGetCallingUserId());
     }
 
+    /** Return the name of the currently active transport. */
+    @Nullable
+    public String getCurrentTransport(@UserIdInt int userId) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "getCurrentTransport()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.getCurrentTransport();
+    }
+
     /**
      * 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.
@@ -695,13 +776,37 @@
     @Override
     @Nullable
     public ComponentName getCurrentTransportComponentForUser(int userId) {
-        return (isUserReadyForBackup(userId))
-                ? mService.getCurrentTransportComponent(userId) : null;
+        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.
+     */
+    @Nullable
+    public ComponentName getCurrentTransportComponent(@UserIdInt int userId) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "getCurrentTransportComponent()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.getCurrentTransportComponent();
     }
 
     @Override
     public String[] listAllTransportsForUser(int userId) throws RemoteException {
-        return (isUserReadyForBackup(userId)) ? mService.listAllTransports(userId) : null;
+        return (isUserReadyForBackup(userId)) ? listAllTransports(userId) : null;
+    }
+
+    /** Report all known, available backup transports by name. */
+    @Nullable
+    public String[] listAllTransports(@UserIdInt int userId) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "listAllTransports()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.listAllTransports();
     }
 
     @Override
@@ -712,7 +817,18 @@
     @Override
     public ComponentName[] listAllTransportComponentsForUser(int userId) throws RemoteException {
         return (isUserReadyForBackup(userId))
-                ? mService.listAllTransportComponents(userId) : null;
+                ? listAllTransportComponents(userId) : null;
+    }
+
+    /** Report all known, available backup transports by {@link ComponentName}. */
+    @Nullable
+    public ComponentName[] listAllTransportComponents(@UserIdInt int userId) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "listAllTransportComponents()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.listAllTransportComponents();
     }
 
     @Override
@@ -741,7 +857,7 @@
             @Nullable Intent dataManagementIntent,
             CharSequence dataManagementLabel) {
         if (isUserReadyForBackup(userId)) {
-            mService.updateTransportAttributes(
+            updateTransportAttributes(
                     userId,
                     transportComponent,
                     name,
@@ -752,11 +868,56 @@
         }
     }
 
+    /**
+     * 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
+     * ignored. Only the host process of the transport can change its description, otherwise a
+     * {@link SecurityException} will be thrown.
+     *
+     * @param transportComponent The identity of the transport being described.
+     * @param name A {@link String} with the new name for the transport. This is NOT for
+     *     identification. MUST NOT be {@code null}.
+     * @param configurationIntent An {@link Intent} that can be passed to {@link
+     *     Context#startActivity} in order to launch the transport's configuration UI. It may be
+     *     {@code null} if the transport does not offer any user-facing configuration UI.
+     * @param currentDestinationString A {@link String} describing the destination to which the
+     *     transport is currently sending data. MUST NOT be {@code null}.
+     * @param dataManagementIntent An {@link Intent} that can be passed to {@link
+     *     Context#startActivity} in order to launch the transport's data-management UI. It may be
+     *     {@code null} if the transport does not offer any user-facing data management UI.
+     * @param dataManagementLabel A {@link CharSequence} to be used as the label for the transport's
+     *     data management affordance. This MUST be {@code null} when dataManagementIntent is {@code
+     *     null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
+     * @throws SecurityException If the UID of the calling process differs from the package UID of
+     *     {@code transportComponent} or if the caller does NOT have BACKUP permission.
+     */
+    public void updateTransportAttributes(
+            @UserIdInt int userId,
+            ComponentName transportComponent,
+            String name,
+            @Nullable Intent configurationIntent,
+            String currentDestinationString,
+            @Nullable Intent dataManagementIntent,
+            CharSequence dataManagementLabel) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "updateTransportAttributes()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.updateTransportAttributes(
+                    transportComponent,
+                    name,
+                    configurationIntent,
+                    currentDestinationString,
+                    dataManagementIntent,
+                    dataManagementLabel);
+        }
+    }
+
     @Override
     public String selectBackupTransportForUser(int userId, String transport)
             throws RemoteException {
         return (isUserReadyForBackup(userId))
-                ? mService.selectBackupTransport(userId, transport) : null;
+                ? selectBackupTransport(userId, transport) : null;
     }
 
     @Override
@@ -764,11 +925,28 @@
         return selectBackupTransportForUser(binderGetCallingUserId(), transport);
     }
 
+    /**
+     * Selects transport {@code transportName} and returns the previously selected transport.
+     *
+     * @deprecated Use {@link #selectBackupTransportAsync(ComponentName,
+     *     ISelectBackupTransportCallback)} instead.
+     */
+    @Deprecated
+    @Nullable
+    public String selectBackupTransport(@UserIdInt int userId, String transportName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "selectBackupTransport()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.selectBackupTransport(transportName);
+    }
+
     @Override
     public void selectBackupTransportAsyncForUser(int userId, ComponentName transport,
             ISelectBackupTransportCallback listener) throws RemoteException {
         if (isUserReadyForBackup(userId)) {
-            mService.selectBackupTransportAsync(userId, transport, listener);
+            selectBackupTransportAsync(userId, transport, listener);
         } else {
             if (listener != null) {
                 try {
@@ -780,10 +958,26 @@
         }
     }
 
+    /**
+     * Selects transport {@code transportComponent} asynchronously and notifies {@code listener}
+     * with the result upon completion.
+     */
+    public void selectBackupTransportAsync(
+            @UserIdInt int userId,
+            ComponentName transportComponent,
+            ISelectBackupTransportCallback listener) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "selectBackupTransportAsync()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.selectBackupTransportAsync(transportComponent, listener);
+        }
+    }
+
     @Override
     public Intent getConfigurationIntentForUser(int userId, String transport)
             throws RemoteException {
-        return isUserReadyForBackup(userId) ? mService.getConfigurationIntent(userId, transport)
+        return isUserReadyForBackup(userId) ? getConfigurationIntent(userId, transport)
                 : null;
     }
 
@@ -793,9 +987,24 @@
         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
+     * returns {@code null}.
+     */
+    @Nullable
+    public Intent getConfigurationIntent(@UserIdInt int userId, String transportName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "getConfigurationIntent()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.getConfigurationIntent(transportName);
+    }
+
     @Override
     public String getDestinationStringForUser(int userId, String transport) throws RemoteException {
-        return isUserReadyForBackup(userId) ? mService.getDestinationString(userId, transport)
+        return isUserReadyForBackup(userId) ? getDestinationString(userId, transport)
                 : null;
     }
 
@@ -804,11 +1013,30 @@
         return getDestinationStringForUser(binderGetCallingUserId(), transport);
     }
 
+    /**
+     * Supply the current destination string for the given transport. If the name is not one of the
+     * registered transports the method will return null.
+     *
+     * <p>This string is used VERBATIM as the summary text of the relevant Settings item.
+     *
+     * @param transportName The name of the registered transport.
+     * @return The current destination string or null if the transport is not registered.
+     */
+    @Nullable
+    public String getDestinationString(@UserIdInt int userId, String transportName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "getDestinationString()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.getDestinationString(transportName);
+    }
+
     @Override
     public Intent getDataManagementIntentForUser(int userId, String transport)
             throws RemoteException {
         return isUserReadyForBackup(userId)
-                ? mService.getDataManagementIntent(userId, transport) : null;
+                ? getDataManagementIntent(userId, transport) : null;
     }
 
     @Override
@@ -817,13 +1045,38 @@
         return getDataManagementIntentForUser(binderGetCallingUserId(), transport);
     }
 
+    /** Supply the manage-data intent for the given transport. */
+    @Nullable
+    public Intent getDataManagementIntent(@UserIdInt int userId, String transportName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "getDataManagementIntent()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.getDataManagementIntent(transportName);
+    }
+
     @Override
     public CharSequence getDataManagementLabelForUser(int userId, String transport)
             throws RemoteException {
-        return isUserReadyForBackup(userId) ? mService.getDataManagementLabel(userId, transport)
+        return isUserReadyForBackup(userId) ? getDataManagementLabel(userId, transport)
                 : null;
     }
 
+    /**
+     * Supply the menu label for affordances that fire the manage-data intent for the given
+     * transport.
+     */
+    @Nullable
+    public CharSequence getDataManagementLabel(@UserIdInt int userId, String transportName) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "getDataManagementLabel()");
+
+        return userBackupManagerService == null
+                ? null
+                : userBackupManagerService.getDataManagementLabel(transportName);
+    }
+
     @Override
     public IRestoreSession beginRestoreSessionForUser(
             int userId, String packageName, String transportID) throws RemoteException {
@@ -834,7 +1087,7 @@
     @Override
     public void opCompleteForUser(int userId, int token, long result) throws RemoteException {
         if (isUserReadyForBackup(userId)) {
-            mService.opComplete(userId, token, result);
+            opComplete(userId, token, result);
         }
     }
 
@@ -843,6 +1096,19 @@
         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, "opComplete()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.opComplete(token, result);
+        }
+    }
+
     @Override
     public long getAvailableRestoreTokenForUser(int userId, String packageName) {
         return isUserReadyForBackup(userId) ? mService.getAvailableRestoreToken(userId,
@@ -889,18 +1155,62 @@
         cancelBackupsForUser(binderGetCallingUserId());
     }
 
+    /**
+     * 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.
+     */
     @Override
-    @Nullable public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
+    @Nullable
+    public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
         if (mGlobalDisable) {
             return null;
         }
-        return mService.getUserForAncestralSerialNumber(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 = mUserServices.get(userId);
+            if (userBackupManagerService != null) {
+                if (userBackupManagerService.getAncestralSerialNumber() == ancestralSerialNumber) {
+                    return UserHandle.of(userId);
+                }
+            }
+        }
+
+        return null;
     }
 
+    /**
+     * 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.
+     */
     @Override
     public void setAncestralSerialNumber(long ancestralSerialNumber) {
-        if (!mGlobalDisable) {
-            mService.setAncestralSerialNumber(ancestralSerialNumber);
+        if (mGlobalDisable) {
+            return;
+        }
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(
+                        Binder.getCallingUserHandle().getIdentifier(),
+                        "setAncestralSerialNumber()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.setAncestralSerialNumber(ancestralSerialNumber);
         }
     }
 
@@ -926,4 +1236,41 @@
             mService.endFullBackup(userId);
         }
     }
+
+    /**
+     * 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.
+     */
+    @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;
+    }
+
+    /**
+     * 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.
+     */
+    void enforceCallingPermissionOnUserId(@UserIdInt int userId, String message) {
+        if (Binder.getCallingUserHandle().getIdentifier() != userId) {
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
+        }
+    }
 }
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 474dbfe..c838c60 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -13,7 +13,6 @@
     },
     srcs: [
         "java/**/*.java",
-        ":platformcompat_aidl",
         ":dumpstate_aidl",
         ":idmap2_aidl",
         ":installd_aidl",
@@ -82,11 +81,3 @@
     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 fede487..9a97ddb 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -172,7 +172,7 @@
     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 @@
                 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/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index a303718..62930b0 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 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 @@
         }
 
         // 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 @@
          * 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 @@
             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 @@
 
         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 0000000..1273249
--- /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/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index dee89e5..ea3dd3d 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.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 @@
     // 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 @@
                                 "package-watchdog.xml")),
                 new Handler(Looper.myLooper()), BackgroundThread.getHandler(),
                 new ExplicitHealthCheckController(context),
-                NetworkStackClient.getInstance());
+                ConnectivityModuleConnector.getInstance());
     }
 
     /**
@@ -147,13 +147,13 @@
     @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 @@
                     () -> syncRequestsAsync());
             setPropertyChangedListenerLocked();
             updateConfigs();
-            registerNetworkStackHealthListener();
+            registerConnectivityModuleHealthListener();
         }
     }
 
@@ -743,11 +743,11 @@
         }
     }
 
-    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/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6965519..19c818f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -330,7 +330,7 @@
 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;
@@ -1135,7 +1135,7 @@
     /**
      * Access to DeviceIdleController service.
      */
-    DeviceIdleController.LocalService mLocalDeviceIdleController;
+    DeviceIdleInternal mLocalDeviceIdleController;
 
     /**
      * Power-save whitelisted app-ids (not including except-idle-whitelisted ones).
@@ -9003,8 +9003,8 @@
             }
 
             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();
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 9cf342c..ace0a7d 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 @@
                 makeRelativeToEpochStart(currentOps, nowMillis);
                 currentOps.accept(visitor);
 
-                if(isPersistenceInitializedMLocked()) {
+                if (!isPersistenceInitializedMLocked()) {
                     Slog.e(LOG_TAG, "Interaction before persistence initialized");
                     return;
                 }
@@ -457,7 +457,7 @@
                 // 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 @@
                 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 @@
             }
             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/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 3eea194..27050fa 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/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e7a8b13..fb94907 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.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 @@
         // 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/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index f6c49ed..e7f537b 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.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 @@
 
         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 cc319bf..731d899 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 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 @@
 
     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 2d472de6..7f0a271 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.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 @@
 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 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/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index f1f6d50..f38f2f9 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.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.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 @@
     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 @@
             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 @@
         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 @@
                 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 @@
         }
         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 @@
     }
 
     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 @@
      * - 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 @@
 
     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 @@
         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 @@
      * 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 @@
     @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 @@
      */
     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 @@
                 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 @@
             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 @@
             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 @@
             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 @@
         } 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 @@
         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 @@
             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 @@
     }
 
     /** 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 @@
 
     @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 @@
 
     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 @@
     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 @@
 
     @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 @@
                 | 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 @@
      */
     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 @@
         // 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 @@
             // 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 @@
     }
 
     @Override
-    public boolean checkVoldPassword(int userId) throws RemoteException {
+    public boolean checkVoldPassword(int userId) {
         if (!mFirstCallToVold) {
             return false;
         }
@@ -2030,6 +2042,9 @@
         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 @@
         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 @@
 
     @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 @@
         }
     }
 
-    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 @@
         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 @@
      * 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 @@
     @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 @@
         } 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 @@
                 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 @@
     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 @@
     @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 @@
 
             // 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 @@
             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 @@
     @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 @@
 
         // 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 @@
      * 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 @@
         }
     }
 
-    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 @@
     }
 
     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 @@
 
     @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 @@
         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 @@
         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 @@
         @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 @@
                 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 29b8aa2..fe12a94 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 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 @@
                 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 @@
                 }
                 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 @@
                 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 @@
         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 4ef63c0..17aca15 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 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 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 388e51f..ea0fb47 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 @@
 
 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.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 @@
         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 @@
         } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException
                 | IllegalBlockSizeException | BadPaddingException | IOException
                 | InvalidParameterSpecException e) {
-            e.printStackTrace();
+            Slog.e(TAG, "Failed to encrypt", e);
             return null;
         }
     }
@@ -116,7 +118,7 @@
         } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException
                 | IllegalBlockSizeException | BadPaddingException
                 | InvalidAlgorithmParameterException e) {
-            e.printStackTrace();
+            Slog.e(TAG, "Failed to decrypt", e);
             return null;
         }
     }
@@ -130,8 +132,8 @@
             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 @@
                 | 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 @@
                 | 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 @@
             keyStore.deleteEntry(keyAlias);
         } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
                 | IOException e) {
-            e.printStackTrace();
+            Slog.e(TAG, "Failed to destroy blob", e);
         }
     }
 
@@ -202,7 +204,7 @@
             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 @@
             }
             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 1ba0e8c..955a9aa 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 @@
      * 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 @@
      * 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 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 @@
      * 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 @@
             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 @@
                 return i;
             }
         }
-        throw new RuntimeException("Run out of weaver slots.");
+        throw new IllegalStateException("Run out of weaver slots.");
     }
 
     /**
@@ -622,11 +634,12 @@
      *
      * @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 @@
             // 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 @@
         } 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 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 @@
         }
         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 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 @@
             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 @@
         // 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 @@
      * 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 @@
         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 @@
      * 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 @@
     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/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6fe924e..aa548f2 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.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;
@@ -4830,7 +4830,7 @@
                 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) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index ce95181..8171a8d 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -752,7 +752,7 @@
         @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 +772,13 @@
                     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 7b13720..4431d86 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -28,13 +28,11 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.permission.IPermissionManager;
-import android.provider.DeviceConfig;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.R;
-import com.android.server.FgThread;
 
 import java.io.PrintWriter;
 import java.util.Collections;
@@ -135,19 +133,7 @@
         }
         IPermissionManager permissionmgr =
                 (IPermissionManager) ServiceManager.getService("permissionmgr");
-        return new AppsFilter(() -> {
-            if (featureEnabled.get() < 0) {
-                featureEnabled.set(DeviceConfig.getBoolean(
-                        DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
-                        "package_query_filtering_enabled", false) ? 1 : 0);
-                DeviceConfig.addOnPropertiesChangedListener(
-                        DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
-                        FgThread.getExecutor(),
-                        pr -> featureEnabled.set(
-                                pr.getBoolean("package_query_filtering_enabled", false) ? 1 : 0));
-            }
-            return featureEnabled.get() == 1;
-        }, permissionmgr,
+        return new AppsFilter(() -> false, permissionmgr,
                 context.getSystemService(AppOpsManager.class), forcedQueryablePackageNames,
                 forceSystemAppsQueryable);
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index af20346..4f0e4c8 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.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;
@@ -816,7 +816,7 @@
         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;
@@ -832,7 +832,7 @@
                 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,
@@ -912,7 +912,7 @@
             return mActivityTaskManagerProducer.get(this, mPackageManager);
         }
 
-        public DeviceIdleController.LocalService getLocalDeviceIdleController() {
+        public DeviceIdleInternal getLocalDeviceIdleController() {
             return mLocalDeviceIdleController.get(this, mPackageManager);
         }
 
@@ -1249,7 +1249,7 @@
             final BroadcastOptions options = BroadcastOptions.makeBasic();
             options.setTemporaryAppWhitelistDuration(whitelistTimeout);
 
-            DeviceIdleController.LocalService idleController =
+            DeviceIdleInternal idleController =
                     mInjector.getLocalDeviceIdleController();
             idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
                     mIntentFilterVerifierComponent.getPackageName(), whitelistTimeout,
@@ -2425,7 +2425,7 @@
                                 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),
@@ -14511,7 +14511,7 @@
                     final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
                             receivers, verificationState);
 
-                    DeviceIdleController.LocalService idleController =
+                    DeviceIdleInternal idleController =
                             mInjector.getLocalDeviceIdleController();
                     final long idleDuration = getVerificationTimeout();
 
@@ -14580,17 +14580,6 @@
                             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 +14588,6 @@
                             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)),
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 6d3424c..dd1eb83 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.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 @@
         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 @@
                     "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 @@
         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 @@
             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 ead9d7a..1fe5512 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2252,14 +2252,10 @@
 
     @GuardedBy({"mPackagesLock", "mRestrictionsLock"})
     private void fallbackToSingleUserLP() {
-        int flags = UserInfo.FLAG_SYSTEM | 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_FULL;
+            flags |= UserInfo.FLAG_PRIMARY | UserInfo.FLAG_FULL;
         }
         // Create the system user
         UserInfo system = new UserInfo(UserHandle.USER_SYSTEM, null, null, flags);
@@ -2773,9 +2769,9 @@
                         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) {
diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
index f5f7d67..cae09ea3 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 @@
     }
 
     /**
-     * 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 @@
                         + packageRollbackInfo.getPackageName() + ", userId: " + user, ie);
             }
         }
+        packageRollbackInfo.getSnapshottedUsers().addAll(IntArray.wrap(userIds));
     }
 
     /**
@@ -96,14 +98,14 @@
 
         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 @@
                 // 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 @@
                         + packageRollbackInfo.getPackageName(), ie);
         }
 
-        return changedRollbackData;
+        return changedRollback;
     }
 
     /**
@@ -158,29 +160,29 @@
      * 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 @@
      * 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 @@
         }
 
         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 @@
         }
 
         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 @@
             }
         }
 
-        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
similarity index 85%
rename from services/core/java/com/android/server/rollback/RollbackData.java
rename to services/core/java/com/android/server/rollback/Rollback.java
index b37e268..0d5746b 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 @@
  * 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 @@
     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 @@
     }
 
     /**
-     * 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 @@
 
     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 @@
     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 f0cf9cf..02f98b4 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 @@
     @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 @@
     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 @@
 
         // 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 @@
                             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;
@@ -303,9 +301,9 @@
         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);
                 }
             }
             return new ParceledListSlice<>(rollbacks);
@@ -319,9 +317,9 @@
         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 +349,11 @@
                 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 +377,8 @@
             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 +402,14 @@
                     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 +424,7 @@
                 params.setRequestDowngrade(true);
                 params.setRequiredInstalledVersionCode(
                         info.getVersionRolledBackFrom().getLongVersionCode());
-                if (data.isStaged()) {
+                if (rollback.isStaged()) {
                     params.setStaged();
                 }
                 if (info.isApex()) {
@@ -435,7 +433,7 @@
                 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 +474,8 @@
                                     // 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 +485,17 @@
                             }
 
                             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 +510,8 @@
             );
 
             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 +533,7 @@
             updateRollbackLifetimeDurationInMillis();
             synchronized (mLock) {
                 mRollbacks.clear();
-                mRollbacks.addAll(mRollbackStore.loadAllRollbackData());
+                mRollbacks.addAll(mRollbackStore.loadRollbacks());
             }
             latch.countDown();
         });
@@ -553,13 +551,13 @@
                 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;
                     }
                 }
@@ -583,16 +581,16 @@
 
     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 +613,19 @@
         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 +634,32 @@
                 }
             }
 
-            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 +686,19 @@
         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 +754,18 @@
         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 +820,12 @@
      *
      * @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 +870,15 @@
 
         // 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 +894,7 @@
         }
         newRollback.addToken(token);
 
-        return enableRollbackForPackageSession(newRollback.data, packageSession, installedUsers);
+        return enableRollbackForPackageSession(newRollback.rollback, packageSession);
     }
 
     /**
@@ -929,8 +904,8 @@
      *
      * @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 +963,14 @@
         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 +979,7 @@
         }
 
         synchronized (mLock) {
-            data.info.getPackages().add(packageRollbackInfo);
+            rollback.info.getPackages().add(packageRollbackInfo);
         }
         return true;
     }
@@ -1019,7 +993,7 @@
         }
 
         getHandler().post(() -> {
-            snapshotUserDataInternal(packageName);
+            snapshotUserDataInternal(packageName, userIds);
             restoreUserDataInternal(packageName, userIds, appId, ceDataInode, seInfo, token);
             final PackageManagerInternal pmi = LocalServices.getService(
                     PackageManagerInternal.class);
@@ -1027,19 +1001,20 @@
         });
     }
 
-    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 +1022,11 @@
             // 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 +1035,31 @@
     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 +1089,7 @@
             }
 
             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 +1103,7 @@
                         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 +1128,20 @@
             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 +1251,7 @@
             }
 
             if (newRollback != null) {
-                RollbackData rollback = completeEnableRollback(newRollback, success);
+                Rollback rollback = completeEnableRollback(newRollback, success);
                 if (rollback != null && !rollback.isStaged()) {
                     makeRollbackAvailable(rollback);
                 }
@@ -1291,32 +1264,32 @@
      * 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 +1297,25 @@
             // 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 +1323,8 @@
         // 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 +1332,14 @@
     }
 
     /*
-     * 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 +1349,11 @@
 
     /**
      * 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 +1377,30 @@
         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 +1408,14 @@
     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 +1425,7 @@
                             + " -> " + 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 +1451,7 @@
     }
 
     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 +1469,9 @@
         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 +1481,8 @@
          */
         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 +1497,13 @@
 
     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 +1513,7 @@
             packageSessionIds = new int[]{parentSessionId};
         }
 
-        return new NewRollback(data, packageSessionIds);
+        return new NewRollback(rollback, packageSessionIds);
     }
 
     /**
@@ -1552,10 +1524,10 @@
     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 1c36dc7..b2448f6 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 @@
     }
 
     /**
-     * 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 @@
     }
 
     /**
-     * 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 @@
      * 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 @@
      * 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 @@
      * 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);
+            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(data.backupDir, "rollback.json"));
+            PrintWriter pw = new PrintWriter(new File(rollback.backupDir, "rollback.json"));
             pw.println(dataJson.toString());
             pw.close();
         } catch (JSONException e) {
@@ -270,23 +270,23 @@
     }
 
     /**
-     * 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 @@
 
         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 @@
 
         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 2f681a3..3c06d0e 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.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 @@
         }
 
         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/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e14514b..d87a0ed 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 @@
             // 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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3d2a3f6..ed900b1 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -40,7 +40,9 @@
 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;
@@ -1283,6 +1285,14 @@
                 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");
             try {
                 NetworkStackClient.getInstance().init();
@@ -1345,40 +1355,6 @@
             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);
@@ -2177,12 +2153,21 @@
                 // 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) {
diff --git a/services/net/java/android/net/ConnectivityModuleConnector.java b/services/net/java/android/net/ConnectivityModuleConnector.java
new file mode 100644
index 0000000..7333f58
--- /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 56b728c..abb4666 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 @@
     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 @@
 
     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 @@
     }
 
     /**
-     * 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 @@
         });
     }
 
-    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 @@
      * 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 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/BackupManagerServiceTest.java
index c92737b..ca3c6ce 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -21,8 +21,6 @@
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.Manifest.permission.PACKAGE_USAGE_STATS;
 
-import static com.android.server.backup.testing.TransportData.backupTransport;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
@@ -41,10 +39,7 @@
 import android.app.backup.IBackupManagerMonitor;
 import android.app.backup.IBackupObserver;
 import android.app.backup.IFullBackupRestoreObserver;
-import android.app.backup.ISelectBackupTransportCallback;
 import android.content.Context;
-import android.content.Intent;
-import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.UserHandle;
@@ -52,7 +47,6 @@
 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;
@@ -222,475 +216,6 @@
     }
 
     // ---------------------------------------------
-    // Backup agent tests
-    // ---------------------------------------------
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
-    public void testDataChanged_onRegisteredUser_callsMethodForUser() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
-        backupManagerService.dataChanged(mUserOneId, TEST_PACKAGE);
-
-        verify(mUserOneService).dataChanged(TEST_PACKAGE);
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testDataChanged_onUnknownUser_doesNotPropagateCall() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
-        backupManagerService.dataChanged(mUserTwoId, TEST_PACKAGE);
-
-        verify(mUserOneService, never()).dataChanged(TEST_PACKAGE);
-    }
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
-    public void testAgentConnected_onRegisteredUser_callsMethodForUser() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-        IBinder agentBinder = mock(IBinder.class);
-
-        backupManagerService.agentConnected(mUserOneId, TEST_PACKAGE, agentBinder);
-
-        verify(mUserOneService).agentConnected(TEST_PACKAGE, agentBinder);
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testAgentConnected_onUnknownUser_doesNotPropagateCall() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-        IBinder agentBinder = mock(IBinder.class);
-
-        backupManagerService.agentConnected(mUserTwoId, TEST_PACKAGE, agentBinder);
-
-        verify(mUserOneService, never()).agentConnected(TEST_PACKAGE, agentBinder);
-    }
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
-    public void testAgentDisconnected_onRegisteredUser_callsMethodForUser() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        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 {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        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 {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
-        backupManagerService.opComplete(mUserOneId, /* token */ 0, /* result */ 0L);
-
-        verify(mUserOneService).opComplete(/* token */ 0, /* result */ 0L);
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testOpComplete_onUnknownUser_doesNotPropagateCall() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
-        backupManagerService.opComplete(mUserTwoId, /* token */ 0, /* result */ 0L);
-
-        verify(mUserOneService, never()).opComplete(/* token */ 0, /* result */ 0L);
-    }
-
-    // ---------------------------------------------
-    // Transport tests
-    // ---------------------------------------------
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
-    public void testInitializeTransports_onRegisteredUser_callsMethodForUser() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-        String[] transports = {TEST_TRANSPORT};
-
-        backupManagerService.initializeTransports(mUserOneId, transports, /* observer */ null);
-
-        verify(mUserOneService).initializeTransports(transports, /* observer */ null);
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testInitializeTransports_onUnknownUser_doesNotPropagateCall() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-        String[] transports = {TEST_TRANSPORT};
-
-        backupManagerService.initializeTransports(mUserTwoId, transports, /* observer */ null);
-
-        verify(mUserOneService, never()).initializeTransports(transports, /* observer */ null);
-    }
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
-    public void testClearBackupData_onRegisteredUser_callsMethodForUser() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
-        backupManagerService.clearBackupData(mUserOneId, TEST_TRANSPORT, TEST_PACKAGE);
-
-        verify(mUserOneService).clearBackupData(TEST_TRANSPORT, TEST_PACKAGE);
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testClearBackupData_onUnknownUser_doesNotPropagateCall() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
-        backupManagerService.clearBackupData(mUserTwoId, TEST_TRANSPORT, TEST_PACKAGE);
-
-        verify(mUserOneService, never()).clearBackupData(TEST_TRANSPORT, TEST_PACKAGE);
-    }
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
-    public void testGetCurrentTransport_onRegisteredUser_callsMethodForUser() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
-        backupManagerService.getCurrentTransport(mUserOneId);
-
-        verify(mUserOneService).getCurrentTransport();
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testGetCurrentTransport_onUnknownUser_doesNotPropagateCall() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
-        backupManagerService.getCurrentTransport(mUserTwoId);
-
-        verify(mUserOneService, never()).getCurrentTransport();
-    }
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
-    public void testGetCurrentTransportComponent_onRegisteredUser_callsMethodForUser()
-            throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
-        backupManagerService.getCurrentTransportComponent(mUserOneId);
-
-        verify(mUserOneService).getCurrentTransportComponent();
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testGetCurrentTransportComponent_onUnknownUser_doesNotPropagateCall()
-            throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
-        backupManagerService.getCurrentTransportComponent(mUserTwoId);
-
-        verify(mUserOneService, never()).getCurrentTransportComponent();
-    }
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
-    public void testListAllTransports_onRegisteredUser_callsMethodForUser() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
-        backupManagerService.listAllTransports(mUserOneId);
-
-        verify(mUserOneService).listAllTransports();
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testListAllTransports_onUnknownUser_doesNotPropagateCall() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
-        backupManagerService.listAllTransports(mUserTwoId);
-
-        verify(mUserOneService, never()).listAllTransports();
-    }
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
-    public void testListAllTransportComponents_onRegisteredUser_callsMethodForUser()
-            throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
-        backupManagerService.listAllTransportComponents(mUserOneId);
-
-        verify(mUserOneService).listAllTransportComponents();
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testListAllTransportComponents_onUnknownUser_doesNotPropagateCall()
-            throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
-        backupManagerService.listAllTransportComponents(mUserTwoId);
-
-        verify(mUserOneService, never()).listAllTransportComponents();
-    }
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
-    public void testUpdateTransportAttributes_onRegisteredUser_callsMethodForUser()
-            throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        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 {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        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 {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
-        backupManagerService.selectBackupTransport(mUserOneId, TEST_TRANSPORT);
-
-        verify(mUserOneService).selectBackupTransport(TEST_TRANSPORT);
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testSelectBackupTransport_onUnknownUser_doesNotPropagateCall() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
-        backupManagerService.selectBackupTransport(mUserTwoId, TEST_TRANSPORT);
-
-        verify(mUserOneService, never()).selectBackupTransport(TEST_TRANSPORT);
-    }
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
-    public void testSelectTransportAsync_onRegisteredUser_callsMethodForUser() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-        TransportData transport = backupTransport();
-        ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
-
-        backupManagerService.selectBackupTransportAsync(
-                mUserOneId, transport.getTransportComponent(), callback);
-
-        verify(mUserOneService)
-                .selectBackupTransportAsync(transport.getTransportComponent(), callback);
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testSelectBackupTransportAsync_onUnknownUser_doesNotPropagateCall()
-            throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-        TransportData transport = backupTransport();
-        ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
-
-        backupManagerService.selectBackupTransportAsync(
-                mUserTwoId, transport.getTransportComponent(), callback);
-
-        verify(mUserOneService, never())
-                .selectBackupTransportAsync(transport.getTransportComponent(), callback);
-    }
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
-    public void testGetConfigurationIntent_onRegisteredUser_callsMethodForUser() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
-        backupManagerService.getConfigurationIntent(mUserOneId, TEST_TRANSPORT);
-
-        verify(mUserOneService).getConfigurationIntent(TEST_TRANSPORT);
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testGetConfigurationIntent_onUnknownUser_doesNotPropagateCall() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
-        backupManagerService.getConfigurationIntent(mUserTwoId, TEST_TRANSPORT);
-
-        verify(mUserOneService, never()).getConfigurationIntent(TEST_TRANSPORT);
-    }
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
-    public void testGetDestinationString_onRegisteredUser_callsMethodForUser() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
-        backupManagerService.getDestinationString(mUserOneId, TEST_TRANSPORT);
-
-        verify(mUserOneService).getDestinationString(TEST_TRANSPORT);
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testGetDestinationString_onUnknownUser_doesNotPropagateCall() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
-        backupManagerService.getDestinationString(mUserTwoId, TEST_TRANSPORT);
-
-        verify(mUserOneService, never()).getDestinationString(TEST_TRANSPORT);
-    }
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
-    public void testGetDataManagementIntent_onRegisteredUser_callsMethodForUser() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
-        backupManagerService.getDataManagementIntent(mUserOneId, TEST_TRANSPORT);
-
-        verify(mUserOneService).getDataManagementIntent(TEST_TRANSPORT);
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testGetDataManagementIntent_onUnknownUser_doesNotPropagateCall() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
-        backupManagerService.getDataManagementIntent(mUserTwoId, TEST_TRANSPORT);
-
-        verify(mUserOneService, never()).getDataManagementIntent(TEST_TRANSPORT);
-    }
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
-    public void testGetDataManagementLabel_onRegisteredUser_callsMethodForUser() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
-        backupManagerService.getDataManagementLabel(mUserOneId, TEST_TRANSPORT);
-
-        verify(mUserOneService).getDataManagementLabel(TEST_TRANSPORT);
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testGetDataManagementLabel_onUnknownUser_doesNotPropagateCall() throws Exception {
-        registerUser(mUserOneId, mUserOneService);
-        BackupManagerService backupManagerService = createService();
-        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
-
-        backupManagerService.getDataManagementLabel(mUserTwoId, TEST_TRANSPORT);
-
-        verify(mUserOneService, never()).getDataManagementLabel(TEST_TRANSPORT);
-    }
-
-    // ---------------------------------------------
     // Settings tests
     // ---------------------------------------------
     /**
diff --git a/services/robotests/backup/src/com/android/server/backup/TrampolineRoboTest.java b/services/robotests/backup/src/com/android/server/backup/TrampolineRoboTest.java
index dfad1a9..d1fb10a 100644
--- a/services/robotests/backup/src/com/android/server/backup/TrampolineRoboTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/TrampolineRoboTest.java
@@ -19,21 +19,28 @@
 import static android.Manifest.permission.BACKUP;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 
+import static com.android.server.backup.testing.TransportData.backupTransport;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.robolectric.Shadows.shadowOf;
 
 import android.annotation.UserIdInt;
 import android.app.Application;
+import android.app.backup.ISelectBackupTransportCallback;
 import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
 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;
@@ -63,6 +70,9 @@
         })
 @Presubmit
 public class TrampolineRoboTest {
+    private static final String TEST_PACKAGE = "package";
+    private static final String TEST_TRANSPORT = "transport";
+
     private Context mContext;
     private ShadowContextWrapper mShadowContext;
     private ShadowUserManager mShadowUserManager;
@@ -161,10 +171,461 @@
         assertThat(serviceUsers.size()).isEqualTo(0);
     }
 
+    // ---------------------------------------------
+    // Backup agent tests
+    // ---------------------------------------------
+
+    /** Test that the backup service routes methods correctly to the user that requests it. */
+    @Test
+    public void testDataChanged_onRegisteredUser_callsMethodForUser() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+        backupManagerService.dataChanged(mUserOneId, TEST_PACKAGE);
+
+        verify(mUserOneService).dataChanged(TEST_PACKAGE);
+    }
+
+    /** Test that the backup service does not route methods for non-registered users. */
+    @Test
+    public void testDataChanged_onUnknownUser_doesNotPropagateCall() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+        backupManagerService.dataChanged(mUserTwoId, TEST_PACKAGE);
+
+        verify(mUserOneService, never()).dataChanged(TEST_PACKAGE);
+    }
+
+    /** Test that the backup service routes methods correctly to the user that requests it. */
+    @Test
+    public void testAgentConnected_onRegisteredUser_callsMethodForUser() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+        IBinder agentBinder = mock(IBinder.class);
+
+        backupManagerService.agentConnected(mUserOneId, TEST_PACKAGE, agentBinder);
+
+        verify(mUserOneService).agentConnected(TEST_PACKAGE, agentBinder);
+    }
+
+    /** Test that the backup service does not route methods for non-registered users. */
+    @Test
+    public void testAgentConnected_onUnknownUser_doesNotPropagateCall() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+        IBinder agentBinder = mock(IBinder.class);
+
+        backupManagerService.agentConnected(mUserTwoId, TEST_PACKAGE, agentBinder);
+
+        verify(mUserOneService, never()).agentConnected(TEST_PACKAGE, agentBinder);
+    }
+
+    /** Test that the backup service routes methods correctly to the user that requests it. */
+    @Test
+    public void testOpComplete_onRegisteredUser_callsMethodForUser() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+        backupManagerService.opComplete(mUserOneId, /* token */ 0, /* result */ 0L);
+
+        verify(mUserOneService).opComplete(/* token */ 0, /* result */ 0L);
+    }
+
+    /** Test that the backup service does not route methods for non-registered users. */
+    @Test
+    public void testOpComplete_onUnknownUser_doesNotPropagateCall() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+        backupManagerService.opComplete(mUserTwoId, /* token */ 0, /* result */ 0L);
+
+        verify(mUserOneService, never()).opComplete(/* token */ 0, /* result */ 0L);
+    }
+
+    // ---------------------------------------------
+    // Transport tests
+    // ---------------------------------------------
+
+    /** Test that the backup service routes methods correctly to the user that requests it. */
+    @Test
+    public void testInitializeTransports_onRegisteredUser_callsMethodForUser() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+        String[] transports = {TEST_TRANSPORT};
+
+        backupManagerService.initializeTransports(mUserOneId, transports, /* observer */ null);
+
+        verify(mUserOneService).initializeTransports(transports, /* observer */ null);
+    }
+
+    /** Test that the backup service does not route methods for non-registered users. */
+    @Test
+    public void testInitializeTransports_onUnknownUser_doesNotPropagateCall() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+        String[] transports = {TEST_TRANSPORT};
+
+        backupManagerService.initializeTransports(mUserTwoId, transports, /* observer */ null);
+
+        verify(mUserOneService, never()).initializeTransports(transports, /* observer */ null);
+    }
+
+    /** Test that the backup service routes methods correctly to the user that requests it. */
+    @Test
+    public void testClearBackupData_onRegisteredUser_callsMethodForUser() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+        backupManagerService.clearBackupData(mUserOneId, TEST_TRANSPORT, TEST_PACKAGE);
+
+        verify(mUserOneService).clearBackupData(TEST_TRANSPORT, TEST_PACKAGE);
+    }
+
+    /** Test that the backup service does not route methods for non-registered users. */
+    @Test
+    public void testClearBackupData_onUnknownUser_doesNotPropagateCall() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+        backupManagerService.clearBackupData(mUserTwoId, TEST_TRANSPORT, TEST_PACKAGE);
+
+        verify(mUserOneService, never()).clearBackupData(TEST_TRANSPORT, TEST_PACKAGE);
+    }
+
+    /** Test that the backup service routes methods correctly to the user that requests it. */
+    @Test
+    public void testGetCurrentTransport_onRegisteredUser_callsMethodForUser() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+        backupManagerService.getCurrentTransport(mUserOneId);
+
+        verify(mUserOneService).getCurrentTransport();
+    }
+
+    /** Test that the backup service does not route methods for non-registered users. */
+    @Test
+    public void testGetCurrentTransport_onUnknownUser_doesNotPropagateCall() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+        backupManagerService.getCurrentTransport(mUserTwoId);
+
+        verify(mUserOneService, never()).getCurrentTransport();
+    }
+
+    /** Test that the backup service routes methods correctly to the user that requests it. */
+    @Test
+    public void testGetCurrentTransportComponent_onRegisteredUser_callsMethodForUser()
+            throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+        backupManagerService.getCurrentTransportComponent(mUserOneId);
+
+        verify(mUserOneService).getCurrentTransportComponent();
+    }
+
+    /** Test that the backup service does not route methods for non-registered users. */
+    @Test
+    public void testGetCurrentTransportComponent_onUnknownUser_doesNotPropagateCall()
+            throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+        backupManagerService.getCurrentTransportComponent(mUserTwoId);
+
+        verify(mUserOneService, never()).getCurrentTransportComponent();
+    }
+
+    /** Test that the backup service routes methods correctly to the user that requests it. */
+    @Test
+    public void testListAllTransports_onRegisteredUser_callsMethodForUser() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+        backupManagerService.listAllTransports(mUserOneId);
+
+        verify(mUserOneService).listAllTransports();
+    }
+
+    /** Test that the backup service does not route methods for non-registered users. */
+    @Test
+    public void testListAllTransports_onUnknownUser_doesNotPropagateCall() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+        backupManagerService.listAllTransports(mUserTwoId);
+
+        verify(mUserOneService, never()).listAllTransports();
+    }
+
+    /** Test that the backup service routes methods correctly to the user that requests it. */
+    @Test
+    public void testListAllTransportComponents_onRegisteredUser_callsMethodForUser()
+            throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+        backupManagerService.listAllTransportComponents(mUserOneId);
+
+        verify(mUserOneService).listAllTransportComponents();
+    }
+
+    /** Test that the backup service does not route methods for non-registered users. */
+    @Test
+    public void testListAllTransportComponents_onUnknownUser_doesNotPropagateCall()
+            throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+        backupManagerService.listAllTransportComponents(mUserTwoId);
+
+        verify(mUserOneService, never()).listAllTransportComponents();
+    }
+
+    /** Test that the backup service routes methods correctly to the user that requests it. */
+    @Test
+    public void testSelectBackupTransport_onRegisteredUser_callsMethodForUser() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+        backupManagerService.selectBackupTransport(mUserOneId, TEST_TRANSPORT);
+
+        verify(mUserOneService).selectBackupTransport(TEST_TRANSPORT);
+    }
+
+    /** Test that the backup service does not route methods for non-registered users. */
+    @Test
+    public void testSelectBackupTransport_onUnknownUser_doesNotPropagateCall() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+        backupManagerService.selectBackupTransport(mUserTwoId, TEST_TRANSPORT);
+
+        verify(mUserOneService, never()).selectBackupTransport(TEST_TRANSPORT);
+    }
+
+    /** Test that the backup service routes methods correctly to the user that requests it. */
+    @Test
+    public void testSelectTransportAsync_onRegisteredUser_callsMethodForUser() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+        TransportData transport = backupTransport();
+        ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
+
+        backupManagerService.selectBackupTransportAsync(
+                mUserOneId, transport.getTransportComponent(), callback);
+
+        verify(mUserOneService)
+                .selectBackupTransportAsync(transport.getTransportComponent(), callback);
+    }
+
+    /** Test that the backup service does not route methods for non-registered users. */
+    @Test
+    public void testSelectBackupTransportAsync_onUnknownUser_doesNotPropagateCall()
+            throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+        TransportData transport = backupTransport();
+        ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
+
+        backupManagerService.selectBackupTransportAsync(
+                mUserTwoId, transport.getTransportComponent(), callback);
+
+        verify(mUserOneService, never())
+                .selectBackupTransportAsync(transport.getTransportComponent(), callback);
+    }
+
+    /** Test that the backup service routes methods correctly to the user that requests it. */
+    @Test
+    public void testGetConfigurationIntent_onRegisteredUser_callsMethodForUser() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+        backupManagerService.getConfigurationIntent(mUserOneId, TEST_TRANSPORT);
+
+        verify(mUserOneService).getConfigurationIntent(TEST_TRANSPORT);
+    }
+
+    /** Test that the backup service does not route methods for non-registered users. */
+    @Test
+    public void testGetConfigurationIntent_onUnknownUser_doesNotPropagateCall() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+        backupManagerService.getConfigurationIntent(mUserTwoId, TEST_TRANSPORT);
+
+        verify(mUserOneService, never()).getConfigurationIntent(TEST_TRANSPORT);
+    }
+
+    /** Test that the backup service routes methods correctly to the user that requests it. */
+    @Test
+    public void testGetDestinationString_onRegisteredUser_callsMethodForUser() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+        backupManagerService.getDestinationString(mUserOneId, TEST_TRANSPORT);
+
+        verify(mUserOneService).getDestinationString(TEST_TRANSPORT);
+    }
+
+    /** Test that the backup service does not route methods for non-registered users. */
+    @Test
+    public void testGetDestinationString_onUnknownUser_doesNotPropagateCall() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+        backupManagerService.getDestinationString(mUserTwoId, TEST_TRANSPORT);
+
+        verify(mUserOneService, never()).getDestinationString(TEST_TRANSPORT);
+    }
+
+    /** Test that the backup service routes methods correctly to the user that requests it. */
+    @Test
+    public void testGetDataManagementIntent_onRegisteredUser_callsMethodForUser() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+        backupManagerService.getDataManagementIntent(mUserOneId, TEST_TRANSPORT);
+
+        verify(mUserOneService).getDataManagementIntent(TEST_TRANSPORT);
+    }
+
+    /** Test that the backup service does not route methods for non-registered users. */
+    @Test
+    public void testGetDataManagementIntent_onUnknownUser_doesNotPropagateCall() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+        backupManagerService.getDataManagementIntent(mUserTwoId, TEST_TRANSPORT);
+
+        verify(mUserOneService, never()).getDataManagementIntent(TEST_TRANSPORT);
+    }
+
+    /** Test that the backup service routes methods correctly to the user that requests it. */
+    @Test
+    public void testGetDataManagementLabel_onRegisteredUser_callsMethodForUser() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+        backupManagerService.getDataManagementLabel(mUserOneId, TEST_TRANSPORT);
+
+        verify(mUserOneService).getDataManagementLabel(TEST_TRANSPORT);
+    }
+
+    /** Test that the backup service does not route methods for non-registered users. */
+    @Test
+    public void testGetDataManagementLabel_onUnknownUser_doesNotPropagateCall() throws Exception {
+        Trampoline backupManagerService = createService();
+        registerUser(backupManagerService, mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+        backupManagerService.getDataManagementLabel(mUserTwoId, TEST_TRANSPORT);
+
+        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 {
+        Trampoline 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 {
+        Trampoline 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");
+    }
+
     private Trampoline createService() {
         return new Trampoline(mContext);
     }
 
+    private void registerUser(
+            Trampoline trampoline, int userId, UserBackupManagerService userBackupManagerService) {
+        trampoline.setBackupServiceActive(userId, true);
+        trampoline.startServiceForUser(userId, userBackupManagerService);
+    }
+
     private Trampoline createServiceAndRegisterUser(
             int userId, UserBackupManagerService userBackupManagerService) {
         Trampoline backupManagerService = createService();
@@ -172,4 +633,19 @@
         backupManagerService.startServiceForUser(userId, userBackupManagerService);
         return backupManagerService;
     }
+
+    /**
+     * Sets the calling user to {@code userId} and grants the permission INTERACT_ACROSS_USERS_FULL
+     * to the caller if {@code shouldGrantPermission} is {@code true}, else it denies the
+     * permission.
+     */
+    private void setCallerAndGrantInteractUserPermission(
+            @UserIdInt int userId, boolean shouldGrantPermission) {
+        ShadowBinder.setCallingUserHandle(UserHandle.of(userId));
+        if (shouldGrantPermission) {
+            mShadowContext.grantPermissions(INTERACT_ACROSS_USERS_FULL);
+        } else {
+            mShadowContext.denyPermissions(INTERACT_ACROSS_USERS_FULL);
+        }
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 1e29ed6..6e8b86a 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 @@
         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 6feac52..108b017 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 @@
 
         @Override
         ConstraintController getConstraintController(
-                Handler handler, DeviceIdleController.LocalService localService) {
+                Handler handler, DeviceIdleInternal localService) {
             return constraintController;
         }
 
@@ -291,7 +291,7 @@
         // 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 f74ac1f..a9d1c2d 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 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 @@
     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 22cd3d3..71f7d2c 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.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 @@
         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/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
index 1f93513..e95c578 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
@@ -16,18 +16,18 @@
 
 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.anyInt;
 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.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
@@ -42,7 +42,6 @@
 import android.app.job.JobScheduler;
 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;
@@ -139,7 +138,6 @@
         mUserServices = new SparseArray<>();
         mUserServices.append(UserHandle.USER_SYSTEM, mUserBackupManagerService);
         mUserServices.append(NON_USER_SYSTEM, mUserBackupManagerService);
-        when(mBackupManagerServiceMock.getUserServices()).thenReturn(mUserServices);
 
         when(mUserManagerMock.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(mUserInfoMock);
         when(mUserManagerMock.getUserInfo(NON_USER_SYSTEM)).thenReturn(mUserInfoMock);
@@ -484,73 +482,6 @@
     }
 
     @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);
@@ -709,92 +640,9 @@
     }
 
     @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<>());
+        mUserServices.clear();
         CompletableFuture<Integer> future = new CompletableFuture<>();
         ISelectBackupTransportCallback listener =
                 new ISelectBackupTransportCallback.Stub() {
@@ -841,111 +689,6 @@
     }
 
     @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);
@@ -1043,17 +786,21 @@
     public void testGetUserForAncestralSerialNumber() {
         TrampolineTestable.sBackupDisabled = false;
         Trampoline trampoline = new TrampolineTestable(mContextMock, mUserServices);
+        when(mUserBackupManagerService.getAncestralSerialNumber()).thenReturn(11L);
 
-        trampoline.getUserForAncestralSerialNumber(0L);
-        verify(mBackupManagerServiceMock).getUserForAncestralSerialNumber(anyInt());
+        UserHandle user = trampoline.getUserForAncestralSerialNumber(11L);
+
+        assertThat(user).isEqualTo(UserHandle.of(1));
     }
 
     public void testGetUserForAncestralSerialNumber_whenDisabled() {
         TrampolineTestable.sBackupDisabled = true;
         Trampoline trampoline = new TrampolineTestable(mContextMock, mUserServices);
+        when(mUserBackupManagerService.getAncestralSerialNumber()).thenReturn(11L);
 
-        trampoline.getUserForAncestralSerialNumber(0L);
-        verify(mBackupManagerServiceMock, never()).getUserForAncestralSerialNumber(anyInt());
+        UserHandle user = trampoline.getUserForAncestralSerialNumber(11L);
+
+        assertThat(user).isNull();
     }
 
     private static class TrampolineTestable extends Trampoline {
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 09ae3a2..ba12b73 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 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 @@
     };
 
     private void registerLocalServices() {
-        addLocalServiceMock(DeviceIdleController.LocalService.class);
+        addLocalServiceMock(DeviceIdleInternal.class);
 
         final UsageStatsManagerInternal usageStats =
                 addLocalServiceMock(UsageStatsManagerInternal.class);
@@ -442,7 +442,7 @@
         // 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/rollback/AppDataRollbackHelperTest.java b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
index 7986055..8cb5197 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 @@
         // 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 @@
         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 @@
         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 @@
         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 @@
 
         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/wifi/Android.bp b/services/wifi/Android.bp
new file mode 100644
index 0000000..3c916a6
--- /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 0000000..eadc726
--- /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 0000000..fa66e4c
--- /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/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java
index 5d8d793..89d30c0d 100644
--- a/telephony/java/android/telephony/data/DataServiceCallback.java
+++ b/telephony/java/android/telephony/data/DataServiceCallback.java
@@ -42,6 +42,8 @@
 
     private static final String TAG = DataServiceCallback.class.getSimpleName();
 
+    private static final boolean DBG = true;
+
     /**
      * Result of data requests
      * @hide
@@ -81,6 +83,7 @@
         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 @@
         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 @@
         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/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index c61ad42..f10398f 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -194,7 +194,7 @@
      * @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="
@@ -429,9 +429,6 @@
             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);
                 }
             }
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 232b5cb..c42201f 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.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 @@
     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 @@
         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 @@
         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/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index bbf71e7..99a686b 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1084,7 +1084,8 @@
 
       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 324807c..56bff8f 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 @@
 
   // Flattening options.
   TableFlattenerOptions table_flattener_options;
+  SerializeTableOptions proto_table_flattener_options;
   bool keep_raw_values = false;
 
   // Split APK options.
@@ -245,9 +247,9 @@
             "<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 @@
     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 aa6547e..e4b3fce 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -290,8 +290,10 @@
     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 @@
     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 @@
         // 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 33ffd18..7a3ea99 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.h
+++ b/tools/aapt2/format/proto/ProtoSerialize.h
@@ -35,6 +35,11 @@
   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 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/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 20d772c..ca65736 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -50,6 +50,7 @@
 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 @@
      * {@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 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 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 @@
         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 @@
             return new HashMap<>();
         }
         try {
-            return mService.getMatchingOsuProviders(scanResults);
+            return getIWifiManager().getMatchingOsuProviders(scanResults);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1320,7 +1343,7 @@
     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 @@
      */
     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 @@
         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 @@
         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 @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 @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 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 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 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 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 int matchProviderWithCurrentNetwork(String fqdn) {
         try {
-            return mService.matchProviderWithCurrentNetwork(fqdn);
+            return getIWifiManager().matchProviderWithCurrentNetwork(fqdn);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1854,7 +1880,7 @@
      */
     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 @@
     @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 @@
 
         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 @@
     @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 @@
     @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 @@
     @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 @@
     @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 @@
 
     private long getSupportedFeatures() {
         try {
-            return mService.getSupportedFeatures();
+            return getIWifiManager().getSupportedFeatures();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2261,10 +2288,9 @@
      * @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 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 WifiInfo getConnectionInfo() {
         try {
-            return mService.getConnectionInfo(mContext.getOpPackageName());
+            return getIWifiManager().getConnectionInfo(mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2347,7 +2373,7 @@
      */
     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 @@
     @Deprecated
     public boolean isScanAlwaysAvailable() {
         try {
-            return mService.isScanAlwaysAvailable();
+            return getIWifiManager().isScanAlwaysAvailable();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2397,7 +2423,7 @@
      */
     public void setCountryCode(@NonNull String country) {
         try {
-            mService.setCountryCode(country);
+            getIWifiManager().setCountryCode(country);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2411,12 +2437,12 @@
     */
     @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 @@
     @UnsupportedAppUsage
     public boolean isDualBandSupported() {
         try {
-            return mService.isDualBandSupported();
+            return getIWifiManager().isDualBandSupported();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2440,7 +2466,7 @@
      */
     public boolean isDualModeSupported() {
         try {
-            return mService.needs5GHzToAnyApBandConversion();
+            return getIWifiManager().needs5GHzToAnyApBandConversion();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2453,7 +2479,7 @@
      */
     public DhcpInfo getDhcpInfo() {
         try {
-            return mService.getDhcpInfo();
+            return getIWifiManager().getDhcpInfo();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2480,7 +2506,7 @@
     @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 int getWifiState() {
         try {
-            return mService.getWifiEnabledState();
+            return getIWifiManager().getWifiEnabledState();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2569,7 +2595,7 @@
      */
     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 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 boolean stopSoftAp() {
         try {
-            return mService.stopSoftAp();
+            return getIWifiManager().stopSoftAp();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2671,7 +2697,7 @@
                     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 @@
             }
             mLOHSCallbackProxy = null;
             try {
-                mService.stopLocalOnlyHotspot();
+                getIWifiManager().stopLocalOnlyHotspot();
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -2753,7 +2779,7 @@
             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 @@
             }
             mLOHSObserverProxy = null;
             try {
-                mService.stopWatchLocalOnlyHotspot();
+                getIWifiManager().stopWatchLocalOnlyHotspot();
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -2797,7 +2823,7 @@
     @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 @@
     @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 @@
     @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 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 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 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 @@
         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 @@
         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 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 @@
     @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 @@
             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 @@
             synchronized (mBinder) {
                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
                     try {
-                        mService.releaseWifiLock(mBinder);
+                        getIWifiManager().releaseWifiLock(mBinder);
                         synchronized (WifiManager.this) {
                             mActiveLockCount--;
                         }
@@ -3980,7 +4007,7 @@
                 }
                 if (changed && mHeld) {
                     try {
-                        mService.updateWifiLockWorkSource(mBinder, mWorkSource);
+                        getIWifiManager().updateWifiLockWorkSource(mBinder, mWorkSource);
                     } catch (RemoteException e) {
                         throw e.rethrowFromSystemServer();
                     }
@@ -4008,7 +4035,7 @@
             synchronized (mBinder) {
                 if (mHeld) {
                     try {
-                        mService.releaseWifiLock(mBinder);
+                        getIWifiManager().releaseWifiLock(mBinder);
                         synchronized (WifiManager.this) {
                             mActiveLockCount--;
                         }
@@ -4121,10 +4148,10 @@
             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 @@
             synchronized (mBinder) {
                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
                     try {
-                        mService.releaseMulticastLock(mTag);
+                        getIWifiManager().releaseMulticastLock(mTag);
                         synchronized (WifiManager.this) {
                             mActiveLockCount--;
                         }
@@ -4243,7 +4270,7 @@
      */
     public boolean isMulticastEnabled() {
         try {
-            return mService.isMulticastEnabled();
+            return getIWifiManager().isMulticastEnabled();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -4256,7 +4283,7 @@
     @UnsupportedAppUsage
     public boolean initializeMulticastFiltering() {
         try {
-            mService.initializeMulticastFiltering();
+            getIWifiManager().initializeMulticastFiltering();
             return true;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -4281,7 +4308,7 @@
     @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 @@
     @UnsupportedAppUsage
     public int getVerboseLoggingLevel() {
         try {
-            return mService.getVerboseLoggingLevel();
+            return getIWifiManager().getVerboseLoggingLevel();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -4309,7 +4336,7 @@
      */
     public void factoryReset() {
         try {
-            mService.factoryReset(mContext.getOpPackageName());
+            getIWifiManager().factoryReset(mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -4323,7 +4350,7 @@
     @UnsupportedAppUsage
     public Network getCurrentNetwork() {
         try {
-            return mService.getCurrentNetwork();
+            return getIWifiManager().getCurrentNetwork();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -4355,7 +4382,7 @@
      */
     public void enableWifiConnectivityManager(boolean enabled) {
         try {
-            mService.enableWifiConnectivityManager(enabled);
+            getIWifiManager().enableWifiConnectivityManager(enabled);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -4367,7 +4394,7 @@
      */
     public byte[] retrieveBackupData() {
         try {
-            return mService.retrieveBackupData();
+            return getIWifiManager().retrieveBackupData();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -4379,7 +4406,7 @@
      */
     public void restoreBackupData(byte[] data) {
         try {
-            mService.restoreBackupData(data);
+            getIWifiManager().restoreBackupData(data);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -4395,7 +4422,7 @@
     @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 @@
             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 @@
         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 @@
         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 @@
     @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 @@
     @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 @@
             @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 @@
             @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 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 @@
             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 @@
             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 @@
     @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();
         }