summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--METADATA3
-rw-r--r--StubLibraries.bp77
-rw-r--r--apct-tests/perftests/OWNERS11
-rw-r--r--apct-tests/perftests/core/src/android/os/OWNERS1
-rw-r--r--apex/Android.bp4
-rw-r--r--apex/OWNERS13
-rw-r--r--apex/permission/Android.bp43
-rw-r--r--apex/permission/OWNERS6
-rw-r--r--apex/permission/TEST_MAPPING7
-rw-r--r--apex/permission/apex_manifest.json4
-rw-r--r--apex/permission/com.android.permission.avbpubkeybin1032 -> 0 bytes
-rw-r--r--apex/permission/com.android.permission.pem51
-rw-r--r--apex/permission/com.android.permission.pk8bin2376 -> 0 bytes
-rw-r--r--apex/permission/com.android.permission.x509.pem35
-rw-r--r--apex/permission/framework/Android.bp45
-rw-r--r--apex/permission/framework/api/current.txt1
-rw-r--r--apex/permission/framework/api/module-lib-current.txt1
-rw-r--r--apex/permission/framework/api/module-lib-removed.txt1
-rw-r--r--apex/permission/framework/api/system-current.txt1
-rw-r--r--apex/permission/framework/api/system-removed.txt1
-rw-r--r--apex/permission/service/Android.bp44
-rw-r--r--apex/permission/service/api/current.txt1
-rw-r--r--apex/permission/service/api/system-server-current.txt46
-rw-r--r--apex/permission/service/api/system-server-removed.txt1
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java74
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java265
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java222
-rw-r--r--apex/permission/service/java/com/android/role/persistence/RolesPersistence.java73
-rw-r--r--apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java218
-rw-r--r--apex/permission/service/java/com/android/role/persistence/RolesState.java115
-rw-r--r--apex/permission/testing/test_manifest.json4
-rw-r--r--apex/permission/tests/Android.bp37
-rw-r--r--apex/permission/tests/AndroidManifest.xml32
-rw-r--r--apex/permission/tests/java/com/android/permission/persistence/RuntimePermissionsPersistenceTest.kt110
-rw-r--r--apex/permission/tests/java/com/android/role/persistence/RolesPersistenceTest.kt101
-rw-r--r--api/Android.bp30
-rw-r--r--boot/Android.bp18
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java5
-rw-r--r--cmds/app_process/Android.bp9
-rw-r--r--cmds/sm/src/com/android/commands/sm/Sm.java18
-rw-r--r--config/OWNERS6
-rw-r--r--config/hiddenapi-max-target-r-loprio.txt (renamed from config/hiddenapi-temp-blocklist.txt)0
-rw-r--r--core/api/current.txt302
-rw-r--r--core/api/module-lib-current.txt41
-rw-r--r--core/api/system-current.txt853
-rw-r--r--core/api/test-current.txt26
-rw-r--r--core/java/android/accessibilityservice/OWNERS2
-rw-r--r--core/java/android/annotation/RequiresFeature.java13
-rw-r--r--core/java/android/app/ContextImpl.java39
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl2
-rw-r--r--core/java/android/app/OWNERS20
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java59
-rw-r--r--core/java/android/app/search/OWNERS2
-rw-r--r--core/java/android/apphibernation/AppHibernationManager.java79
-rw-r--r--core/java/android/apphibernation/IAppHibernationService.aidl26
-rw-r--r--core/java/android/appwidget/OWNERS3
-rw-r--r--core/java/android/bluetooth/BluetoothA2dp.java114
-rw-r--r--core/java/android/bluetooth/BufferConstraint.java105
-rw-r--r--core/java/android/bluetooth/BufferConstraints.java96
-rw-r--r--core/java/android/content/Context.java43
-rw-r--r--core/java/android/content/ContextWrapper.java29
-rw-r--r--core/java/android/content/integrity/OWNERS5
-rw-r--r--core/java/android/content/om/IOverlayManager.aidl15
-rw-r--r--core/java/android/content/om/OverlayManager.java23
-rw-r--r--core/java/android/content/om/OverlayManagerTransaction.aidl19
-rw-r--r--core/java/android/content/om/OverlayManagerTransaction.java216
-rw-r--r--core/java/android/content/pm/OWNERS1
-rw-r--r--core/java/android/content/pm/PackageManager.java32
-rw-r--r--core/java/android/graphics/fonts/OWNERS1
-rw-r--r--core/java/android/net/ConnectivityManager.java243
-rw-r--r--core/java/android/net/IConnectivityManager.aidl14
-rw-r--r--core/java/android/net/INetworkPolicyManager.aidl1
-rw-r--r--core/java/android/net/INetworkStatsService.aidl4
-rw-r--r--core/java/android/net/IQosCallback.aidl (renamed from apex/permission/service/java/com/android/permission/persistence/IoUtils.java)28
-rw-r--r--core/java/android/net/IpSecManager.java95
-rw-r--r--core/java/android/net/MatchAllNetworkSpecifier.java11
-rw-r--r--core/java/android/net/NattSocketKeepalive.java2
-rw-r--r--core/java/android/net/Network.java19
-rw-r--r--core/java/android/net/NetworkAgent.java126
-rw-r--r--core/java/android/net/NetworkAgentConfig.java4
-rw-r--r--core/java/android/net/NetworkCapabilities.java70
-rw-r--r--core/java/android/net/NetworkIdentity.java16
-rw-r--r--core/java/android/net/NetworkPolicyManager.java16
-rw-r--r--core/java/android/net/NetworkReleasedException.java32
-rw-r--r--core/java/android/net/NetworkRequest.java4
-rw-r--r--core/java/android/net/NetworkUtils.java8
-rw-r--r--core/java/android/net/ProxyInfo.java2
-rw-r--r--core/java/android/net/QosCallback.java91
-rw-r--r--core/java/android/net/QosCallbackConnection.java128
-rw-r--r--core/java/android/net/QosCallbackException.java110
-rw-r--r--core/java/android/net/QosFilter.java75
-rw-r--r--core/java/android/net/QosFilterParcelable.aidl21
-rw-r--r--core/java/android/net/QosFilterParcelable.java113
-rw-r--r--core/java/android/net/QosSession.aidl21
-rw-r--r--core/java/android/net/QosSession.java136
-rw-r--r--core/java/android/net/QosSessionAttributes.java30
-rw-r--r--core/java/android/net/QosSocketFilter.java166
-rw-r--r--core/java/android/net/QosSocketInfo.aidl21
-rw-r--r--core/java/android/net/QosSocketInfo.java154
-rw-r--r--core/java/android/net/SocketLocalAddressChangedException.java32
-rw-r--r--core/java/android/net/SocketNotBoundException.java32
-rw-r--r--core/java/android/net/TcpSocketKeepalive.java4
-rw-r--r--core/java/android/net/TestNetworkInterface.java16
-rw-r--r--core/java/android/net/TestNetworkManager.java35
-rw-r--r--core/java/android/net/TransportInfo.java38
-rw-r--r--core/java/android/net/UnderlyingNetworkInfo.aidl (renamed from core/java/com/android/internal/net/VpnInfo.aidl)4
-rw-r--r--core/java/android/net/UnderlyingNetworkInfo.java110
-rw-r--r--core/java/android/net/metrics/ApfProgramEvent.java4
-rw-r--r--core/java/android/net/metrics/ApfStats.java4
-rw-r--r--core/java/android/net/metrics/DhcpClientEvent.java4
-rw-r--r--core/java/android/net/metrics/DhcpErrorEvent.java4
-rw-r--r--core/java/android/net/metrics/IpConnectivityLog.java6
-rw-r--r--core/java/android/net/metrics/IpManagerEvent.java4
-rw-r--r--core/java/android/net/metrics/IpReachabilityEvent.java4
-rw-r--r--core/java/android/net/metrics/NetworkEvent.java4
-rw-r--r--core/java/android/net/metrics/RaEvent.java4
-rw-r--r--core/java/android/net/metrics/ValidationProbeEvent.java4
-rw-r--r--core/java/android/net/util/MultinetworkPolicyTracker.java11
-rw-r--r--core/java/android/net/vcn/IVcnManagementService.aidl8
-rw-r--r--core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl22
-rw-r--r--core/java/android/net/vcn/VcnConfig.java18
-rw-r--r--core/java/android/net/vcn/VcnGatewayConnectionConfig.java144
-rw-r--r--core/java/android/net/vcn/VcnManager.java143
-rw-r--r--core/java/android/net/vcn/VcnTransportInfo.java125
-rw-r--r--core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl (renamed from apex/permission/framework/java/android/permission/PermissionState.java)8
-rw-r--r--core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java110
-rw-r--r--core/java/android/nfc/INfcAdapter.aidl3
-rw-r--r--core/java/android/nfc/NfcAdapter.java126
-rw-r--r--core/java/android/nfc/tech/Ndef.java2
-rw-r--r--core/java/android/os/BugreportManager.java190
-rwxr-xr-xcore/java/android/os/Build.java10
-rw-r--r--core/java/android/os/UserManager.java28
-rw-r--r--core/java/android/os/storage/DiskInfo.java6
-rw-r--r--core/java/android/os/storage/IStorageManager.aidl1
-rw-r--r--core/java/android/os/storage/OWNERS7
-rwxr-xr-xcore/java/android/provider/Settings.java14
-rw-r--r--core/java/android/se/OWNERS5
-rw-r--r--core/java/android/se/omapi/OWNERS5
-rw-r--r--core/java/android/se/omapi/SEService.java25
-rw-r--r--core/java/android/security/keymaster/KeymasterDefs.java1
-rw-r--r--core/java/android/service/resumeonreboot/IResumeOnRebootService.aidl25
-rw-r--r--core/java/android/service/resumeonreboot/ResumeOnRebootService.java164
-rw-r--r--core/java/android/service/search/OWNERS2
-rw-r--r--core/java/android/service/textservice/OWNERS4
-rw-r--r--core/java/android/telephony/PhoneStateListener.java1421
-rw-r--r--core/java/android/telephony/TelephonyRegistryManager.java380
-rw-r--r--core/java/android/text/format/Formatter.java5
-rw-r--r--core/java/android/util/FeatureFlagUtils.java2
-rw-r--r--core/java/android/util/OWNERS3
-rw-r--r--core/java/android/uwb/AngleMeasurement.java2
-rw-r--r--core/java/android/uwb/AngleOfArrivalMeasurement.java20
-rw-r--r--core/java/android/uwb/DistanceMeasurement.java2
-rw-r--r--core/java/android/uwb/RangingMeasurement.java2
-rw-r--r--core/java/android/uwb/RangingReport.java2
-rw-r--r--core/java/android/uwb/RangingSession.java2
-rw-r--r--core/java/android/uwb/UwbAddress.java2
-rw-r--r--core/java/android/uwb/UwbManager.java2
-rw-r--r--core/java/android/view/accessibility/OWNERS1
-rw-r--r--core/java/android/view/textclassifier/OWNERS2
-rw-r--r--core/java/android/view/textservice/OWNERS4
-rw-r--r--core/java/android/widget/AbsSeekBar.java21
-rw-r--r--core/java/com/android/internal/app/IBatteryStats.aidl2
-rw-r--r--core/java/com/android/internal/app/OWNERS2
-rw-r--r--core/java/com/android/internal/compat/IPlatformCompat.aidl158
-rw-r--r--core/java/com/android/internal/graphics/fonts/OWNERS1
-rw-r--r--core/java/com/android/internal/net/VpnConfig.java2
-rw-r--r--core/java/com/android/internal/net/VpnInfo.java71
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHelper.java9
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java11
-rw-r--r--core/java/com/android/internal/os/WrapperInit.java5
-rw-r--r--core/java/com/android/internal/telephony/IPhoneStateListener.aidl3
-rw-r--r--core/java/com/android/internal/telephony/ITelephonyRegistry.aidl15
-rw-r--r--core/java/com/android/internal/textservice/OWNERS3
-rw-r--r--core/java/com/android/internal/util/LocationPermissionChecker.java41
-rw-r--r--core/java/com/android/internal/widget/OWNERS6
-rw-r--r--core/jni/android_media_AudioErrors.h2
-rw-r--r--core/jni/android_media_AudioTrack.cpp54
-rw-r--r--core/jni/android_net_NetUtils.cpp27
-rw-r--r--core/jni/android_os_HwBlob.cpp12
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp12
-rw-r--r--core/res/AndroidManifest.xml19
-rw-r--r--core/res/OWNERS2
-rw-r--r--core/res/res/values/attrs.xml5
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/public.xml1
-rw-r--r--core/res/res/values/strings.xml2
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/sysprop/WatchdogProperties.sysprop9
-rw-r--r--core/sysprop/api/com.android.sysprop.watchdog-latest.txt4
-rw-r--r--core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java137
-rw-r--r--core/tests/coretests/src/android/app/OWNERS5
-rw-r--r--core/tests/coretests/src/android/app/people/OWNERS1
-rw-r--r--core/tests/coretests/src/android/content/OWNERS3
-rw-r--r--core/tests/coretests/src/android/content/integrity/OWNERS1
-rw-r--r--core/tests/coretests/src/android/content/pm/OWNERS5
-rw-r--r--core/tests/coretests/src/android/content/res/OWNERS1
-rw-r--r--core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java16
-rw-r--r--core/tests/coretests/src/android/text/format/FormatterTest.java2
-rw-r--r--core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java4
-rw-r--r--core/tests/coretests/src/android/view/autofill/OWNERS3
-rw-r--r--core/tests/coretests/src/android/view/contentcapture/OWNERS3
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/OWNERS1
-rw-r--r--core/tests/coretests/src/android/view/textservice/OWNERS3
-rw-r--r--core/tests/coretests/src/android/widget/AbsSeekBarTest.java49
-rw-r--r--core/tests/mockingcoretests/src/android/view/OWNERS2
-rw-r--r--core/tests/overlaytests/device/Android.bp6
-rw-r--r--core/tests/overlaytests/device/AndroidManifest.xml2
-rw-r--r--core/tests/overlaytests/device/AndroidTest.xml13
-rw-r--r--core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java78
-rw-r--r--core/tests/overlaytests/device/src/com/android/overlaytest/TransactionTest.java133
-rw-r--r--core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java9
-rw-r--r--core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java11
-rw-r--r--core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java9
-rw-r--r--core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp2
-rw-r--r--core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp2
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java21
-rw-r--r--core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java8
-rw-r--r--core/tests/uwbtests/src/android/uwb/UwbTestUtils.java4
-rw-r--r--data/etc/OWNERS3
-rw-r--r--data/etc/privapp-permissions-platform.xml2
-rw-r--r--identity/java/android/security/identity/CredstoreIdentityCredential.java86
-rw-r--r--identity/java/android/security/identity/CredstoreIdentityCredentialStore.java1
-rw-r--r--identity/java/android/security/identity/CredstoreWritableIdentityCredential.java10
-rw-r--r--identity/java/android/security/identity/IdentityCredential.java155
-rw-r--r--identity/java/android/security/identity/IdentityCredentialStore.java14
-rw-r--r--keystore/java/android/security/AuthTokenUtils.java75
-rw-r--r--keystore/java/android/security/Authorization.java107
-rw-r--r--keystore/java/android/security/KeyStore.java1
-rw-r--r--keystore/java/android/security/KeyStore2.java39
-rw-r--r--keystore/java/android/security/KeyStoreOperation.java3
-rw-r--r--keystore/java/android/security/KeyStoreSecurityLevel.java11
-rw-r--r--keystore/java/android/security/keystore/BackendBusyException.java37
-rw-r--r--keystore/java/android/security/keystore/KeyProperties.java10
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java5
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java240
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java3
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java8
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreRSAPublicKey.java7
-rw-r--r--keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java4
-rw-r--r--libs/androidfw/LocaleDataTables.cpp195
-rw-r--r--libs/androidfw/ResourceTypes.cpp9
-rwxr-xr-xmedia/java/android/media/AudioManager.java23
-rw-r--r--media/java/android/media/AudioTrack.java10
-rwxr-xr-xmedia/java/android/media/IAudioService.aidl6
-rw-r--r--media/java/android/media/IMediaRouterService.aidl2
-rw-r--r--media/java/android/media/MediaRouter2Manager.java30
-rw-r--r--media/java/android/media/RouteDiscoveryPreference.java1
-rw-r--r--media/java/android/media/tv/ITvInputManager.aidl2
-rw-r--r--media/java/android/media/tv/ITvInputSession.aidl2
-rw-r--r--media/java/android/media/tv/ITvInputSessionWrapper.java20
-rw-r--r--media/java/android/media/tv/TvInputHardwareInfo.java14
-rw-r--r--media/java/android/media/tv/TvInputInfo.java40
-rw-r--r--media/java/android/media/tv/TvInputManager.java34
-rwxr-xr-xmedia/java/android/media/tv/TvInputService.java38
-rw-r--r--media/java/android/media/tv/TvRecordingClient.java135
-rw-r--r--media/java/android/media/tv/tuner/dvr/DvrRecorder.java25
-rw-r--r--media/jni/android_media_tv_Tuner.cpp6
-rw-r--r--packages/Connectivity/framework/Android.bp (renamed from apex/permission/testing/Android.bp)26
-rw-r--r--packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl49
-rw-r--r--packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl41
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java17
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java13
-rw-r--r--packages/SettingsLib/res/values/arrays.xml6
-rw-r--r--packages/Shell/AndroidManifest.xml8
-rw-r--r--packages/SystemUI/Android.bp2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java9
-rw-r--r--packages/services/CameraExtensionsProxy/OWNERS1
-rw-r--r--services/Android.bp21
-rw-r--r--services/OWNERS5
-rw-r--r--services/accessibility/OWNERS2
-rw-r--r--services/appwidget/java/com/android/server/appwidget/OWNERS1
-rw-r--r--services/core/Android.bp6
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java1270
-rw-r--r--services/core/java/com/android/server/DynamicSystemService.java24
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java6
-rw-r--r--services/core/java/com/android/server/OWNERS5
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java31
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java931
-rw-r--r--services/core/java/com/android/server/TestNetworkService.java1
-rw-r--r--services/core/java/com/android/server/VcnManagementService.java92
-rw-r--r--services/core/java/com/android/server/Watchdog.java4
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java23
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java59
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java41
-rw-r--r--services/core/java/com/android/server/apphibernation/AppHibernationService.java349
-rw-r--r--services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java109
-rwxr-xr-xservices/core/java/com/android/server/audio/AudioService.java206
-rw-r--r--services/core/java/com/android/server/compat/CompatChange.java68
-rw-r--r--services/core/java/com/android/server/compat/CompatConfig.java299
-rw-r--r--services/core/java/com/android/server/compat/PlatformCompat.java193
-rw-r--r--services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java2
-rw-r--r--services/core/java/com/android/server/connectivity/Nat464Xlat.java5
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java91
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkDiagnostics.java2
-rw-r--r--services/core/java/com/android/server/connectivity/PacProxyInstaller.java76
-rw-r--r--services/core/java/com/android/server/connectivity/ProxyTracker.java11
-rw-r--r--services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java192
-rw-r--r--services/core/java/com/android/server/connectivity/QosCallbackTracker.java277
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java26
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java1
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java9
-rw-r--r--services/core/java/com/android/server/location/contexthub/OWNERS1
-rw-r--r--services/core/java/com/android/server/location/timezone/OWNERS3
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java2
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsStorage.java23
-rw-r--r--services/core/java/com/android/server/locksettings/RebootEscrowManager.java35
-rw-r--r--services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java202
-rw-r--r--services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java249
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2Provider.java2
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java8
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java130
-rw-r--r--services/core/java/com/android/server/media/MediaRouterService.java12
-rw-r--r--services/core/java/com/android/server/net/LockdownVpnTracker.java10
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java35
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsFactory.java19
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java6
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java578
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerServiceImpl.java172
-rw-r--r--services/core/java/com/android/server/om/PackageAndUser.java57
-rw-r--r--services/core/java/com/android/server/os/BugreportManagerServiceImpl.java70
-rw-r--r--services/core/java/com/android/server/pm/ModuleInfoProvider.java2
-rw-r--r--services/core/java/com/android/server/recoverysystem/RecoverySystemService.java77
-rw-r--r--services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java2
-rw-r--r--services/core/java/com/android/server/security/OWNERS4
-rw-r--r--services/core/java/com/android/server/storage/StorageSessionController.java6
-rw-r--r--services/core/java/com/android/server/textservices/OWNERS3
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java7
-rw-r--r--services/core/java/com/android/server/tv/TvInputHal.java11
-rwxr-xr-xservices/core/java/com/android/server/tv/TvInputHardwareManager.java40
-rwxr-xr-xservices/core/java/com/android/server/tv/TvInputManagerService.java41
-rw-r--r--services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java6
-rw-r--r--services/core/java/com/android/server/vcn/VcnGatewayConnection.java524
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java5
-rw-r--r--services/core/jni/com_android_server_tv_TvInputHal.cpp18
-rw-r--r--services/core/xsd/Android.bp12
-rw-r--r--services/core/xsd/platform-compat-schema/removed.txt1
-rw-r--r--services/core/xsd/platform-compat/OWNERS (renamed from services/core/xsd/platform-compat-schema/OWNERS)0
-rw-r--r--services/core/xsd/platform-compat/config/platform-compat-config.xsd (renamed from services/core/xsd/platform-compat-config.xsd)0
-rw-r--r--services/core/xsd/platform-compat/config/schema/current.txt (renamed from services/core/xsd/platform-compat-schema/current.txt)0
-rw-r--r--services/core/xsd/platform-compat/config/schema/last_current.txt (renamed from services/core/xsd/platform-compat-schema/last_current.txt)0
-rw-r--r--services/core/xsd/platform-compat/config/schema/last_removed.txt (renamed from services/core/xsd/platform-compat-schema/last_removed.txt)0
-rw-r--r--services/core/xsd/platform-compat/config/schema/removed.txt (renamed from apex/permission/framework/api/removed.txt)0
-rw-r--r--services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd55
-rw-r--r--services/core/xsd/platform-compat/overrides/schema/current.txt51
-rw-r--r--services/core/xsd/platform-compat/overrides/schema/last_current.txt0
-rw-r--r--services/core/xsd/platform-compat/overrides/schema/last_removed.txt0
-rw-r--r--services/core/xsd/platform-compat/overrides/schema/removed.txt (renamed from apex/permission/service/api/removed.txt)0
-rw-r--r--services/java/com/android/server/SystemServer.java11
-rw-r--r--services/searchui/OWNERS2
-rw-r--r--services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java168
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java88
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java53
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/location/timezone/OWNERS3
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java102
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java145
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/ResumeOnRebootServiceProviderTests.java111
-rw-r--r--services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java76
-rw-r--r--services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java41
-rw-r--r--services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java20
-rw-r--r--services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/textservices/OWNERS3
-rw-r--r--services/tests/shortcutmanagerutils/OWNERS1
-rw-r--r--telecomm/java/android/telecom/Connection.java14
-rw-r--r--telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java238
-rw-r--r--telephony/java/android/telephony/AccessNetworkConstants.java623
-rw-r--r--telephony/java/android/telephony/AccessNetworkUtils.java425
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java46
-rw-r--r--telephony/java/android/telephony/DataFailCause.java5
-rw-r--r--telephony/java/android/telephony/ImsiEncryptionInfo.java4
-rw-r--r--telephony/java/android/telephony/PhoneCapability.java2
-rw-r--r--telephony/java/android/telephony/PhoneNumberUtils.java49
-rw-r--r--telephony/java/android/telephony/PhysicalChannelConfig.java433
-rw-r--r--telephony/java/android/telephony/PreciseDisconnectCause.java2
-rw-r--r--telephony/java/android/telephony/RadioInterfaceCapabilities.java53
-rw-r--r--telephony/java/android/telephony/ServiceState.java19
-rw-r--r--telephony/java/android/telephony/SignalStrengthUpdateRequest.aidl20
-rw-r--r--telephony/java/android/telephony/SignalStrengthUpdateRequest.java272
-rw-r--r--telephony/java/android/telephony/SignalThresholdInfo.java546
-rw-r--r--telephony/java/android/telephony/SmsManager.java61
-rw-r--r--telephony/java/android/telephony/TelephonyDisplayInfo.java4
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java290
-rw-r--r--telephony/java/android/telephony/data/DataCallResponse.java47
-rw-r--r--telephony/java/android/telephony/data/DataService.java19
-rw-r--r--telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.aidl19
-rw-r--r--telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java234
-rw-r--r--telephony/java/android/telephony/data/IDataService.aidl3
-rw-r--r--telephony/java/android/telephony/data/SliceInfo.aidl20
-rw-r--r--telephony/java/android/telephony/data/SliceInfo.java342
-rw-r--r--telephony/java/android/telephony/euicc/DownloadableSubscription.java52
-rw-r--r--telephony/java/android/telephony/ims/DelegateRegistrationState.java7
-rw-r--r--telephony/java/android/telephony/ims/ImsUtListener.java7
-rw-r--r--telephony/java/android/telephony/ims/RcsContactPresenceTuple.java144
-rw-r--r--telephony/java/android/telephony/ims/RcsContactUceCapability.java48
-rw-r--r--telephony/java/android/telephony/ims/RcsUceAdapter.java49
-rw-r--r--telephony/java/android/telephony/ims/RegistrationManager.java17
-rw-r--r--telephony/java/android/telephony/ims/SipMessage.java43
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl2
-rw-r--r--telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java15
-rw-r--r--telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java13
-rw-r--r--telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java24
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java38
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java31
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsUtImplBase.java27
-rw-r--r--telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java100
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl32
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java1
-rw-r--r--test-mock/api/current.txt1
-rw-r--r--test-mock/src/android/test/mock/MockContext.java5
-rw-r--r--tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt8
-rw-r--r--tests/StagedInstallTest/OWNERS4
-rw-r--r--tests/net/common/Android.bp1
-rw-r--r--tests/net/common/java/android/net/CaptivePortalDataTest.kt24
-rw-r--r--tests/net/common/java/android/net/NetworkCapabilitiesTest.java94
-rw-r--r--tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt50
-rw-r--r--tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt17
-rw-r--r--tests/net/integration/util/com/android/server/NetworkAgentWrapper.java73
-rw-r--r--tests/net/java/android/net/ConnectivityManagerTest.java61
-rw-r--r--tests/net/java/android/net/NetworkTemplateTest.kt1
-rw-r--r--tests/net/java/android/net/QosSocketFilterTest.java75
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java1290
-rw-r--r--tests/net/java/com/android/server/connectivity/LingerMonitorTest.java10
-rw-r--r--tests/net/java/com/android/server/connectivity/VpnTest.java10
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsBaseTest.java13
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java53
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsServiceTest.java129
-rw-r--r--tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java6
-rw-r--r--tests/vcn/Android.bp1
-rw-r--r--tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java20
-rw-r--r--tests/vcn/java/android/net/vcn/VcnManagerTest.java135
-rw-r--r--tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java71
-rw-r--r--tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java51
-rw-r--r--tests/vcn/java/com/android/server/VcnManagementServiceTest.java91
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java105
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java84
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java71
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java128
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnTestUtils.java44
-rw-r--r--tools/stringslint/stringslint.py12
-rwxr-xr-xtools/stringslint/stringslint_sha.sh2
446 files changed, 21273 insertions, 5355 deletions
diff --git a/Android.bp b/Android.bp
index 23168232b7a3..402cf1c245ab 100644
--- a/Android.bp
+++ b/Android.bp
@@ -483,6 +483,7 @@ java_library {
"android.hardware.vibrator-V1.2-java",
"android.hardware.vibrator-V1.3-java",
"android.security.apc-java",
+ "android.security.authorization-java",
"android.system.keystore2-java",
"android.system.suspend.control.internal-java",
"devicepolicyprotosnano",
diff --git a/METADATA b/METADATA
index d97975ca3b99..95577d8df535 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,4 @@
third_party {
- license_type: NOTICE
+ # would be NOTICE save for libs/usb/tests/accessorytest/f_accessory.h
+ license_type: RESTRICTED
}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index ed8781e2ff86..6afed7a78a08 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -113,13 +113,27 @@ droidstubs {
last_released: {
api_file: ":android-non-updatable.api.public.latest",
removed_api_file: ":android-non-updatable-removed.api.public.latest",
- baseline_file: ":public-api-incompatibilities-with-last-released",
+ baseline_file: ":android-incompatibilities.api.public.latest",
},
api_lint: {
enabled: true,
new_since: ":android-non-updatable.api.public.latest",
},
},
+ dists: [
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "android-non-updatable.txt",
+ tag: ".api.txt",
+ },
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "android-non-updatable-removed.txt",
+ tag: ".removed-api.txt",
+ },
+ ],
}
priv_apps =
@@ -151,7 +165,7 @@ droidstubs {
last_released: {
api_file: ":android-non-updatable.api.system.latest",
removed_api_file: ":android-non-updatable-removed.api.system.latest",
- baseline_file: ":system-api-incompatibilities-with-last-released"
+ baseline_file: ":android-incompatibilities.api.system.latest"
},
api_lint: {
enabled: true,
@@ -159,6 +173,20 @@ droidstubs {
baseline_file: "core/api/system-lint-baseline.txt",
},
},
+ dists: [
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/system/api",
+ dest: "android-non-updatable.txt",
+ tag: ".api.txt",
+ },
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/system/api",
+ dest: "android-non-updatable-removed.txt",
+ tag: ".removed-api.txt",
+ },
+ ],
}
droidstubs {
@@ -175,11 +203,32 @@ droidstubs {
baseline_file: "core/api/test-lint-baseline.txt",
},
},
- dist: {
- targets: ["sdk", "win_sdk"],
- dir: "apistubs/android/test/api",
- dest: "android.txt",
- },
+ dists: [
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android.txt",
+ tag: ".api.txt",
+ },
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "removed.txt",
+ tag: ".removed-api.txt",
+ },
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android-non-updatable.txt",
+ tag: ".api.txt",
+ },
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android-non-updatable-removed.txt",
+ tag: ".removed-api.txt",
+ },
+ ],
}
droidstubs {
@@ -200,6 +249,20 @@ droidstubs {
new_since: ":android-non-updatable.api.module-lib.latest",
},
},
+ dists: [
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/module-lib/api",
+ dest: "android-non-updatable.txt",
+ tag: ".api.txt",
+ },
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/module-lib/api",
+ dest: "android-non-updatable-removed.txt",
+ tag: ".removed-api.txt",
+ },
+ ],
}
/////////////////////////////////////////////////////////////////////
diff --git a/apct-tests/perftests/OWNERS b/apct-tests/perftests/OWNERS
index a060ad9a5a7e..7e7feafdc5a5 100644
--- a/apct-tests/perftests/OWNERS
+++ b/apct-tests/perftests/OWNERS
@@ -1,2 +1,11 @@
-timmurray@google.com
+balejs@google.com
+carmenjackson@google.com
+cfijalkovich@google.com
+dualli@google.com
+edgararriaga@google.com
+jpakaravoor@google.com
+kevinjeon@google.com
philipcuadra@google.com
+shombert@google.com
+timmurray@google.com
+wessam@google.com
diff --git a/apct-tests/perftests/core/src/android/os/OWNERS b/apct-tests/perftests/core/src/android/os/OWNERS
new file mode 100644
index 000000000000..a1719c9c31d1
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/os/OWNERS
@@ -0,0 +1 @@
+per-file PackageParsingPerfTest.kt = file:/services/core/java/com/android/server/pm/OWNERS \ No newline at end of file
diff --git a/apex/Android.bp b/apex/Android.bp
index 0a535a8fe9b9..c6edc8fb227c 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -96,6 +96,10 @@ java_defaults {
sdk_version: "module_current",
},
+ // installable implies we'll create a non-apex (platform) variant, which
+ // we shouldn't ordinarily need (and it can create issues), so disable that.
+ installable: false,
+
// Configure framework module specific metalava options.
droiddoc_options: [mainline_stubs_args],
diff --git a/apex/OWNERS b/apex/OWNERS
index 97600135a103..bde2bec0816b 100644
--- a/apex/OWNERS
+++ b/apex/OWNERS
@@ -1,7 +1,8 @@
-# Shared module build rule owners
-per-file *.bp=hansson@google.com
-per-file *.bp=jiyong@google.com
+# Mainline modularization team
-# This file, and all other OWNERS files
-per-file OWNERS=dariofreni@google.com
-per-file OWNERS=hansson@google.com
+andreionea@google.com
+dariofreni@google.com
+hansson@google.com
+mathewi@google.com
+pedroql@google.com
+satayev@google.com
diff --git a/apex/permission/Android.bp b/apex/permission/Android.bp
deleted file mode 100644
index e30df05b2340..000000000000
--- a/apex/permission/Android.bp
+++ /dev/null
@@ -1,43 +0,0 @@
-// 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.
-
-apex {
- name: "com.android.permission",
- defaults: ["com.android.permission-defaults"],
- manifest: "apex_manifest.json",
-}
-
-apex_defaults {
- name: "com.android.permission-defaults",
- updatable: true,
- min_sdk_version: "30",
- key: "com.android.permission.key",
- certificate: ":com.android.permission.certificate",
- java_libs: [
- "framework-permission",
- "service-permission",
- ],
- apps: ["PermissionController"],
-}
-
-apex_key {
- name: "com.android.permission.key",
- public_key: "com.android.permission.avbpubkey",
- private_key: "com.android.permission.pem",
-}
-
-android_app_certificate {
- name: "com.android.permission.certificate",
- certificate: "com.android.permission",
-}
diff --git a/apex/permission/OWNERS b/apex/permission/OWNERS
deleted file mode 100644
index 957e10a582a0..000000000000
--- a/apex/permission/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-svetoslavganov@google.com
-moltmann@google.com
-eugenesusla@google.com
-zhanghai@google.com
-evanseverson@google.com
-ntmyren@google.com
diff --git a/apex/permission/TEST_MAPPING b/apex/permission/TEST_MAPPING
deleted file mode 100644
index 6e67ce92a27e..000000000000
--- a/apex/permission/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "presubmit" : [
- {
- "name" : "PermissionApexTests"
- }
- ]
-}
diff --git a/apex/permission/apex_manifest.json b/apex/permission/apex_manifest.json
deleted file mode 100644
index 7960598affa3..000000000000
--- a/apex/permission/apex_manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "com.android.permission",
- "version": 300000000
-}
diff --git a/apex/permission/com.android.permission.avbpubkey b/apex/permission/com.android.permission.avbpubkey
deleted file mode 100644
index 9eaf85259637..000000000000
--- a/apex/permission/com.android.permission.avbpubkey
+++ /dev/null
Binary files differ
diff --git a/apex/permission/com.android.permission.pem b/apex/permission/com.android.permission.pem
deleted file mode 100644
index 3d584be5440d..000000000000
--- a/apex/permission/com.android.permission.pem
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIJKgIBAAKCAgEA6snt4eqoz85xiL9Sf6w1S1b9FgSHK05zYTh2JYPvQKQ3yeZp
-E6avJ6FN6XcbmkDzSd658BvUGDBSPhOlzuUO4BsoKBuLMxP6TxIQXFKidzDqY0vQ
-4qkS++bdIhUjwBP3OSZ3Czu0BiihK8GC75Abr//EyCyObGIGGfHEGANiOgrpP4X5
-+OmLzQLCjk4iE1kg+U6cRSRI/XLaoWC0TvIIuzxznrQ6r5GmzgTOwyBWyIB+bj73
-bmsweHTU+w9Y7kGOx4hO3XCLIhoBWEw0EbuW9nZmQ4sZls5Jo/CbyJlCclF11yVo
-SCf2LG/T+9pah5NOmDQ1kPbU+0iKZIV4YFHGTIhyGDE/aPOuUT05ziCGDifgHr0u
-SG1x/RLqsVh/POvNxnvP9cQFMQ08BvbEJaTTgB785iwKsvdqCfmng/SAyxSetmzP
-StXVB3fh1OoZ8vunRbQYxnmUxycVqaA96zmBx2wLvbvzKo7pZFDE6nbhnT5+MRAM
-z/VIK89W26uB4gj8sBFslqZjT0jPqsAZuvDm7swOtMwIcEolyGJuFLqlhN7UwMz2
-9y8+IpYixR+HvD1TZI9NtmuCmv3kPrWgoMZg6yvaBayTIr8RdYzi6FO/C1lLiraz
-48dH3sXWRa8cgw6VcSUwYrEBIc3sotdsupO1iOjcFybIwaee0YTZJfjvbqkCAwEA
-AQKCAgEArRnfdpaJi1xLPGTCMDsIt9kUku0XswgN7PmxsYsKFAB+2S40/jYAIRm9
-1YjpItsMA8RgFfSOdJ77o6TctCMQyo17F8bm4+uwuic5RLfv7Cx2QmsdQF8jDfFx
-y7UGPJD7znjbf76uxXOjEB2FqZX3s9TAgkzHXIUQtoQW7RVhkCWHPjxKxgd5+NY2
-FrDoUpd9xhD9CcTsw1+wbRZdGW88nL6/B50dP2AFORM2VYo8MWr6y9FEn3YLsGOC
-uu7fxBk1aUrHyl81VRkTMMROB1zkuiUk1FtzrEm+5U15rXXBFYOVe9+qeLhtuOlh
-wueDoz0pzvF/JLe24uTik6YL0Ae6SD0pFXQ2KDrdH3cUHLok3r76/yGzaDNTFjS2
-2WbQ8dEJV8veNHk8gjGpFTJIsBUlcZpmUCDHlfvVMb3+2ahQ+28piQUt5t3zqJdZ
-NDqsOHzY6BRPc+Wm85Xii/lWiQceZSee/b1Enu+nchsyXhSenBfC6bIGZReyMI0K
-KKKuVhyR6OSOiR5ZdZ/NyXGqsWy05fn/h0X9hnpETsNaNYNKWvpHLfKll+STJpf7
-AZquJPIclQyiq5NONx6kfPztoCLkKV/zOgIj3Sx5oSZq+5gpO91nXWVwkTbqK1d1
-004q2Mah6UQyAk1XGQc2pHx7ouVcWawjU30vZ4C015Hv2lm/gVkCggEBAPltATYS
-OqOSL1YAtIHPiHxMjNAgUdglq8JiJFXVfkocGU9eNub3Ed3sSWu6GB9Myu/sSKje
-bJ5DZqxJnvB2Fqmu9I9OunLGFSD0aXs4prwsQ1Rm5FcbImtrxcciASdkoo8Pj0z4
-vk2r2NZD3VtER5Uh+YjSDkxcS9gBStXUpCL6gj69UpOxMmWqZVjyHatVB4lEvYJl
-N82uT7N7QVNL1DzcZ9z4C4r7ks1Pm7ka12s5m/oaAlAMdVeofiPJe1xA9zRToSr4
-tIbMkOeXFLVRLuji/7XsOgal5Rl59p+OwLshX5cswPVOMrH6zt+hbsJ5q8M5dqnX
-VAOBK7KNQ/EKZwcCggEBAPD6KVvyCim46n5EbcEqCkO7gevwZkw/9vLwmM5YsxTh
-z9FQkPO0iB7mwbX8w04I91Pre4NdfcgMG0pP1b13Sb4KHBchqW1a+TCs3kSGC6gn
-1SxmXHnA9jRxAkrWlGkoAQEz+aP61cXiiy2tXpQwJ8xQCKprfoqWZwhkCtEVU6CE
-S7v9cscOHIqgNxx4WoceMmq4EoihHAZzHxTcNVbByckMjb2XQJ0iNw3lDP4ddvc+
-a4HzHfHkhzeQ5ZNc8SvWU8z80aSCOKRsSD3aUTZzxhZ4O2tZSW7v7p+FpvVee7bC
-g8YCfszTdpVUMlLRLjScimAcovcFLSvtyupinxWg4M8CggEAN9YGEmOsSte7zwXj
-YrfhtumwEBtcFwX/2Ej+F1Tuq4p0xAa0RaoDjumJWhtTsRYQy/raHSuFpzwxbNoi
-QXQ+CIhI6RfXtz/OlQ0B2/rHoJJMFEXgUfuaDfAXW0eqeHYXyezSyIlamKqipPyW
-Pgsf9yue39keKEv1EorfhNTQVaA8rezV4oglXwrxGyNALw2e3UTNI7ai8mFWKDis
-XAg6n9E7UwUYGGnO6DUtCBgRJ0jDOQ6/e8n+LrxiWIKPIgzNCiK6jpMUXqTGv4Fb
-umdNGAdQ9RnHt5tFmRlrczaSwJFtA7uaCpAR2zPpQbiywchZAiAIB2dTwGEXNiZX
-kksg2wKCAQEA6pNad3qhkgPDoK6T+Jkn7M82paoaqtcJWWwEE7oceZNnbWZz9Agl
-CY+vuawXonrv5+0vCq2Tp4zBdBFLC2h3jFrjBVFrUFxifpOIukOSTVqZFON/2bWQ
-9XOcu6UuSz7522Xw+UNPnZXtzcUacD6AP08ZYGvLfrTyDyTzspyED5k48ALEHCkM
-d5WGkFxII4etpF0TDZVnZo/iDbhe49k4yFFEGO6Ho26PESOLBkNAb2V/2bwDxlij
-l9+g21Z6HiZA5SamHPH2mXgeyrcen1cL2QupK9J6vVcqfnboE6qp2zp2c+Yx8MlY
-gfy4EA44YFaSDQVTTgrn8f9Eq+zc130H2QKCAQEAqOKgv68nIPdDSngNyCVyWego
-boFiDaEJoBBg8FrBjTJ6wFLrNAnXmbvfTtgNmNAzF1cUPJZlIIsHgGrMCfpehbXq
-WQQIw+E+yFbTGLxseGRfsLrV0CsgnAoOVeod+yIHmqc3livaUbrWhL1V2f6Ue+sE
-7YLp/iP43NaMfA4kYk2ep7+ZJoEVkCjHJJaHWgAG3RynPJHkTJlSgu7wLYvGc9uE
-ZsEFUM46lX02t7rrtMfasVGrUy1c2xOxFb4v1vG6iEZ7+YWeq5o3AkxUwEGn+mG4
-/3p+k4AaTXJDXgyZ0Sv6CkGuPHenAYG4cswcUUEf/G4Ag77x6LBNMgycJBxUJA==
------END RSA PRIVATE KEY-----
diff --git a/apex/permission/com.android.permission.pk8 b/apex/permission/com.android.permission.pk8
deleted file mode 100644
index d51673dbc2fc..000000000000
--- a/apex/permission/com.android.permission.pk8
+++ /dev/null
Binary files differ
diff --git a/apex/permission/com.android.permission.x509.pem b/apex/permission/com.android.permission.x509.pem
deleted file mode 100644
index 4b146c9edd4f..000000000000
--- a/apex/permission/com.android.permission.x509.pem
+++ /dev/null
@@ -1,35 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIGKzCCBBOgAwIBAgIUezo3fQeVZsmLpm/dkpGWJ/G/MN8wDQYJKoZIhvcNAQEL
-BQAwgaMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
-DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
-b2lkMR8wHQYDVQQDDBZjb20uYW5kcm9pZC5wZXJtaXNzaW9uMSIwIAYJKoZIhvcN
-AQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMCAXDTE5MTAwOTIxMzExOVoYDzQ3NTcw
-OTA0MjEzMTE5WjCBozELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx
-FjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB0FuZHJvaWQxEDAOBgNV
-BAsMB0FuZHJvaWQxHzAdBgNVBAMMFmNvbS5hbmRyb2lkLnBlcm1pc3Npb24xIjAg
-BgkqhkiG9w0BCQEWE2FuZHJvaWRAYW5kcm9pZC5jb20wggIiMA0GCSqGSIb3DQEB
-AQUAA4ICDwAwggIKAoICAQCxefguRJ7E6tBCTEOeU2HJEGs6AQQapLz9hMed0aaJ
-Qr7aTQiYJEk+sG4+jPYbjpxa8JDDzJHp+4g7DjfSb+dvT9n84A8lWaI/yRXTZTQN
-Hu5m/bgHhi0LbySpiaFyodXBKUAnOhZyGPtYjtBFywFylueub8ryc1Z6UxxU7udH
-1mkIr7sE48Qkq5SyjFROE96iFmYA+vS/JXOfS0NBHiMB4GBxx4V7kXpvrTI7hhZG
-HiyhKvNh7wyHIhO9nDEw1rwtAH6CsL3YkQEVBeAU98m+0Au+qStLYkKHh2l8zT4W
-7sVK1VSqfB+VqOUmeIGdzlBfqMsoXD+FJz6KnIdUHIwjFDjL7Xr+hd+7xve+Q3S+
-U3Blk/U6atY8PM09wNfilG+SvwcKk5IgriDcu3rWKgIFxbUUaxLrDW7pLlu6wt/d
-GGtKK+Bc0jF+9Z901Tl33i5xhc5yOktT0btkKs7lSeE6VzP/Nk5g0SuzixmuRoh9
-f5Ge41N2ZCEHNXx3wZeVZwHIIPfYrL7Yql1Xoxbfs4ETFk6ChzVQcvjfDQQuK58J
-uNc+TOCoI/qflXwGCwpuHl0ier8V5Z4tpMUl5rWyVR/QGRtLPvs2lLuxczDw1OXq
-wEVtCMn9aNnd4y7R9PZ52hi53HAvDjpWefrLYi+Q04J6iGFQ1qAFBClK9DquBvmR
-swIDAQABo1MwUTAdBgNVHQ4EFgQULpfus5s5SrqLkoUKyPXA0D1iHPMwHwYDVR0j
-BBgwFoAULpfus5s5SrqLkoUKyPXA0D1iHPMwDwYDVR0TAQH/BAUwAwEB/zANBgkq
-hkiG9w0BAQsFAAOCAgEAjxQG5EFv8V/9yV2glI53VOmlWMjfEgvUjd39s/XLyPlr
-OzPOKSB0NFo8To3l4l+MsManxPK8y0OyfEVKbWVz9onv0ovo5MVokBmV/2G0jmsV
-B4e9yjOq+DmqIvY/Qh63Ywb97sTgcFI8620MhQDbh2IpEGv4ZNV0H6rgXmgdSCBw
-1EjBoYfFpN5aMgZjeyzZcq+d1IapdWqdhuEJQkMvoYS4WIumNIJlEXPQRoq/F5Ih
-nszdbKI/jVyiGFa2oeZ3rja1Y6GCRU8TYEoKx1pjS8uQDOEDTwsG/QnUe9peEj0V
-SsCkIidJWTomAmq9Tub9vpBe1zuTpuRAwxwR0qwgSxozV1Mvow1dJ19oFtHX0yD6
-ZjCpRn5PW9kMvSWSlrcrFs1NJf0j1Cvf7bHpkEDqLqpMnnh9jaFQq3nzDY+MWcIR
-jDcgQpI+AiE2/qtauZnFEVhbce49nCnk9+5bpTTIZJdzqeaExe5KXHwEtZLaEDh4
-atLY9LuEvPsjmDIMOR6hycD9FvwGXhJOQBjESIWFwigtSb1Yud9n6201jw3MLJ4k
-+WhkbmZgWy+xc+Mdm5H3XyB1lvHaHGkxu+QB9KyQuVQKwbUVcbwZIfTFPN6Zr/dS
-ZXJqAbBhG/dBgF0LazuLaPVpibi+a3Y+tb9b8eXGkz4F97PWZIEDkELQ+9KOvhc=
------END CERTIFICATE-----
diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp
deleted file mode 100644
index c0560f61460f..000000000000
--- a/apex/permission/framework/Android.bp
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-filegroup {
- name: "framework-permission-sources",
- srcs: [
- "java/**/*.java",
- "java/**/*.aidl",
- ],
- path: "java",
-}
-
-java_sdk_library {
- name: "framework-permission",
- defaults: ["framework-module-defaults"],
-
- // Restrict access to implementation library.
- impl_library_visibility: ["//frameworks/base/apex/permission:__subpackages__"],
-
- srcs: [
- ":framework-permission-sources",
- ],
-
- apex_available: [
- "com.android.permission",
- "test_com.android.permission",
- ],
- permitted_packages: [
- "android.permission",
- "android.app.role",
- ],
- hostdex: true,
- installable: true,
-}
diff --git a/apex/permission/framework/api/current.txt b/apex/permission/framework/api/current.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/framework/api/current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework/api/module-lib-current.txt b/apex/permission/framework/api/module-lib-current.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/framework/api/module-lib-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework/api/module-lib-removed.txt b/apex/permission/framework/api/module-lib-removed.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/framework/api/module-lib-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework/api/system-current.txt b/apex/permission/framework/api/system-current.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/framework/api/system-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework/api/system-removed.txt b/apex/permission/framework/api/system-removed.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/framework/api/system-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/service/Android.bp b/apex/permission/service/Android.bp
deleted file mode 100644
index 6e04edfe02f1..000000000000
--- a/apex/permission/service/Android.bp
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-filegroup {
- name: "service-permission-sources",
- srcs: [
- "java/**/*.java",
- ],
- path: "java",
-}
-
-java_sdk_library {
- name: "service-permission",
- defaults: ["framework-system-server-module-defaults"],
- impl_library_visibility: [
- "//frameworks/base/apex/permission/tests",
- "//frameworks/base/services/tests/mockingservicestests",
- "//frameworks/base/services/tests/servicestests",
- ],
- srcs: [
- ":service-permission-sources",
- ],
- libs: [
- "framework-permission",
- ],
- apex_available: [
- "com.android.permission",
- "test_com.android.permission",
- ],
- installable: true,
- // We don't have last-api tracking files for the public part of this jar's API.
- unsafe_ignore_missing_latest_api: true,
-}
diff --git a/apex/permission/service/api/current.txt b/apex/permission/service/api/current.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/service/api/current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/service/api/system-server-current.txt b/apex/permission/service/api/system-server-current.txt
deleted file mode 100644
index c76cc3275737..000000000000
--- a/apex/permission/service/api/system-server-current.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-// Signature format: 2.0
-package com.android.permission.persistence {
-
- public interface RuntimePermissionsPersistence {
- method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance();
- method public void deleteForUser(@NonNull android.os.UserHandle);
- method @Nullable public com.android.permission.persistence.RuntimePermissionsState readForUser(@NonNull android.os.UserHandle);
- method public void writeForUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
- }
-
- public final class RuntimePermissionsState {
- ctor public RuntimePermissionsState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>);
- method @Nullable public String getFingerprint();
- method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getPackagePermissions();
- method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getSharedUserPermissions();
- method public int getVersion();
- field public static final int NO_VERSION = -1; // 0xffffffff
- }
-
- public static final class RuntimePermissionsState.PermissionState {
- ctor public RuntimePermissionsState.PermissionState(@NonNull String, boolean, int);
- method public int getFlags();
- method @NonNull public String getName();
- method public boolean isGranted();
- }
-
-}
-
-package com.android.role.persistence {
-
- public interface RolesPersistence {
- method @NonNull public static com.android.role.persistence.RolesPersistence createInstance();
- method public void deleteForUser(@NonNull android.os.UserHandle);
- method @Nullable public com.android.role.persistence.RolesState readForUser(@NonNull android.os.UserHandle);
- method public void writeForUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
- }
-
- public final class RolesState {
- ctor public RolesState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>>);
- method @Nullable public String getPackagesHash();
- method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getRoles();
- method public int getVersion();
- }
-
-}
-
diff --git a/apex/permission/service/api/system-server-removed.txt b/apex/permission/service/api/system-server-removed.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/service/api/system-server-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
deleted file mode 100644
index aedba290db1f..000000000000
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.permission.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.SystemApi.Client;
-import android.os.UserHandle;
-
-/**
- * Persistence for runtime permissions.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-@SystemApi(client = Client.SYSTEM_SERVER)
-public interface RuntimePermissionsPersistence {
-
- /**
- * Read the runtime permissions from persistence.
- *
- * This will perform I/O operations synchronously.
- *
- * @param user the user to read for
- * @return the runtime permissions read
- */
- @Nullable
- RuntimePermissionsState readForUser(@NonNull UserHandle user);
-
- /**
- * Write the runtime permissions to persistence.
- *
- * This will perform I/O operations synchronously.
- *
- * @param runtimePermissions the runtime permissions to write
- * @param user the user to write for
- */
- void writeForUser(@NonNull RuntimePermissionsState runtimePermissions,
- @NonNull UserHandle user);
-
- /**
- * Delete the runtime permissions from persistence.
- *
- * This will perform I/O operations synchronously.
- *
- * @param user the user to delete for
- */
- void deleteForUser(@NonNull UserHandle user);
-
- /**
- * Create a new instance of {@link RuntimePermissionsPersistence} implementation.
- *
- * @return the new instance.
- */
- @NonNull
- static RuntimePermissionsPersistence createInstance() {
- return new RuntimePermissionsPersistenceImpl();
- }
-}
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
deleted file mode 100644
index e43f59a3377a..000000000000
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.permission.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ApexEnvironment;
-import android.content.pm.PackageManager;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-import android.util.AtomicFile;
-import android.util.Log;
-import android.util.Xml;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Persistence implementation for runtime permissions.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPersistence {
-
- private static final String LOG_TAG = RuntimePermissionsPersistenceImpl.class.getSimpleName();
-
- private static final String APEX_MODULE_NAME = "com.android.permission";
-
- private static final String RUNTIME_PERMISSIONS_FILE_NAME = "runtime-permissions.xml";
-
- private static final String TAG_PACKAGE = "package";
- private static final String TAG_PERMISSION = "permission";
- private static final String TAG_RUNTIME_PERMISSIONS = "runtime-permissions";
- private static final String TAG_SHARED_USER = "shared-user";
-
- private static final String ATTRIBUTE_FINGERPRINT = "fingerprint";
- private static final String ATTRIBUTE_FLAGS = "flags";
- private static final String ATTRIBUTE_GRANTED = "granted";
- private static final String ATTRIBUTE_NAME = "name";
- private static final String ATTRIBUTE_VERSION = "version";
-
- @Nullable
- @Override
- public RuntimePermissionsState readForUser(@NonNull UserHandle user) {
- File file = getFile(user);
- try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(inputStream, null);
- return parseXml(parser);
- } catch (FileNotFoundException e) {
- Log.i(LOG_TAG, "runtime-permissions.xml not found");
- return null;
- } catch (XmlPullParserException | IOException e) {
- throw new IllegalStateException("Failed to read runtime-permissions.xml: " + file , e);
- }
- }
-
- @NonNull
- private static RuntimePermissionsState parseXml(@NonNull XmlPullParser parser)
- throws IOException, XmlPullParserException {
- int type;
- int depth;
- int innerDepth = parser.getDepth() + 1;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
- if (depth > innerDepth || type != XmlPullParser.START_TAG) {
- continue;
- }
-
- if (parser.getName().equals(TAG_RUNTIME_PERMISSIONS)) {
- return parseRuntimePermissions(parser);
- }
- }
- throw new IllegalStateException("Missing <" + TAG_RUNTIME_PERMISSIONS
- + "> in runtime-permissions.xml");
- }
-
- @NonNull
- private static RuntimePermissionsState parseRuntimePermissions(@NonNull XmlPullParser parser)
- throws IOException, XmlPullParserException {
- String versionValue = parser.getAttributeValue(null, ATTRIBUTE_VERSION);
- int version = versionValue != null ? Integer.parseInt(versionValue)
- : RuntimePermissionsState.NO_VERSION;
- String fingerprint = parser.getAttributeValue(null, ATTRIBUTE_FINGERPRINT);
-
- Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
- new ArrayMap<>();
- Map<String, List<RuntimePermissionsState.PermissionState>> sharedUserPermissions =
- new ArrayMap<>();
- int type;
- int depth;
- int innerDepth = parser.getDepth() + 1;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
- if (depth > innerDepth || type != XmlPullParser.START_TAG) {
- continue;
- }
-
- switch (parser.getName()) {
- case TAG_PACKAGE: {
- String packageName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
- List<RuntimePermissionsState.PermissionState> permissions = parsePermissions(
- parser);
- packagePermissions.put(packageName, permissions);
- break;
- }
- case TAG_SHARED_USER: {
- String sharedUserName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
- List<RuntimePermissionsState.PermissionState> permissions = parsePermissions(
- parser);
- sharedUserPermissions.put(sharedUserName, permissions);
- break;
- }
- }
- }
-
- return new RuntimePermissionsState(version, fingerprint, packagePermissions,
- sharedUserPermissions);
- }
-
- @NonNull
- private static List<RuntimePermissionsState.PermissionState> parsePermissions(
- @NonNull XmlPullParser parser) throws IOException, XmlPullParserException {
- List<RuntimePermissionsState.PermissionState> permissions = new ArrayList<>();
- int type;
- int depth;
- int innerDepth = parser.getDepth() + 1;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
- if (depth > innerDepth || type != XmlPullParser.START_TAG) {
- continue;
- }
-
- if (parser.getName().equals(TAG_PERMISSION)) {
- String name = parser.getAttributeValue(null, ATTRIBUTE_NAME);
- boolean granted = Boolean.parseBoolean(parser.getAttributeValue(null,
- ATTRIBUTE_GRANTED));
- int flags = Integer.parseInt(parser.getAttributeValue(null,
- ATTRIBUTE_FLAGS), 16);
- RuntimePermissionsState.PermissionState permission =
- new RuntimePermissionsState.PermissionState(name, granted, flags);
- permissions.add(permission);
- }
- }
- return permissions;
- }
-
- @Override
- public void writeForUser(@NonNull RuntimePermissionsState runtimePermissions,
- @NonNull UserHandle user) {
- File file = getFile(user);
- AtomicFile atomicFile = new AtomicFile(file);
- FileOutputStream outputStream = null;
- try {
- outputStream = atomicFile.startWrite();
-
- XmlSerializer serializer = Xml.newSerializer();
- serializer.setOutput(outputStream, StandardCharsets.UTF_8.name());
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
- serializer.startDocument(null, true);
-
- serializeRuntimePermissions(serializer, runtimePermissions);
-
- serializer.endDocument();
- atomicFile.finishWrite(outputStream);
- } catch (Exception e) {
- Log.wtf(LOG_TAG, "Failed to write runtime-permissions.xml, restoring backup: " + file,
- e);
- atomicFile.failWrite(outputStream);
- } finally {
- IoUtils.closeQuietly(outputStream);
- }
- }
-
- private static void serializeRuntimePermissions(@NonNull XmlSerializer serializer,
- @NonNull RuntimePermissionsState runtimePermissions) throws IOException {
- serializer.startTag(null, TAG_RUNTIME_PERMISSIONS);
-
- int version = runtimePermissions.getVersion();
- serializer.attribute(null, ATTRIBUTE_VERSION, Integer.toString(version));
- String fingerprint = runtimePermissions.getFingerprint();
- if (fingerprint != null) {
- serializer.attribute(null, ATTRIBUTE_FINGERPRINT, fingerprint);
- }
-
- for (Map.Entry<String, List<RuntimePermissionsState.PermissionState>> entry
- : runtimePermissions.getPackagePermissions().entrySet()) {
- String packageName = entry.getKey();
- List<RuntimePermissionsState.PermissionState> permissions = entry.getValue();
-
- serializer.startTag(null, TAG_PACKAGE);
- serializer.attribute(null, ATTRIBUTE_NAME, packageName);
- serializePermissions(serializer, permissions);
- serializer.endTag(null, TAG_PACKAGE);
- }
-
- for (Map.Entry<String, List<RuntimePermissionsState.PermissionState>> entry
- : runtimePermissions.getSharedUserPermissions().entrySet()) {
- String sharedUserName = entry.getKey();
- List<RuntimePermissionsState.PermissionState> permissions = entry.getValue();
-
- serializer.startTag(null, TAG_SHARED_USER);
- serializer.attribute(null, ATTRIBUTE_NAME, sharedUserName);
- serializePermissions(serializer, permissions);
- serializer.endTag(null, TAG_SHARED_USER);
- }
-
- serializer.endTag(null, TAG_RUNTIME_PERMISSIONS);
- }
-
- private static void serializePermissions(@NonNull XmlSerializer serializer,
- @NonNull List<RuntimePermissionsState.PermissionState> permissions) throws IOException {
- int permissionsSize = permissions.size();
- for (int i = 0; i < permissionsSize; i++) {
- RuntimePermissionsState.PermissionState permissionState = permissions.get(i);
-
- serializer.startTag(null, TAG_PERMISSION);
- serializer.attribute(null, ATTRIBUTE_NAME, permissionState.getName());
- serializer.attribute(null, ATTRIBUTE_GRANTED, Boolean.toString(
- permissionState.isGranted() && (permissionState.getFlags()
- & PackageManager.FLAG_PERMISSION_ONE_TIME) == 0));
- serializer.attribute(null, ATTRIBUTE_FLAGS, Integer.toHexString(
- permissionState.getFlags()));
- serializer.endTag(null, TAG_PERMISSION);
- }
- }
-
- @Override
- public void deleteForUser(@NonNull UserHandle user) {
- getFile(user).delete();
- }
-
- @NonNull
- private static File getFile(@NonNull UserHandle user) {
- ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment(APEX_MODULE_NAME);
- File dataDirectory = apexEnvironment.getDeviceProtectedDataDirForUser(user);
- return new File(dataDirectory, RUNTIME_PERMISSIONS_FILE_NAME);
- }
-}
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
deleted file mode 100644
index c6bfc6d32989..000000000000
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.permission.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.SystemApi.Client;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * State of all runtime permissions.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-@SystemApi(client = Client.SYSTEM_SERVER)
-public final class RuntimePermissionsState {
-
- /**
- * Special value for {@link #mVersion} to indicate that no version was read.
- */
- public static final int NO_VERSION = -1;
-
- /**
- * The version of the runtime permissions.
- */
- private final int mVersion;
-
- /**
- * The fingerprint of the runtime permissions.
- */
- @Nullable
- private final String mFingerprint;
-
- /**
- * The runtime permissions by packages.
- */
- @NonNull
- private final Map<String, List<PermissionState>> mPackagePermissions;
-
- /**
- * The runtime permissions by shared users.
- */
- @NonNull
- private final Map<String, List<PermissionState>> mSharedUserPermissions;
-
- /**
- * Create a new instance of this class.
- *
- * @param version the version of the runtime permissions
- * @param fingerprint the fingerprint of the runtime permissions
- * @param packagePermissions the runtime permissions by packages
- * @param sharedUserPermissions the runtime permissions by shared users
- */
- public RuntimePermissionsState(int version, @Nullable String fingerprint,
- @NonNull Map<String, List<PermissionState>> packagePermissions,
- @NonNull Map<String, List<PermissionState>> sharedUserPermissions) {
- mVersion = version;
- mFingerprint = fingerprint;
- mPackagePermissions = packagePermissions;
- mSharedUserPermissions = sharedUserPermissions;
- }
-
- /**
- * Get the version of the runtime permissions.
- *
- * @return the version of the runtime permissions
- */
- public int getVersion() {
- return mVersion;
- }
-
- /**
- * Get the fingerprint of the runtime permissions.
- *
- * @return the fingerprint of the runtime permissions
- */
- @Nullable
- public String getFingerprint() {
- return mFingerprint;
- }
-
- /**
- * Get the runtime permissions by packages.
- *
- * @return the runtime permissions by packages
- */
- @NonNull
- public Map<String, List<PermissionState>> getPackagePermissions() {
- return mPackagePermissions;
- }
-
- /**
- * Get the runtime permissions by shared users.
- *
- * @return the runtime permissions by shared users
- */
- @NonNull
- public Map<String, List<PermissionState>> getSharedUserPermissions() {
- return mSharedUserPermissions;
- }
-
- @Override
- public boolean equals(Object object) {
- if (this == object) {
- return true;
- }
- if (object == null || getClass() != object.getClass()) {
- return false;
- }
- RuntimePermissionsState that = (RuntimePermissionsState) object;
- return mVersion == that.mVersion
- && Objects.equals(mFingerprint, that.mFingerprint)
- && Objects.equals(mPackagePermissions, that.mPackagePermissions)
- && Objects.equals(mSharedUserPermissions, that.mSharedUserPermissions);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mVersion, mFingerprint, mPackagePermissions, mSharedUserPermissions);
- }
-
- /**
- * State of a single permission.
- */
- public static final class PermissionState {
-
- /**
- * The name of the permission.
- */
- @NonNull
- private final String mName;
-
- /**
- * Whether the permission is granted.
- */
- private final boolean mGranted;
-
- /**
- * The flags of the permission.
- */
- private final int mFlags;
-
- /**
- * Create a new instance of this class.
- *
- * @param name the name of the permission
- * @param granted whether the permission is granted
- * @param flags the flags of the permission
- */
- public PermissionState(@NonNull String name, boolean granted, int flags) {
- mName = name;
- mGranted = granted;
- mFlags = flags;
- }
-
- /**
- * Get the name of the permission.
- *
- * @return the name of the permission
- */
- @NonNull
- public String getName() {
- return mName;
- }
-
- /**
- * Get whether the permission is granted.
- *
- * @return whether the permission is granted
- */
- public boolean isGranted() {
- return mGranted;
- }
-
- /**
- * Get the flags of the permission.
- *
- * @return the flags of the permission
- */
- public int getFlags() {
- return mFlags;
- }
-
- @Override
- public boolean equals(Object object) {
- if (this == object) {
- return true;
- }
- if (object == null || getClass() != object.getClass()) {
- return false;
- }
- PermissionState that = (PermissionState) object;
- return mGranted == that.mGranted
- && mFlags == that.mFlags
- && Objects.equals(mName, that.mName);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mName, mGranted, mFlags);
- }
- }
-}
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
deleted file mode 100644
index 2e5a28aa1d6a..000000000000
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.role.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.SystemApi.Client;
-import android.os.UserHandle;
-
-/**
- * Persistence for roles.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-@SystemApi(client = Client.SYSTEM_SERVER)
-public interface RolesPersistence {
-
- /**
- * Read the roles from persistence.
- *
- * This will perform I/O operations synchronously.
- *
- * @param user the user to read for
- * @return the roles read
- */
- @Nullable
- RolesState readForUser(@NonNull UserHandle user);
-
- /**
- * Write the roles to persistence.
- *
- * This will perform I/O operations synchronously.
- *
- * @param roles the roles to write
- * @param user the user to write for
- */
- void writeForUser(@NonNull RolesState roles, @NonNull UserHandle user);
-
- /**
- * Delete the roles from persistence.
- *
- * This will perform I/O operations synchronously.
- *
- * @param user the user to delete for
- */
- void deleteForUser(@NonNull UserHandle user);
-
- /**
- * Create a new instance of {@link RolesPersistence} implementation.
- *
- * @return the new instance.
- */
- @NonNull
- static RolesPersistence createInstance() {
- return new RolesPersistenceImpl();
- }
-}
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
deleted file mode 100644
index f66257f13ef6..000000000000
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.role.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ApexEnvironment;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.AtomicFile;
-import android.util.Log;
-import android.util.Xml;
-
-import com.android.permission.persistence.IoUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Persistence implementation for roles.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-public class RolesPersistenceImpl implements RolesPersistence {
-
- private static final String LOG_TAG = RolesPersistenceImpl.class.getSimpleName();
-
- private static final String APEX_MODULE_NAME = "com.android.permission";
-
- private static final String ROLES_FILE_NAME = "roles.xml";
-
- private static final String TAG_ROLES = "roles";
- private static final String TAG_ROLE = "role";
- private static final String TAG_HOLDER = "holder";
-
- private static final String ATTRIBUTE_VERSION = "version";
- private static final String ATTRIBUTE_NAME = "name";
- private static final String ATTRIBUTE_PACKAGES_HASH = "packagesHash";
-
- @Nullable
- @Override
- public RolesState readForUser(@NonNull UserHandle user) {
- File file = getFile(user);
- try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(inputStream, null);
- return parseXml(parser);
- } catch (FileNotFoundException e) {
- Log.i(LOG_TAG, "roles.xml not found");
- return null;
- } catch (XmlPullParserException | IOException e) {
- throw new IllegalStateException("Failed to read roles.xml: " + file , e);
- }
- }
-
- @NonNull
- private static RolesState parseXml(@NonNull XmlPullParser parser)
- throws IOException, XmlPullParserException {
- int type;
- int depth;
- int innerDepth = parser.getDepth() + 1;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
- if (depth > innerDepth || type != XmlPullParser.START_TAG) {
- continue;
- }
-
- if (parser.getName().equals(TAG_ROLES)) {
- return parseRoles(parser);
- }
- }
- throw new IllegalStateException("Missing <" + TAG_ROLES + "> in roles.xml");
- }
-
- @NonNull
- private static RolesState parseRoles(@NonNull XmlPullParser parser)
- throws IOException, XmlPullParserException {
- int version = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_VERSION));
- String packagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH);
-
- Map<String, Set<String>> roles = new ArrayMap<>();
- int type;
- int depth;
- int innerDepth = parser.getDepth() + 1;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
- if (depth > innerDepth || type != XmlPullParser.START_TAG) {
- continue;
- }
-
- if (parser.getName().equals(TAG_ROLE)) {
- String roleName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
- Set<String> roleHolders = parseRoleHolders(parser);
- roles.put(roleName, roleHolders);
- }
- }
-
- return new RolesState(version, packagesHash, roles);
- }
-
- @NonNull
- private static Set<String> parseRoleHolders(@NonNull XmlPullParser parser)
- throws IOException, XmlPullParserException {
- Set<String> roleHolders = new ArraySet<>();
- int type;
- int depth;
- int innerDepth = parser.getDepth() + 1;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
- if (depth > innerDepth || type != XmlPullParser.START_TAG) {
- continue;
- }
-
- if (parser.getName().equals(TAG_HOLDER)) {
- String roleHolder = parser.getAttributeValue(null, ATTRIBUTE_NAME);
- roleHolders.add(roleHolder);
- }
- }
- return roleHolders;
- }
-
- @Override
- public void writeForUser(@NonNull RolesState roles, @NonNull UserHandle user) {
- File file = getFile(user);
- AtomicFile atomicFile = new AtomicFile(file);
- FileOutputStream outputStream = null;
- try {
- outputStream = atomicFile.startWrite();
-
- XmlSerializer serializer = Xml.newSerializer();
- serializer.setOutput(outputStream, StandardCharsets.UTF_8.name());
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
- serializer.startDocument(null, true);
-
- serializeRoles(serializer, roles);
-
- serializer.endDocument();
- atomicFile.finishWrite(outputStream);
- } catch (Exception e) {
- Log.wtf(LOG_TAG, "Failed to write roles.xml, restoring backup: " + file,
- e);
- atomicFile.failWrite(outputStream);
- } finally {
- IoUtils.closeQuietly(outputStream);
- }
- }
-
- private static void serializeRoles(@NonNull XmlSerializer serializer,
- @NonNull RolesState roles) throws IOException {
- serializer.startTag(null, TAG_ROLES);
-
- int version = roles.getVersion();
- serializer.attribute(null, ATTRIBUTE_VERSION, Integer.toString(version));
- String packagesHash = roles.getPackagesHash();
- if (packagesHash != null) {
- serializer.attribute(null, ATTRIBUTE_PACKAGES_HASH, packagesHash);
- }
-
- for (Map.Entry<String, Set<String>> entry : roles.getRoles().entrySet()) {
- String roleName = entry.getKey();
- Set<String> roleHolders = entry.getValue();
-
- serializer.startTag(null, TAG_ROLE);
- serializer.attribute(null, ATTRIBUTE_NAME, roleName);
- serializeRoleHolders(serializer, roleHolders);
- serializer.endTag(null, TAG_ROLE);
- }
-
- serializer.endTag(null, TAG_ROLES);
- }
-
- private static void serializeRoleHolders(@NonNull XmlSerializer serializer,
- @NonNull Set<String> roleHolders) throws IOException {
- for (String roleHolder : roleHolders) {
- serializer.startTag(null, TAG_HOLDER);
- serializer.attribute(null, ATTRIBUTE_NAME, roleHolder);
- serializer.endTag(null, TAG_HOLDER);
- }
- }
-
- @Override
- public void deleteForUser(@NonNull UserHandle user) {
- getFile(user).delete();
- }
-
- @NonNull
- private static File getFile(@NonNull UserHandle user) {
- ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment(APEX_MODULE_NAME);
- File dataDirectory = apexEnvironment.getDeviceProtectedDataDirForUser(user);
- return new File(dataDirectory, ROLES_FILE_NAME);
- }
-}
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesState.java b/apex/permission/service/java/com/android/role/persistence/RolesState.java
deleted file mode 100644
index f61efa0e840d..000000000000
--- a/apex/permission/service/java/com/android/role/persistence/RolesState.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.role.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.SystemApi.Client;
-
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * State of all roles.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-@SystemApi(client = Client.SYSTEM_SERVER)
-public final class RolesState {
-
- /**
- * The version of the roles.
- */
- private final int mVersion;
-
- /**
- * The hash of all packages in the system.
- */
- @Nullable
- private final String mPackagesHash;
-
- /**
- * The roles.
- */
- @NonNull
- private final Map<String, Set<String>> mRoles;
-
- /**
- * Create a new instance of this class.
- *
- * @param version the version of the roles
- * @param packagesHash the hash of all packages in the system
- * @param roles the roles
- */
- public RolesState(int version, @Nullable String packagesHash,
- @NonNull Map<String, Set<String>> roles) {
- mVersion = version;
- mPackagesHash = packagesHash;
- mRoles = roles;
- }
-
- /**
- * Get the version of the roles.
- *
- * @return the version of the roles
- */
- public int getVersion() {
- return mVersion;
- }
-
- /**
- * Get the hash of all packages in the system.
- *
- * @return the hash of all packages in the system
- */
- @Nullable
- public String getPackagesHash() {
- return mPackagesHash;
- }
-
- /**
- * Get the roles.
- *
- * @return the roles
- */
- @NonNull
- public Map<String, Set<String>> getRoles() {
- return mRoles;
- }
-
- @Override
- public boolean equals(Object object) {
- if (this == object) {
- return true;
- }
- if (object == null || getClass() != object.getClass()) {
- return false;
- }
- RolesState that = (RolesState) object;
- return mVersion == that.mVersion
- && Objects.equals(mPackagesHash, that.mPackagesHash)
- && Objects.equals(mRoles, that.mRoles);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mVersion, mPackagesHash, mRoles);
- }
-}
diff --git a/apex/permission/testing/test_manifest.json b/apex/permission/testing/test_manifest.json
deleted file mode 100644
index bc19a9ea0172..000000000000
--- a/apex/permission/testing/test_manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "com.android.permission",
- "version": 2147483647
-}
diff --git a/apex/permission/tests/Android.bp b/apex/permission/tests/Android.bp
deleted file mode 100644
index 271e328c1139..000000000000
--- a/apex/permission/tests/Android.bp
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-android_test {
- name: "PermissionApexTests",
- sdk_version: "test_current",
- srcs: [
- "java/**/*.kt",
- ],
- static_libs: [
- "service-permission.impl",
- "androidx.test.rules",
- "androidx.test.ext.junit",
- "androidx.test.ext.truth",
- "mockito-target-extended-minus-junit4",
- ],
- jni_libs: [
- "libdexmakerjvmtiagent",
- "libstaticjvmtiagent",
- ],
- compile_multilib: "both",
- test_suites: [
- "general-tests",
- "mts",
- ],
-}
diff --git a/apex/permission/tests/AndroidManifest.xml b/apex/permission/tests/AndroidManifest.xml
deleted file mode 100644
index 57ee6417aeb3..000000000000
--- a/apex/permission/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<manifest
- xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.permission.test">
-
- <!-- The application has to be debuggable for static mocking to work. -->
- <application android:debuggable="true">
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation
- android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.permission.test"
- android:label="Permission APEX Tests" />
-</manifest>
diff --git a/apex/permission/tests/java/com/android/permission/persistence/RuntimePermissionsPersistenceTest.kt b/apex/permission/tests/java/com/android/permission/persistence/RuntimePermissionsPersistenceTest.kt
deleted file mode 100644
index 2987da087e51..000000000000
--- a/apex/permission/tests/java/com/android/permission/persistence/RuntimePermissionsPersistenceTest.kt
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.permission.persistence
-
-import android.content.ApexEnvironment
-import android.content.Context
-import android.os.Process
-import android.os.UserHandle
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
-import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.MockitoAnnotations.initMocks
-import org.mockito.MockitoSession
-import org.mockito.quality.Strictness
-import java.io.File
-
-@RunWith(AndroidJUnit4::class)
-class RuntimePermissionsPersistenceTest {
- private val context = InstrumentationRegistry.getInstrumentation().context
-
- private lateinit var mockDataDirectory: File
-
- private lateinit var mockitoSession: MockitoSession
- @Mock
- lateinit var apexEnvironment: ApexEnvironment
-
- private val persistence = RuntimePermissionsPersistence.createInstance()
- private val permissionState = RuntimePermissionsState.PermissionState("permission", true, 3)
- private val state = RuntimePermissionsState(
- 1, "fingerprint", mapOf("package" to listOf(permissionState)),
- mapOf("sharedUser" to listOf(permissionState))
- )
- private val user = Process.myUserHandle()
-
- @Before
- fun createMockDataDirectory() {
- mockDataDirectory = context.getDir("mock_data", Context.MODE_PRIVATE)
- mockDataDirectory.listFiles()!!.forEach { assertThat(it.deleteRecursively()).isTrue() }
- }
-
- @Before
- fun mockApexEnvironment() {
- initMocks(this)
- mockitoSession = mockitoSession()
- .mockStatic(ApexEnvironment::class.java)
- .strictness(Strictness.LENIENT)
- .startMocking()
- `when`(ApexEnvironment.getApexEnvironment(eq(APEX_MODULE_NAME))).thenReturn(apexEnvironment)
- `when`(apexEnvironment.getDeviceProtectedDataDirForUser(any(UserHandle::class.java))).then {
- File(mockDataDirectory, it.arguments[0].toString()).also { it.mkdirs() }
- }
- }
-
- @After
- fun finishMockingApexEnvironment() {
- mockitoSession.finishMocking()
- }
-
- @Test
- fun testReadWrite() {
- persistence.writeForUser(state, user)
- val persistedState = persistence.readForUser(user)
-
- assertThat(persistedState).isEqualTo(state)
- assertThat(persistedState!!.version).isEqualTo(state.version)
- assertThat(persistedState.fingerprint).isEqualTo(state.fingerprint)
- assertThat(persistedState.packagePermissions).isEqualTo(state.packagePermissions)
- val persistedPermissionState = persistedState.packagePermissions.values.first().first()
- assertThat(persistedPermissionState.name).isEqualTo(permissionState.name)
- assertThat(persistedPermissionState.isGranted).isEqualTo(permissionState.isGranted)
- assertThat(persistedPermissionState.flags).isEqualTo(permissionState.flags)
- assertThat(persistedState.sharedUserPermissions).isEqualTo(state.sharedUserPermissions)
- }
-
- @Test
- fun testDelete() {
- persistence.writeForUser(state, user)
- persistence.deleteForUser(user)
- val persistedState = persistence.readForUser(user)
-
- assertThat(persistedState).isNull()
- }
-
- companion object {
- private const val APEX_MODULE_NAME = "com.android.permission"
- }
-}
diff --git a/apex/permission/tests/java/com/android/role/persistence/RolesPersistenceTest.kt b/apex/permission/tests/java/com/android/role/persistence/RolesPersistenceTest.kt
deleted file mode 100644
index f9d9d5afb25d..000000000000
--- a/apex/permission/tests/java/com/android/role/persistence/RolesPersistenceTest.kt
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.role.persistence
-
-import android.content.ApexEnvironment
-import android.content.Context
-import android.os.Process
-import android.os.UserHandle
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
-import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.MockitoAnnotations.initMocks
-import org.mockito.MockitoSession
-import org.mockito.quality.Strictness
-import java.io.File
-
-@RunWith(AndroidJUnit4::class)
-class RolesPersistenceTest {
- private val context = InstrumentationRegistry.getInstrumentation().context
-
- private lateinit var mockDataDirectory: File
-
- private lateinit var mockitoSession: MockitoSession
- @Mock
- lateinit var apexEnvironment: ApexEnvironment
-
- private val persistence = RolesPersistence.createInstance()
- private val state = RolesState(1, "packagesHash", mapOf("role" to setOf("holder1", "holder2")))
- private val user = Process.myUserHandle()
-
- @Before
- fun createMockDataDirectory() {
- mockDataDirectory = context.getDir("mock_data", Context.MODE_PRIVATE)
- mockDataDirectory.listFiles()!!.forEach { assertThat(it.deleteRecursively()).isTrue() }
- }
-
- @Before
- fun mockApexEnvironment() {
- initMocks(this)
- mockitoSession = mockitoSession()
- .mockStatic(ApexEnvironment::class.java)
- .strictness(Strictness.LENIENT)
- .startMocking()
- `when`(ApexEnvironment.getApexEnvironment(eq(APEX_MODULE_NAME))).thenReturn(apexEnvironment)
- `when`(apexEnvironment.getDeviceProtectedDataDirForUser(any(UserHandle::class.java))).then {
- File(mockDataDirectory, it.arguments[0].toString()).also { it.mkdirs() }
- }
- }
-
- @After
- fun finishMockingApexEnvironment() {
- mockitoSession.finishMocking()
- }
-
- @Test
- fun testReadWrite() {
- persistence.writeForUser(state, user)
- val persistedState = persistence.readForUser(user)
-
- assertThat(persistedState).isEqualTo(state)
- assertThat(persistedState!!.version).isEqualTo(state.version)
- assertThat(persistedState.packagesHash).isEqualTo(state.packagesHash)
- assertThat(persistedState.roles).isEqualTo(state.roles)
- }
-
- @Test
- fun testDelete() {
- persistence.writeForUser(state, user)
- persistence.deleteForUser(user)
- val persistedState = persistence.readForUser(user)
-
- assertThat(persistedState).isNull()
- }
-
- companion object {
- private const val APEX_MODULE_NAME = "com.android.permission"
- }
-}
diff --git a/api/Android.bp b/api/Android.bp
index 9a157b8a0578..fdfef4cb8a74 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -50,10 +50,7 @@ genrule {
dest: "current.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk", "win_sdk"],
dir: "apistubs/android/public/api",
dest: "android.txt",
},
@@ -106,6 +103,11 @@ genrule {
dir: "api",
dest: "removed.txt",
},
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "removed.txt",
+ },
],
}
@@ -131,10 +133,7 @@ genrule {
dest: "system-current.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk", "win_sdk"],
dir: "apistubs/android/system/api",
dest: "android.txt",
},
@@ -163,6 +162,11 @@ genrule {
dir: "api",
dest: "system-removed.txt",
},
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/system/api",
+ dest: "removed.txt",
+ },
],
visibility: ["//visibility:public"],
}
@@ -189,10 +193,7 @@ genrule {
dest: "module-lib-current.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk", "win_sdk"],
dir: "apistubs/android/module-lib/api",
dest: "android.txt",
},
@@ -220,6 +221,11 @@ genrule {
dir: "api",
dest: "module-lib-removed.txt",
},
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/module-lib/api",
+ dest: "removed.txt",
+ },
],
}
diff --git a/boot/Android.bp b/boot/Android.bp
new file mode 100644
index 000000000000..dd4066a7d151
--- /dev/null
+++ b/boot/Android.bp
@@ -0,0 +1,18 @@
+// Copyright (C) 2021 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.
+
+boot_image {
+ name: "framework-boot-image",
+ image_name: "boot",
+}
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index bdb83804d903..846a34eb41c9 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -174,10 +174,6 @@ public class Am extends BaseCommand {
instrument.noWindowAnimation = true;
} else if (opt.equals("--no-hidden-api-checks")) {
instrument.disableHiddenApiChecks = true;
- } else if (opt.equals("--no-test-api-checks")) {
- // TODO(satayev): remove this option, only kept for backwards compatibility with
- // cached tradefed instance
- instrument.disableTestApiChecks = false;
} else if (opt.equals("--no-test-api-access")) {
instrument.disableTestApiChecks = false;
} else if (opt.equals("--no-isolated-storage")) {
@@ -198,7 +194,6 @@ public class Am extends BaseCommand {
}
instrument.componentNameArg = nextArgRequired();
-
instrument.run();
}
}
diff --git a/cmds/app_process/Android.bp b/cmds/app_process/Android.bp
index 07221f97c72b..14ebb713b6ae 100644
--- a/cmds/app_process/Android.bp
+++ b/cmds/app_process/Android.bp
@@ -62,4 +62,13 @@ cc_binary {
// Create a symlink from app_process to app_process32 or 64
// depending on the target configuration.
symlink_preferred_arch: true,
+
+ // Enable ASYNC MTE in the zygote, in order to allow apps and the system
+ // server to use MTE. We use ASYNC because we don't expect the pre-fork
+ // zygote to have substantial memory corruption bugs (as it's primarily Java
+ // code), and we don't want to waste memory recording malloc/free stack
+ // traces (which happens in SYNC mode).
+ sanitize: {
+ memtag_heap: true,
+ },
}
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index c2ee6dcd13b2..dc2868a59840 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -20,6 +20,7 @@ import android.os.IVoldTaskListener;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.os.storage.DiskInfo;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
@@ -30,6 +31,8 @@ import java.util.concurrent.CompletableFuture;
public final class Sm {
private static final String TAG = "Sm";
+ private static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
+ "persist.sys.vold_app_data_isolation_enabled";
IStorageManager mSm;
@@ -107,6 +110,8 @@ public final class Sm {
runStartCheckpoint();
} else if ("supports-checkpoint".equals(op)) {
runSupportsCheckpoint();
+ } else if ("unmount-app-data-dirs".equals(op)) {
+ runDisableAppDataIsolation();
} else {
throw new IllegalArgumentException();
}
@@ -253,6 +258,17 @@ public final class Sm {
System.out.println(result.get());
}
+ public void runDisableAppDataIsolation() throws RemoteException {
+ if (!SystemProperties.getBoolean(
+ ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false)) {
+ throw new IllegalStateException("Storage app data isolation is not enabled.");
+ }
+ final String pkgName = nextArg();
+ final int pid = Integer.parseInt(nextArg());
+ final int userId = Integer.parseInt(nextArg());
+ mSm.disableAppDataIsolation(pkgName, pid, userId);
+ }
+
public void runForget() throws RemoteException {
final String fsUuid = nextArg();
if ("all".equals(fsUuid)) {
@@ -373,6 +389,8 @@ public final class Sm {
System.err.println("");
System.err.println(" sm supports-checkpoint");
System.err.println("");
+ System.err.println(" sm unmount-app-data-dirs PACKAGE_NAME PID USER_ID");
+ System.err.println("");
return 1;
}
}
diff --git a/config/OWNERS b/config/OWNERS
index d59c6f2d72ba..001038d139c4 100644
--- a/config/OWNERS
+++ b/config/OWNERS
@@ -4,5 +4,11 @@ include /ZYGOTE_OWNERS
per-file hiddenapi-* = andreionea@google.com, mathewi@google.com, satayev@google.com
+# art-team@ manages the boot image profiles
+per-file boot-* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+per-file dirty-image-objects = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+per-file generate-preloaded-classes.sh = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+per-file preloaded-classes* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+
# Escalations:
per-file hiddenapi-* = bdc@google.com, narayan@google.com
diff --git a/config/hiddenapi-temp-blocklist.txt b/config/hiddenapi-max-target-r-loprio.txt
index 246eeea35a19..246eeea35a19 100644
--- a/config/hiddenapi-temp-blocklist.txt
+++ b/config/hiddenapi-max-target-r-loprio.txt
diff --git a/core/api/current.txt b/core/api/current.txt
index 252c33c4efda..717e3bd02994 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -385,6 +385,7 @@ package android {
field public static final int calendarViewShown = 16843596; // 0x101034c
field public static final int calendarViewStyle = 16843613; // 0x101035d
field public static final int canControlMagnification = 16844039; // 0x1010507
+ field public static final int canPauseRecording = 16844311; // 0x1010617
field public static final int canPerformGestures = 16844045; // 0x101050d
field public static final int canRecord = 16844060; // 0x101051c
field @Deprecated public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
@@ -10144,6 +10145,7 @@ package android.content {
method public void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyBroadcast(@RequiresPermission android.content.Intent);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public void sendStickyBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable android.os.Bundle);
method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyOrderedBroadcast(@RequiresPermission android.content.Intent, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
@@ -10186,6 +10188,7 @@ package android.content {
field public static final String BIOMETRIC_SERVICE = "biometric";
field public static final String BLOB_STORE_SERVICE = "blob_store";
field public static final String BLUETOOTH_SERVICE = "bluetooth";
+ field public static final String BUGREPORT_SERVICE = "bugreport";
field public static final String CAMERA_SERVICE = "camera";
field public static final String CAPTIONING_SERVICE = "captioning";
field public static final String CARRIER_CONFIG_SERVICE = "carrier_config";
@@ -12125,6 +12128,8 @@ package android.content.pm {
field public static final String FEATURE_GAMEPAD = "android.hardware.gamepad";
field public static final String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
field public static final String FEATURE_HOME_SCREEN = "android.software.home_screen";
+ field public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE = "android.hardware.identity_credential";
+ field public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE_DIRECT_ACCESS = "android.hardware.identity_credential_direct_access";
field public static final String FEATURE_INPUT_METHODS = "android.software.input_methods";
field public static final String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels";
field public static final String FEATURE_IRIS = "android.hardware.biometrics.iris";
@@ -12211,7 +12216,7 @@ package android.content.pm {
field @Deprecated public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
field public static final int GET_GIDS = 256; // 0x100
field public static final int GET_INSTRUMENTATION = 16; // 0x10
- field public static final int GET_INTENT_FILTERS = 32; // 0x20
+ field @Deprecated public static final int GET_INTENT_FILTERS = 32; // 0x20
field public static final int GET_META_DATA = 128; // 0x80
field public static final int GET_PERMISSIONS = 4096; // 0x1000
field public static final int GET_PROVIDERS = 8; // 0x8
@@ -24265,6 +24270,7 @@ package android.media.tv {
}
public final class TvInputInfo implements android.os.Parcelable {
+ method public boolean canPauseRecording();
method public boolean canRecord();
method @Deprecated public android.content.Intent createSettingsIntent();
method public android.content.Intent createSetupIntent();
@@ -24298,6 +24304,7 @@ package android.media.tv {
public static final class TvInputInfo.Builder {
ctor public TvInputInfo.Builder(android.content.Context, android.content.ComponentName);
method public android.media.tv.TvInputInfo build();
+ method @NonNull public android.media.tv.TvInputInfo.Builder setCanPauseRecording(boolean);
method public android.media.tv.TvInputInfo.Builder setCanRecord(boolean);
method public android.media.tv.TvInputInfo.Builder setExtras(android.os.Bundle);
method public android.media.tv.TvInputInfo.Builder setTunerCount(int);
@@ -24389,7 +24396,9 @@ package android.media.tv {
method public void notifyRecordingStopped(android.net.Uri);
method public void notifyTuned(android.net.Uri);
method public void onAppPrivateCommand(@NonNull String, android.os.Bundle);
+ method public void onPauseRecording(@NonNull android.os.Bundle);
method public abstract void onRelease();
+ method public void onResumeRecording(@NonNull android.os.Bundle);
method public abstract void onStartRecording(@Nullable android.net.Uri);
method public void onStartRecording(@Nullable android.net.Uri, @NonNull android.os.Bundle);
method public abstract void onStopRecording();
@@ -24439,7 +24448,11 @@ package android.media.tv {
public class TvRecordingClient {
ctor public TvRecordingClient(android.content.Context, String, @NonNull android.media.tv.TvRecordingClient.RecordingCallback, android.os.Handler);
+ method public void pauseRecording();
+ method public void pauseRecording(@NonNull android.os.Bundle);
method public void release();
+ method public void resumeRecording();
+ method public void resumeRecording(@NonNull android.os.Bundle);
method public void sendAppPrivateCommand(@NonNull String, android.os.Bundle);
method public void startRecording(@Nullable android.net.Uri);
method public void startRecording(@Nullable android.net.Uri, @NonNull android.os.Bundle);
@@ -25073,6 +25086,8 @@ package android.net {
method public void applyTransportModeTransform(@NonNull java.net.Socket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
method public void applyTransportModeTransform(@NonNull java.net.DatagramSocket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
method public void applyTransportModeTransform(@NonNull java.io.FileDescriptor, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
+ method @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
+ method @NonNull @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
method public void removeTransportModeTransforms(@NonNull java.net.Socket) throws java.io.IOException;
@@ -25082,6 +25097,12 @@ package android.net {
field public static final int DIRECTION_OUT = 1; // 0x1
}
+ public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
+ method @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public void addAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
+ method public void close();
+ method @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
+ }
+
public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
}
@@ -29587,6 +29608,24 @@ package android.os {
method public boolean unlinkToDeath(@NonNull android.os.IBinder.DeathRecipient, int);
}
+ public final class BugreportManager {
+ method public void cancelBugreport();
+ method public void startConnectivityBugreport(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
+ }
+
+ public abstract static class BugreportManager.BugreportCallback {
+ ctor public BugreportManager.BugreportCallback();
+ method public void onEarlyReportFinished();
+ method public void onError(int);
+ method public void onFinished();
+ method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float);
+ field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5
+ field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1
+ field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2
+ field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4
+ field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3
+ }
+
public class Build {
ctor public Build();
method @NonNull public static java.util.List<android.os.Build.Partition> getFingerprintedPartitions();
@@ -29610,6 +29649,8 @@ package android.os {
field @Deprecated public static final String RADIO;
field @Deprecated public static final String SERIAL;
field @NonNull public static final String SKU;
+ field @NonNull public static final String SOC_MANUFACTURER;
+ field @NonNull public static final String SOC_MODEL;
field public static final String[] SUPPORTED_32_BIT_ABIS;
field public static final String[] SUPPORTED_64_BIT_ABIS;
field public static final String[] SUPPORTED_ABIS;
@@ -33918,6 +33959,7 @@ package android.provider {
field public static final String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
field public static final String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
field public static final String ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION";
+ field public static final String ACTION_MANAGE_ALL_SUBSCRIPTIONS_SETTINGS = "android.settings.MANAGE_ALL_SUBSCRIPTIONS_SETTINGS";
field public static final String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
field public static final String ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION";
field public static final String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
@@ -35859,6 +35901,9 @@ package android.se.omapi {
method @NonNull public String getVersion();
method public boolean isConnected();
method public void shutdown();
+ field public static final String ACTION_SECURE_ELEMENT_STATE_CHANGED = "android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED";
+ field public static final String EXTRA_READER_NAME = "android.se.omapi.extra.READER_NAME";
+ field public static final String EXTRA_READER_STATE = "android.se.omapi.extra.READER_STATE";
}
public static interface SEService.OnConnectedListener {
@@ -36041,15 +36086,20 @@ package android.security.identity {
public abstract class IdentityCredential {
method @NonNull public abstract java.security.KeyPair createEphemeralKeyPair();
method @NonNull public abstract byte[] decryptMessageFromReader(@NonNull byte[]) throws android.security.identity.MessageDecryptionException;
+ method @NonNull public byte[] delete(@NonNull byte[]);
method @NonNull public abstract byte[] encryptMessageToReader(@NonNull byte[]);
method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getAuthKeysNeedingCertification();
method @NonNull public abstract int[] getAuthenticationDataUsageCount();
method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getCredentialKeyCertificateChain();
method @NonNull public abstract android.security.identity.ResultData getEntries(@Nullable byte[], @NonNull java.util.Map<java.lang.String,java.util.Collection<java.lang.String>>, @Nullable byte[], @Nullable byte[]) throws android.security.identity.EphemeralPublicKeyNotFoundException, android.security.identity.InvalidReaderSignatureException, android.security.identity.InvalidRequestMessageException, android.security.identity.NoAuthenticationKeyAvailableException, android.security.identity.SessionTranscriptMismatchException;
+ method @NonNull public byte[] proveOwnership(@NonNull byte[]);
method public abstract void setAllowUsingExhaustedKeys(boolean);
+ method public void setAllowUsingExpiredKeys(boolean);
method public abstract void setAvailableAuthenticationKeys(int, int);
method public abstract void setReaderEphemeralPublicKey(@NonNull java.security.PublicKey) throws java.security.InvalidKeyException;
- method public abstract void storeStaticAuthenticationData(@NonNull java.security.cert.X509Certificate, @NonNull byte[]) throws android.security.identity.UnknownAuthenticationKeyException;
+ method @Deprecated public abstract void storeStaticAuthenticationData(@NonNull java.security.cert.X509Certificate, @NonNull byte[]) throws android.security.identity.UnknownAuthenticationKeyException;
+ method public void storeStaticAuthenticationData(@NonNull java.security.cert.X509Certificate, @NonNull java.time.Instant, @NonNull byte[]) throws android.security.identity.UnknownAuthenticationKeyException;
+ method @NonNull public byte[] update(@NonNull android.security.identity.PersonalizationData);
}
public class IdentityCredentialException extends java.lang.Exception {
@@ -36059,7 +36109,7 @@ package android.security.identity {
public abstract class IdentityCredentialStore {
method @NonNull public abstract android.security.identity.WritableIdentityCredential createCredential(@NonNull String, @NonNull String) throws android.security.identity.AlreadyPersonalizedException, android.security.identity.DocTypeNotSupportedException;
- method @Nullable public abstract byte[] deleteCredentialByName(@NonNull String);
+ method @Deprecated @Nullable public abstract byte[] deleteCredentialByName(@NonNull String);
method @Nullable public abstract android.security.identity.IdentityCredential getCredentialByName(@NonNull String, int) throws android.security.identity.CipherSuiteNotSupportedException;
method @Nullable public static android.security.identity.IdentityCredentialStore getDirectAccessInstance(@NonNull android.content.Context);
method @Nullable public static android.security.identity.IdentityCredentialStore getInstance(@NonNull android.content.Context);
@@ -36135,9 +36185,10 @@ package android.security.identity {
package android.security.keystore {
public class BackendBusyException extends java.security.ProviderException {
- ctor public BackendBusyException();
- ctor public BackendBusyException(@NonNull String);
- ctor public BackendBusyException(@NonNull String, @NonNull Throwable);
+ ctor public BackendBusyException(long);
+ ctor public BackendBusyException(long, @NonNull String);
+ ctor public BackendBusyException(long, @NonNull String, @NonNull Throwable);
+ method public long getBackOffHintMillis();
}
public class KeyExpiredException extends java.security.InvalidKeyException {
@@ -36275,6 +36326,7 @@ package android.security.keystore {
field public static final int ORIGIN_IMPORTED = 2; // 0x2
field public static final int ORIGIN_SECURELY_IMPORTED = 8; // 0x8
field public static final int ORIGIN_UNKNOWN = 4; // 0x4
+ field public static final int PURPOSE_AGREE_KEY = 64; // 0x40
field public static final int PURPOSE_DECRYPT = 2; // 0x2
field public static final int PURPOSE_ENCRYPT = 1; // 0x1
field public static final int PURPOSE_SIGN = 4; // 0x4
@@ -39217,6 +39269,7 @@ package android.telephony {
field public static final int BAND_25 = 25; // 0x19
field public static final int BAND_257 = 257; // 0x101
field public static final int BAND_258 = 258; // 0x102
+ field public static final int BAND_26 = 26; // 0x1a
field public static final int BAND_260 = 260; // 0x104
field public static final int BAND_261 = 261; // 0x105
field public static final int BAND_28 = 28; // 0x1c
@@ -39228,10 +39281,12 @@ package android.telephony {
field public static final int BAND_39 = 39; // 0x27
field public static final int BAND_40 = 40; // 0x28
field public static final int BAND_41 = 41; // 0x29
+ field public static final int BAND_46 = 46; // 0x2e
field public static final int BAND_48 = 48; // 0x30
field public static final int BAND_5 = 5; // 0x5
field public static final int BAND_50 = 50; // 0x32
field public static final int BAND_51 = 51; // 0x33
+ field public static final int BAND_53 = 53; // 0x35
field public static final int BAND_65 = 65; // 0x41
field public static final int BAND_66 = 66; // 0x42
field public static final int BAND_7 = 7; // 0x7
@@ -39257,6 +39312,7 @@ package android.telephony {
field public static final int BAND_93 = 93; // 0x5d
field public static final int BAND_94 = 94; // 0x5e
field public static final int BAND_95 = 95; // 0x5f
+ field public static final int BAND_96 = 96; // 0x60
}
public static final class AccessNetworkConstants.UtranBand {
@@ -39544,6 +39600,7 @@ package android.telephony {
field public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool";
field public static final String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
field public static final String KEY_RTT_SUPPORTED_FOR_VT_BOOL = "rtt_supported_for_vt_bool";
+ field public static final String KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL = "rtt_supported_while_roaming_bool";
field public static final String KEY_RTT_UPGRADE_SUPPORTED_BOOL = "rtt_upgrade_supported_bool";
field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool";
field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool";
@@ -40219,6 +40276,7 @@ package android.telephony {
field public static final int SERVICE_OPTION_OUT_OF_ORDER = 34; // 0x22
field public static final int SIGNAL_LOST = -3; // 0xfffffffd
field public static final int SIM_CARD_CHANGED = 2043; // 0x7fb
+ field public static final int SLICE_REJECTED = 2252; // 0x8cc
field public static final int SYNCHRONIZATION_FAILURE = 2184; // 0x888
field public static final int TEST_LOOPBACK_REGULAR_DEACTIVATION = 2196; // 0x894
field public static final int TETHERED_CALL_ACTIVE = -6; // 0xfffffffa
@@ -40486,6 +40544,12 @@ package android.telephony {
field public static final int SCAN_TYPE_PERIODIC = 1; // 0x1
}
+ public final class PhoneCapability implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhoneCapability> CREATOR;
+ }
+
public class PhoneNumberFormattingTextWatcher implements android.text.TextWatcher {
ctor public PhoneNumberFormattingTextWatcher();
ctor public PhoneNumberFormattingTextWatcher(String);
@@ -40497,12 +40561,13 @@ package android.telephony {
public class PhoneNumberUtils {
ctor public PhoneNumberUtils();
method public static void addTtsSpan(android.text.Spannable, int, int);
+ method public static boolean areSamePhoneNumber(@NonNull String, @NonNull String, @NonNull String);
method @Deprecated public static String calledPartyBCDFragmentToString(byte[], int, int);
method public static String calledPartyBCDFragmentToString(byte[], int, int, int);
method @Deprecated public static String calledPartyBCDToString(byte[], int, int);
method public static String calledPartyBCDToString(byte[], int, int, int);
- method public static boolean compare(String, String);
- method public static boolean compare(android.content.Context, String, String);
+ method @Deprecated public static boolean compare(String, String);
+ method @Deprecated public static boolean compare(android.content.Context, String, String);
method public static String convertKeypadLettersToDigits(String);
method public static android.text.style.TtsSpan createTtsSpan(String);
method public static CharSequence createTtsSpannable(CharSequence);
@@ -40554,10 +40619,10 @@ package android.telephony {
public class PhoneStateListener {
ctor public PhoneStateListener();
- ctor public PhoneStateListener(@NonNull java.util.concurrent.Executor);
+ ctor @Deprecated public PhoneStateListener(@NonNull java.util.concurrent.Executor);
method public void onActiveDataSubscriptionIdChanged(int);
method public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo);
- method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onCallDisconnectCauseChanged(int, int);
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallDisconnectCauseChanged(int, int);
method public void onCallForwardingIndicatorChanged(boolean);
method public void onCallStateChanged(int, String);
method public void onCellInfoChanged(java.util.List<android.telephony.CellInfo>);
@@ -40565,36 +40630,150 @@ package android.telephony {
method public void onDataActivity(int);
method public void onDataConnectionStateChanged(int);
method public void onDataConnectionStateChanged(int, int);
- method @RequiresPermission("android.permission.READ_PHONE_STATE") public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
method public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>);
- method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
method public void onMessageWaitingIndicatorChanged(boolean);
- method @RequiresPermission("android.permission.MODIFY_PHONE_STATE") public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
method public void onRegistrationFailed(@NonNull android.telephony.CellIdentity, @NonNull String, int, int, int);
method public void onServiceStateChanged(android.telephony.ServiceState);
method @Deprecated public void onSignalStrengthChanged(int);
method public void onSignalStrengthsChanged(android.telephony.SignalStrength);
method public void onUserMobileDataStateChanged(boolean);
- field public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 4194304; // 0x400000
- field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_BARRING_INFO = -2147483648; // 0x80000000
- field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000
- field public static final int LISTEN_CALL_FORWARDING_INDICATOR = 8; // 0x8
- field public static final int LISTEN_CALL_STATE = 32; // 0x20
- field public static final int LISTEN_CELL_INFO = 1024; // 0x400
- field public static final int LISTEN_CELL_LOCATION = 16; // 0x10
- field public static final int LISTEN_DATA_ACTIVITY = 128; // 0x80
- field public static final int LISTEN_DATA_CONNECTION_STATE = 64; // 0x40
- field public static final int LISTEN_DISPLAY_INFO_CHANGED = 1048576; // 0x100000
- field public static final int LISTEN_EMERGENCY_NUMBER_LIST = 16777216; // 0x1000000
- field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000
- field public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4
+ field @Deprecated public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 4194304; // 0x400000
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_BARRING_INFO = -2147483648; // 0x80000000
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000
+ field @Deprecated public static final int LISTEN_CALL_FORWARDING_INDICATOR = 8; // 0x8
+ field @Deprecated public static final int LISTEN_CALL_STATE = 32; // 0x20
+ field @Deprecated public static final int LISTEN_CELL_INFO = 1024; // 0x400
+ field @Deprecated public static final int LISTEN_CELL_LOCATION = 16; // 0x10
+ field @Deprecated public static final int LISTEN_DATA_ACTIVITY = 128; // 0x80
+ field @Deprecated public static final int LISTEN_DATA_CONNECTION_STATE = 64; // 0x40
+ field @Deprecated public static final int LISTEN_DISPLAY_INFO_CHANGED = 1048576; // 0x100000
+ field @Deprecated public static final int LISTEN_EMERGENCY_NUMBER_LIST = 16777216; // 0x1000000
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000
+ field @Deprecated public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4
field public static final int LISTEN_NONE = 0; // 0x0
- field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000
- field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000
- field public static final int LISTEN_SERVICE_STATE = 1; // 0x1
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000
+ field @Deprecated public static final int LISTEN_SERVICE_STATE = 1; // 0x1
field @Deprecated public static final int LISTEN_SIGNAL_STRENGTH = 2; // 0x2
- field public static final int LISTEN_SIGNAL_STRENGTHS = 256; // 0x100
- field public static final int LISTEN_USER_MOBILE_DATA_STATE = 524288; // 0x80000
+ field @Deprecated public static final int LISTEN_SIGNAL_STRENGTHS = 256; // 0x100
+ field @Deprecated public static final int LISTEN_USER_MOBILE_DATA_STATE = 524288; // 0x80000
+ }
+
+ public static interface PhoneStateListener.ActiveDataSubscriptionIdChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onActiveDataSubscriptionIdChanged(int);
+ }
+
+ public static interface PhoneStateListener.AlwaysReportedSignalStrengthChangedListener {
+ method @RequiresPermission("android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH") public void onSignalStrengthsChanged(@NonNull android.telephony.SignalStrength);
+ }
+
+ public static interface PhoneStateListener.BarringInfoChangedListener {
+ method @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo);
+ }
+
+ public static interface PhoneStateListener.CallDisconnectCauseChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallDisconnectCauseChanged(int, int);
+ }
+
+ public static interface PhoneStateListener.CallForwardingIndicatorChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onCallForwardingIndicatorChanged(boolean);
+ }
+
+ public static interface PhoneStateListener.CallStateChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public void onCallStateChanged(int, @Nullable String);
+ }
+
+ public static interface PhoneStateListener.CarrierNetworkChangeListener {
+ method public void onCarrierNetworkChange(boolean);
+ }
+
+ public static interface PhoneStateListener.CellInfoChangedListener {
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void onCellInfoChanged(@NonNull java.util.List<android.telephony.CellInfo>);
+ }
+
+ public static interface PhoneStateListener.CellLocationChangedListener {
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void onCellLocationChanged(@NonNull android.telephony.CellLocation);
+ }
+
+ public static interface PhoneStateListener.DataActivationStateChangedListener {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataActivationStateChanged(int);
+ }
+
+ public static interface PhoneStateListener.DataActivityListener {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataActivity(int);
+ }
+
+ public static interface PhoneStateListener.DataConnectionStateChangedListener {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataConnectionStateChanged(int, int);
+ }
+
+ public static interface PhoneStateListener.DisplayInfoChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
+ }
+
+ public static interface PhoneStateListener.EmergencyNumberListChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>);
+ }
+
+ public static interface PhoneStateListener.ImsCallDisconnectCauseChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
+ }
+
+ public static interface PhoneStateListener.MessageWaitingIndicatorChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onMessageWaitingIndicatorChanged(boolean);
+ }
+
+ public static interface PhoneStateListener.PhoneCapabilityChangedListener {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onPhoneCapabilityChanged(@NonNull android.telephony.PhoneCapability);
+ }
+
+ public static interface PhoneStateListener.PreciseDataConnectionStateChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
+ }
+
+ public static interface PhoneStateListener.RegistrationFailedListener {
+ method @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onRegistrationFailed(@NonNull android.telephony.CellIdentity, @NonNull String, int, int, int);
+ }
+
+ public static interface PhoneStateListener.ServiceStateChangedListener {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onServiceStateChanged(@NonNull android.telephony.ServiceState);
+ }
+
+ public static interface PhoneStateListener.SignalStrengthsChangedListener {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onSignalStrengthsChanged(@NonNull android.telephony.SignalStrength);
+ }
+
+ public static interface PhoneStateListener.UserMobileDataStateChangedListener {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onUserMobileDataStateChanged(boolean);
+ }
+
+ public final class PhysicalChannelConfig implements android.os.Parcelable {
+ method public int describeContents();
+ method @IntRange(from=1, to=261) public int getBand();
+ method @IntRange(from=1) public int getCellBandwidthDownlinkKhz();
+ method @IntRange(from=1) public int getCellBandwidthUplinkKhz();
+ method @Deprecated public int getChannelNumber();
+ method public int getConnectionStatus();
+ method @IntRange(from=0) public int getDownlinkChannelNumber();
+ method @IntRange(from=0) public int getDownlinkFrequencyKhz();
+ method public int getNetworkType();
+ method @IntRange(from=0, to=1007) public int getPhysicalCellId();
+ method @IntRange(from=0) public int getUplinkChannelNumber();
+ method @IntRange(from=0) public int getUplinkFrequencyKhz();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int BAND_UNKNOWN = 0; // 0x0
+ field public static final int CELL_BANDWIDTH_UNKNOWN = 0; // 0x0
+ field public static final int CHANNEL_NUMBER_UNKNOWN = -1; // 0xffffffff
+ field public static final int CONNECTION_PRIMARY_SERVING = 1; // 0x1
+ field public static final int CONNECTION_SECONDARY_SERVING = 2; // 0x2
+ field public static final int CONNECTION_UNKNOWN = -1; // 0xffffffff
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhysicalChannelConfig> CREATOR;
+ field public static final int FREQUENCY_UNKNOWN = -1; // 0xffffffff
+ field public static final int PHYSICAL_CELL_ID_MAXIMUM_VALUE = 1007; // 0x3ef
+ field public static final int PHYSICAL_CELL_ID_UNKNOWN = -1; // 0xffffffff
}
public final class PreciseDataConnectionState implements android.os.Parcelable {
@@ -40676,6 +40855,50 @@ package android.telephony {
field public static final int INVALID = 2147483647; // 0x7fffffff
}
+ public final class SignalStrengthUpdateRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.os.IBinder getLiveToken();
+ method @NonNull public java.util.Collection<android.telephony.SignalThresholdInfo> getSignalThresholdInfos();
+ method public boolean isReportingRequestedWhileIdle();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SignalStrengthUpdateRequest> CREATOR;
+ }
+
+ public static final class SignalStrengthUpdateRequest.Builder {
+ ctor public SignalStrengthUpdateRequest.Builder();
+ method @NonNull public android.telephony.SignalStrengthUpdateRequest build();
+ method @NonNull public android.telephony.SignalStrengthUpdateRequest.Builder setReportingRequestedWhileIdle(boolean);
+ method @NonNull public android.telephony.SignalStrengthUpdateRequest.Builder setSignalThresholdInfos(@NonNull java.util.Collection<android.telephony.SignalThresholdInfo>);
+ }
+
+ public final class SignalThresholdInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public static int getMaximumNumberOfThresholdsAllowed();
+ method public static int getMinimumNumberOfThresholdsAllowed();
+ method public int getRadioAccessNetworkType();
+ method public int getSignalMeasurementType();
+ method @NonNull public int[] getThresholds();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SignalThresholdInfo> CREATOR;
+ field public static final int SIGNAL_MEASUREMENT_TYPE_RSCP = 2; // 0x2
+ field public static final int SIGNAL_MEASUREMENT_TYPE_RSRP = 3; // 0x3
+ field public static final int SIGNAL_MEASUREMENT_TYPE_RSRQ = 4; // 0x4
+ field public static final int SIGNAL_MEASUREMENT_TYPE_RSSI = 1; // 0x1
+ field public static final int SIGNAL_MEASUREMENT_TYPE_RSSNR = 5; // 0x5
+ field public static final int SIGNAL_MEASUREMENT_TYPE_SSRSRP = 6; // 0x6
+ field public static final int SIGNAL_MEASUREMENT_TYPE_SSRSRQ = 7; // 0x7
+ field public static final int SIGNAL_MEASUREMENT_TYPE_SSSINR = 8; // 0x8
+ field public static final int SIGNAL_MEASUREMENT_TYPE_UNKNOWN = 0; // 0x0
+ }
+
+ public static final class SignalThresholdInfo.Builder {
+ ctor public SignalThresholdInfo.Builder();
+ method @NonNull public android.telephony.SignalThresholdInfo build();
+ method @NonNull public android.telephony.SignalThresholdInfo.Builder setRadioAccessNetworkType(int);
+ method @NonNull public android.telephony.SignalThresholdInfo.Builder setSignalMeasurementType(int);
+ method @NonNull public android.telephony.SignalThresholdInfo.Builder setThresholds(@NonNull int[]);
+ }
+
public final class SmsManager {
method public String createAppSpecificSmsToken(android.app.PendingIntent);
method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
@@ -41012,6 +41235,7 @@ package android.telephony {
public class TelephonyManager {
method public boolean canChangeDtmfToneLength();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void clearSignalStrengthUpdateRequest(@NonNull android.telephony.SignalStrengthUpdateRequest);
method @Nullable public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
method public android.telephony.TelephonyManager createForSubscriptionId(int);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean doesSwitchMultiSimConfigTriggerReboot();
@@ -41090,7 +41314,7 @@ package android.telephony {
method @Deprecated public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
method public boolean isConcurrentVoiceAndDataSupported();
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isDataConnectionAllowed();
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean isDataEnabled();
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabled();
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledForReason(int);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
method public boolean isEmergencyNumber(@NonNull String);
@@ -41105,7 +41329,8 @@ package android.telephony {
method public boolean isVoiceCapable();
method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
method public boolean isWorldPhone();
- method public void listen(android.telephony.PhoneStateListener, int);
+ method @Deprecated public void listen(android.telephony.PhoneStateListener, int);
+ method public void registerPhoneStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.PhoneStateListener);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestCellInfoUpdate(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback);
method public void sendDialerSpecialCode(String);
@@ -41123,11 +41348,13 @@ package android.telephony {
method public boolean setOperatorBrandOverride(String);
method public boolean setPreferredNetworkTypeToGlobal();
method public void setPreferredOpportunisticDataSubscription(int, boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSignalStrengthUpdateRequest(@NonNull android.telephony.SignalStrengthUpdateRequest);
method public void setVisualVoicemailSmsFilterSettings(android.telephony.VisualVoicemailSmsFilterSettings);
method public boolean setVoiceMailNumber(String, String);
method @Deprecated public void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri);
method @Deprecated public void setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void switchMultiSimConfig(int);
+ method public void unregisterPhoneStateListener(@NonNull android.telephony.PhoneStateListener);
method public void updateAvailableNetworks(@NonNull java.util.List<android.telephony.AvailableNetworkInfo>, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
field public static final String ACTION_CARRIER_MESSAGING_CLIENT_SERVICE = "android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE";
field public static final String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
@@ -41149,6 +41376,7 @@ package android.telephony {
field public static final int AUTHTYPE_EAP_SIM = 128; // 0x80
field public static final int CALL_COMPOSER_STATUS_OFF = 0; // 0x0
field public static final int CALL_COMPOSER_STATUS_ON = 1; // 0x1
+ field public static final int CALL_COMPOSER_STATUS_ON_NO_PICTURES = 2; // 0x2
field public static final int CALL_STATE_IDLE = 0; // 0x0
field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
field public static final int CALL_STATE_RINGING = 1; // 0x1
@@ -41489,6 +41717,14 @@ package android.telephony.euicc {
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.euicc.DownloadableSubscription> CREATOR;
}
+ public static final class DownloadableSubscription.Builder {
+ ctor public DownloadableSubscription.Builder(@NonNull android.telephony.euicc.DownloadableSubscription);
+ ctor public DownloadableSubscription.Builder(@NonNull String);
+ method @NonNull public android.telephony.euicc.DownloadableSubscription build();
+ method @NonNull public android.telephony.euicc.DownloadableSubscription.Builder setConfirmationCode(@NonNull String);
+ method @NonNull public android.telephony.euicc.DownloadableSubscription.Builder setEncodedActivationCode(@NonNull String);
+ }
+
public final class EuiccInfo implements android.os.Parcelable {
ctor public EuiccInfo(@Nullable String);
method public int describeContents();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 9349770ee4fd..230863da4661 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -10,6 +10,27 @@ package android.app {
package android.net {
+ public class ConnectivityManager {
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @Nullable android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
+ }
+
+ public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
+ method public int getResourceId();
+ }
+
+ public final class NetworkAgentConfig implements android.os.Parcelable {
+ method @Nullable public String getSubscriberId();
+ }
+
+ public static final class NetworkAgentConfig.Builder {
+ method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
+ }
+
+ public final class NetworkCapabilities implements android.os.Parcelable {
+ field public static final int TRANSPORT_TEST = 7; // 0x7
+ }
+
public final class TcpRepairWindow {
ctor public TcpRepairWindow(int, int, int, int, int, int);
field public final int maxWindow;
@@ -20,6 +41,22 @@ package android.net {
field public final int sndWnd;
}
+ public final class TestNetworkInterface implements android.os.Parcelable {
+ ctor public TestNetworkInterface(@NonNull android.os.ParcelFileDescriptor, @NonNull String);
+ method public int describeContents();
+ method @NonNull public android.os.ParcelFileDescriptor getFileDescriptor();
+ method @NonNull public String getInterfaceName();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkInterface> CREATOR;
+ }
+
+ public class TestNetworkManager {
+ method @NonNull public android.net.TestNetworkInterface createTapInterface();
+ method @NonNull public android.net.TestNetworkInterface createTunInterface(@NonNull java.util.Collection<android.net.LinkAddress>);
+ method public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder);
+ method public void teardownTestNetwork(@NonNull android.net.Network);
+ }
+
}
package android.os {
@@ -28,6 +65,10 @@ package android.os {
method public final void markVintfStability();
}
+ public static class Build.VERSION {
+ field public static final int FIRST_SDK_INT;
+ }
+
public interface Parcelable {
method public default int getStability();
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 9f41c139a46a..a7c5b7480334 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -44,6 +44,7 @@ package android {
field public static final String BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE = "android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE";
field public static final String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
field public static final String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
+ field public static final String BIND_RESUME_ON_REBOOT_SERVICE = "android.permission.BIND_RESUME_ON_REBOOT_SERVICE";
field public static final String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
field public static final String BIND_SETTINGS_SUGGESTIONS_SERVICE = "android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE";
field public static final String BIND_SOUND_TRIGGER_DETECTION_SERVICE = "android.permission.BIND_SOUND_TRIGGER_DETECTION_SERVICE";
@@ -126,6 +127,7 @@ package android {
field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
field public static final String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
+ field public static final String MANAGE_TEST_NETWORKS = "android.permission.MANAGE_TEST_NETWORKS";
field public static final String MANAGE_USB = "android.permission.MANAGE_USB";
field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS";
field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
@@ -199,6 +201,7 @@ package android {
field public static final String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES";
field public static final String REQUEST_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE";
field public static final String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
+ field public static final String RESTART_WIFI_SUBSYSTEM = "android.permission.RESTART_WIFI_SUBSYSTEM";
field public static final String RESTORE_RUNTIME_PERMISSIONS = "android.permission.RESTORE_RUNTIME_PERMISSIONS";
field public static final String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
field public static final String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
@@ -1409,11 +1412,26 @@ package android.app.usage {
}
+package android.apphibernation {
+
+ public final class AppHibernationManager {
+ method public boolean isHibernating(@NonNull String);
+ method public void setHibernating(@NonNull String, boolean);
+ }
+
+}
+
package android.bluetooth {
public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
+ method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public android.bluetooth.BufferConstraints getBufferConstraints();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getDynamicBufferSupport();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setBufferMillis(int, int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1; // 0x1
+ field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2; // 0x2
+ field public static final int DYNAMIC_BUFFER_SUPPORT_NONE = 0; // 0x0
field public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0; // 0x0
field public static final int OPTIONAL_CODECS_PREF_DISABLED = 0; // 0x0
field public static final int OPTIONAL_CODECS_PREF_ENABLED = 1; // 0x1
@@ -1595,6 +1613,25 @@ package android.bluetooth {
field public static final int UUID_BYTES_32_BIT = 4; // 0x4
}
+ public final class BufferConstraint implements android.os.Parcelable {
+ ctor public BufferConstraint(int, int, int);
+ method public int describeContents();
+ method public int getDefaultMillis();
+ method public int getMaxMillis();
+ method public int getMinMillis();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BufferConstraint> CREATOR;
+ }
+
+ public final class BufferConstraints implements android.os.Parcelable {
+ ctor public BufferConstraints(@NonNull java.util.List<android.bluetooth.BufferConstraint>);
+ method public int describeContents();
+ method @Nullable public android.bluetooth.BufferConstraint getCodec(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int BUFFER_CODEC_MAX_NUM = 32; // 0x20
+ field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BufferConstraints> CREATOR;
+ }
+
}
package android.bluetooth.le {
@@ -1680,11 +1717,11 @@ package android.content {
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle);
method public abstract void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle);
+ field public static final String APP_HIBERNATION_SERVICE = "app_hibernation";
field public static final String APP_INTEGRITY_SERVICE = "app_integrity";
field public static final String APP_PREDICTION_SERVICE = "app_prediction";
field public static final String BACKUP_SERVICE = "backup";
field public static final String BATTERY_STATS_SERVICE = "batterystats";
- field public static final String BUGREPORT_SERVICE = "bugreport";
field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
field public static final String CONTEXTHUB_SERVICE = "contexthub";
field public static final String ETHERNET_SERVICE = "ethernet";
@@ -5994,6 +6031,7 @@ package android.net {
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
+ method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull android.net.QosCallback, @NonNull java.util.concurrent.Executor);
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
@@ -6003,6 +6041,7 @@ package android.net {
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
+ method public void unregisterQosCallback(@NonNull android.net.QosCallback);
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
@@ -6092,15 +6131,11 @@ package android.net {
}
public final class IpSecManager {
- method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
}
public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
- method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
- method public void close();
method @NonNull public String getInterfaceName();
- method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
}
public static class IpSecTransform.Builder {
@@ -6196,6 +6231,8 @@ package android.net {
method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
method public void onAutomaticReconnectDisabled();
method public void onNetworkUnwanted();
+ method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
+ method public void onQosCallbackUnregistered(int);
method public void onRemoveKeepalivePacketFilter(int);
method public void onSaveAcceptUnvalidated(boolean);
method public void onSignalStrengthThresholdsUpdated(@NonNull int[]);
@@ -6206,6 +6243,9 @@ package android.net {
method public final void sendLinkProperties(@NonNull android.net.LinkProperties);
method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
+ method public final void sendQosCallbackError(int, int);
+ method public final void sendQosSessionAvailable(int, int, @NonNull android.telephony.data.EpsBearerQosSessionAttributes);
+ method public final void sendQosSessionLost(int, int);
method public final void sendSocketKeepaliveEvent(int, int);
method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
method public void unregister();
@@ -6235,6 +6275,7 @@ package android.net {
}
public final class NetworkCapabilities implements android.os.Parcelable {
+ ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, boolean);
method @NonNull public int[] getAdministratorUids();
method @Nullable public String getSsid();
method @NonNull public int[] getTransportTypes();
@@ -6291,6 +6332,9 @@ package android.net {
method public abstract void onRequestScores(android.net.NetworkKey[]);
}
+ public class NetworkReleasedException extends java.lang.Exception {
+ }
+
public class NetworkRequest implements android.os.Parcelable {
method @Nullable public String getRequestorPackageName();
method public int getRequestorUid();
@@ -6363,6 +6407,47 @@ package android.net {
ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long);
}
+ public abstract class QosCallback {
+ ctor public QosCallback();
+ method public void onError(@NonNull android.net.QosCallbackException);
+ method public void onQosSessionAvailable(@NonNull android.net.QosSession, @NonNull android.net.QosSessionAttributes);
+ method public void onQosSessionLost(@NonNull android.net.QosSession);
+ }
+
+ public static class QosCallback.QosCallbackRegistrationException extends java.lang.RuntimeException {
+ }
+
+ public final class QosCallbackException extends java.lang.Exception {
+ }
+
+ public abstract class QosFilter {
+ method @NonNull public abstract android.net.Network getNetwork();
+ method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int);
+ }
+
+ public final class QosSession implements android.os.Parcelable {
+ ctor public QosSession(int, int);
+ method public int describeContents();
+ method public int getSessionId();
+ method public int getSessionType();
+ method public long getUniqueId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
+ field public static final int TYPE_EPS_BEARER = 1; // 0x1
+ }
+
+ public interface QosSessionAttributes {
+ }
+
+ public final class QosSocketInfo implements android.os.Parcelable {
+ ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.Socket) throws java.io.IOException;
+ method public int describeContents();
+ method @NonNull public java.net.InetSocketAddress getLocalSocketAddress();
+ method @NonNull public android.net.Network getNetwork();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR;
+ }
+
public final class RouteInfo implements android.os.Parcelable {
ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
@@ -6408,6 +6493,12 @@ package android.net {
field public static final int SUCCESS = 0; // 0x0
}
+ public class SocketLocalAddressChangedException extends java.lang.Exception {
+ }
+
+ public class SocketNotBoundException extends java.lang.Exception {
+ }
+
public final class StaticIpConfiguration implements android.os.Parcelable {
ctor public StaticIpConfiguration();
ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
@@ -6457,6 +6548,11 @@ package android.net {
field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = -256; // 0xffffff00
}
+ public interface TransportInfo {
+ method public default boolean hasLocationSensitiveFields();
+ method @NonNull public default android.net.TransportInfo makeCopy(boolean);
+ }
+
public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable {
method @NonNull public String toSafeString();
}
@@ -6499,157 +6595,157 @@ package android.net.apf {
package android.net.metrics {
- public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
- }
-
- public static final class ApfProgramEvent.Builder {
- ctor public ApfProgramEvent.Builder();
- method @NonNull public android.net.metrics.ApfProgramEvent build();
- method @NonNull public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long);
- method @NonNull public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int);
- method @NonNull public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int);
- method @NonNull public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean);
- method @NonNull public android.net.metrics.ApfProgramEvent.Builder setLifetime(long);
- method @NonNull public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int);
- }
-
- public final class ApfStats implements android.net.metrics.IpConnectivityLog.Event {
- }
-
- public static final class ApfStats.Builder {
- ctor public ApfStats.Builder();
- method @NonNull public android.net.metrics.ApfStats build();
- method @NonNull public android.net.metrics.ApfStats.Builder setDroppedRas(int);
- method @NonNull public android.net.metrics.ApfStats.Builder setDurationMs(long);
- method @NonNull public android.net.metrics.ApfStats.Builder setMatchingRas(int);
- method @NonNull public android.net.metrics.ApfStats.Builder setMaxProgramSize(int);
- method @NonNull public android.net.metrics.ApfStats.Builder setParseErrors(int);
- method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdates(int);
- method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int);
- method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int);
- method @NonNull public android.net.metrics.ApfStats.Builder setReceivedRas(int);
- method @NonNull public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int);
- }
-
- public final class DhcpClientEvent implements android.net.metrics.IpConnectivityLog.Event {
- }
-
- public static final class DhcpClientEvent.Builder {
- ctor public DhcpClientEvent.Builder();
- method @NonNull public android.net.metrics.DhcpClientEvent build();
- method @NonNull public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int);
- method @NonNull public android.net.metrics.DhcpClientEvent.Builder setMsg(String);
- }
-
- public final class DhcpErrorEvent implements android.net.metrics.IpConnectivityLog.Event {
- ctor public DhcpErrorEvent(int);
- method public static int errorCodeWithOption(int, int);
- field public static final int BOOTP_TOO_SHORT = 67174400; // 0x4010000
- field public static final int BUFFER_UNDERFLOW = 83951616; // 0x5010000
- field public static final int DHCP_BAD_MAGIC_COOKIE = 67239936; // 0x4020000
- field public static final int DHCP_ERROR = 4; // 0x4
- field public static final int DHCP_INVALID_OPTION_LENGTH = 67305472; // 0x4030000
- field public static final int DHCP_NO_COOKIE = 67502080; // 0x4060000
- field public static final int DHCP_NO_MSG_TYPE = 67371008; // 0x4040000
- field public static final int DHCP_UNKNOWN_MSG_TYPE = 67436544; // 0x4050000
- field public static final int L2_ERROR = 1; // 0x1
- field public static final int L2_TOO_SHORT = 16842752; // 0x1010000
- field public static final int L2_WRONG_ETH_TYPE = 16908288; // 0x1020000
- field public static final int L3_ERROR = 2; // 0x2
- field public static final int L3_INVALID_IP = 33751040; // 0x2030000
- field public static final int L3_NOT_IPV4 = 33685504; // 0x2020000
- field public static final int L3_TOO_SHORT = 33619968; // 0x2010000
- field public static final int L4_ERROR = 3; // 0x3
- field public static final int L4_NOT_UDP = 50397184; // 0x3010000
- field public static final int L4_WRONG_PORT = 50462720; // 0x3020000
- field public static final int MISC_ERROR = 5; // 0x5
- field public static final int PARSING_ERROR = 84082688; // 0x5030000
- field public static final int RECEIVE_ERROR = 84017152; // 0x5020000
- }
-
- public class IpConnectivityLog {
- ctor public IpConnectivityLog();
- method public boolean log(long, @NonNull android.net.metrics.IpConnectivityLog.Event);
- method public boolean log(@NonNull String, @NonNull android.net.metrics.IpConnectivityLog.Event);
- method public boolean log(@NonNull android.net.Network, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
- method public boolean log(int, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
- method public boolean log(@NonNull android.net.metrics.IpConnectivityLog.Event);
- }
-
- public static interface IpConnectivityLog.Event extends android.os.Parcelable {
- }
-
- public final class IpManagerEvent implements android.net.metrics.IpConnectivityLog.Event {
- ctor public IpManagerEvent(int, long);
- field public static final int COMPLETE_LIFECYCLE = 3; // 0x3
- field public static final int ERROR_INTERFACE_NOT_FOUND = 8; // 0x8
- field public static final int ERROR_INVALID_PROVISIONING = 7; // 0x7
- field public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6; // 0x6
- field public static final int ERROR_STARTING_IPV4 = 4; // 0x4
- field public static final int ERROR_STARTING_IPV6 = 5; // 0x5
- field public static final int PROVISIONING_FAIL = 2; // 0x2
- field public static final int PROVISIONING_OK = 1; // 0x1
- }
-
- public final class IpReachabilityEvent implements android.net.metrics.IpConnectivityLog.Event {
- ctor public IpReachabilityEvent(int);
- field public static final int NUD_FAILED = 512; // 0x200
- field public static final int NUD_FAILED_ORGANIC = 1024; // 0x400
- field public static final int PROBE = 256; // 0x100
- field public static final int PROVISIONING_LOST = 768; // 0x300
- field public static final int PROVISIONING_LOST_ORGANIC = 1280; // 0x500
- }
-
- public final class NetworkEvent implements android.net.metrics.IpConnectivityLog.Event {
- ctor public NetworkEvent(int, long);
- ctor public NetworkEvent(int);
- field public static final int NETWORK_CAPTIVE_PORTAL_FOUND = 4; // 0x4
- field public static final int NETWORK_CONNECTED = 1; // 0x1
- field public static final int NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND = 12; // 0xc
- field public static final int NETWORK_DISCONNECTED = 7; // 0x7
- field public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10; // 0xa
- field public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8; // 0x8
- field public static final int NETWORK_LINGER = 5; // 0x5
- field public static final int NETWORK_PARTIAL_CONNECTIVITY = 13; // 0xd
- field public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11; // 0xb
- field public static final int NETWORK_REVALIDATION_SUCCESS = 9; // 0x9
- field public static final int NETWORK_UNLINGER = 6; // 0x6
- field public static final int NETWORK_VALIDATED = 2; // 0x2
- field public static final int NETWORK_VALIDATION_FAILED = 3; // 0x3
- }
-
- public final class RaEvent implements android.net.metrics.IpConnectivityLog.Event {
- }
-
- public static final class RaEvent.Builder {
- ctor public RaEvent.Builder();
- method @NonNull public android.net.metrics.RaEvent build();
- method @NonNull public android.net.metrics.RaEvent.Builder updateDnsslLifetime(long);
- method @NonNull public android.net.metrics.RaEvent.Builder updatePrefixPreferredLifetime(long);
- method @NonNull public android.net.metrics.RaEvent.Builder updatePrefixValidLifetime(long);
- method @NonNull public android.net.metrics.RaEvent.Builder updateRdnssLifetime(long);
- method @NonNull public android.net.metrics.RaEvent.Builder updateRouteInfoLifetime(long);
- method @NonNull public android.net.metrics.RaEvent.Builder updateRouterLifetime(long);
- }
-
- public final class ValidationProbeEvent implements android.net.metrics.IpConnectivityLog.Event {
- method @NonNull public static String getProbeName(int);
- field public static final int DNS_FAILURE = 0; // 0x0
- field public static final int DNS_SUCCESS = 1; // 0x1
- field public static final int PROBE_DNS = 0; // 0x0
- field public static final int PROBE_FALLBACK = 4; // 0x4
- field public static final int PROBE_HTTP = 1; // 0x1
- field public static final int PROBE_HTTPS = 2; // 0x2
- field public static final int PROBE_PAC = 3; // 0x3
- field public static final int PROBE_PRIVDNS = 5; // 0x5
- }
-
- public static final class ValidationProbeEvent.Builder {
- ctor public ValidationProbeEvent.Builder();
- method @NonNull public android.net.metrics.ValidationProbeEvent build();
- method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long);
- method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean);
- method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int);
+ @Deprecated public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
+ }
+
+ @Deprecated public static final class ApfProgramEvent.Builder {
+ ctor @Deprecated public ApfProgramEvent.Builder();
+ method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent build();
+ method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long);
+ method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int);
+ method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int);
+ method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean);
+ method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setLifetime(long);
+ method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int);
+ }
+
+ @Deprecated public final class ApfStats implements android.net.metrics.IpConnectivityLog.Event {
+ }
+
+ @Deprecated public static final class ApfStats.Builder {
+ ctor @Deprecated public ApfStats.Builder();
+ method @Deprecated @NonNull public android.net.metrics.ApfStats build();
+ method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setDroppedRas(int);
+ method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setDurationMs(long);
+ method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setMatchingRas(int);
+ method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setMaxProgramSize(int);
+ method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setParseErrors(int);
+ method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdates(int);
+ method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int);
+ method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int);
+ method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setReceivedRas(int);
+ method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int);
+ }
+
+ @Deprecated public final class DhcpClientEvent implements android.net.metrics.IpConnectivityLog.Event {
+ }
+
+ @Deprecated public static final class DhcpClientEvent.Builder {
+ ctor @Deprecated public DhcpClientEvent.Builder();
+ method @Deprecated @NonNull public android.net.metrics.DhcpClientEvent build();
+ method @Deprecated @NonNull public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int);
+ method @Deprecated @NonNull public android.net.metrics.DhcpClientEvent.Builder setMsg(String);
+ }
+
+ @Deprecated public final class DhcpErrorEvent implements android.net.metrics.IpConnectivityLog.Event {
+ ctor @Deprecated public DhcpErrorEvent(int);
+ method @Deprecated public static int errorCodeWithOption(int, int);
+ field @Deprecated public static final int BOOTP_TOO_SHORT = 67174400; // 0x4010000
+ field @Deprecated public static final int BUFFER_UNDERFLOW = 83951616; // 0x5010000
+ field @Deprecated public static final int DHCP_BAD_MAGIC_COOKIE = 67239936; // 0x4020000
+ field @Deprecated public static final int DHCP_ERROR = 4; // 0x4
+ field @Deprecated public static final int DHCP_INVALID_OPTION_LENGTH = 67305472; // 0x4030000
+ field @Deprecated public static final int DHCP_NO_COOKIE = 67502080; // 0x4060000
+ field @Deprecated public static final int DHCP_NO_MSG_TYPE = 67371008; // 0x4040000
+ field @Deprecated public static final int DHCP_UNKNOWN_MSG_TYPE = 67436544; // 0x4050000
+ field @Deprecated public static final int L2_ERROR = 1; // 0x1
+ field @Deprecated public static final int L2_TOO_SHORT = 16842752; // 0x1010000
+ field @Deprecated public static final int L2_WRONG_ETH_TYPE = 16908288; // 0x1020000
+ field @Deprecated public static final int L3_ERROR = 2; // 0x2
+ field @Deprecated public static final int L3_INVALID_IP = 33751040; // 0x2030000
+ field @Deprecated public static final int L3_NOT_IPV4 = 33685504; // 0x2020000
+ field @Deprecated public static final int L3_TOO_SHORT = 33619968; // 0x2010000
+ field @Deprecated public static final int L4_ERROR = 3; // 0x3
+ field @Deprecated public static final int L4_NOT_UDP = 50397184; // 0x3010000
+ field @Deprecated public static final int L4_WRONG_PORT = 50462720; // 0x3020000
+ field @Deprecated public static final int MISC_ERROR = 5; // 0x5
+ field @Deprecated public static final int PARSING_ERROR = 84082688; // 0x5030000
+ field @Deprecated public static final int RECEIVE_ERROR = 84017152; // 0x5020000
+ }
+
+ @Deprecated public class IpConnectivityLog {
+ ctor @Deprecated public IpConnectivityLog();
+ method @Deprecated public boolean log(long, @NonNull android.net.metrics.IpConnectivityLog.Event);
+ method @Deprecated public boolean log(@NonNull String, @NonNull android.net.metrics.IpConnectivityLog.Event);
+ method @Deprecated public boolean log(@NonNull android.net.Network, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
+ method @Deprecated public boolean log(int, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
+ method @Deprecated public boolean log(@NonNull android.net.metrics.IpConnectivityLog.Event);
+ }
+
+ @Deprecated public static interface IpConnectivityLog.Event extends android.os.Parcelable {
+ }
+
+ @Deprecated public final class IpManagerEvent implements android.net.metrics.IpConnectivityLog.Event {
+ ctor @Deprecated public IpManagerEvent(int, long);
+ field @Deprecated public static final int COMPLETE_LIFECYCLE = 3; // 0x3
+ field @Deprecated public static final int ERROR_INTERFACE_NOT_FOUND = 8; // 0x8
+ field @Deprecated public static final int ERROR_INVALID_PROVISIONING = 7; // 0x7
+ field @Deprecated public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6; // 0x6
+ field @Deprecated public static final int ERROR_STARTING_IPV4 = 4; // 0x4
+ field @Deprecated public static final int ERROR_STARTING_IPV6 = 5; // 0x5
+ field @Deprecated public static final int PROVISIONING_FAIL = 2; // 0x2
+ field @Deprecated public static final int PROVISIONING_OK = 1; // 0x1
+ }
+
+ @Deprecated public final class IpReachabilityEvent implements android.net.metrics.IpConnectivityLog.Event {
+ ctor @Deprecated public IpReachabilityEvent(int);
+ field @Deprecated public static final int NUD_FAILED = 512; // 0x200
+ field @Deprecated public static final int NUD_FAILED_ORGANIC = 1024; // 0x400
+ field @Deprecated public static final int PROBE = 256; // 0x100
+ field @Deprecated public static final int PROVISIONING_LOST = 768; // 0x300
+ field @Deprecated public static final int PROVISIONING_LOST_ORGANIC = 1280; // 0x500
+ }
+
+ @Deprecated public final class NetworkEvent implements android.net.metrics.IpConnectivityLog.Event {
+ ctor @Deprecated public NetworkEvent(int, long);
+ ctor @Deprecated public NetworkEvent(int);
+ field @Deprecated public static final int NETWORK_CAPTIVE_PORTAL_FOUND = 4; // 0x4
+ field @Deprecated public static final int NETWORK_CONNECTED = 1; // 0x1
+ field @Deprecated public static final int NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND = 12; // 0xc
+ field @Deprecated public static final int NETWORK_DISCONNECTED = 7; // 0x7
+ field @Deprecated public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10; // 0xa
+ field @Deprecated public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8; // 0x8
+ field @Deprecated public static final int NETWORK_LINGER = 5; // 0x5
+ field @Deprecated public static final int NETWORK_PARTIAL_CONNECTIVITY = 13; // 0xd
+ field @Deprecated public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11; // 0xb
+ field @Deprecated public static final int NETWORK_REVALIDATION_SUCCESS = 9; // 0x9
+ field @Deprecated public static final int NETWORK_UNLINGER = 6; // 0x6
+ field @Deprecated public static final int NETWORK_VALIDATED = 2; // 0x2
+ field @Deprecated public static final int NETWORK_VALIDATION_FAILED = 3; // 0x3
+ }
+
+ @Deprecated public final class RaEvent implements android.net.metrics.IpConnectivityLog.Event {
+ }
+
+ @Deprecated public static final class RaEvent.Builder {
+ ctor @Deprecated public RaEvent.Builder();
+ method @Deprecated @NonNull public android.net.metrics.RaEvent build();
+ method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updateDnsslLifetime(long);
+ method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updatePrefixPreferredLifetime(long);
+ method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updatePrefixValidLifetime(long);
+ method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updateRdnssLifetime(long);
+ method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updateRouteInfoLifetime(long);
+ method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updateRouterLifetime(long);
+ }
+
+ @Deprecated public final class ValidationProbeEvent implements android.net.metrics.IpConnectivityLog.Event {
+ method @Deprecated @NonNull public static String getProbeName(int);
+ field @Deprecated public static final int DNS_FAILURE = 0; // 0x0
+ field @Deprecated public static final int DNS_SUCCESS = 1; // 0x1
+ field @Deprecated public static final int PROBE_DNS = 0; // 0x0
+ field @Deprecated public static final int PROBE_FALLBACK = 4; // 0x4
+ field @Deprecated public static final int PROBE_HTTP = 1; // 0x1
+ field @Deprecated public static final int PROBE_HTTPS = 2; // 0x2
+ field @Deprecated public static final int PROBE_PAC = 3; // 0x3
+ field @Deprecated public static final int PROBE_PRIVDNS = 5; // 0x5
+ }
+
+ @Deprecated public static final class ValidationProbeEvent.Builder {
+ ctor @Deprecated public ValidationProbeEvent.Builder();
+ method @Deprecated @NonNull public android.net.metrics.ValidationProbeEvent build();
+ method @Deprecated @NonNull public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long);
+ method @Deprecated @NonNull public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean);
+ method @Deprecated @NonNull public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int);
}
}
@@ -6920,7 +7016,10 @@ package android.nfc {
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush();
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isAlwaysOnEnabled();
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isAlwaysOnSupported();
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setAlwaysOn(boolean);
method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
}
@@ -7040,24 +7139,10 @@ package android.os {
}
public final class BugreportManager {
- method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport();
method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.BugreportParams, @Nullable CharSequence, @Nullable CharSequence);
method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
}
- public abstract static class BugreportManager.BugreportCallback {
- ctor public BugreportManager.BugreportCallback();
- method public void onEarlyReportFinished();
- method public void onError(int);
- method public void onFinished();
- method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float);
- field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5
- field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1
- field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2
- field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4
- field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3
- }
-
public final class BugreportParams {
ctor public BugreportParams(int);
method public int getMode();
@@ -7510,11 +7595,13 @@ package android.os {
}
public class UserManager {
+ method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean canHaveRestrictedProfile();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void clearSeedAccountData();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle createProfile(@NonNull String, @NonNull String, @NonNull java.util.Set<java.lang.String>) throws android.os.UserManager.UserOperationException;
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getAllProfiles();
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getEnabledProfiles();
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
+ method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle getRestrictedProfileParent();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountName();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.PersistableBundle getSeedAccountOptions();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountType();
@@ -8984,6 +9071,18 @@ package android.service.resolver {
}
+package android.service.resumeonreboot {
+
+ public abstract class ResumeOnRebootService extends android.app.Service {
+ ctor public ResumeOnRebootService();
+ method @Nullable public android.os.IBinder onBind(@Nullable android.content.Intent);
+ method @NonNull public abstract byte[] onUnwrap(@NonNull byte[]) throws java.io.IOException;
+ method @NonNull public abstract byte[] onWrap(@NonNull byte[], long) throws java.io.IOException;
+ field public static final String SERVICE_INTERFACE = "android.service.resumeonreboot.ResumeOnRebootService";
+ }
+
+}
+
package android.service.settings.suggestions {
public final class Suggestion implements android.os.Parcelable {
@@ -9805,17 +9904,87 @@ package android.telephony {
method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
method @Deprecated public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber);
method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber, int);
- method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
method public void onRadioPowerStateChanged(int);
method public void onSrvccStateChanged(int);
method public void onVoiceActivationStateChanged(int);
- field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000
- field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000
- field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000
- field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800
- field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000
- field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000
- field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000
+ field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED = 23; // 0x17
+ field @RequiresPermission("android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH") public static final int EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED = 10; // 0xa
+ field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_BARRING_INFO_CHANGED = 32; // 0x20
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_ATTRIBUTES_CHANGED = 27; // 0x1b
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_DISCONNECT_CAUSE_CHANGED = 26; // 0x1a
+ field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4; // 0x4
+ field @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public static final int EVENT_CALL_STATE_CHANGED = 6; // 0x6
+ field public static final int EVENT_CARRIER_NETWORK_CHANGED = 17; // 0x11
+ field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_INFO_CHANGED = 11; // 0xb
+ field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_LOCATION_CHANGED = 5; // 0x5
+ field public static final int EVENT_DATA_ACTIVATION_STATE_CHANGED = 19; // 0x13
+ field public static final int EVENT_DATA_ACTIVITY_CHANGED = 8; // 0x8
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED = 14; // 0xe
+ field public static final int EVENT_DATA_CONNECTION_STATE_CHANGED = 7; // 0x7
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_DATA_ENABLED_CHANGED = 34; // 0x22
+ field public static final int EVENT_DISPLAY_INFO_CHANGED = 21; // 0x15
+ field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_EMERGENCY_NUMBER_LIST_CHANGED = 25; // 0x19
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = 28; // 0x1c
+ field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_MESSAGE_WAITING_INDICATOR_CHANGED = 3; // 0x3
+ field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_OEM_HOOK_RAW = 15; // 0xf
+ field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int EVENT_OUTGOING_EMERGENCY_CALL = 29; // 0x1d
+ field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int EVENT_OUTGOING_EMERGENCY_SMS = 30; // 0x1e
+ field public static final int EVENT_PHONE_CAPABILITY_CHANGED = 22; // 0x16
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 33; // 0x21
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PRECISE_CALL_STATE_CHANGED = 12; // 0xc
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED = 13; // 0xd
+ field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_RADIO_POWER_STATE_CHANGED = 24; // 0x18
+ field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_REGISTRATION_FAILURE = 31; // 0x1f
+ field public static final int EVENT_SERVICE_STATE_CHANGED = 1; // 0x1
+ field public static final int EVENT_SIGNAL_STRENGTHS_CHANGED = 9; // 0x9
+ field public static final int EVENT_SIGNAL_STRENGTH_CHANGED = 2; // 0x2
+ field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_SRVCC_STATE_CHANGED = 16; // 0x10
+ field public static final int EVENT_USER_MOBILE_DATA_STATE_CHANGED = 20; // 0x14
+ field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_VOICE_ACTIVATION_STATE_CHANGED = 18; // 0x12
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000
+ }
+
+ public static interface PhoneStateListener.CallAttributesChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
+ }
+
+ public static interface PhoneStateListener.DataEnabledChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onDataEnabledChanged(boolean, int);
+ }
+
+ public static interface PhoneStateListener.OutgoingEmergencyCallListener {
+ method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
+ }
+
+ public static interface PhoneStateListener.OutgoingEmergencySmsListener {
+ method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber, int);
+ }
+
+ public static interface PhoneStateListener.PhysicalChannelConfigChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPhysicalChannelConfigChanged(@NonNull java.util.List<android.telephony.PhysicalChannelConfig>);
+ }
+
+ public static interface PhoneStateListener.PreciseCallStateChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
+ }
+
+ public static interface PhoneStateListener.RadioPowerStateChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onRadioPowerStateChanged(int);
+ }
+
+ public static interface PhoneStateListener.SrvccStateChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onSrvccStateChanged(int);
+ }
+
+ public static interface PhoneStateListener.VoiceActivationStateChangedListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onVoiceActivationStateChanged(int);
}
public final class PinResult implements android.os.Parcelable {
@@ -10545,6 +10714,7 @@ package android.telephony.data {
method public int getPduSessionId();
method public int getProtocolType();
method public long getRetryDurationMillis();
+ method @Nullable public android.telephony.data.SliceInfo getSliceInfo();
method @Deprecated public int getSuggestedRetryTime();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR;
@@ -10579,6 +10749,7 @@ package android.telephony.data {
method @NonNull public android.telephony.data.DataCallResponse.Builder setPduSessionId(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryDurationMillis(long);
+ method @NonNull public android.telephony.data.DataCallResponse.Builder setSliceInfo(@Nullable android.telephony.data.SliceInfo);
method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int);
}
@@ -10651,7 +10822,7 @@ package android.telephony.data {
method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @NonNull android.telephony.data.DataServiceCallback);
method public void setInitialAttachApn(@NonNull android.telephony.data.DataProfile, boolean, @NonNull android.telephony.data.DataServiceCallback);
method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @NonNull android.telephony.data.DataServiceCallback);
- method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @IntRange(from=0, to=15) int, @NonNull android.telephony.data.DataServiceCallback);
+ method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @IntRange(from=0, to=15) int, @Nullable android.telephony.data.SliceInfo, @NonNull android.telephony.data.DataServiceCallback);
method public void startHandover(int, @NonNull android.telephony.data.DataServiceCallback);
}
@@ -10672,6 +10843,19 @@ package android.telephony.data {
field public static final int RESULT_SUCCESS = 0; // 0x0
}
+ public final class EpsBearerQosSessionAttributes implements android.os.Parcelable android.net.QosSessionAttributes {
+ method @NonNull public static android.telephony.data.EpsBearerQosSessionAttributes create(@NonNull android.os.Parcel);
+ method public int describeContents();
+ method public long getGuaranteedDownlinkBitRate();
+ method public long getGuaranteedUplinkBitRate();
+ method public long getMaxDownlinkBitRate();
+ method public long getMaxUplinkBitRate();
+ method public int getQci();
+ method @NonNull public java.util.List<java.net.InetSocketAddress> getRemoteAddresses();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.EpsBearerQosSessionAttributes> CREATOR;
+ }
+
public abstract class QualifiedNetworksService extends android.app.Service {
ctor public QualifiedNetworksService();
method @NonNull public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int);
@@ -10686,6 +10870,32 @@ package android.telephony.data {
method public final void updateQualifiedNetworkTypes(int, @NonNull java.util.List<java.lang.Integer>);
}
+ public final class SliceInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) public int getMappedHplmnSliceDifferentiator();
+ method public int getMappedHplmnSliceServiceType();
+ method @IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) public int getSliceDifferentiator();
+ method public int getSliceServiceType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.SliceInfo> CREATOR;
+ field public static final int MAX_SLICE_DIFFERENTIATOR = 16777214; // 0xfffffe
+ field public static final int MIN_SLICE_DIFFERENTIATOR = -1; // 0xffffffff
+ field public static final int SLICE_DIFFERENTIATOR_NO_SLICE = -1; // 0xffffffff
+ field public static final int SLICE_SERVICE_TYPE_EMBB = 1; // 0x1
+ field public static final int SLICE_SERVICE_TYPE_MIOT = 3; // 0x3
+ field public static final int SLICE_SERVICE_TYPE_NONE = 0; // 0x0
+ field public static final int SLICE_SERVICE_TYPE_URLLC = 2; // 0x2
+ }
+
+ public static final class SliceInfo.Builder {
+ ctor public SliceInfo.Builder();
+ method @NonNull public android.telephony.data.SliceInfo build();
+ method @NonNull public android.telephony.data.SliceInfo.Builder setMappedHplmnSliceDifferentiator(@IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) int);
+ method @NonNull public android.telephony.data.SliceInfo.Builder setMappedHplmnSliceServiceType(int);
+ method @NonNull public android.telephony.data.SliceInfo.Builder setSliceDifferentiator(@IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) int);
+ method @NonNull public android.telephony.data.SliceInfo.Builder setSliceServiceType(int);
+ }
+
}
package android.telephony.euicc {
@@ -10697,12 +10907,8 @@ package android.telephony.euicc {
public static final class DownloadableSubscription.Builder {
ctor public DownloadableSubscription.Builder();
- ctor public DownloadableSubscription.Builder(android.telephony.euicc.DownloadableSubscription);
- method public android.telephony.euicc.DownloadableSubscription build();
- method public android.telephony.euicc.DownloadableSubscription.Builder setAccessRules(java.util.List<android.telephony.UiccAccessRule>);
- method public android.telephony.euicc.DownloadableSubscription.Builder setCarrierName(String);
- method public android.telephony.euicc.DownloadableSubscription.Builder setConfirmationCode(String);
- method public android.telephony.euicc.DownloadableSubscription.Builder setEncodedActivationCode(String);
+ method @NonNull public android.telephony.euicc.DownloadableSubscription.Builder setAccessRules(@NonNull java.util.List<android.telephony.UiccAccessRule>);
+ method @NonNull public android.telephony.euicc.DownloadableSubscription.Builder setCarrierName(@NonNull String);
}
public class EuiccCardManager {
@@ -11572,11 +11778,100 @@ package android.telephony.ims {
field public static final String RCS_PROFILE_2_3 = "UP_2.3";
}
+ public final class RcsContactPresenceTuple implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.net.Uri getContactUri();
+ method @Nullable public android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities getServiceCapabilities();
+ method @Nullable public String getServiceDescription();
+ method @NonNull public String getServiceId();
+ method @NonNull public String getServiceVersion();
+ method @NonNull public String getStatus();
+ method @Nullable public String getTimestamp();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactPresenceTuple> CREATOR;
+ field public static final String SERVICE_ID_CALL_COMPOSER = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callcomposer";
+ field public static final String SERVICE_ID_CHATBOT = "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.chatbot";
+ field public static final String SERVICE_ID_CHATBOT_ROLE = "org.gsma.rcs.isbot";
+ field public static final String SERVICE_ID_CHATBOT_STANDALONE = " org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.chatbot.sa";
+ field public static final String SERVICE_ID_CHAT_V1 = "org.openmobilealliance:IM-session";
+ field public static final String SERVICE_ID_CHAT_V2 = "org.openmobilealliance:ChatSession";
+ field public static final String SERVICE_ID_FT = "org.openmobilealliance:File-Transfer-HTTP";
+ field public static final String SERVICE_ID_FT_OVER_SMS = "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.ftsms";
+ field public static final String SERVICE_ID_GEO_PUSH = "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.geopush";
+ field public static final String SERVICE_ID_GEO_PUSH_VIA_SMS = "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.geosms";
+ field public static final String SERVICE_ID_MMTEL = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.mmtel";
+ field public static final String SERVICE_ID_POST_CALL = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callunanswered";
+ field public static final String SERVICE_ID_SHARED_MAP = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.sharedmap";
+ field public static final String SERVICE_ID_SHARED_SKETCH = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.sharedsketch";
+ field public static final String TUPLE_BASIC_STATUS_CLOSED = "closed";
+ field public static final String TUPLE_BASIC_STATUS_OPEN = "open";
+ }
+
+ public static final class RcsContactPresenceTuple.Builder {
+ ctor public RcsContactPresenceTuple.Builder(@NonNull String, @NonNull String, @NonNull String);
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple build();
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setContactUri(@NonNull android.net.Uri);
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setServiceCapabilities(@NonNull android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities);
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setServiceDescription(@NonNull String);
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setTimestamp(@NonNull String);
+ }
+
+ public static final class RcsContactPresenceTuple.ServiceCapabilities implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.List<java.lang.String> getSupportedDuplexModes();
+ method @NonNull public java.util.List<java.lang.String> getUnsupportedDuplexModes();
+ method public boolean isAudioCapable();
+ method public boolean isVideoCapable();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities> CREATOR;
+ field public static final String DUPLEX_MODE_FULL = "full";
+ field public static final String DUPLEX_MODE_HALF = "half";
+ field public static final String DUPLEX_MODE_RECEIVE_ONLY = "receive-only";
+ field public static final String DUPLEX_MODE_SEND_ONLY = "send-only";
+ }
+
+ public static final class RcsContactPresenceTuple.ServiceCapabilities.Builder {
+ ctor public RcsContactPresenceTuple.ServiceCapabilities.Builder(boolean, boolean);
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities.Builder addSupportedDuplexMode(@NonNull String);
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities.Builder addUnsupportedDuplexMode(@NonNull String);
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities build();
+ }
+
+ public final class RcsContactUceCapability implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getCapabilityMechanism();
+ method @Nullable public android.telephony.ims.RcsContactPresenceTuple getCapabilityTuple(@NonNull String);
+ method @NonNull public java.util.List<android.telephony.ims.RcsContactPresenceTuple> getCapabilityTuples();
+ method @NonNull public android.net.Uri getContactUri();
+ method public int getRequestResult();
+ method public int getSourceType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CAPABILITY_MECHANISM_OPTIONS = 2; // 0x2
+ field public static final int CAPABILITY_MECHANISM_PRESENCE = 1; // 0x1
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactUceCapability> CREATOR;
+ field public static final int REQUEST_RESULT_FOUND = 3; // 0x3
+ field public static final int REQUEST_RESULT_NOT_FOUND = 2; // 0x2
+ field public static final int REQUEST_RESULT_NOT_ONLINE = 1; // 0x1
+ field public static final int REQUEST_RESULT_UNKNOWN = 0; // 0x0
+ field public static final int SOURCE_TYPE_CACHED = 1; // 0x1
+ field public static final int SOURCE_TYPE_NETWORK = 0; // 0x0
+ }
+
+ public static final class RcsContactUceCapability.PresenceBuilder {
+ ctor public RcsContactUceCapability.PresenceBuilder(@NonNull android.net.Uri, int, int);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability.PresenceBuilder addCapabilityTuple(@NonNull android.telephony.ims.RcsContactPresenceTuple);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability.PresenceBuilder addCapabilityTuples(@NonNull java.util.List<android.telephony.ims.RcsContactPresenceTuple>);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability build();
+ }
+
public class RcsUceAdapter {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addOnPublishStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.OnPublishStateChangedListener) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getUcePublishState() throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeOnPublishStateChangedListener(@NonNull android.telephony.ims.RcsUceAdapter.OnPublishStateChangedListener) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestAvailability(@NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
+ field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 1; // 0x1
field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 7; // 0x7
field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 6; // 0x6
@@ -11589,6 +11884,18 @@ package android.telephony.ims {
field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; // 0xb
field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 8; // 0x8
field public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 0; // 0x0
+ field public static final int ERROR_FORBIDDEN = 6; // 0x6
+ field public static final int ERROR_GENERIC_FAILURE = 1; // 0x1
+ field public static final int ERROR_INSUFFICIENT_MEMORY = 10; // 0xa
+ field public static final int ERROR_LOST_NETWORK = 11; // 0xb
+ field public static final int ERROR_NOT_AUTHORIZED = 5; // 0x5
+ field public static final int ERROR_NOT_AVAILABLE = 3; // 0x3
+ field public static final int ERROR_NOT_ENABLED = 2; // 0x2
+ field public static final int ERROR_NOT_FOUND = 7; // 0x7
+ field public static final int ERROR_NOT_REGISTERED = 4; // 0x4
+ field public static final int ERROR_REQUEST_TIMEOUT = 9; // 0x9
+ field public static final int ERROR_REQUEST_TOO_LARGE = 8; // 0x8
+ field public static final int ERROR_SERVER_UNAVAILABLE = 12; // 0xc
field public static final int PUBLISH_STATE_NOT_PUBLISHED = 2; // 0x2
field public static final int PUBLISH_STATE_OK = 1; // 0x1
field public static final int PUBLISH_STATE_OTHER_ERROR = 6; // 0x6
@@ -11597,6 +11904,12 @@ package android.telephony.ims {
field public static final int PUBLISH_STATE_VOICE_PROVISION_ERROR = 3; // 0x3
}
+ public static interface RcsUceAdapter.CapabilitiesCallback {
+ method public void onCapabilitiesReceived(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>);
+ method public void onComplete();
+ method public void onError(int, long);
+ }
+
public static interface RcsUceAdapter.OnPublishStateChangedListener {
method public void onPublishStateChange(int);
}
@@ -11718,6 +12031,7 @@ package android.telephony.ims {
ctor public SipMessage(@NonNull String, @NonNull String, @NonNull byte[]);
method public int describeContents();
method @NonNull public byte[] getContent();
+ method @NonNull public byte[] getEncodedMessage();
method @NonNull public String getHeaderSection();
method @NonNull public String getStartLine();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -12006,6 +12320,7 @@ package android.telephony.ims.stub {
public class RcsCapabilityExchangeImplBase {
ctor public RcsCapabilityExchangeImplBase(@NonNull java.util.concurrent.Executor);
method public void publishCapabilities(@NonNull String, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.PublishResponseCallback);
+ method public void subscribeForCapabilities(@NonNull java.util.List<android.net.Uri>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.SubscribeResponseCallback);
field public static final int COMMAND_CODE_FETCH_ERROR = 3; // 0x3
field public static final int COMMAND_CODE_GENERIC_FAILURE = 1; // 0x1
field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 5; // 0x5
@@ -12024,6 +12339,14 @@ package android.telephony.ims.stub {
method public void onNetworkResponse(@IntRange(from=100, to=699) int, @NonNull String) throws android.telephony.ims.ImsException;
}
+ public static interface RcsCapabilityExchangeImplBase.SubscribeResponseCallback {
+ method public void onCommandError(int) throws android.telephony.ims.ImsException;
+ method public void onNetworkResponse(@IntRange(from=100, to=699) int, @NonNull String) throws android.telephony.ims.ImsException;
+ method public void onNotifyCapabilitiesUpdate(@NonNull java.util.List<java.lang.String>) throws android.telephony.ims.ImsException;
+ method public void onResourceTerminated(@NonNull java.util.List<android.util.Pair<android.net.Uri,java.lang.String>>) throws android.telephony.ims.ImsException;
+ method public void onTerminated(@NonNull String, long) throws android.telephony.ims.ImsException;
+ }
+
public interface SipDelegate {
method public void closeDialog(@NonNull String);
method public void notifyMessageReceiveError(@NonNull String, int);
@@ -12155,6 +12478,164 @@ package android.util {
}
+package android.uwb {
+
+ public final class AngleMeasurement implements android.os.Parcelable {
+ method public int describeContents();
+ method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel();
+ method @FloatRange(from=0.0, to=3.141592653589793) public double getErrorRadians();
+ method @FloatRange(from=-3.141592653589793, to=3.141592653589793) public double getRadians();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.uwb.AngleMeasurement> CREATOR;
+ }
+
+ public static final class AngleMeasurement.Builder {
+ ctor public AngleMeasurement.Builder();
+ method @NonNull public android.uwb.AngleMeasurement build();
+ method @NonNull public android.uwb.AngleMeasurement.Builder setConfidenceLevel(double);
+ method @NonNull public android.uwb.AngleMeasurement.Builder setErrorRadians(double);
+ method @NonNull public android.uwb.AngleMeasurement.Builder setRadians(double);
+ }
+
+ public final class AngleOfArrivalMeasurement implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.uwb.AngleMeasurement getAltitude();
+ method @NonNull public android.uwb.AngleMeasurement getAzimuth();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.uwb.AngleOfArrivalMeasurement> CREATOR;
+ }
+
+ public static final class AngleOfArrivalMeasurement.Builder {
+ ctor public AngleOfArrivalMeasurement.Builder();
+ method @NonNull public android.uwb.AngleOfArrivalMeasurement build();
+ method @NonNull public android.uwb.AngleOfArrivalMeasurement.Builder setAltitude(@NonNull android.uwb.AngleMeasurement);
+ method @NonNull public android.uwb.AngleOfArrivalMeasurement.Builder setAzimuth(@NonNull android.uwb.AngleMeasurement);
+ }
+
+ public final class DistanceMeasurement implements android.os.Parcelable {
+ method public int describeContents();
+ method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel();
+ method public double getErrorMeters();
+ method public double getMeters();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.uwb.DistanceMeasurement> CREATOR;
+ }
+
+ public static final class DistanceMeasurement.Builder {
+ ctor public DistanceMeasurement.Builder();
+ method @NonNull public android.uwb.DistanceMeasurement build();
+ method @NonNull public android.uwb.DistanceMeasurement.Builder setConfidenceLevel(double);
+ method @NonNull public android.uwb.DistanceMeasurement.Builder setErrorMeters(double);
+ method @NonNull public android.uwb.DistanceMeasurement.Builder setMeters(double);
+ }
+
+ public final class RangingMeasurement implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.uwb.AngleOfArrivalMeasurement getAngleOfArrivalMeasurement();
+ method @Nullable public android.uwb.DistanceMeasurement getDistanceMeasurement();
+ method public long getElapsedRealtimeNanos();
+ method @NonNull public android.uwb.UwbAddress getRemoteDeviceAddress();
+ method public int getStatus();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.uwb.RangingMeasurement> CREATOR;
+ field public static final int RANGING_STATUS_FAILURE_OUT_OF_RANGE = 1; // 0x1
+ field public static final int RANGING_STATUS_FAILURE_UNKNOWN_ERROR = -1; // 0xffffffff
+ field public static final int RANGING_STATUS_SUCCESS = 0; // 0x0
+ }
+
+ public static final class RangingMeasurement.Builder {
+ ctor public RangingMeasurement.Builder();
+ method @NonNull public android.uwb.RangingMeasurement build();
+ method @NonNull public android.uwb.RangingMeasurement.Builder setAngleOfArrivalMeasurement(@NonNull android.uwb.AngleOfArrivalMeasurement);
+ method @NonNull public android.uwb.RangingMeasurement.Builder setDistanceMeasurement(@NonNull android.uwb.DistanceMeasurement);
+ method @NonNull public android.uwb.RangingMeasurement.Builder setElapsedRealtimeNanos(long);
+ method @NonNull public android.uwb.RangingMeasurement.Builder setRemoteDeviceAddress(@NonNull android.uwb.UwbAddress);
+ method @NonNull public android.uwb.RangingMeasurement.Builder setStatus(int);
+ }
+
+ public final class RangingReport implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.List<android.uwb.RangingMeasurement> getMeasurements();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.uwb.RangingReport> CREATOR;
+ }
+
+ public static final class RangingReport.Builder {
+ ctor public RangingReport.Builder();
+ method @NonNull public android.uwb.RangingReport.Builder addMeasurement(@NonNull android.uwb.RangingMeasurement);
+ method @NonNull public android.uwb.RangingReport.Builder addMeasurements(@NonNull java.util.List<android.uwb.RangingMeasurement>);
+ method @NonNull public android.uwb.RangingReport build();
+ }
+
+ public final class RangingSession implements java.lang.AutoCloseable {
+ method public void close();
+ method public void reconfigure(@NonNull android.os.PersistableBundle);
+ method public void start(@NonNull android.os.PersistableBundle);
+ method public void stop();
+ }
+
+ public static interface RangingSession.Callback {
+ method public void onClosed(int, @NonNull android.os.PersistableBundle);
+ method public void onOpenFailed(int, @NonNull android.os.PersistableBundle);
+ method public void onOpened(@NonNull android.uwb.RangingSession);
+ method public void onReconfigureFailed(int, @NonNull android.os.PersistableBundle);
+ method public void onReconfigured(@NonNull android.os.PersistableBundle);
+ method public void onReportReceived(@NonNull android.uwb.RangingReport);
+ method public void onStartFailed(int, @NonNull android.os.PersistableBundle);
+ method public void onStarted(@NonNull android.os.PersistableBundle);
+ method public void onStopFailed(int, @NonNull android.os.PersistableBundle);
+ method public void onStopped();
+ field public static final int REASON_BAD_PARAMETERS = 3; // 0x3
+ field public static final int REASON_GENERIC_ERROR = 4; // 0x4
+ field public static final int REASON_LOCAL_REQUEST = 1; // 0x1
+ field public static final int REASON_MAX_SESSIONS_REACHED = 5; // 0x5
+ field public static final int REASON_PROTOCOL_SPECIFIC_ERROR = 7; // 0x7
+ field public static final int REASON_REMOTE_REQUEST = 2; // 0x2
+ field public static final int REASON_SYSTEM_POLICY = 6; // 0x6
+ field public static final int REASON_UNKNOWN = 0; // 0x0
+ }
+
+ public final class UwbAddress implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public static android.uwb.UwbAddress fromBytes(@NonNull byte[]);
+ method public int size();
+ method @NonNull public byte[] toBytes();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.uwb.UwbAddress> CREATOR;
+ field public static final int EXTENDED_ADDRESS_BYTE_LENGTH = 8; // 0x8
+ field public static final int SHORT_ADDRESS_BYTE_LENGTH = 2; // 0x2
+ }
+
+ public final class UwbManager {
+ method public long elapsedRealtimeResolutionNanos();
+ method public int getAngleOfArrivalSupport();
+ method public int getMaxRemoteDevicesPerInitiatorSession();
+ method public int getMaxRemoteDevicesPerResponderSession();
+ method public int getMaxSimultaneousSessions();
+ method @NonNull public android.os.PersistableBundle getSpecificationInfo();
+ method @NonNull public java.util.List<java.lang.Integer> getSupportedChannelNumbers();
+ method @NonNull public java.util.Set<java.lang.Integer> getSupportedPreambleCodeIndices();
+ method public boolean isRangingSupported();
+ method @NonNull public AutoCloseable openRangingSession(@NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull android.uwb.RangingSession.Callback);
+ method public void registerAdapterStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.uwb.UwbManager.AdapterStateCallback);
+ method public void unregisterAdapterStateCallback(@NonNull android.uwb.UwbManager.AdapterStateCallback);
+ field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D = 2; // 0x2
+ field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL = 3; // 0x3
+ field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL = 4; // 0x4
+ field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE = 1; // 0x1
+ }
+
+ public static interface UwbManager.AdapterStateCallback {
+ method public void onStateChanged(boolean, int);
+ field public static final int STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED = 1; // 0x1
+ field public static final int STATE_CHANGED_REASON_ERROR_UNKNOWN = 4; // 0x4
+ field public static final int STATE_CHANGED_REASON_SESSION_STARTED = 0; // 0x0
+ field public static final int STATE_CHANGED_REASON_SYSTEM_BOOT = 3; // 0x3
+ field public static final int STATE_CHANGED_REASON_SYSTEM_POLICY = 2; // 0x2
+ }
+
+}
+
package android.view {
public abstract class Window {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 9cf9ce45602b..546e72b8f834 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -980,10 +980,6 @@ package android.media.tv {
package android.net {
- public class ConnectivityManager {
- method @RequiresPermission(anyOf={"android.permission.MANAGE_TEST_NETWORKS", android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
- }
-
public class EthernetManager {
method public void setIncludeTestInterfaces(boolean);
}
@@ -992,31 +988,10 @@ package android.net {
field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
}
- public final class NetworkCapabilities implements android.os.Parcelable {
- method public int[] getCapabilities();
- field public static final int TRANSPORT_TEST = 7; // 0x7
- }
-
public class NetworkStack {
method public static void setServiceForTest(@Nullable android.os.IBinder);
}
- public final class TestNetworkInterface implements android.os.Parcelable {
- ctor public TestNetworkInterface(android.os.ParcelFileDescriptor, String);
- method public int describeContents();
- method public android.os.ParcelFileDescriptor getFileDescriptor();
- method public String getInterfaceName();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.TestNetworkInterface> CREATOR;
- }
-
- public class TestNetworkManager {
- method public android.net.TestNetworkInterface createTapInterface();
- method public android.net.TestNetworkInterface createTunInterface(@NonNull android.net.LinkAddress[]);
- method public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder);
- method public void teardownTestNetwork(@NonNull android.net.Network);
- }
-
public class TrafficStats {
method public static long getLoopbackRxBytes();
method public static long getLoopbackRxPackets();
@@ -1751,7 +1726,6 @@ package android.util {
method public static java.util.Map<java.lang.String,java.lang.String> getAllFeatureFlags();
method public static boolean isEnabled(android.content.Context, String);
method public static void setEnabled(android.content.Context, String, boolean);
- field public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
field public static final String FFLAG_OVERRIDE_PREFIX = "sys.fflag.override.";
field public static final String FFLAG_PREFIX = "sys.fflag.";
field public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
diff --git a/core/java/android/accessibilityservice/OWNERS b/core/java/android/accessibilityservice/OWNERS
index c6f42f719caa..a31cfae995b2 100644
--- a/core/java/android/accessibilityservice/OWNERS
+++ b/core/java/android/accessibilityservice/OWNERS
@@ -1,4 +1,4 @@
svetoslavganov@google.com
pweaver@google.com
rhedjao@google.com
-qasid@google.com
+ryanlwlin@google.com
diff --git a/core/java/android/annotation/RequiresFeature.java b/core/java/android/annotation/RequiresFeature.java
index fc93f03d76cf..08861d42be39 100644
--- a/core/java/android/annotation/RequiresFeature.java
+++ b/core/java/android/annotation/RequiresFeature.java
@@ -30,7 +30,6 @@ import java.lang.annotation.Target;
* Denotes that the annotated element requires one or more device features. This
* is used to auto-generate documentation.
*
- * @see PackageManager#hasSystemFeature(String)
* @hide
*/
@Retention(SOURCE)
@@ -38,8 +37,16 @@ import java.lang.annotation.Target;
public @interface RequiresFeature {
/**
* The name of the device feature that is required.
- *
- * @see PackageManager#hasSystemFeature(String)
*/
String value();
+
+ /**
+ * Defines the name of the method that should be called to check whether the feature is
+ * available, using the same signature format as javadoc. The feature checking method can have
+ * multiple parameters, but the feature name parameter must be of type String and must also be
+ * the first String-type parameter.
+ * <p>
+ * By default, the enforcement is {@link PackageManager#hasSystemFeature(String)}.
+ */
+ String enforcement() default("android.content.pm.PackageManager#hasSystemFeature");
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 602b835a03f8..12c9cd90222a 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1428,6 +1428,45 @@ class ContextImpl extends Context {
}
}
+ /**
+ * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
+ * Intent you are sending stays around after the broadcast is complete,
+ * so that others can quickly retrieve that data through the return
+ * value of {@link #registerReceiver(BroadcastReceiver, IntentFilter)}. In
+ * all other ways, this behaves the same as
+ * {@link #sendBroadcast(Intent)}.
+ *
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
+ * @param intent The Intent to broadcast; all receivers matching this
+ * Intent will receive the broadcast, and the Intent will be held to
+ * be re-broadcast to future receivers.
+ * @param options (optional) Additional sending options, generated from a
+ * {@link android.app.BroadcastOptions}.
+ *
+ * @see #sendBroadcast(Intent)
+ * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
+ */
+ @Override
+ @Deprecated
+ public void sendStickyBroadcast(@NonNull Intent intent, @Nullable Bundle options) {
+ warnIfCallingFromSystemProcess();
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ try {
+ intent.prepareToLeaveProcess(this);
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options,
+ false, true, getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
@Override
@Deprecated
public void sendStickyOrderedBroadcast(Intent intent,
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index be1681bc7cc6..66a832505ead 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -223,7 +223,7 @@ interface IActivityTaskManager {
*/
IBinder requestStartActivityPermissionToken(in IBinder delegatorToken);
- void releaseSomeActivities(in IApplicationThread app);
+ oneway void releaseSomeActivities(in IApplicationThread app);
Bitmap getTaskDescriptionIcon(in String filename, int userId);
void registerTaskStackListener(in ITaskStackListener listener);
void unregisterTaskStackListener(in ITaskStackListener listener);
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 6d79e2d3c166..e6aa7a77357c 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -42,11 +42,27 @@ per-file *AppOp* = file:/core/java/android/permission/OWNERS
# Multiuser
per-file *User* = file:/MULTIUSER_OWNERS
-# Notification
+# Notification, DND, Status bar
per-file *Notification* = file:/packages/SystemUI/OWNERS
+per-file *Zen* = file:/packages/SystemUI/OWNERS
+per-file *StatusBar* = file:/packages/SystemUI/OWNERS
+
+# PackageManager
+per-file ApplicationPackageManager.java = file:/services/core/java/com/android/server/pm/OWNERS
+per-file InstantAppResolverService.java = file:/services/core/java/com/android/server/pm/OWNERS
+per-file LoadedApk.java = file:/services/core/java/com/android/server/pm/OWNERS
+per-file PackageDeleteObserver.java = file:/services/core/java/com/android/server/pm/OWNERS
+per-file PackageInstallObserver.java = file:/services/core/java/com/android/server/pm/OWNERS
+per-file EphemeralResolveInfo.aidl = file:/services/core/java/com/android/server/pm/OWNERS
+per-file IEphemeralResolver.aidl = file:/services/core/java/com/android/server/pm/OWNERS
+per-file IInstantAppResolver.aidl = file:/services/core/java/com/android/server/pm/OWNERS
+per-file InstantAppResolveInfo.aidl = file:/services/core/java/com/android/server/pm/OWNERS
# ResourcesManager
-per-file ResourcesManager = rtmitchell@google.com, toddke@google.com
+per-file ResourcesManager.java = rtmitchell@google.com, toddke@google.com
+
+# VoiceInteraction
+per-file *VoiceInteract* = file:/core/java/android/service/voice/OWNERS
# Wallpaper
per-file *Wallpaper* = file:/core/java/android/service/wallpaper/OWNERS
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9acf675615a6..69d387994568 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -85,8 +85,10 @@ import android.security.keystore.StrongBoxUnavailableException;
import android.service.restrictions.RestrictionsReceiver;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.net.NetworkUtilsInternal;
@@ -4524,30 +4526,10 @@ public class DevicePolicyManager {
if (!proxySpec.type().equals(Proxy.Type.HTTP)) {
throw new IllegalArgumentException();
}
- InetSocketAddress sa = (InetSocketAddress)proxySpec.address();
- String hostName = sa.getHostName();
- int port = sa.getPort();
- StringBuilder hostBuilder = new StringBuilder();
- hostSpec = hostBuilder.append(hostName)
- .append(":").append(Integer.toString(port)).toString();
- if (exclusionList == null) {
- exclSpec = "";
- } else {
- StringBuilder listBuilder = new StringBuilder();
- boolean firstDomain = true;
- for (String exclDomain : exclusionList) {
- if (!firstDomain) {
- listBuilder = listBuilder.append(",");
- } else {
- firstDomain = false;
- }
- listBuilder = listBuilder.append(exclDomain.trim());
- }
- exclSpec = listBuilder.toString();
- }
- if (android.net.Proxy.validate(hostName, Integer.toString(port), exclSpec)
- != android.net.Proxy.PROXY_VALID)
- throw new IllegalArgumentException();
+ final Pair<String, String> proxyParams =
+ getProxyParameters(proxySpec, exclusionList);
+ hostSpec = proxyParams.first;
+ exclSpec = proxyParams.second;
}
return mService.setGlobalProxy(admin, hostSpec, exclSpec);
} catch (RemoteException e) {
@@ -4558,6 +4540,35 @@ public class DevicePolicyManager {
}
/**
+ * Build HTTP proxy parameters for {@link IDevicePolicyManager#setGlobalProxy}.
+ * @throws IllegalArgumentException Invalid proxySpec
+ * @hide
+ */
+ @VisibleForTesting
+ public Pair<String, String> getProxyParameters(Proxy proxySpec, List<String> exclusionList) {
+ InetSocketAddress sa = (InetSocketAddress) proxySpec.address();
+ String hostName = sa.getHostName();
+ int port = sa.getPort();
+ final List<String> trimmedExclList;
+ if (exclusionList == null) {
+ trimmedExclList = Collections.emptyList();
+ } else {
+ trimmedExclList = new ArrayList<>(exclusionList.size());
+ for (String exclDomain : exclusionList) {
+ trimmedExclList.add(exclDomain.trim());
+ }
+ }
+ final ProxyInfo info = ProxyInfo.buildDirectProxy(hostName, port, trimmedExclList);
+ // The hostSpec is built assuming that there is a specified port and hostname,
+ // but ProxyInfo.isValid() accepts 0 / empty as unspecified: also reject them.
+ if (port == 0 || TextUtils.isEmpty(hostName) || !info.isValid()) {
+ throw new IllegalArgumentException();
+ }
+
+ return new Pair<>(hostName + ":" + port, TextUtils.join(",", trimmedExclList));
+ }
+
+ /**
* Set a network-independent global HTTP proxy. This is not normally what you want for typical
* HTTP proxies - they are generally network dependent. However if you're doing something
* unusual like general internal filtering this may be useful. On a private network where the
diff --git a/core/java/android/app/search/OWNERS b/core/java/android/app/search/OWNERS
new file mode 100644
index 000000000000..92835c2b0626
--- /dev/null
+++ b/core/java/android/app/search/OWNERS
@@ -0,0 +1,2 @@
+hyunyoungs@google.com
+sfufa@google.com
diff --git a/core/java/android/apphibernation/AppHibernationManager.java b/core/java/android/apphibernation/AppHibernationManager.java
new file mode 100644
index 000000000000..8f1934c7b77a
--- /dev/null
+++ b/core/java/android/apphibernation/AppHibernationManager.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2021 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.apphibernation;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+/**
+ * This class provides an API surface for system apps to manipulate the app hibernation
+ * state of a package for the user provided in the context.
+ * @hide
+ */
+@SystemApi
+@SystemService(Context.APP_HIBERNATION_SERVICE)
+public final class AppHibernationManager {
+ private static final String TAG = "AppHibernationManager";
+ private final Context mContext;
+ private final IAppHibernationService mIAppHibernationService;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param context The current context associated with the user
+ *
+ * @hide
+ */
+ public AppHibernationManager(@NonNull Context context) {
+ mContext = context;
+ mIAppHibernationService = IAppHibernationService.Stub.asInterface(
+ ServiceManager.getService(Context.APP_HIBERNATION_SERVICE));
+ }
+
+ /**
+ * Returns true if the package is hibernating, false otherwise.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isHibernating(@NonNull String packageName) {
+ try {
+ return mIAppHibernationService.isHibernating(packageName, mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Set whether the package is hibernating.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void setHibernating(@NonNull String packageName, boolean isHibernating) {
+ try {
+ mIAppHibernationService.setHibernating(packageName, mContext.getUserId(),
+ isHibernating);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/java/android/apphibernation/IAppHibernationService.aidl b/core/java/android/apphibernation/IAppHibernationService.aidl
new file mode 100644
index 000000000000..db57ecb73051
--- /dev/null
+++ b/core/java/android/apphibernation/IAppHibernationService.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021 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.apphibernation;
+
+/**
+ * Binder interface to communicate with AppHibernationService.
+ * @hide
+ */
+interface IAppHibernationService {
+ boolean isHibernating(String packageName, int userId);
+ void setHibernating(String packageName, int userId, boolean isHibernating);
+} \ No newline at end of file
diff --git a/core/java/android/appwidget/OWNERS b/core/java/android/appwidget/OWNERS
new file mode 100644
index 000000000000..439df4b86cf0
--- /dev/null
+++ b/core/java/android/appwidget/OWNERS
@@ -0,0 +1,3 @@
+pinyaoting@google.com
+suprabh@google.com
+sunnygoyal@google.com
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 15daf1c59d1a..cd91aa9b16b7 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -225,6 +225,39 @@ public final class BluetoothA2dp implements BluetoothProfile {
@SystemApi
public static final int OPTIONAL_CODECS_PREF_ENABLED = 1;
+ /** @hide */
+ @IntDef(prefix = "DYNAMIC_BUFFER_SUPPORT_", value = {
+ DYNAMIC_BUFFER_SUPPORT_NONE,
+ DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD,
+ DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
+ /**
+ * Indicates the supported type of Dynamic Audio Buffer is not supported.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int DYNAMIC_BUFFER_SUPPORT_NONE = 0;
+
+ /**
+ * Indicates the supported type of Dynamic Audio Buffer is A2DP offload.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1;
+
+ /**
+ * Indicates the supported type of Dynamic Audio Buffer is A2DP software encoding.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2;
+
private BluetoothAdapter mAdapter;
private final BluetoothProfileConnector<IBluetoothA2dp> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.A2DP, "BluetoothA2dp",
@@ -845,6 +878,87 @@ public final class BluetoothA2dp implements BluetoothProfile {
}
/**
+ * Get the supported type of the Dynamic Audio Buffer.
+ * <p>Possible return values are
+ * {@link #DYNAMIC_BUFFER_SUPPORT_NONE},
+ * {@link #DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD},
+ * {@link #DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING}.
+ *
+ * @return supported type of Dynamic Audio Buffer feature
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public @Type int getDynamicBufferSupport() {
+ if (VDBG) log("getDynamicBufferSupport()");
+ try {
+ final IBluetoothA2dp service = getService();
+ if (service != null && isEnabled()) {
+ return service.getDynamicBufferSupport();
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return DYNAMIC_BUFFER_SUPPORT_NONE;
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to get getDynamicBufferSupport, error: ", e);
+ return DYNAMIC_BUFFER_SUPPORT_NONE;
+ }
+ }
+
+ /**
+ * Return the record of {@link BufferConstraints} object that
+ * has the default/maximum/minimum audio buffer. This can be used to inform what the controller
+ * has support for the audio buffer.
+ *
+ * @return a record with {@link BufferConstraints} or null if report is unavailable
+ * or unsupported
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public @Nullable BufferConstraints getBufferConstraints() {
+ if (VDBG) log("getBufferConstraints()");
+ try {
+ final IBluetoothA2dp service = getService();
+ if (service != null && isEnabled()) {
+ return service.getBufferConstraints();
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return null;
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ return null;
+ }
+ }
+
+ /**
+ * Set Dynamic Audio Buffer Size.
+ *
+ * @param codec audio codec
+ * @param value buffer millis
+ * @return true to indicate success, or false on immediate error
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setBufferMillis(@BluetoothCodecConfig.SourceCodecType int codec, int value) {
+ if (VDBG) log("setBufferMillis(" + codec + ", " + value + ")");
+ try {
+ final IBluetoothA2dp service = getService();
+ if (service != null && isEnabled()) {
+ return service.setBufferMillis(codec, value);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ return false;
+ }
+ }
+
+ /**
* Helper for converting a state to a string.
*
* For debug use only - strings are not internationalized.
diff --git a/core/java/android/bluetooth/BufferConstraint.java b/core/java/android/bluetooth/BufferConstraint.java
new file mode 100644
index 000000000000..cbffc788c35d
--- /dev/null
+++ b/core/java/android/bluetooth/BufferConstraint.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Stores a codec's constraints on buffering length in milliseconds.
+ *
+ * {@hide}
+ */
+@SystemApi
+public final class BufferConstraint implements Parcelable {
+
+ private static final String TAG = "BufferConstraint";
+ private int mDefaultMillis;
+ private int mMaxMillis;
+ private int mMinMillis;
+
+ public BufferConstraint(int defaultMillis, int maxMillis,
+ int minMillis) {
+ mDefaultMillis = defaultMillis;
+ mMaxMillis = maxMillis;
+ mMinMillis = minMillis;
+ }
+
+ BufferConstraint(Parcel in) {
+ mDefaultMillis = in.readInt();
+ mMaxMillis = in.readInt();
+ mMinMillis = in.readInt();
+ }
+
+ public static final @NonNull Parcelable.Creator<BufferConstraint> CREATOR =
+ new Parcelable.Creator<BufferConstraint>() {
+ public BufferConstraint createFromParcel(Parcel in) {
+ return new BufferConstraint(in);
+ }
+
+ public BufferConstraint[] newArray(int size) {
+ return new BufferConstraint[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeInt(mDefaultMillis);
+ out.writeInt(mMaxMillis);
+ out.writeInt(mMinMillis);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Get the default buffer millis
+ *
+ * @return default buffer millis
+ * @hide
+ */
+ @SystemApi
+ public int getDefaultMillis() {
+ return mDefaultMillis;
+ }
+
+ /**
+ * Get the maximum buffer millis
+ *
+ * @return maximum buffer millis
+ * @hide
+ */
+ @SystemApi
+ public int getMaxMillis() {
+ return mMaxMillis;
+ }
+
+ /**
+ * Get the minimum buffer millis
+ *
+ * @return minimum buffer millis
+ * @hide
+ */
+ @SystemApi
+ public int getMinMillis() {
+ return mMinMillis;
+ }
+}
diff --git a/core/java/android/bluetooth/BufferConstraints.java b/core/java/android/bluetooth/BufferConstraints.java
new file mode 100644
index 000000000000..7e5ec1e78435
--- /dev/null
+++ b/core/java/android/bluetooth/BufferConstraints.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * A parcelable collection of buffer constraints by codec type.
+ *
+ * {@hide}
+ */
+@SystemApi
+public final class BufferConstraints implements Parcelable {
+ public static final int BUFFER_CODEC_MAX_NUM = 32;
+
+ private static final String TAG = "BufferConstraints";
+
+ private Map<Integer, BufferConstraint> mBufferConstraints;
+ private List<BufferConstraint> mBufferConstraintList;
+
+ public BufferConstraints(@NonNull List<BufferConstraint>
+ bufferConstraintList) {
+
+ mBufferConstraintList = new ArrayList<BufferConstraint>(bufferConstraintList);
+ mBufferConstraints = new HashMap<Integer, BufferConstraint>();
+ for (int i = 0; i < BUFFER_CODEC_MAX_NUM; i++) {
+ mBufferConstraints.put(i, bufferConstraintList.get(i));
+ }
+ }
+
+ BufferConstraints(Parcel in) {
+ mBufferConstraintList = new ArrayList<BufferConstraint>();
+ mBufferConstraints = new HashMap<Integer, BufferConstraint>();
+ in.readList(mBufferConstraintList, BufferConstraint.class.getClassLoader());
+ for (int i = 0; i < mBufferConstraintList.size(); i++) {
+ mBufferConstraints.put(i, mBufferConstraintList.get(i));
+ }
+ }
+
+ public static final @NonNull Parcelable.Creator<BufferConstraints> CREATOR =
+ new Parcelable.Creator<BufferConstraints>() {
+ public BufferConstraints createFromParcel(Parcel in) {
+ return new BufferConstraints(in);
+ }
+
+ public BufferConstraints[] newArray(int size) {
+ return new BufferConstraints[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeList(mBufferConstraintList);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Get the buffer constraints by codec type.
+ *
+ * @param codec Audio codec
+ * @return buffer constraints by codec type.
+ * @hide
+ */
+ @SystemApi
+ public @Nullable BufferConstraint getCodec(@BluetoothCodecConfig.SourceCodecType int codec) {
+ return mBufferConstraints.get(codec);
+ }
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 92ede1ca45fb..9c8856650ae0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2602,6 +2602,36 @@ public abstract class Context {
public abstract void sendStickyBroadcast(@RequiresPermission Intent intent);
/**
+ * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
+ * Intent you are sending stays around after the broadcast is complete,
+ * so that others can quickly retrieve that data through the return
+ * value of {@link #registerReceiver(BroadcastReceiver, IntentFilter)}. In
+ * all other ways, this behaves the same as
+ * {@link #sendBroadcast(Intent)}.
+ *
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
+ * @param intent The Intent to broadcast; all receivers matching this
+ * Intent will receive the broadcast, and the Intent will be held to
+ * be re-broadcast to future receivers.
+ * @param options (optional) Additional sending options, generated from a
+ * {@link android.app.BroadcastOptions}.
+ *
+ * @see #sendBroadcast(Intent)
+ * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
+ */
+ @Deprecated
+ @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY)
+ public void sendStickyBroadcast(@RequiresPermission @NonNull Intent intent,
+ @Nullable Bundle options) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* <p>Version of {@link #sendStickyBroadcast} that allows you to
* receive data back from the broadcast. This is accomplished by
* supplying your own BroadcastReceiver when calling, which will be
@@ -4509,6 +4539,17 @@ public abstract class Context {
public static final String PERMISSION_CONTROLLER_SERVICE = "permission_controller";
/**
+ * Use with {@link #getSystemService(String) to retrieve an
+ * {@link android.apphibernation.AppHibernationManager}} for
+ * communicating with the hibernation service.
+ * @hide
+ *
+ * @see #getSystemService(String)
+ */
+ @SystemApi
+ public static final String APP_HIBERNATION_SERVICE = "app_hibernation";
+
+ /**
* Use with {@link #getSystemService(String)} to retrieve an
* {@link android.app.backup.IBackupManager IBackupManager} for communicating
* with the backup mechanism.
@@ -4999,9 +5040,7 @@ public abstract class Context {
* Service to capture a bugreport.
* @see #getSystemService(String)
* @see android.os.BugreportManager
- * @hide
*/
- @SystemApi
public static final String BUGREPORT_SERVICE = "bugreport";
/**
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 5bdd521e92dd..e351c244b04c 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -617,6 +617,35 @@ public class ContextWrapper extends Context {
mBase.sendStickyBroadcast(intent);
}
+ /**
+ * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
+ * Intent you are sending stays around after the broadcast is complete,
+ * so that others can quickly retrieve that data through the return
+ * value of {@link #registerReceiver(BroadcastReceiver, IntentFilter)}. In
+ * all other ways, this behaves the same as
+ * {@link #sendBroadcast(Intent)}.
+ *
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
+ * @param intent The Intent to broadcast; all receivers matching this
+ * Intent will receive the broadcast, and the Intent will be held to
+ * be re-broadcast to future receivers.
+ * @param options (optional) Additional sending options, generated from a
+ * {@link android.app.BroadcastOptions}.
+ *
+ * @see #sendBroadcast(Intent)
+ * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
+ */
+ @Override
+ @Deprecated
+ public void sendStickyBroadcast(@NonNull Intent intent, @Nullable Bundle options) {
+ mBase.sendStickyBroadcast(intent, options);
+ }
+
@Override
@Deprecated
public void sendStickyOrderedBroadcast(
diff --git a/core/java/android/content/integrity/OWNERS b/core/java/android/content/integrity/OWNERS
new file mode 100644
index 000000000000..20c758aedd67
--- /dev/null
+++ b/core/java/android/content/integrity/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 722021
+
+toddke@android.com
+toddke@google.com
+patb@google.com
diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl
index 44b5c4482599..0b950b461285 100644
--- a/core/java/android/content/om/IOverlayManager.aidl
+++ b/core/java/android/content/om/IOverlayManager.aidl
@@ -17,6 +17,7 @@
package android.content.om;
import android.content.om.OverlayInfo;
+import android.content.om.OverlayManagerTransaction;
/**
* Api for getting information about overlay packages.
@@ -163,4 +164,18 @@ interface IOverlayManager {
* @param packageName The name of the overlay package whose idmap should be deleted.
*/
void invalidateCachesForOverlay(in String packageName, in int userIs);
+
+ /**
+ * Perform a series of requests related to overlay packages. This is an
+ * atomic operation: either all requests were performed successfully and
+ * the changes were propagated to the rest of the system, or at least one
+ * request could not be performed successfully and nothing is changed and
+ * nothing is propagated to the rest of the system.
+ *
+ * @see OverlayManagerTransaction
+ *
+ * @param transaction the series of overlay related requests to perform
+ * @throws SecurityException if the transaction failed
+ */
+ void commit(in OverlayManagerTransaction transaction);
}
diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java
index 217f637cf9e3..7c14c2891d01 100644
--- a/core/java/android/content/om/OverlayManager.java
+++ b/core/java/android/content/om/OverlayManager.java
@@ -254,6 +254,29 @@ public class OverlayManager {
}
/**
+ * Perform a series of requests related to overlay packages. This is an
+ * atomic operation: either all requests were performed successfully and
+ * the changes were propagated to the rest of the system, or at least one
+ * request could not be performed successfully and nothing is changed and
+ * nothing is propagated to the rest of the system.
+ *
+ * @see OverlayManagerTransaction
+ *
+ * @param transaction the series of overlay related requests to perform
+ * @throws Exception if not all the requests could be successfully and
+ * atomically executed
+ *
+ * @hide
+ */
+ public void commit(@NonNull final OverlayManagerTransaction transaction) {
+ try {
+ mService.commit(transaction);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Starting on R, actor enforcement and app visibility changes introduce additional failure
* cases, but the SecurityException thrown with these checks is unexpected for existing
* consumers of the API.
diff --git a/core/java/android/content/om/OverlayManagerTransaction.aidl b/core/java/android/content/om/OverlayManagerTransaction.aidl
new file mode 100644
index 000000000000..6715c82d4e6f
--- /dev/null
+++ b/core/java/android/content/om/OverlayManagerTransaction.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.content.om;
+
+parcelable OverlayManagerTransaction;
diff --git a/core/java/android/content/om/OverlayManagerTransaction.java b/core/java/android/content/om/OverlayManagerTransaction.java
new file mode 100644
index 000000000000..1fa8973c35b5
--- /dev/null
+++ b/core/java/android/content/om/OverlayManagerTransaction.java
@@ -0,0 +1,216 @@
+/*
+ * 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.content.om;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Container for a batch of requests to the OverlayManagerService.
+ *
+ * Transactions are created using a builder interface. Example usage:
+ *
+ * final OverlayManager om = ctx.getSystemService(OverlayManager.class);
+ * final OverlayManagerTransaction t = new OverlayManagerTransaction.Builder()
+ * .setEnabled(...)
+ * .setEnabled(...)
+ * .build();
+ * om.commit(t);
+ *
+ * @hide
+ */
+public class OverlayManagerTransaction
+ implements Iterable<OverlayManagerTransaction.Request>, Parcelable {
+ // TODO: remove @hide from this class when OverlayManager is added to the
+ // SDK, but keep OverlayManagerTransaction.Request @hidden
+ private final List<Request> mRequests;
+
+ OverlayManagerTransaction(@NonNull final List<Request> requests) {
+ checkNotNull(requests);
+ if (requests.contains(null)) {
+ throw new IllegalArgumentException("null request");
+ }
+ mRequests = requests;
+ }
+
+ private OverlayManagerTransaction(@NonNull final Parcel source) {
+ final int size = source.readInt();
+ mRequests = new ArrayList<Request>(size);
+ for (int i = 0; i < size; i++) {
+ final int request = source.readInt();
+ final String packageName = source.readString();
+ final int userId = source.readInt();
+ mRequests.add(new Request(request, packageName, userId));
+ }
+ }
+
+ @Override
+ public Iterator<Request> iterator() {
+ return mRequests.iterator();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("OverlayManagerTransaction { mRequests = %s }", mRequests);
+ }
+
+ /**
+ * A single unit of the transaction, such as a request to enable an
+ * overlay, or to disable an overlay.
+ *
+ * @hide
+ */
+ public static class Request {
+ @IntDef(prefix = "TYPE_", value = {
+ TYPE_SET_ENABLED,
+ TYPE_SET_DISABLED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface RequestType {}
+
+ public static final int TYPE_SET_ENABLED = 0;
+ public static final int TYPE_SET_DISABLED = 1;
+
+ @RequestType public final int type;
+ public final String packageName;
+ public final int userId;
+
+ public Request(@RequestType final int type, @NonNull final String packageName,
+ final int userId) {
+ this.type = type;
+ this.packageName = packageName;
+ this.userId = userId;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Request{type=0x%02x (%s), packageName=%s, userId=%d}",
+ type, typeToString(), packageName, userId);
+ }
+
+ /**
+ * Translate the request type into a human readable string. Only
+ * intended for debugging.
+ *
+ * @hide
+ */
+ public String typeToString() {
+ switch (type) {
+ case TYPE_SET_ENABLED: return "TYPE_SET_ENABLED";
+ case TYPE_SET_DISABLED: return "TYPE_SET_DISABLED";
+ default: return String.format("TYPE_UNKNOWN (0x%02x)", type);
+ }
+ }
+ }
+
+ /**
+ * Builder class for OverlayManagerTransaction objects.
+ *
+ * @hide
+ */
+ public static class Builder {
+ private final List<Request> mRequests = new ArrayList<>();
+
+ /**
+ * Request that an overlay package be enabled and change its loading
+ * order to the last package to be loaded, or disabled
+ *
+ * If the caller has the correct permissions, it is always possible to
+ * disable an overlay. Due to technical and security reasons it may not
+ * always be possible to enable an overlay, for instance if the overlay
+ * does not successfully overlay any target resources due to
+ * overlayable policy restrictions.
+ *
+ * An enabled overlay is a part of target package's resources, i.e. it will
+ * be part of any lookups performed via {@link android.content.res.Resources}
+ * and {@link android.content.res.AssetManager}. A disabled overlay will no
+ * longer affect the resources of the target package. If the target is
+ * currently running, its outdated resources will be replaced by new ones.
+ *
+ * @param packageName The name of the overlay package.
+ * @param enable true to enable the overlay, false to disable it.
+ * @return this Builder object, so you can chain additional requests
+ */
+ public Builder setEnabled(@NonNull String packageName, boolean enable) {
+ return setEnabled(packageName, enable, UserHandle.myUserId());
+ }
+
+ /**
+ * @hide
+ */
+ public Builder setEnabled(@NonNull String packageName, boolean enable, int userId) {
+ checkNotNull(packageName);
+ @Request.RequestType final int type =
+ enable ? Request.TYPE_SET_ENABLED : Request.TYPE_SET_DISABLED;
+ mRequests.add(new Request(type, packageName, userId));
+ return this;
+ }
+
+ /**
+ * Create a new transaction out of the requests added so far. Execute
+ * the transaction by calling OverlayManager#commit.
+ *
+ * @see OverlayManager#commit
+ * @return a new transaction
+ */
+ public OverlayManagerTransaction build() {
+ return new OverlayManagerTransaction(mRequests);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ final int size = mRequests.size();
+ dest.writeInt(size);
+ for (int i = 0; i < size; i++) {
+ final Request req = mRequests.get(i);
+ dest.writeInt(req.type);
+ dest.writeString(req.packageName);
+ dest.writeInt(req.userId);
+ }
+ }
+
+ public static final Parcelable.Creator<OverlayManagerTransaction> CREATOR =
+ new Parcelable.Creator<OverlayManagerTransaction>() {
+
+ @Override
+ public OverlayManagerTransaction createFromParcel(Parcel source) {
+ return new OverlayManagerTransaction(source);
+ }
+
+ @Override
+ public OverlayManagerTransaction[] newArray(int size) {
+ return new OverlayManagerTransaction[size];
+ }
+ };
+}
diff --git a/core/java/android/content/pm/OWNERS b/core/java/android/content/pm/OWNERS
index fd32efccbcec..f0def80505ce 100644
--- a/core/java/android/content/pm/OWNERS
+++ b/core/java/android/content/pm/OWNERS
@@ -6,5 +6,6 @@ patb@google.com
per-file PackageParser.java = chiuwinson@google.com
per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
+per-file AppSearchPerson.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS
per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS
per-file UserInfo* = file:/MULTIUSER_OWNERS
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 00f5fb95768f..31beb6e6a565 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -299,7 +299,10 @@ public abstract class PackageManager {
/**
* {@link PackageInfo} flag: return information about the
* intent filters supported by the activity.
+ *
+ * @deprecated The platform does not support getting {@link IntentFilter}s for the package.
*/
+ @Deprecated
public static final int GET_INTENT_FILTERS = 0x00000020;
/**
@@ -2122,6 +2125,35 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device supports
+ * {@link android.security.identity.IdentityCredentialStore} implemented in secure hardware
+ * at the given feature version.
+ *
+ * <p>Known feature versions include:
+ * <ul>
+ * <li><code>202009</code>: corresponds to the features included in the Identity Credential
+ * API shipped in Android 11.
+ * <li><code>202101</code>: corresponds to the features included in the Identity Credential
+ * API shipped in Android 12.
+ * </ul>
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE =
+ "android.hardware.identity_credential";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device supports
+ * {@link android.security.identity.IdentityCredentialStore} implemented in secure hardware
+ * with direct access at the given feature version.
+ * See {@link #FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known feature versions.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE_DIRECT_ACCESS =
+ "android.hardware.identity_credential_direct_access";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports one or more methods of
* reporting current location.
*/
diff --git a/core/java/android/graphics/fonts/OWNERS b/core/java/android/graphics/fonts/OWNERS
new file mode 100644
index 000000000000..18486af9d12c
--- /dev/null
+++ b/core/java/android/graphics/fonts/OWNERS
@@ -0,0 +1 @@
+include /graphics/java/android/graphics/fonts/OWNERS
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 06c159804a45..7f07bba668a3 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -15,7 +15,13 @@
*/
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
import static android.net.IpSecManager.INVALID_RESOURCE_ID;
+import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
+import static android.net.NetworkRequest.Type.LISTEN;
+import static android.net.NetworkRequest.Type.REQUEST;
+import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
+import static android.net.QosCallback.QosCallbackRegistrationException;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
@@ -24,9 +30,9 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
-import android.annotation.TestApi;
import android.app.PendingIntent;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -69,7 +75,6 @@ import com.android.internal.util.Protocol;
import libcore.net.event.NetworkEventDispatcher;
-import java.io.FileDescriptor;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.annotation.Retention;
@@ -1955,6 +1960,12 @@ public class ConnectivityManager {
return k;
}
+ // Construct an invalid fd.
+ private ParcelFileDescriptor createInvalidFd() {
+ final int invalidFd = -1;
+ return ParcelFileDescriptor.adoptFd(invalidFd);
+ }
+
/**
* Request that keepalives be started on a IPsec NAT-T socket.
*
@@ -1985,7 +1996,7 @@ public class ConnectivityManager {
} catch (IOException ignored) {
// Construct an invalid fd, so that if the user later calls start(), it will fail with
// ERROR_INVALID_SOCKET.
- dup = new ParcelFileDescriptor(new FileDescriptor());
+ dup = createInvalidFd();
}
return new NattSocketKeepalive(mService, network, dup, socket.getResourceId(), source,
destination, executor, callback);
@@ -2027,7 +2038,7 @@ public class ConnectivityManager {
} catch (IOException ignored) {
// Construct an invalid fd, so that if the user later calls start(), it will fail with
// ERROR_INVALID_SOCKET.
- dup = new ParcelFileDescriptor(new FileDescriptor());
+ dup = createInvalidFd();
}
return new NattSocketKeepalive(mService, network, dup,
INVALID_RESOURCE_ID /* Unused */, source, destination, executor, callback);
@@ -2064,7 +2075,7 @@ public class ConnectivityManager {
} catch (UncheckedIOException ignored) {
// Construct an invalid fd, so that if the user later calls start(), it will fail with
// ERROR_INVALID_SOCKET.
- dup = new ParcelFileDescriptor(new FileDescriptor());
+ dup = createInvalidFd();
}
return new TcpSocketKeepalive(mService, network, dup, executor, callback);
}
@@ -3730,14 +3741,12 @@ public class ConnectivityManager {
private static final HashMap<NetworkRequest, NetworkCallback> sCallbacks = new HashMap<>();
private static CallbackHandler sCallbackHandler;
- private static final int LISTEN = 1;
- private static final int REQUEST = 2;
-
private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
- int timeoutMs, int action, int legacyType, CallbackHandler handler) {
+ int timeoutMs, NetworkRequest.Type reqType, int legacyType, CallbackHandler handler) {
printStackTrace();
checkCallbackNotNull(callback);
- Preconditions.checkArgument(action == REQUEST || need != null, "null NetworkCapabilities");
+ Preconditions.checkArgument(
+ reqType == TRACK_DEFAULT || need != null, "null NetworkCapabilities");
final NetworkRequest request;
final String callingPackageName = mContext.getOpPackageName();
try {
@@ -3750,13 +3759,13 @@ public class ConnectivityManager {
}
Messenger messenger = new Messenger(handler);
Binder binder = new Binder();
- if (action == LISTEN) {
+ if (reqType == LISTEN) {
request = mService.listenForNetwork(
need, messenger, binder, callingPackageName);
} else {
request = mService.requestNetwork(
- need, messenger, timeoutMs, binder, legacyType, callingPackageName,
- getAttributionTag());
+ need, reqType.ordinal(), messenger, timeoutMs, binder, legacyType,
+ callingPackageName, getAttributionTag());
}
if (request != null) {
sCallbacks.put(request, callback);
@@ -4260,7 +4269,7 @@ public class ConnectivityManager {
// request, i.e., the system default network.
CallbackHandler cbHandler = new CallbackHandler(handler);
sendRequestForNetwork(null /* NetworkCapabilities need */, networkCallback, 0,
- REQUEST, TYPE_NONE, cbHandler);
+ TRACK_DEFAULT, TYPE_NONE, cbHandler);
}
/**
@@ -4817,6 +4826,8 @@ public class ConnectivityManager {
/**
* Simulates a Data Stall for the specified Network.
*
+ * <p>This method should only be used for tests.
+ *
* <p>The caller must be the owner of the specified Network.
*
* @param detectionMethod The detection method used to identify the Data Stall.
@@ -4826,7 +4837,7 @@ public class ConnectivityManager {
* @throws SecurityException if the caller is not the owner of the given network.
* @hide
*/
- @TestApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_TEST_NETWORKS,
android.Manifest.permission.NETWORK_STACK})
public void simulateDataStall(int detectionMethod, long timestampMillis,
@@ -4842,4 +4853,206 @@ public class ConnectivityManager {
Log.d(TAG, "setOemNetworkPreference called with preference: "
+ preference.toString());
}
+
+ @NonNull
+ private final List<QosCallbackConnection> mQosCallbackConnections = new ArrayList<>();
+
+ /**
+ * Registers a {@link QosSocketInfo} with an associated {@link QosCallback}. The callback will
+ * receive available QoS events related to the {@link Network} and local ip + port
+ * specified within socketInfo.
+ * <p/>
+ * The same {@link QosCallback} must be unregistered before being registered a second time,
+ * otherwise {@link QosCallbackRegistrationException} is thrown.
+ * <p/>
+ * This API does not, in itself, require any permission if called with a network that is not
+ * restricted. However, the underlying implementation currently only supports the IMS network,
+ * which is always restricted. That means non-preinstalled callers can't possibly find this API
+ * useful, because they'd never be called back on networks that they would have access to.
+ *
+ * @throws SecurityException if {@link QosSocketInfo#getNetwork()} is restricted and the app is
+ * missing CONNECTIVITY_USE_RESTRICTED_NETWORKS permission.
+ * @throws QosCallback.QosCallbackRegistrationException if qosCallback is already registered.
+ * @throws RuntimeException if the app already has too many callbacks registered.
+ *
+ * Exceptions after the time of registration is passed through
+ * {@link QosCallback#onError(QosCallbackException)}. see: {@link QosCallbackException}.
+ *
+ * @param socketInfo the socket information used to match QoS events
+ * @param callback receives qos events that satisfy socketInfo
+ * @param executor The executor on which the callback will be invoked. The provided
+ * {@link Executor} must run callback sequentially, otherwise the order of
+ * callbacks cannot be guaranteed.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void registerQosCallback(@NonNull final QosSocketInfo socketInfo,
+ @NonNull final QosCallback callback,
+ @CallbackExecutor @NonNull final Executor executor) {
+ Objects.requireNonNull(socketInfo, "socketInfo must be non-null");
+ Objects.requireNonNull(callback, "callback must be non-null");
+ Objects.requireNonNull(executor, "executor must be non-null");
+
+ try {
+ synchronized (mQosCallbackConnections) {
+ if (getQosCallbackConnection(callback) == null) {
+ final QosCallbackConnection connection =
+ new QosCallbackConnection(this, callback, executor);
+ mQosCallbackConnections.add(connection);
+ mService.registerQosSocketCallback(socketInfo, connection);
+ } else {
+ Log.e(TAG, "registerQosCallback: Callback already registered");
+ throw new QosCallbackRegistrationException();
+ }
+ }
+ } catch (final RemoteException e) {
+ Log.e(TAG, "registerQosCallback: Error while registering ", e);
+
+ // The same unregister method method is called for consistency even though nothing
+ // will be sent to the ConnectivityService since the callback was never successfully
+ // registered.
+ unregisterQosCallback(callback);
+ e.rethrowFromSystemServer();
+ } catch (final ServiceSpecificException e) {
+ Log.e(TAG, "registerQosCallback: Error while registering ", e);
+ unregisterQosCallback(callback);
+ throw convertServiceException(e);
+ }
+ }
+
+ /**
+ * Unregisters the given {@link QosCallback}. The {@link QosCallback} will no longer receive
+ * events once unregistered and can be registered a second time.
+ * <p/>
+ * If the {@link QosCallback} does not have an active registration, it is a no-op.
+ *
+ * @param callback the callback being unregistered
+ *
+ * @hide
+ */
+ @SystemApi
+ public void unregisterQosCallback(@NonNull final QosCallback callback) {
+ Objects.requireNonNull(callback, "The callback must be non-null");
+ try {
+ synchronized (mQosCallbackConnections) {
+ final QosCallbackConnection connection = getQosCallbackConnection(callback);
+ if (connection != null) {
+ connection.stopReceivingMessages();
+ mService.unregisterQosCallback(connection);
+ mQosCallbackConnections.remove(connection);
+ } else {
+ Log.d(TAG, "unregisterQosCallback: Callback not registered");
+ }
+ }
+ } catch (final RemoteException e) {
+ Log.e(TAG, "unregisterQosCallback: Error while unregistering ", e);
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Gets the connection related to the callback.
+ *
+ * @param callback the callback to look up
+ * @return the related connection
+ */
+ @Nullable
+ private QosCallbackConnection getQosCallbackConnection(final QosCallback callback) {
+ for (final QosCallbackConnection connection : mQosCallbackConnections) {
+ // Checking by reference here is intentional
+ if (connection.getCallback() == callback) {
+ return connection;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, but
+ * does not cause any networks to retain the NET_CAPABILITY_FOREGROUND capability. This can
+ * be used to request that the system provide a network without causing the network to be
+ * in the foreground.
+ *
+ * <p>This method will attempt to find the best network that matches the passed
+ * {@link NetworkRequest}, and to bring up one that does if none currently satisfies the
+ * criteria. The platform will evaluate which network is the best at its own discretion.
+ * Throughput, latency, cost per byte, policy, user preference and other considerations
+ * may be factored in the decision of what is considered the best network.
+ *
+ * <p>As long as this request is outstanding, the platform will try to maintain the best network
+ * matching this request, while always attempting to match the request to a better network if
+ * possible. If a better match is found, the platform will switch this request to the now-best
+ * network and inform the app of the newly best network by invoking
+ * {@link NetworkCallback#onAvailable(Network)} on the provided callback. Note that the platform
+ * will not try to maintain any other network than the best one currently matching the request:
+ * a network not matching any network request may be disconnected at any time.
+ *
+ * <p>For example, an application could use this method to obtain a connected cellular network
+ * even if the device currently has a data connection over Ethernet. This may cause the cellular
+ * radio to consume additional power. Or, an application could inform the system that it wants
+ * a network supporting sending MMSes and have the system let it know about the currently best
+ * MMS-supporting network through the provided {@link NetworkCallback}.
+ *
+ * <p>The status of the request can be followed by listening to the various callbacks described
+ * in {@link NetworkCallback}. The {@link Network} object passed to the callback methods can be
+ * used to direct traffic to the network (although accessing some networks may be subject to
+ * holding specific permissions). Callers will learn about the specific characteristics of the
+ * network through
+ * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} and
+ * {@link NetworkCallback#onLinkPropertiesChanged(Network, LinkProperties)}. The methods of the
+ * provided {@link NetworkCallback} will only be invoked due to changes in the best network
+ * matching the request at any given time; therefore when a better network matching the request
+ * becomes available, the {@link NetworkCallback#onAvailable(Network)} method is called
+ * with the new network after which no further updates are given about the previously-best
+ * network, unless it becomes the best again at some later time. All callbacks are invoked
+ * in order on the same thread, which by default is a thread created by the framework running
+ * in the app.
+ *
+ * <p>This{@link NetworkRequest} will live until released via
+ * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits, at
+ * which point the system may let go of the network at any time.
+ *
+ * <p>It is presently unsupported to request a network with mutable
+ * {@link NetworkCapabilities} such as
+ * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
+ * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}
+ * as these {@code NetworkCapabilities} represent states that a particular
+ * network may never attain, and whether a network will attain these states
+ * is unknown prior to bringing up the network so the framework does not
+ * know how to go about satisfying a request with these capabilities.
+ *
+ * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+ * number of outstanding requests to 100 per app (identified by their UID), shared with
+ * all variants of this method, of {@link #registerNetworkCallback} as well as
+ * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+ * Requesting a network with this method will count toward this limit. If this limit is
+ * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+ * make sure to unregister the callbacks with
+ * {@link #unregisterNetworkCallback(NetworkCallback)}.
+ *
+ * @param request {@link NetworkRequest} describing this request.
+ * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * If null, the callback is invoked on the default internal Handler.
+ * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+ * the callback must not be shared - it uniquely specifies this request.
+ * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+ * @throws SecurityException if missing the appropriate permissions.
+ * @throws RuntimeException if the app already has too many callbacks registered.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @SuppressLint("ExecutorRegistration")
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+ })
+ public void requestBackgroundNetwork(@NonNull NetworkRequest request,
+ @Nullable Handler handler, @NonNull NetworkCallback networkCallback) {
+ final NetworkCapabilities nc = request.networkCapabilities;
+ sendRequestForNetwork(nc, networkCallback, 0, BACKGROUND_REQUEST,
+ TYPE_NONE, handler == null ? getDefaultHandler() : new CallbackHandler(handler));
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index b32c98b49cfc..1b4d2e413943 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -20,6 +20,8 @@ import android.app.PendingIntent;
import android.net.ConnectionInfo;
import android.net.ConnectivityDiagnosticsManager;
import android.net.IConnectivityDiagnosticsCallback;
+import android.net.IQosCallback;
+import android.net.ISocketKeepaliveCallback;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkAgentConfig;
@@ -27,9 +29,9 @@ import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.NetworkState;
-import android.net.ISocketKeepaliveCallback;
import android.net.ProxyInfo;
import android.net.UidRange;
+import android.net.QosSocketInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.os.INetworkActivityListener;
@@ -41,7 +43,6 @@ import android.os.ResultReceiver;
import com.android.connectivity.aidl.INetworkAgent;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
/**
@@ -167,7 +168,7 @@ interface IConnectivityManager
in NetworkCapabilities nc, int score, in NetworkAgentConfig config,
in int factorySerialNumber);
- NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities,
+ NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, int reqType,
in Messenger messenger, int timeoutSec, in IBinder binder, int legacy,
String callingPackageName, String callingAttributionTag);
@@ -206,11 +207,11 @@ interface IConnectivityManager
void startNattKeepalive(in Network network, int intervalSeconds,
in ISocketKeepaliveCallback cb, String srcAddr, int srcPort, String dstAddr);
- void startNattKeepaliveWithFd(in Network network, in FileDescriptor fd, int resourceId,
+ void startNattKeepaliveWithFd(in Network network, in ParcelFileDescriptor pfd, int resourceId,
int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr,
String dstAddr);
- void startTcpKeepalive(in Network network, in FileDescriptor fd, int intervalSeconds,
+ void startTcpKeepalive(in Network network, in ParcelFileDescriptor pfd, int intervalSeconds,
in ISocketKeepaliveCallback cb);
void stopKeepalive(in Network network, int slot);
@@ -239,4 +240,7 @@ interface IConnectivityManager
void unregisterNetworkActivityListener(in INetworkActivityListener l);
boolean isDefaultNetworkActive();
+
+ void registerQosSocketCallback(in QosSocketInfo socketInfo, in IQosCallback callback);
+ void unregisterQosCallback(in IQosCallback callback);
}
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 792e5b410afc..29a3fdf59e8b 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -81,4 +81,5 @@ interface INetworkPolicyManager {
void factoryReset(String subscriber);
boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork);
+ boolean isUidRestrictedOnMeteredNetworks(int uid);
}
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 1a3dc974480c..0baf11e850c7 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -23,11 +23,11 @@ import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
+import android.net.UnderlyingNetworkInfo;
import android.net.netstats.provider.INetworkStatsProvider;
import android.net.netstats.provider.INetworkStatsProviderCallback;
import android.os.IBinder;
import android.os.Messenger;
-import com.android.internal.net.VpnInfo;
/** {@hide} */
interface INetworkStatsService {
@@ -70,7 +70,7 @@ interface INetworkStatsService {
in Network[] defaultNetworks,
in NetworkState[] networkStates,
in String activeIface,
- in VpnInfo[] vpnInfos);
+ in UnderlyingNetworkInfo[] underlyingNetworkInfos);
/** Force update of statistics. */
@UnsupportedAppUsage
void forceUpdate();
diff --git a/apex/permission/service/java/com/android/permission/persistence/IoUtils.java b/core/java/android/net/IQosCallback.aidl
index 569a78c0ab41..91c75759f85c 100644
--- a/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
+++ b/core/java/android/net/IQosCallback.aidl
@@ -14,27 +14,21 @@
* limitations under the License.
*/
-package com.android.permission.persistence;
+package android.net;
-import android.annotation.NonNull;
+import android.os.Bundle;
+import android.net.QosSession;
+import android.telephony.data.EpsBearerQosSessionAttributes;
/**
- * Utility class for IO.
+ * AIDL interface for QosCallback
*
* @hide
*/
-public class IoUtils {
-
- private IoUtils() {}
-
- /**
- * Close 'closeable' ignoring any exceptions.
- */
- public static void closeQuietly(@NonNull AutoCloseable closeable) {
- try {
- closeable.close();
- } catch (Exception ignored) {
- // Ignored.
- }
- }
+oneway interface IQosCallback
+{
+ void onQosEpsBearerSessionAvailable(in QosSession session,
+ in EpsBearerQosSessionAttributes attributes);
+ void onQosSessionLost(in QosSession session);
+ void onError(in int type);
}
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index d83715c692f7..60923f5ea8c6 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -15,6 +15,8 @@
*/
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.NonNull;
@@ -628,7 +630,7 @@ public final class IpSecManager {
}
/** @hide */
- @VisibleForTesting
+ @SystemApi(client = MODULE_LIBRARIES)
public int getResourceId() {
return mResourceId;
}
@@ -705,7 +707,7 @@ public final class IpSecManager {
}
/**
- * This class represents an IpSecTunnelInterface
+ * This class represents an IpSecTunnelInterface.
*
* <p>IpSecTunnelInterface objects track tunnel interfaces that serve as
* local endpoints for IPsec tunnels.
@@ -714,9 +716,7 @@ public final class IpSecManager {
* applied to provide IPsec security to packets sent through the tunnel. While a tunnel
* cannot be used in standalone mode within Android, the higher layers may use the tunnel
* to create Network objects which are accessible to the Android system.
- * @hide
*/
- @SystemApi
public static final class IpSecTunnelInterface implements AutoCloseable {
private final String mOpPackageName;
private final IIpSecService mService;
@@ -727,23 +727,26 @@ public final class IpSecManager {
private String mInterfaceName;
private int mResourceId = INVALID_RESOURCE_ID;
- /** Get the underlying SPI held by this object. */
+ /**
+ * Get the underlying SPI held by this object.
+ *
+ * @hide
+ */
+ @SystemApi
@NonNull
public String getInterfaceName() {
return mInterfaceName;
}
/**
- * Add an address to the IpSecTunnelInterface
+ * Add an address to the IpSecTunnelInterface.
*
* <p>Add an address which may be used as the local inner address for
* tunneled traffic.
*
* @param address the local address for traffic inside the tunnel
* @param prefixLen length of the InetAddress prefix
- * @hide
*/
- @SystemApi
@RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
@RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
@@ -758,15 +761,13 @@ public final class IpSecManager {
}
/**
- * Remove an address from the IpSecTunnelInterface
+ * Remove an address from the IpSecTunnelInterface.
*
- * <p>Remove an address which was previously added to the IpSecTunnelInterface
+ * <p>Remove an address which was previously added to the IpSecTunnelInterface.
*
* @param address to be removed
* @param prefixLen length of the InetAddress prefix
- * @hide
*/
- @SystemApi
@RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
@RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
@@ -817,7 +818,7 @@ public final class IpSecManager {
}
/**
- * Delete an IpSecTunnelInterface
+ * Delete an IpSecTunnelInterface.
*
* <p>Calling close will deallocate the IpSecTunnelInterface and all of its system
* resources. Any packets bound for this interface either inbound or outbound will
@@ -839,7 +840,12 @@ public final class IpSecManager {
}
}
- /** Check that the Interface was closed properly. */
+
+ /**
+ * Check that the Interface was closed properly.
+ *
+ * @hide
+ */
@Override
protected void finalize() throws Throwable {
if (mCloseGuard != null) {
@@ -871,17 +877,52 @@ public final class IpSecManager {
* Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic.
*
* <p>An application that creates tunnels is responsible for cleaning up the tunnel when the
- * underlying network goes away, and the onLost() callback is received.
+ * underlying network disconnects, and the {@link
+ * ConnectivityManager.NetworkCallback#onLost(Network)} callback is received.
+ *
+ * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. Packets
+ * that go through the tunnel will need a underlying network to transit to the IPsec peer.
+ * This network should almost certainly be a physical network such as WiFi.
+ * @return a new {@link IpSecTunnelInterface} with the specified properties
+ * @throws IOException indicating that the tunnel could not be created due to a lower-layer
+ * error
+ * @throws ResourceUnavailableException indicating that the number of opening tunnels has
+ * reached the limit.
+ */
+ @NonNull
+ @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
+ @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
+ public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull Network underlyingNetwork)
+ throws ResourceUnavailableException, IOException {
+
+ // TODO: Remove the need for adding two unused addresses with IPsec tunnels when {@link
+ // #createIpSecTunnelInterface(localAddress, remoteAddress, underlyingNetwork)} can be
+ // safely removed.
+ final InetAddress address = InetAddress.getLocalHost();
+ return createIpSecTunnelInterface(address, address, underlyingNetwork);
+ }
+
+ /**
+ * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic.
*
- * @param localAddress The local addres of the tunnel
- * @param remoteAddress The local addres of the tunnel
- * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel.
- * This network should almost certainly be a network such as WiFi with an L2 address.
- * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties
- * @throws IOException indicating that the socket could not be opened or bound
- * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
+ * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the
+ * underlying network disconnects, and the {@link
+ * ConnectivityManager.NetworkCallback#onLost(Network)} callback is received.
+ *
+ * @param localAddress The local address of the tunnel
+ * @param remoteAddress The local address of the tunnel
+ * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. Packets
+ * that go through the tunnel will need a underlying network to transit to the IPsec peer.
+ * This network should almost certainly be a physical network such as WiFi.
+ * @return a new {@link IpSecTunnelInterface} with the specified properties
+ * @throws IOException indicating that the tunnel could not be created due to a lower-layer
+ * error
+ * @throws ResourceUnavailableException indicating that the number of opening tunnels has
+ * reached the limit.
* @hide
+ * @deprecated Callers should use {@link #createIpSecTunnelInterface(Network)}
*/
+ @Deprecated
@SystemApi
@NonNull
@RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
@@ -905,16 +946,14 @@ public final class IpSecManager {
* <p>Applications should probably not use this API directly.
*
*
- * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied
+ * @param tunnel The {@link IpSecTunnelInterface} that will use the supplied
* transform.
- * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which
+ * @param direction the direction, {@link #DIRECTION_OUT} or {@link #DIRECTION_IN} in which
* the transform will be used.
* @param transform an {@link IpSecTransform} created in tunnel mode
- * @throws IOException indicating that the transform could not be applied due to a lower
- * layer failure.
- * @hide
+ * @throws IOException indicating that the transform could not be applied due to a lower-layer
+ * error
*/
- @SystemApi
@RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
@RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel,
diff --git a/core/java/android/net/MatchAllNetworkSpecifier.java b/core/java/android/net/MatchAllNetworkSpecifier.java
index 70c4a7235b9d..011a04c26137 100644
--- a/core/java/android/net/MatchAllNetworkSpecifier.java
+++ b/core/java/android/net/MatchAllNetworkSpecifier.java
@@ -31,17 +31,6 @@ import android.os.Parcelable;
*/
@SystemApi
public final class MatchAllNetworkSpecifier extends NetworkSpecifier implements Parcelable {
- /**
- * Utility method which verifies that the ns argument is not a MatchAllNetworkSpecifier and
- * throws an IllegalArgumentException if it is.
- * @hide
- */
- public static void checkNotMatchAllNetworkSpecifier(NetworkSpecifier ns) {
- if (ns instanceof MatchAllNetworkSpecifier) {
- throw new IllegalArgumentException("A MatchAllNetworkSpecifier is not permitted");
- }
- }
-
/** @hide */
@Override
public boolean canBeSatisfiedBy(NetworkSpecifier other) {
diff --git a/core/java/android/net/NattSocketKeepalive.java b/core/java/android/net/NattSocketKeepalive.java
index b0ce0c71fbeb..a15d165e65e7 100644
--- a/core/java/android/net/NattSocketKeepalive.java
+++ b/core/java/android/net/NattSocketKeepalive.java
@@ -51,7 +51,7 @@ public final class NattSocketKeepalive extends SocketKeepalive {
void startImpl(int intervalSec) {
mExecutor.execute(() -> {
try {
- mService.startNattKeepaliveWithFd(mNetwork, mPfd.getFileDescriptor(), mResourceId,
+ mService.startNattKeepaliveWithFd(mNetwork, mPfd, mResourceId,
intervalSec, mCallback,
mSource.getHostAddress(), mDestination.getHostAddress());
} catch (RemoteException e) {
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index f98a1f8a220d..b07bd68a0f50 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -21,6 +21,7 @@ import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.system.ErrnoException;
import android.system.Os;
@@ -380,7 +381,13 @@ public class Network implements Parcelable {
// Query a property of the underlying socket to ensure that the socket's file descriptor
// exists, is available to bind to a network and is not closed.
socket.getReuseAddress();
- bindSocket(socket.getFileDescriptor$());
+ final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket);
+ bindSocket(pfd.getFileDescriptor());
+ // ParcelFileDescriptor.fromSocket() creates a dup of the original fd. The original and the
+ // dup share the underlying socket in the kernel. The socket is never truly closed until the
+ // last fd pointing to the socket being closed. So close the dup one after binding the
+ // socket to control the lifetime of the dup fd.
+ pfd.close();
}
/**
@@ -392,7 +399,13 @@ public class Network implements Parcelable {
// Query a property of the underlying socket to ensure that the socket's file descriptor
// exists, is available to bind to a network and is not closed.
socket.getReuseAddress();
- bindSocket(socket.getFileDescriptor$());
+ final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
+ bindSocket(pfd.getFileDescriptor());
+ // ParcelFileDescriptor.fromSocket() creates a dup of the original fd. The original and the
+ // dup share the underlying socket in the kernel. The socket is never truly closed until the
+ // last fd pointing to the socket being closed. So close the dup one after binding the
+ // socket to control the lifetime of the dup fd.
+ pfd.close();
}
/**
@@ -420,7 +433,7 @@ public class Network implements Parcelable {
throw new SocketException("Only AF_INET/AF_INET6 sockets supported");
}
- final int err = NetworkUtils.bindSocketToNetwork(fd.getInt$(), netId);
+ final int err = NetworkUtils.bindSocketToNetwork(fd, netId);
if (err != 0) {
// bindSocketToNetwork returns negative errno.
throw new ErrnoException("Binding socket to network " + netId, -err)
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 4166c2c4f244..d22d82d1f4d0 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -30,6 +30,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.telephony.data.EpsBearerQosSessionAttributes;
import android.util.Log;
import com.android.connectivity.aidl.INetworkAgent;
@@ -228,12 +229,6 @@ public abstract class NetworkAgent {
public static final String REDIRECT_URL_KEY = "redirect URL";
/**
- * Bundle key for the underlying networks in {@code EVENT_UNDERLYING_NETWORKS_CHANGED}.
- * @hide
- */
- public static final String UNDERLYING_NETWORKS_KEY = "underlyingNetworks";
-
- /**
* Sent by the NetworkAgent to ConnectivityService to indicate this network was
* explicitly selected. This should be sent before the NetworkInfo is marked
* CONNECTED so it can be given special treatment at that time.
@@ -347,6 +342,24 @@ public abstract class NetworkAgent {
*/
private static final int EVENT_AGENT_DISCONNECTED = BASE + 19;
+ /**
+ * Sent by QosCallbackTracker to {@link NetworkAgent} to register a new filter with
+ * callback.
+ *
+ * arg1 = QoS agent callback ID
+ * obj = {@link QosFilter}
+ * @hide
+ */
+ public static final int CMD_REGISTER_QOS_CALLBACK = BASE + 20;
+
+ /**
+ * Sent by QosCallbackTracker to {@link NetworkAgent} to unregister a callback.
+ *
+ * arg1 = QoS agent callback ID
+ * @hide
+ */
+ public static final int CMD_UNREGISTER_QOS_CALLBACK = BASE + 21;
+
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
// The subtype can be changed with (TODO) setLegacySubtype, but it starts
// with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description.
@@ -408,7 +421,8 @@ public abstract class NetworkAgent {
throw new IllegalArgumentException();
}
- mInitialConfiguration = new InitialConfiguration(context, new NetworkCapabilities(nc),
+ mInitialConfiguration = new InitialConfiguration(context,
+ new NetworkCapabilities(nc, /* parcelLocationSensitiveFields */ true),
new LinkProperties(lp), score, config, ni);
}
@@ -525,6 +539,17 @@ public abstract class NetworkAgent {
onRemoveKeepalivePacketFilter(msg.arg1 /* slot */);
break;
}
+ case CMD_REGISTER_QOS_CALLBACK: {
+ onQosCallbackRegistered(
+ msg.arg1 /* QoS callback id */,
+ (QosFilter) msg.obj /* QoS filter */);
+ break;
+ }
+ case CMD_UNREGISTER_QOS_CALLBACK: {
+ onQosCallbackUnregistered(
+ msg.arg1 /* QoS callback id */);
+ break;
+ }
}
}
}
@@ -558,6 +583,8 @@ public abstract class NetworkAgent {
}
private static class NetworkAgentBinder extends INetworkAgent.Stub {
+ private static final String LOG_TAG = NetworkAgentBinder.class.getSimpleName();
+
private final Handler mHandler;
private NetworkAgentBinder(Handler handler) {
@@ -644,6 +671,25 @@ public abstract class NetworkAgent {
mHandler.sendMessage(mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER,
slot, 0));
}
+
+ @Override
+ public void onQosFilterCallbackRegistered(final int qosCallbackId,
+ final QosFilterParcelable qosFilterParcelable) {
+ if (qosFilterParcelable.getQosFilter() != null) {
+ mHandler.sendMessage(
+ mHandler.obtainMessage(CMD_REGISTER_QOS_CALLBACK, qosCallbackId, 0,
+ qosFilterParcelable.getQosFilter()));
+ return;
+ }
+
+ Log.wtf(LOG_TAG, "onQosFilterCallbackRegistered: qos filter is null.");
+ }
+
+ @Override
+ public void onQosCallbackUnregistered(final int qosCallbackId) {
+ mHandler.sendMessage(mHandler.obtainMessage(
+ CMD_UNREGISTER_QOS_CALLBACK, qosCallbackId, 0, null));
+ }
}
/**
@@ -818,7 +864,9 @@ public abstract class NetworkAgent {
Objects.requireNonNull(networkCapabilities);
mBandwidthUpdatePending.set(false);
mLastBwRefreshTime = System.currentTimeMillis();
- final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
+ final NetworkCapabilities nc =
+ new NetworkCapabilities(networkCapabilities,
+ /* parcelLocationSensitiveFields */ true);
queueOrSendMessage(reg -> reg.sendNetworkCapabilities(nc));
}
@@ -1070,8 +1118,68 @@ public abstract class NetworkAgent {
protected void preventAutomaticReconnect() {
}
+ /**
+ * Called when a qos callback is registered with a filter.
+ * @param qosCallbackId the id for the callback registered
+ * @param filter the filter being registered
+ */
+ public void onQosCallbackRegistered(final int qosCallbackId, final @NonNull QosFilter filter) {
+ }
+
+ /**
+ * Called when a qos callback is registered with a filter.
+ * <p/>
+ * Any QoS events that are sent with the same callback id after this method is called
+ * are a no-op.
+ *
+ * @param qosCallbackId the id for the callback being unregistered
+ */
+ public void onQosCallbackUnregistered(final int qosCallbackId) {
+ }
+
+
+ /**
+ * Sends the attributes of Eps Bearer Qos Session back to the Application
+ *
+ * @param qosCallbackId the callback id that the session belongs to
+ * @param sessionId the unique session id across all Eps Bearer Qos Sessions
+ * @param attributes the attributes of the Eps Qos Session
+ */
+ public final void sendQosSessionAvailable(final int qosCallbackId, final int sessionId,
+ @NonNull final EpsBearerQosSessionAttributes attributes) {
+ Objects.requireNonNull(attributes, "The attributes must be non-null");
+ queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId,
+ new QosSession(sessionId, QosSession.TYPE_EPS_BEARER),
+ attributes));
+ }
+
+ /**
+ * Sends event that the Eps Qos Session was lost.
+ *
+ * @param qosCallbackId the callback id that the session belongs to
+ * @param sessionId the unique session id across all Eps Bearer Qos Sessions
+ */
+ public final void sendQosSessionLost(final int qosCallbackId, final int sessionId) {
+ queueOrSendMessage(ra -> ra.sendQosSessionLost(qosCallbackId,
+ new QosSession(sessionId, QosSession.TYPE_EPS_BEARER)));
+ }
+
+ /**
+ * Sends the exception type back to the application.
+ *
+ * The NetworkAgent should not send anymore messages with this id.
+ *
+ * @param qosCallbackId the callback id this exception belongs to
+ * @param exceptionType the type of exception
+ */
+ public final void sendQosCallbackError(final int qosCallbackId,
+ @QosCallbackException.ExceptionType final int exceptionType) {
+ queueOrSendMessage(ra -> ra.sendQosCallbackError(qosCallbackId, exceptionType));
+ }
+
+
/** @hide */
- protected void log(String s) {
+ protected void log(final String s) {
Log.d(LOG_TAG, "NetworkAgent: " + s);
}
}
diff --git a/core/java/android/net/NetworkAgentConfig.java b/core/java/android/net/NetworkAgentConfig.java
index fe1268d79b89..664c2650ff0c 100644
--- a/core/java/android/net/NetworkAgentConfig.java
+++ b/core/java/android/net/NetworkAgentConfig.java
@@ -16,6 +16,8 @@
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -125,6 +127,7 @@ public final class NetworkAgentConfig implements Parcelable {
* @return the subscriber ID, or null if none.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
@Nullable
public String getSubscriberId() {
return subscriberId;
@@ -275,6 +278,7 @@ public final class NetworkAgentConfig implements Parcelable {
* @hide
*/
@NonNull
+ @SystemApi(client = MODULE_LIBRARIES)
public Builder setSubscriberId(@Nullable String subscriberId) {
mConfig.subscriberId = subscriberId;
return this;
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 48c4832b0bd8..3843b9ab93c2 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -23,7 +23,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.ConnectivityManager.NetworkCallback;
import android.os.Build;
@@ -76,12 +75,33 @@ public final class NetworkCapabilities implements Parcelable {
*/
private String mRequestorPackageName;
+ /**
+ * Indicates whether parceling should preserve fields that are set based on permissions of
+ * the process receiving the {@link NetworkCapabilities}.
+ */
+ private final boolean mParcelLocationSensitiveFields;
+
public NetworkCapabilities() {
+ mParcelLocationSensitiveFields = false;
clearAll();
mNetworkCapabilities = DEFAULT_CAPABILITIES;
}
public NetworkCapabilities(NetworkCapabilities nc) {
+ this(nc, false /* parcelLocationSensitiveFields */);
+ }
+
+ /**
+ * Make a copy of NetworkCapabilities.
+ *
+ * @param nc Original NetworkCapabilities
+ * @param parcelLocationSensitiveFields Whether to parcel location sensitive data or not.
+ * @hide
+ */
+ @SystemApi
+ public NetworkCapabilities(
+ @Nullable NetworkCapabilities nc, boolean parcelLocationSensitiveFields) {
+ mParcelLocationSensitiveFields = parcelLocationSensitiveFields;
if (nc != null) {
set(nc);
}
@@ -93,6 +113,12 @@ public final class NetworkCapabilities implements Parcelable {
* @hide
*/
public void clearAll() {
+ // Ensures that the internal copies maintained by the connectivity stack does not set
+ // this bit.
+ if (mParcelLocationSensitiveFields) {
+ throw new UnsupportedOperationException(
+ "Cannot clear NetworkCapabilities when parcelLocationSensitiveFields is set");
+ }
mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0;
mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
mNetworkSpecifier = null;
@@ -109,6 +135,8 @@ public final class NetworkCapabilities implements Parcelable {
/**
* Set all contents of this object to the contents of a NetworkCapabilities.
+ *
+ * @param nc Original NetworkCapabilities
* @hide
*/
public void set(@NonNull NetworkCapabilities nc) {
@@ -117,7 +145,11 @@ public final class NetworkCapabilities implements Parcelable {
mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
mNetworkSpecifier = nc.mNetworkSpecifier;
- mTransportInfo = nc.mTransportInfo;
+ if (nc.getTransportInfo() != null) {
+ setTransportInfo(nc.getTransportInfo().makeCopy(mParcelLocationSensitiveFields));
+ } else {
+ setTransportInfo(null);
+ }
mSignalStrength = nc.mSignalStrength;
setUids(nc.mUids); // Will make the defensive copy
setAdministratorUids(nc.getAdministratorUids());
@@ -172,6 +204,7 @@ public final class NetworkCapabilities implements Parcelable {
NET_CAPABILITY_TEMPORARILY_NOT_METERED,
NET_CAPABILITY_OEM_PRIVATE,
NET_CAPABILITY_VEHICLE_INTERNAL,
+ NET_CAPABILITY_NOT_VCN_MANAGED,
})
public @interface NetCapability { }
@@ -367,8 +400,16 @@ public final class NetworkCapabilities implements Parcelable {
@SystemApi
public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27;
+ /**
+ * Indicates that this network is not managed by a Virtual Carrier Network (VCN).
+ *
+ * TODO(b/177299683): Add additional clarifying javadoc.
+ * @hide
+ */
+ public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28;
+
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
- private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_VEHICLE_INTERNAL;
+ private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_VCN_MANAGED;
/**
* Network capabilities that are expected to be mutable, i.e., can change while a particular
@@ -385,7 +426,8 @@ public final class NetworkCapabilities implements Parcelable {
| (1 << NET_CAPABILITY_NOT_CONGESTED)
| (1 << NET_CAPABILITY_NOT_SUSPENDED)
| (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY)
- | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+ | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED)
+ | (1 << NET_CAPABILITY_NOT_VCN_MANAGED);
/**
* Network capabilities that are not allowed in NetworkRequests. This exists because the
@@ -394,16 +436,21 @@ public final class NetworkCapabilities implements Parcelable {
* can get into a cycle where the NetworkFactory endlessly churns out NetworkAgents that then
* get immediately torn down because they do not have the requested capability.
*/
+ // Note that as a historical exception, the TRUSTED and NOT_VCN_MANAGED capabilities
+ // are mutable but requestable. Factories are responsible for not getting
+ // in an infinite loop about these.
private static final long NON_REQUESTABLE_CAPABILITIES =
- MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_TRUSTED);
+ MUTABLE_CAPABILITIES
+ & ~(1 << NET_CAPABILITY_TRUSTED)
+ & ~(1 << NET_CAPABILITY_NOT_VCN_MANAGED);
/**
* Capabilities that are set by default when the object is constructed.
*/
private static final long DEFAULT_CAPABILITIES =
- (1 << NET_CAPABILITY_NOT_RESTRICTED) |
- (1 << NET_CAPABILITY_TRUSTED) |
- (1 << NET_CAPABILITY_NOT_VPN);
+ (1 << NET_CAPABILITY_NOT_RESTRICTED)
+ | (1 << NET_CAPABILITY_TRUSTED)
+ | (1 << NET_CAPABILITY_NOT_VPN);
/**
* Capabilities that suggest that a network is restricted.
@@ -463,7 +510,8 @@ public final class NetworkCapabilities implements Parcelable {
| (1 << NET_CAPABILITY_NOT_VPN)
| (1 << NET_CAPABILITY_NOT_ROAMING)
| (1 << NET_CAPABILITY_NOT_CONGESTED)
- | (1 << NET_CAPABILITY_NOT_SUSPENDED);
+ | (1 << NET_CAPABILITY_NOT_SUSPENDED)
+ | (1 << NET_CAPABILITY_NOT_VCN_MANAGED);
/**
* Adds the given capability to this {@code NetworkCapability} instance.
@@ -543,7 +591,6 @@ public final class NetworkCapabilities implements Parcelable {
* @hide
*/
@UnsupportedAppUsage
- @TestApi
public @NetCapability int[] getCapabilities() {
return BitUtils.unpackBits(mNetworkCapabilities);
}
@@ -788,7 +835,7 @@ public final class NetworkCapabilities implements Parcelable {
*
* @hide
*/
- @TestApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int TRANSPORT_TEST = 7;
/** @hide */
@@ -1951,6 +1998,7 @@ public final class NetworkCapabilities implements Parcelable {
case NET_CAPABILITY_TEMPORARILY_NOT_METERED: return "TEMPORARILY_NOT_METERED";
case NET_CAPABILITY_OEM_PRIVATE: return "OEM_PRIVATE";
case NET_CAPABILITY_VEHICLE_INTERNAL: return "NET_CAPABILITY_VEHICLE_INTERNAL";
+ case NET_CAPABILITY_NOT_VCN_MANAGED: return "NOT_VCN_MANAGED";
default: return Integer.toString(capability);
}
}
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index a0dc72d4adbf..b644ed56ad8b 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -194,13 +194,15 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
subscriberId = state.subscriberId;
if (type == TYPE_WIFI) {
- if (state.networkId != null) {
- networkId = state.networkId;
- } else {
- final WifiManager wifi = (WifiManager) context.getSystemService(
- Context.WIFI_SERVICE);
- final WifiInfo info = wifi.getConnectionInfo();
- networkId = info != null ? info.getSSID() : null;
+ if (state.networkCapabilities.getSsid() != null) {
+ networkId = state.networkCapabilities.getSsid();
+ if (networkId == null) {
+ // TODO: Figure out if this code path never runs. If so, remove them.
+ final WifiManager wifi = (WifiManager) context.getSystemService(
+ Context.WIFI_SERVICE);
+ final WifiInfo info = wifi.getConnectionInfo();
+ networkId = info != null ? info.getSSID() : null;
+ }
}
}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index c029deae09df..82b035b08428 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -460,6 +460,22 @@ public class NetworkPolicyManager {
}
/**
+ * Check that the given uid is restricted from doing networking on metered networks.
+ *
+ * @param uid The target uid.
+ * @return true if the given uid is restricted from doing networking on metered networks.
+ *
+ * @hide
+ */
+ public boolean isUidRestrictedOnMeteredNetworks(int uid) {
+ try {
+ return mService.isUidRestrictedOnMeteredNetworks(uid);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Get multipath preference for the given network.
*/
public int getMultipathPreference(Network network) {
diff --git a/core/java/android/net/NetworkReleasedException.java b/core/java/android/net/NetworkReleasedException.java
new file mode 100644
index 000000000000..0629b7563aea
--- /dev/null
+++ b/core/java/android/net/NetworkReleasedException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 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 android.annotation.SystemApi;
+
+/**
+ * Indicates that the {@link Network} was released and is no longer available.
+ *
+ * @hide
+ */
+@SystemApi
+public class NetworkReleasedException extends Exception {
+ /** @hide */
+ public NetworkReleasedException() {
+ super("The network was released and is no longer available");
+ }
+}
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index f0c637c76ec5..04011fc6816e 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -353,7 +353,9 @@ public class NetworkRequest implements Parcelable {
* NetworkSpecifier.
*/
public Builder setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
- MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(networkSpecifier);
+ if (networkSpecifier instanceof MatchAllNetworkSpecifier) {
+ throw new IllegalArgumentException("A MatchAllNetworkSpecifier is not permitted");
+ }
mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
return this;
}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index b5962c5bae14..8be4af7b1396 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -81,11 +81,11 @@ public class NetworkUtils {
public native static boolean bindProcessToNetworkForHostResolution(int netId);
/**
- * Explicitly binds {@code socketfd} to the network designated by {@code netId}. This
+ * Explicitly binds {@code fd} to the network designated by {@code netId}. This
* overrides any binding via {@link #bindProcessToNetwork}.
* @return 0 on success or negative errno on failure.
*/
- public native static int bindSocketToNetwork(int socketfd, int netId);
+ public static native int bindSocketToNetwork(FileDescriptor fd, int netId);
/**
* Protect {@code fd} from VPN connections. After protecting, data sent through
@@ -93,9 +93,7 @@ public class NetworkUtils {
* forwarded through the VPN.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static boolean protectFromVpn(FileDescriptor fd) {
- return protectFromVpn(fd.getInt$());
- }
+ public static native boolean protectFromVpn(FileDescriptor fd);
/**
* Protect {@code socketfd} from VPN connections. After protecting, data sent through
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index a202d77a211a..c9bca2876b0a 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -355,7 +355,7 @@ public class ProxyInfo implements Parcelable {
port = in.readInt();
}
String exclList = in.readString();
- String[] parsedExclList = in.readStringArray();
+ String[] parsedExclList = in.createStringArray();
ProxyInfo proxyProperties = new ProxyInfo(host, port, exclList, parsedExclList);
return proxyProperties;
}
diff --git a/core/java/android/net/QosCallback.java b/core/java/android/net/QosCallback.java
new file mode 100644
index 000000000000..22f06bc0e690
--- /dev/null
+++ b/core/java/android/net/QosCallback.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Receives Qos information given a {@link Network}. The callback is registered with
+ * {@link ConnectivityManager#registerQosCallback}.
+ *
+ * <p>
+ * <br/>
+ * The callback will no longer receive calls if any of the following takes place:
+ * <ol>
+ * <li>{@link ConnectivityManager#unregisterQosCallback(QosCallback)} is called with the same
+ * callback instance.</li>
+ * <li>{@link QosCallback#onError(QosCallbackException)} is called.</li>
+ * <li>A network specific issue occurs. eg. Congestion on a carrier network.</li>
+ * <li>The network registered with the callback has no associated QoS providers</li>
+ * </ul>
+ * {@hide}
+ */
+@SystemApi
+public abstract class QosCallback {
+ /**
+ * Invoked after an error occurs on a registered callback. Once called, the callback is
+ * automatically unregistered and the callback will no longer receive calls.
+ *
+ * <p>The underlying exception can either be a runtime exception or a custom exception made for
+ * {@link QosCallback}. see: {@link QosCallbackException}.
+ *
+ * @param exception wraps the underlying cause
+ */
+ public void onError(@NonNull final QosCallbackException exception) {
+ }
+
+ /**
+ * Called when a Qos Session first becomes available to the callback or if its attributes have
+ * changed.
+ * <p>
+ * Note: The callback may be called multiple times with the same attributes.
+ *
+ * @param session the available session
+ * @param sessionAttributes the attributes of the session
+ */
+ public void onQosSessionAvailable(@NonNull final QosSession session,
+ @NonNull final QosSessionAttributes sessionAttributes) {
+ }
+
+ /**
+ * Called after a Qos Session is lost.
+ * <p>
+ * At least one call to
+ * {@link QosCallback#onQosSessionAvailable(QosSession, QosSessionAttributes)}
+ * with the same {@link QosSession} will precede a call to lost.
+ *
+ * @param session the lost session
+ */
+ public void onQosSessionLost(@NonNull final QosSession session) {
+ }
+
+ /**
+ * Thrown when there is a problem registering {@link QosCallback} with
+ * {@link ConnectivityManager#registerQosCallback(QosSocketInfo, QosCallback, Executor)}.
+ */
+ public static class QosCallbackRegistrationException extends RuntimeException {
+ /**
+ * @hide
+ */
+ public QosCallbackRegistrationException() {
+ super();
+ }
+ }
+}
diff --git a/core/java/android/net/QosCallbackConnection.java b/core/java/android/net/QosCallbackConnection.java
new file mode 100644
index 000000000000..bdb4ad68cd7b
--- /dev/null
+++ b/core/java/android/net/QosCallbackConnection.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * Sends messages from {@link com.android.server.ConnectivityService} to the registered
+ * {@link QosCallback}.
+ * <p/>
+ * This is a satellite class of {@link ConnectivityManager} and not meant
+ * to be used in other contexts.
+ *
+ * @hide
+ */
+class QosCallbackConnection extends android.net.IQosCallback.Stub {
+
+ @NonNull private final ConnectivityManager mConnectivityManager;
+ @Nullable private volatile QosCallback mCallback;
+ @NonNull private final Executor mExecutor;
+
+ @VisibleForTesting
+ @Nullable
+ public QosCallback getCallback() {
+ return mCallback;
+ }
+
+ /**
+ * The constructor for the connection
+ *
+ * @param connectivityManager the mgr that created this connection
+ * @param callback the callback to send messages back to
+ * @param executor The executor on which the callback will be invoked. The provided
+ * {@link Executor} must run callback sequentially, otherwise the order of
+ * callbacks cannot be guaranteed.
+ */
+ QosCallbackConnection(@NonNull final ConnectivityManager connectivityManager,
+ @NonNull final QosCallback callback,
+ @NonNull final Executor executor) {
+ mConnectivityManager = Objects.requireNonNull(connectivityManager,
+ "connectivityManager must be non-null");
+ mCallback = Objects.requireNonNull(callback, "callback must be non-null");
+ mExecutor = Objects.requireNonNull(executor, "executor must be non-null");
+ }
+
+ /**
+ * Called when either the {@link EpsBearerQosSessionAttributes} has changed or on the first time
+ * the attributes have become available.
+ *
+ * @param session the session that is now available
+ * @param attributes the corresponding attributes of session
+ */
+ @Override
+ public void onQosEpsBearerSessionAvailable(@NonNull final QosSession session,
+ @NonNull final EpsBearerQosSessionAttributes attributes) {
+
+ mExecutor.execute(() -> {
+ final QosCallback callback = mCallback;
+ if (callback != null) {
+ callback.onQosSessionAvailable(session, attributes);
+ }
+ });
+ }
+
+ /**
+ * Called when the session is lost.
+ *
+ * @param session the session that was lost
+ */
+ @Override
+ public void onQosSessionLost(@NonNull final QosSession session) {
+ mExecutor.execute(() -> {
+ final QosCallback callback = mCallback;
+ if (callback != null) {
+ callback.onQosSessionLost(session);
+ }
+ });
+ }
+
+ /**
+ * Called when there is an error on the registered callback.
+ *
+ * @param errorType the type of error
+ */
+ @Override
+ public void onError(@QosCallbackException.ExceptionType final int errorType) {
+ mExecutor.execute(() -> {
+ final QosCallback callback = mCallback;
+ if (callback != null) {
+ // Messages no longer need to be received since there was an error.
+ stopReceivingMessages();
+ mConnectivityManager.unregisterQosCallback(callback);
+ callback.onError(QosCallbackException.createException(errorType));
+ }
+ });
+ }
+
+ /**
+ * The callback will stop receiving messages.
+ * <p/>
+ * There are no synchronization guarantees on exactly when the callback will stop receiving
+ * messages.
+ */
+ void stopReceivingMessages() {
+ mCallback = null;
+ }
+}
diff --git a/core/java/android/net/QosCallbackException.java b/core/java/android/net/QosCallbackException.java
new file mode 100644
index 000000000000..7fd9a527e2ac
--- /dev/null
+++ b/core/java/android/net/QosCallbackException.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This is the exception type passed back through the onError method on {@link QosCallback}.
+ * {@link QosCallbackException#getCause()} contains the actual error that caused this exception.
+ *
+ * The possible exception types as causes are:
+ * 1. {@link NetworkReleasedException}
+ * 2. {@link SocketNotBoundException}
+ * 3. {@link UnsupportedOperationException}
+ * 4. {@link SocketLocalAddressChangedException}
+ *
+ * @hide
+ */
+@SystemApi
+public final class QosCallbackException extends Exception {
+
+ /** @hide */
+ @IntDef(prefix = {"EX_TYPE_"}, value = {
+ EX_TYPE_FILTER_NONE,
+ EX_TYPE_FILTER_NETWORK_RELEASED,
+ EX_TYPE_FILTER_SOCKET_NOT_BOUND,
+ EX_TYPE_FILTER_NOT_SUPPORTED,
+ EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ExceptionType {}
+
+ private static final String TAG = "QosCallbackException";
+
+ // Types of exceptions supported //
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_NONE = 0;
+
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_NETWORK_RELEASED = 1;
+
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_SOCKET_NOT_BOUND = 2;
+
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_NOT_SUPPORTED = 3;
+
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED = 4;
+
+ /**
+ * Creates exception based off of a type and message. Not all types of exceptions accept a
+ * custom message.
+ *
+ * {@hide}
+ */
+ @NonNull
+ static QosCallbackException createException(@ExceptionType final int type) {
+ switch (type) {
+ case EX_TYPE_FILTER_NETWORK_RELEASED:
+ return new QosCallbackException(new NetworkReleasedException());
+ case EX_TYPE_FILTER_SOCKET_NOT_BOUND:
+ return new QosCallbackException(new SocketNotBoundException());
+ case EX_TYPE_FILTER_NOT_SUPPORTED:
+ return new QosCallbackException(new UnsupportedOperationException(
+ "This device does not support the specified filter"));
+ case EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED:
+ return new QosCallbackException(
+ new SocketLocalAddressChangedException());
+ default:
+ Log.wtf(TAG, "create: No case setup for exception type: '" + type + "'");
+ return new QosCallbackException(
+ new RuntimeException("Unknown exception code: " + type));
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public QosCallbackException(@NonNull final String message) {
+ super(message);
+ }
+
+ /**
+ * @hide
+ */
+ public QosCallbackException(@NonNull final Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/core/java/android/net/QosFilter.java b/core/java/android/net/QosFilter.java
new file mode 100644
index 000000000000..ab55002e02b3
--- /dev/null
+++ b/core/java/android/net/QosFilter.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
+import java.net.InetAddress;
+
+/**
+ * Provides the related filtering logic to the {@link NetworkAgent} to match {@link QosSession}s
+ * to their related {@link QosCallback}.
+ *
+ * Used by the {@link com.android.server.ConnectivityService} to validate a {@link QosCallback}
+ * is still able to receive a {@link QosSession}.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class QosFilter {
+
+ /**
+ * The constructor is kept hidden from outside this package to ensure that all derived types
+ * are known and properly handled when being passed to and from {@link NetworkAgent}.
+ *
+ * @hide
+ */
+ QosFilter() {
+ }
+
+ /**
+ * The network used with this filter.
+ *
+ * @return the registered {@link Network}
+ */
+ @NonNull
+ public abstract Network getNetwork();
+
+ /**
+ * Validates that conditions have not changed such that no further {@link QosSession}s should
+ * be passed back to the {@link QosCallback} associated to this filter.
+ *
+ * @return the error code when present, otherwise the filter is valid
+ *
+ * @hide
+ */
+ @QosCallbackException.ExceptionType
+ public abstract int validate();
+
+ /**
+ * Determines whether or not the parameters is a match for the filter.
+ *
+ * @param address the local address
+ * @param startPort the start of the port range
+ * @param endPort the end of the port range
+ * @return whether the parameters match the local address of the filter
+ */
+ public abstract boolean matchesLocalAddress(@NonNull InetAddress address,
+ int startPort, int endPort);
+}
+
diff --git a/core/java/android/net/QosFilterParcelable.aidl b/core/java/android/net/QosFilterParcelable.aidl
new file mode 100644
index 000000000000..312d6352ee92
--- /dev/null
+++ b/core/java/android/net/QosFilterParcelable.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright (C) 2020 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+parcelable QosFilterParcelable;
+
diff --git a/core/java/android/net/QosFilterParcelable.java b/core/java/android/net/QosFilterParcelable.java
new file mode 100644
index 000000000000..da3b2cf8ff7a
--- /dev/null
+++ b/core/java/android/net/QosFilterParcelable.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 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 android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.util.Objects;
+
+/**
+ * Aware of how to parcel different types of {@link QosFilter}s. Any new type of qos filter must
+ * have a specialized case written here.
+ * <p/>
+ * Specifically leveraged when transferring {@link QosFilter} from
+ * {@link com.android.server.ConnectivityService} to {@link NetworkAgent} when the filter is first
+ * registered.
+ * <p/>
+ * This is not meant to be used in other contexts.
+ *
+ * @hide
+ */
+public final class QosFilterParcelable implements Parcelable {
+
+ private static final String LOG_TAG = QosFilterParcelable.class.getSimpleName();
+
+ // Indicates that the filter was not successfully written to the parcel.
+ private static final int NO_FILTER_PRESENT = 0;
+
+ // The parcel is of type qos socket filter.
+ private static final int QOS_SOCKET_FILTER = 1;
+
+ private final QosFilter mQosFilter;
+
+ /**
+ * The underlying qos filter.
+ * <p/>
+ * Null only in the case parceling failed.
+ */
+ @Nullable
+ public QosFilter getQosFilter() {
+ return mQosFilter;
+ }
+
+ public QosFilterParcelable(@NonNull final QosFilter qosFilter) {
+ Objects.requireNonNull(qosFilter, "qosFilter must be non-null");
+
+ // NOTE: Normally a type check would belong here, but doing so breaks unit tests that rely
+ // on mocking qos filter.
+ mQosFilter = qosFilter;
+ }
+
+ private QosFilterParcelable(final Parcel in) {
+ final int filterParcelType = in.readInt();
+
+ switch (filterParcelType) {
+ case QOS_SOCKET_FILTER: {
+ mQosFilter = new QosSocketFilter(QosSocketInfo.CREATOR.createFromParcel(in));
+ break;
+ }
+
+ case NO_FILTER_PRESENT:
+ default: {
+ mQosFilter = null;
+ }
+ }
+ }
+
+ public static final Creator<QosFilterParcelable> CREATOR = new Creator<QosFilterParcelable>() {
+ @Override
+ public QosFilterParcelable createFromParcel(final Parcel in) {
+ return new QosFilterParcelable(in);
+ }
+
+ @Override
+ public QosFilterParcelable[] newArray(final int size) {
+ return new QosFilterParcelable[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(final Parcel dest, final int flags) {
+ if (mQosFilter instanceof QosSocketFilter) {
+ dest.writeInt(QOS_SOCKET_FILTER);
+ final QosSocketFilter qosSocketFilter = (QosSocketFilter) mQosFilter;
+ qosSocketFilter.getQosSocketInfo().writeToParcel(dest, 0);
+ return;
+ }
+ dest.writeInt(NO_FILTER_PRESENT);
+ Log.e(LOG_TAG, "Parceling failed, unknown type of filter present: " + mQosFilter);
+ }
+}
diff --git a/core/java/android/net/QosSession.aidl b/core/java/android/net/QosSession.aidl
new file mode 100644
index 000000000000..c2cf36624b55
--- /dev/null
+++ b/core/java/android/net/QosSession.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright (C) 2020 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+parcelable QosSession;
+
diff --git a/core/java/android/net/QosSession.java b/core/java/android/net/QosSession.java
new file mode 100644
index 000000000000..4f3bb77c5877
--- /dev/null
+++ b/core/java/android/net/QosSession.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Provides identifying information of a QoS session. Sent to an application through
+ * {@link QosCallback}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class QosSession implements Parcelable {
+
+ /**
+ * The {@link QosSession} is a LTE EPS Session.
+ */
+ public static final int TYPE_EPS_BEARER = 1;
+
+ private final int mSessionId;
+
+ private final int mSessionType;
+
+ /**
+ * Gets the unique id of the session that is used to differentiate sessions across different
+ * types.
+ * <p/>
+ * Note: Different qos sessions can be provided by different actors.
+ *
+ * @return the unique id
+ */
+ public long getUniqueId() {
+ return (long) mSessionType << 32 | mSessionId;
+ }
+
+ /**
+ * Gets the session id that is unique within that type.
+ * <p/>
+ * Note: The session id is set by the actor providing the qos. It can be either manufactured by
+ * the actor, but also may have a particular meaning within that type. For example, using the
+ * bearer id as the session id for {@link android.telephony.data.EpsBearerQosSessionAttributes}
+ * is a straight forward way to keep the sessions unique from one another within that type.
+ *
+ * @return the id of the session
+ */
+ public int getSessionId() {
+ return mSessionId;
+ }
+
+ /**
+ * Gets the type of session.
+ */
+ @QosSessionType
+ public int getSessionType() {
+ return mSessionType;
+ }
+
+ /**
+ * Creates a {@link QosSession}.
+ *
+ * @param sessionId uniquely identifies the session across all sessions of the same type
+ * @param sessionType the type of session
+ */
+ public QosSession(final int sessionId, @QosSessionType final int sessionType) {
+ //Ensures the session id is unique across types of sessions
+ mSessionId = sessionId;
+ mSessionType = sessionType;
+ }
+
+
+ @Override
+ public String toString() {
+ return "QosSession{"
+ + "mSessionId=" + mSessionId
+ + ", mSessionType=" + mSessionType
+ + '}';
+ }
+
+ /**
+ * Annotations for types of qos sessions.
+ */
+ @IntDef(value = {
+ TYPE_EPS_BEARER,
+ })
+ @interface QosSessionType {}
+
+ private QosSession(final Parcel in) {
+ mSessionId = in.readInt();
+ mSessionType = in.readInt();
+ }
+
+ @NonNull
+ public static final Creator<QosSession> CREATOR = new Creator<QosSession>() {
+ @NonNull
+ @Override
+ public QosSession createFromParcel(@NonNull final Parcel in) {
+ return new QosSession(in);
+ }
+
+ @NonNull
+ @Override
+ public QosSession[] newArray(final int size) {
+ return new QosSession[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+ dest.writeInt(mSessionId);
+ dest.writeInt(mSessionType);
+ }
+}
diff --git a/core/java/android/net/QosSessionAttributes.java b/core/java/android/net/QosSessionAttributes.java
new file mode 100644
index 000000000000..7a885942d1b5
--- /dev/null
+++ b/core/java/android/net/QosSessionAttributes.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.SystemApi;
+
+/**
+ * Implemented by classes that encapsulate Qos related attributes that describe a Qos Session.
+ *
+ * Use the instanceof keyword to determine the underlying type.
+ *
+ * @hide
+ */
+@SystemApi
+public interface QosSessionAttributes {
+}
diff --git a/core/java/android/net/QosSocketFilter.java b/core/java/android/net/QosSocketFilter.java
new file mode 100644
index 000000000000..2080e68f5fba
--- /dev/null
+++ b/core/java/android/net/QosSocketFilter.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.net.QosCallbackException.EX_TYPE_FILTER_NONE;
+import static android.net.QosCallbackException.EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.FileDescriptor;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.util.Objects;
+
+/**
+ * Filters a {@link QosSession} according to the binding on the provided {@link Socket}.
+ *
+ * @hide
+ */
+public class QosSocketFilter extends QosFilter {
+
+ private static final String TAG = QosSocketFilter.class.getSimpleName();
+
+ @NonNull
+ private final QosSocketInfo mQosSocketInfo;
+
+ /**
+ * Creates a {@link QosSocketFilter} based off of {@link QosSocketInfo}.
+ *
+ * @param qosSocketInfo the information required to filter and validate
+ */
+ public QosSocketFilter(@NonNull final QosSocketInfo qosSocketInfo) {
+ Objects.requireNonNull(qosSocketInfo, "qosSocketInfo must be non-null");
+ mQosSocketInfo = qosSocketInfo;
+ }
+
+ /**
+ * Gets the parcelable qos socket info that was used to create the filter.
+ */
+ @NonNull
+ public QosSocketInfo getQosSocketInfo() {
+ return mQosSocketInfo;
+ }
+
+ /**
+ * Performs two validations:
+ * 1. If the socket is not bound, then return
+ * {@link QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_BOUND}. This is detected
+ * by checking the local address on the filter which becomes null when the socket is no
+ * longer bound.
+ * 2. In the scenario that the socket is now bound to a different local address, which can
+ * happen in the case of UDP, then
+ * {@link QosCallbackException.EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED} is returned.
+ * @return validation error code
+ */
+ @Override
+ public int validate() {
+ final InetSocketAddress sa = getAddressFromFileDescriptor();
+ if (sa == null) {
+ return QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_BOUND;
+ }
+
+ if (!sa.equals(mQosSocketInfo.getLocalSocketAddress())) {
+ return EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED;
+ }
+
+ return EX_TYPE_FILTER_NONE;
+ }
+
+ /**
+ * The local address of the socket's binding.
+ *
+ * Note: If the socket is no longer bound, null is returned.
+ *
+ * @return the local address
+ */
+ @Nullable
+ private InetSocketAddress getAddressFromFileDescriptor() {
+ final ParcelFileDescriptor parcelFileDescriptor = mQosSocketInfo.getParcelFileDescriptor();
+ if (parcelFileDescriptor == null) return null;
+
+ final FileDescriptor fd = parcelFileDescriptor.getFileDescriptor();
+ if (fd == null) return null;
+
+ final SocketAddress address;
+ try {
+ address = Os.getsockname(fd);
+ } catch (final ErrnoException e) {
+ Log.e(TAG, "getAddressFromFileDescriptor: getLocalAddress exception", e);
+ return null;
+ }
+ if (address instanceof InetSocketAddress) {
+ return (InetSocketAddress) address;
+ }
+ return null;
+ }
+
+ /**
+ * The network used with this filter.
+ *
+ * @return the registered {@link Network}
+ */
+ @NonNull
+ @Override
+ public Network getNetwork() {
+ return mQosSocketInfo.getNetwork();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public boolean matchesLocalAddress(@NonNull final InetAddress address, final int startPort,
+ final int endPort) {
+ if (mQosSocketInfo.getLocalSocketAddress() == null) {
+ return false;
+ }
+
+ return matchesLocalAddress(mQosSocketInfo.getLocalSocketAddress(), address, startPort,
+ endPort);
+ }
+
+ /**
+ * Called from {@link QosSocketFilter#matchesLocalAddress(InetAddress, int, int)} with the
+ * filterSocketAddress coming from {@link QosSocketInfo#getLocalSocketAddress()}.
+ * <p>
+ * This method exists for testing purposes since {@link QosSocketInfo} couldn't be mocked
+ * due to being final.
+ *
+ * @param filterSocketAddress the socket address of the filter
+ * @param address the address to compare the filterSocketAddressWith
+ * @param startPort the start of the port range to check
+ * @param endPort the end of the port range to check
+ */
+ @VisibleForTesting
+ public static boolean matchesLocalAddress(@NonNull final InetSocketAddress filterSocketAddress,
+ @NonNull final InetAddress address,
+ final int startPort, final int endPort) {
+ return startPort <= filterSocketAddress.getPort()
+ && endPort >= filterSocketAddress.getPort()
+ && filterSocketAddress.getAddress().equals(address);
+ }
+}
diff --git a/core/java/android/net/QosSocketInfo.aidl b/core/java/android/net/QosSocketInfo.aidl
new file mode 100644
index 000000000000..476c0900e23e
--- /dev/null
+++ b/core/java/android/net/QosSocketInfo.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright (C) 2020 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+parcelable QosSocketInfo;
+
diff --git a/core/java/android/net/QosSocketInfo.java b/core/java/android/net/QosSocketInfo.java
new file mode 100644
index 000000000000..d37c4691ddde
--- /dev/null
+++ b/core/java/android/net/QosSocketInfo.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.Objects;
+
+/**
+ * Used in conjunction with
+ * {@link ConnectivityManager#registerQosCallback}
+ * in order to receive Qos Sessions related to the local address and port of a bound {@link Socket}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class QosSocketInfo implements Parcelable {
+
+ @NonNull
+ private final Network mNetwork;
+
+ @NonNull
+ private final ParcelFileDescriptor mParcelFileDescriptor;
+
+ @NonNull
+ private final InetSocketAddress mLocalSocketAddress;
+
+ /**
+ * The {@link Network} the socket is on.
+ *
+ * @return the registered {@link Network}
+ */
+ @NonNull
+ public Network getNetwork() {
+ return mNetwork;
+ }
+
+ /**
+ * The parcel file descriptor wrapped around the socket's file descriptor.
+ *
+ * @return the parcel file descriptor of the socket
+ */
+ @NonNull
+ ParcelFileDescriptor getParcelFileDescriptor() {
+ return mParcelFileDescriptor;
+ }
+
+ /**
+ * The local address of the socket passed into {@link QosSocketInfo(Network, Socket)}.
+ * The value does not reflect any changes that occur to the socket after it is first set
+ * in the constructor.
+ *
+ * @return the local address of the socket
+ */
+ @NonNull
+ public InetSocketAddress getLocalSocketAddress() {
+ return mLocalSocketAddress;
+ }
+
+ /**
+ * Creates a {@link QosSocketInfo} given a {@link Network} and bound {@link Socket}. The
+ * {@link Socket} must remain bound in order to receive {@link QosSession}s.
+ *
+ * @param network the network
+ * @param socket the bound {@link Socket}
+ */
+ public QosSocketInfo(@NonNull final Network network, @NonNull final Socket socket)
+ throws IOException {
+ Objects.requireNonNull(socket, "socket cannot be null");
+
+ mNetwork = Objects.requireNonNull(network, "network cannot be null");
+ mParcelFileDescriptor = ParcelFileDescriptor.dup(socket.getFileDescriptor$());
+ mLocalSocketAddress =
+ new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort());
+ }
+
+ /* Parcelable methods */
+ private QosSocketInfo(final Parcel in) {
+ mNetwork = Objects.requireNonNull(Network.CREATOR.createFromParcel(in));
+ mParcelFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(in);
+
+ final int addressLength = in.readInt();
+ mLocalSocketAddress = readSocketAddress(in, addressLength);
+ }
+
+ private InetSocketAddress readSocketAddress(final Parcel in, final int addressLength) {
+ final byte[] address = new byte[addressLength];
+ in.readByteArray(address);
+ final int port = in.readInt();
+
+ try {
+ return new InetSocketAddress(InetAddress.getByAddress(address), port);
+ } catch (final UnknownHostException e) {
+ /* The catch block was purposely left empty. UnknownHostException will never be thrown
+ since the address provided is numeric and non-null. */
+ }
+ return new InetSocketAddress();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+ mNetwork.writeToParcel(dest, 0);
+ mParcelFileDescriptor.writeToParcel(dest, 0);
+
+ final byte[] address = mLocalSocketAddress.getAddress().getAddress();
+ dest.writeInt(address.length);
+ dest.writeByteArray(address);
+ dest.writeInt(mLocalSocketAddress.getPort());
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<QosSocketInfo> CREATOR =
+ new Parcelable.Creator<QosSocketInfo>() {
+ @NonNull
+ @Override
+ public QosSocketInfo createFromParcel(final Parcel in) {
+ return new QosSocketInfo(in);
+ }
+
+ @NonNull
+ @Override
+ public QosSocketInfo[] newArray(final int size) {
+ return new QosSocketInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/net/SocketLocalAddressChangedException.java b/core/java/android/net/SocketLocalAddressChangedException.java
new file mode 100644
index 000000000000..9daad83fd13e
--- /dev/null
+++ b/core/java/android/net/SocketLocalAddressChangedException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 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 android.annotation.SystemApi;
+
+/**
+ * Thrown when the local address of the socket has changed.
+ *
+ * @hide
+ */
+@SystemApi
+public class SocketLocalAddressChangedException extends Exception {
+ /** @hide */
+ public SocketLocalAddressChangedException() {
+ super("The local address of the socket changed");
+ }
+}
diff --git a/core/java/android/net/SocketNotBoundException.java b/core/java/android/net/SocketNotBoundException.java
new file mode 100644
index 000000000000..b1d7026ac981
--- /dev/null
+++ b/core/java/android/net/SocketNotBoundException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 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 android.annotation.SystemApi;
+
+/**
+ * Thrown when a previously bound socket becomes unbound.
+ *
+ * @hide
+ */
+@SystemApi
+public class SocketNotBoundException extends Exception {
+ /** @hide */
+ public SocketNotBoundException() {
+ super("The socket is unbound");
+ }
+}
diff --git a/core/java/android/net/TcpSocketKeepalive.java b/core/java/android/net/TcpSocketKeepalive.java
index 436397ea7754..d89814d49bd0 100644
--- a/core/java/android/net/TcpSocketKeepalive.java
+++ b/core/java/android/net/TcpSocketKeepalive.java
@@ -21,7 +21,6 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;
-import java.io.FileDescriptor;
import java.util.concurrent.Executor;
/** @hide */
@@ -54,8 +53,7 @@ final class TcpSocketKeepalive extends SocketKeepalive {
void startImpl(int intervalSec) {
mExecutor.execute(() -> {
try {
- final FileDescriptor fd = mPfd.getFileDescriptor();
- mService.startTcpKeepalive(mNetwork, fd, intervalSec, mCallback);
+ mService.startTcpKeepalive(mNetwork, mPfd, intervalSec, mCallback);
} catch (RemoteException e) {
Log.e(TAG, "Error starting packet keepalive: ", e);
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/net/TestNetworkInterface.java b/core/java/android/net/TestNetworkInterface.java
index 84550834be07..4449ff80180b 100644
--- a/core/java/android/net/TestNetworkInterface.java
+++ b/core/java/android/net/TestNetworkInterface.java
@@ -15,7 +15,8 @@
*/
package android.net;
-import android.annotation.TestApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
@@ -25,9 +26,11 @@ import android.os.Parcelable;
*
* @hide
*/
-@TestApi
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final class TestNetworkInterface implements Parcelable {
+ @NonNull
private final ParcelFileDescriptor mFileDescriptor;
+ @NonNull
private final String mInterfaceName;
@Override
@@ -36,29 +39,32 @@ public final class TestNetworkInterface implements Parcelable {
}
@Override
- public void writeToParcel(Parcel out, int flags) {
+ public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeParcelable(mFileDescriptor, PARCELABLE_WRITE_RETURN_VALUE);
out.writeString(mInterfaceName);
}
- public TestNetworkInterface(ParcelFileDescriptor pfd, String intf) {
+ public TestNetworkInterface(@NonNull ParcelFileDescriptor pfd, @NonNull String intf) {
mFileDescriptor = pfd;
mInterfaceName = intf;
}
- private TestNetworkInterface(Parcel in) {
+ private TestNetworkInterface(@NonNull Parcel in) {
mFileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
mInterfaceName = in.readString();
}
+ @NonNull
public ParcelFileDescriptor getFileDescriptor() {
return mFileDescriptor;
}
+ @NonNull
public String getInterfaceName() {
return mInterfaceName;
}
+ @NonNull
public static final Parcelable.Creator<TestNetworkInterface> CREATOR =
new Parcelable.Creator<TestNetworkInterface>() {
public TestNetworkInterface createFromParcel(Parcel in) {
diff --git a/core/java/android/net/TestNetworkManager.java b/core/java/android/net/TestNetworkManager.java
index a0a563b37025..4e894143bf91 100644
--- a/core/java/android/net/TestNetworkManager.java
+++ b/core/java/android/net/TestNetworkManager.java
@@ -17,18 +17,21 @@ package android.net;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.TestApi;
+import android.annotation.SystemApi;
import android.os.IBinder;
import android.os.RemoteException;
import com.android.internal.util.Preconditions;
+import java.util.Arrays;
+import java.util.Collection;
+
/**
* Class that allows creation and management of per-app, test-only networks
*
* @hide
*/
-@TestApi
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public class TestNetworkManager {
/**
* Prefix for tun interfaces created by this class.
@@ -57,7 +60,7 @@ public class TestNetworkManager {
* @param network The test network that should be torn down
* @hide
*/
- @TestApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void teardownTestNetwork(@NonNull Network network) {
try {
mService.teardownTestNetwork(network.netId);
@@ -102,7 +105,7 @@ public class TestNetworkManager {
* @param binder A binder object guarding the lifecycle of this test network.
* @hide
*/
- @TestApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void setupTestNetwork(@NonNull String iface, @NonNull IBinder binder) {
setupTestNetwork(iface, null, true, new int[0], binder);
}
@@ -127,12 +130,29 @@ public class TestNetworkManager {
* @param linkAddrs an array of LinkAddresses to assign to the TUN interface
* @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the
* TUN interface.
+ * @deprecated Use {@link #createTunInterface(Collection)} instead.
* @hide
*/
- @TestApi
+ @Deprecated
+ @NonNull
public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
+ return createTunInterface(Arrays.asList(linkAddrs));
+ }
+
+ /**
+ * Create a tun interface for testing purposes
+ *
+ * @param linkAddrs an array of LinkAddresses to assign to the TUN interface
+ * @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the
+ * TUN interface.
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @NonNull
+ public TestNetworkInterface createTunInterface(@NonNull Collection<LinkAddress> linkAddrs) {
try {
- return mService.createTunInterface(linkAddrs);
+ final LinkAddress[] arr = new LinkAddress[linkAddrs.size()];
+ return mService.createTunInterface(linkAddrs.toArray(arr));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -145,7 +165,8 @@ public class TestNetworkManager {
* TAP interface.
* @hide
*/
- @TestApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @NonNull
public TestNetworkInterface createTapInterface() {
try {
return mService.createTapInterface();
diff --git a/core/java/android/net/TransportInfo.java b/core/java/android/net/TransportInfo.java
index b78d3feccfa0..aa4bbb051179 100644
--- a/core/java/android/net/TransportInfo.java
+++ b/core/java/android/net/TransportInfo.java
@@ -16,10 +16,48 @@
package android.net;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
/**
* A container for transport-specific capabilities which is returned by
* {@link NetworkCapabilities#getTransportInfo()}. Specific networks
* may provide concrete implementations of this interface.
+ * @see android.net.wifi.aware.WifiAwareNetworkInfo
+ * @see android.net.wifi.WifiInfo
*/
public interface TransportInfo {
+
+ /**
+ * Create a copy of a {@link TransportInfo} that will preserve location sensitive fields that
+ * were set based on the permissions of the process that originally received it.
+ *
+ * <p>By default {@link TransportInfo} does not preserve such fields during parceling, as
+ * they should not be shared outside of the process that receives them without appropriate
+ * checks.
+ *
+ * @param parcelLocationSensitiveFields Whether the location sensitive fields should be kept
+ * when parceling
+ * @return Copy of this instance.
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ default TransportInfo makeCopy(boolean parcelLocationSensitiveFields) {
+ return this;
+ }
+
+ /**
+ * Returns whether this TransportInfo type has location sensitive fields or not (helps
+ * to determine whether to perform a location permission check or not before sending to
+ * apps).
+ *
+ * @return {@code true} if this instance contains location sensitive info, {@code false}
+ * otherwise.
+ * @hide
+ */
+ @SystemApi
+ default boolean hasLocationSensitiveFields() {
+ return false;
+ }
}
diff --git a/core/java/com/android/internal/net/VpnInfo.aidl b/core/java/android/net/UnderlyingNetworkInfo.aidl
index 6fc97be4095b..a56f2f40583b 100644
--- a/core/java/com/android/internal/net/VpnInfo.aidl
+++ b/core/java/android/net/UnderlyingNetworkInfo.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package com.android.internal.net;
+package android.net;
-parcelable VpnInfo;
+parcelable UnderlyingNetworkInfo;
diff --git a/core/java/android/net/UnderlyingNetworkInfo.java b/core/java/android/net/UnderlyingNetworkInfo.java
new file mode 100644
index 000000000000..8fb4832e06c8
--- /dev/null
+++ b/core/java/android/net/UnderlyingNetworkInfo.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A lightweight container used to carry information on the networks that underly a given
+ * virtual network.
+ *
+ * @hide
+ */
+public final class UnderlyingNetworkInfo implements Parcelable {
+ /** The owner of this network. */
+ public final int ownerUid;
+ /** The interface name of this network. */
+ @NonNull
+ public final String iface;
+ /** The names of the interfaces underlying this network. */
+ @NonNull
+ public final List<String> underlyingIfaces;
+
+ public UnderlyingNetworkInfo(int ownerUid, @NonNull String iface,
+ @NonNull List<String> underlyingIfaces) {
+ Objects.requireNonNull(iface);
+ Objects.requireNonNull(underlyingIfaces);
+ this.ownerUid = ownerUid;
+ this.iface = iface;
+ this.underlyingIfaces = underlyingIfaces;
+ }
+
+ private UnderlyingNetworkInfo(@NonNull Parcel in) {
+ this.ownerUid = in.readInt();
+ this.iface = in.readString();
+ this.underlyingIfaces = new ArrayList<>();
+ in.readList(this.underlyingIfaces, null /*classLoader*/);
+ }
+
+ @Override
+ public String toString() {
+ return "UnderlyingNetworkInfo{"
+ + "ownerUid=" + ownerUid
+ + ", iface='" + iface + '\''
+ + ", underlyingIfaces='" + underlyingIfaces.toString() + '\''
+ + '}';
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(ownerUid);
+ dest.writeString(iface);
+ dest.writeList(underlyingIfaces);
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<UnderlyingNetworkInfo> CREATOR =
+ new Parcelable.Creator<UnderlyingNetworkInfo>() {
+ @NonNull
+ @Override
+ public UnderlyingNetworkInfo createFromParcel(@NonNull Parcel in) {
+ return new UnderlyingNetworkInfo(in);
+ }
+
+ @NonNull
+ @Override
+ public UnderlyingNetworkInfo[] newArray(int size) {
+ return new UnderlyingNetworkInfo[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof UnderlyingNetworkInfo)) return false;
+ final UnderlyingNetworkInfo that = (UnderlyingNetworkInfo) o;
+ return ownerUid == that.ownerUid
+ && Objects.equals(iface, that.iface)
+ && Objects.equals(underlyingIfaces, that.underlyingIfaces);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ownerUid, iface, underlyingIfaces);
+ }
+}
diff --git a/core/java/android/net/metrics/ApfProgramEvent.java b/core/java/android/net/metrics/ApfProgramEvent.java
index ab12cdd22685..3d79f284fcd3 100644
--- a/core/java/android/net/metrics/ApfProgramEvent.java
+++ b/core/java/android/net/metrics/ApfProgramEvent.java
@@ -39,7 +39,11 @@ import java.util.List;
* An event logged when there is a change or event that requires updating the
* the APF program in place with a new APF program.
* {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
*/
+@Deprecated
@SystemApi
public final class ApfProgramEvent implements IpConnectivityLog.Event {
diff --git a/core/java/android/net/metrics/ApfStats.java b/core/java/android/net/metrics/ApfStats.java
index fcafb7ebd676..a32d3a65b73a 100644
--- a/core/java/android/net/metrics/ApfStats.java
+++ b/core/java/android/net/metrics/ApfStats.java
@@ -27,7 +27,11 @@ import android.os.Parcelable;
/**
* An event logged for an interface with APF capabilities when its IpClient state machine exits.
* {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
*/
+@Deprecated
@SystemApi
public final class ApfStats implements IpConnectivityLog.Event {
diff --git a/core/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java
index 8de427de1dab..e175d587c137 100644
--- a/core/java/android/net/metrics/DhcpClientEvent.java
+++ b/core/java/android/net/metrics/DhcpClientEvent.java
@@ -28,7 +28,11 @@ import android.text.TextUtils;
/**
* An event recorded when a DhcpClient state machine transitions to a new state.
* {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
*/
+@Deprecated
@SystemApi
public final class DhcpClientEvent implements IpConnectivityLog.Event {
diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
index de3129d5e94d..7dd0696d81a3 100644
--- a/core/java/android/net/metrics/DhcpErrorEvent.java
+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
@@ -27,7 +27,11 @@ import com.android.internal.util.MessageUtils;
/**
* Event class used to record error events when parsing DHCP response packets.
* {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
*/
+@Deprecated
@SystemApi
public final class DhcpErrorEvent implements IpConnectivityLog.Event {
public static final int L2_ERROR = 1;
diff --git a/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java
index 58ea91573775..5cadb45590bb 100644
--- a/core/java/android/net/metrics/IpConnectivityLog.java
+++ b/core/java/android/net/metrics/IpConnectivityLog.java
@@ -35,7 +35,11 @@ import com.android.internal.util.BitUtils;
/**
* Class for logging IpConnectvity events with IpConnectivityMetrics
* {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
*/
+@Deprecated
@SystemApi
public class IpConnectivityLog {
private static final String TAG = IpConnectivityLog.class.getSimpleName();
@@ -137,7 +141,7 @@ public class IpConnectivityLog {
* @return true if the event was successfully logged.
*/
public boolean log(@NonNull Network network, @NonNull int[] transports, @NonNull Event data) {
- return log(network.netId, transports, data);
+ return log(network.getNetId(), transports, data);
}
/**
diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java
index 4f7f3263117b..3abcc0589dc1 100644
--- a/core/java/android/net/metrics/IpManagerEvent.java
+++ b/core/java/android/net/metrics/IpManagerEvent.java
@@ -33,7 +33,11 @@ import java.lang.annotation.RetentionPolicy;
* An event recorded by IpClient when IP provisioning completes for a network or
* when a network disconnects.
* {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
*/
+@Deprecated
@SystemApi
public final class IpManagerEvent implements IpConnectivityLog.Event {
diff --git a/core/java/android/net/metrics/IpReachabilityEvent.java b/core/java/android/net/metrics/IpReachabilityEvent.java
index d5003badd614..0b65bbdbcbf6 100644
--- a/core/java/android/net/metrics/IpReachabilityEvent.java
+++ b/core/java/android/net/metrics/IpReachabilityEvent.java
@@ -29,7 +29,11 @@ import com.android.internal.util.MessageUtils;
* An event recorded when IpReachabilityMonitor sends a neighbor probe or receives
* a neighbor probe result.
* {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
*/
+@Deprecated
@SystemApi
public final class IpReachabilityEvent implements IpConnectivityLog.Event {
diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java
index 8c28f7a7d643..47eeeff90088 100644
--- a/core/java/android/net/metrics/NetworkEvent.java
+++ b/core/java/android/net/metrics/NetworkEvent.java
@@ -31,7 +31,11 @@ import java.lang.annotation.RetentionPolicy;
/**
* {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
*/
+@Deprecated
@SystemApi
public final class NetworkEvent implements IpConnectivityLog.Event {
diff --git a/core/java/android/net/metrics/RaEvent.java b/core/java/android/net/metrics/RaEvent.java
index b54874f5a573..05a47e55fce4 100644
--- a/core/java/android/net/metrics/RaEvent.java
+++ b/core/java/android/net/metrics/RaEvent.java
@@ -25,7 +25,11 @@ import android.os.Parcelable;
/**
* An event logged when the APF packet socket receives an RA packet.
* {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
*/
+@Deprecated
@SystemApi
public final class RaEvent implements IpConnectivityLog.Event {
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index 7f4e4a73677e..8118fe005d5d 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -32,7 +32,11 @@ import java.lang.annotation.RetentionPolicy;
/**
* An event recorded by NetworkMonitor when sending a probe for finding captive portals.
* {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
*/
+@Deprecated
@SystemApi
public final class ValidationProbeEvent implements IpConnectivityLog.Event {
diff --git a/core/java/android/net/util/MultinetworkPolicyTracker.java b/core/java/android/net/util/MultinetworkPolicyTracker.java
index aa0f6220036c..85e3fa3048ed 100644
--- a/core/java/android/net/util/MultinetworkPolicyTracker.java
+++ b/core/java/android/net/util/MultinetworkPolicyTracker.java
@@ -29,12 +29,11 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
-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 android.util.Log;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -114,8 +113,8 @@ public class MultinetworkPolicyTracker {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- mContext.registerReceiverAsUser(
- mBroadcastReceiver, UserHandle.ALL, intentFilter, null, mHandler);
+ mContext.registerReceiverForAllUsers(mBroadcastReceiver, intentFilter,
+ null /* broadcastPermission */, mHandler);
reevaluate();
}
@@ -204,13 +203,13 @@ public class MultinetworkPolicyTracker {
@Override
public void onChange(boolean selfChange) {
- Slog.wtf(TAG, "Should never be reached.");
+ Log.wtf(TAG, "Should never be reached.");
}
@Override
public void onChange(boolean selfChange, Uri uri) {
if (!mSettingsUris.contains(uri)) {
- Slog.wtf(TAG, "Unexpected settings observation: " + uri);
+ Log.wtf(TAG, "Unexpected settings observation: " + uri);
}
reevaluate();
}
diff --git a/core/java/android/net/vcn/IVcnManagementService.aidl b/core/java/android/net/vcn/IVcnManagementService.aidl
index 04b585cdf420..4f293eeb3c3b 100644
--- a/core/java/android/net/vcn/IVcnManagementService.aidl
+++ b/core/java/android/net/vcn/IVcnManagementService.aidl
@@ -16,7 +16,11 @@
package android.net.vcn;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
+import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
+import android.net.vcn.VcnUnderlyingNetworkPolicy;
import android.os.ParcelUuid;
/**
@@ -25,4 +29,8 @@ import android.os.ParcelUuid;
interface IVcnManagementService {
void setVcnConfig(in ParcelUuid subscriptionGroup, in VcnConfig config, in String opPkgName);
void clearVcnConfig(in ParcelUuid subscriptionGroup);
+
+ void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
+ void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
+ VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy(in NetworkCapabilities nc, in LinkProperties lp);
}
diff --git a/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl b/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl
new file mode 100644
index 000000000000..f8ae492016f0
--- /dev/null
+++ b/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn;
+
+/** @hide */
+interface IVcnUnderlyingNetworkPolicyListener {
+ void onPolicyChanged();
+} \ No newline at end of file
diff --git a/core/java/android/net/vcn/VcnConfig.java b/core/java/android/net/vcn/VcnConfig.java
index ede8faaaf261..5eb4ba6a2f8e 100644
--- a/core/java/android/net/vcn/VcnConfig.java
+++ b/core/java/android/net/vcn/VcnConfig.java
@@ -96,7 +96,11 @@ public final class VcnConfig implements Parcelable {
return mPackageName;
}
- /** Retrieves the set of configured tunnels. */
+ /**
+ * Retrieves the set of configured tunnels.
+ *
+ * @hide
+ */
@NonNull
public Set<VcnGatewayConnectionConfig> getGatewayConnectionConfigs() {
return Collections.unmodifiableSet(mGatewayConnectionConfigs);
@@ -146,7 +150,7 @@ public final class VcnConfig implements Parcelable {
}
@Override
- public void writeToParcel(Parcel out, int flags) {
+ public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeParcelable(toPersistableBundle(), flags);
}
@@ -164,8 +168,12 @@ public final class VcnConfig implements Parcelable {
}
};
- /** This class is used to incrementally build {@link VcnConfig} objects. */
- public static class Builder {
+ /**
+ * This class is used to incrementally build {@link VcnConfig} objects.
+ *
+ * @hide
+ */
+ public static final class Builder {
@NonNull private final String mPackageName;
@NonNull
@@ -182,6 +190,7 @@ public final class VcnConfig implements Parcelable {
*
* @param gatewayConnectionConfig the configuration for an individual gateway connection
* @return this {@link Builder} instance, for chaining
+ * @hide
*/
@NonNull
public Builder addGatewayConnectionConfig(
@@ -196,6 +205,7 @@ public final class VcnConfig implements Parcelable {
* Builds and validates the VcnConfig.
*
* @return an immutable VcnConfig instance
+ * @hide
*/
@NonNull
public VcnConfig build() {
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 039360a69a3a..cead2f1caad1 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -15,10 +15,9 @@
*/
package android.net.vcn;
-import static android.net.NetworkCapabilities.NetCapability;
-
import static com.android.internal.annotations.VisibleForTesting.Visibility;
+import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -27,14 +26,19 @@ import android.os.PersistableBundle;
import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
import com.android.server.vcn.util.PersistableBundleUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
/**
@@ -99,6 +103,26 @@ public final class VcnGatewayConnectionConfig {
ALLOWED_CAPABILITIES = Collections.unmodifiableSet(allowedCaps);
}
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = {"NET_CAPABILITY_"},
+ value = {
+ NetworkCapabilities.NET_CAPABILITY_MMS,
+ NetworkCapabilities.NET_CAPABILITY_SUPL,
+ NetworkCapabilities.NET_CAPABILITY_DUN,
+ NetworkCapabilities.NET_CAPABILITY_FOTA,
+ NetworkCapabilities.NET_CAPABILITY_IMS,
+ NetworkCapabilities.NET_CAPABILITY_CBS,
+ NetworkCapabilities.NET_CAPABILITY_IA,
+ NetworkCapabilities.NET_CAPABILITY_RCS,
+ NetworkCapabilities.NET_CAPABILITY_XCAP,
+ NetworkCapabilities.NET_CAPABILITY_EIMS,
+ NetworkCapabilities.NET_CAPABILITY_INTERNET,
+ NetworkCapabilities.NET_CAPABILITY_MCX,
+ })
+ public @interface VcnSupportedCapability {}
+
private static final int DEFAULT_MAX_MTU = 1500;
/**
@@ -130,10 +154,10 @@ public final class VcnGatewayConnectionConfig {
};
private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities";
- @NonNull private final Set<Integer> mExposedCapabilities;
+ @NonNull private final SortedSet<Integer> mExposedCapabilities;
private static final String UNDERLYING_CAPABILITIES_KEY = "mUnderlyingCapabilities";
- @NonNull private final Set<Integer> mUnderlyingCapabilities;
+ @NonNull private final SortedSet<Integer> mUnderlyingCapabilities;
// TODO: Add Ike/ChildSessionParams as a subclass - maybe VcnIkeGatewayConnectionConfig
@@ -143,14 +167,14 @@ public final class VcnGatewayConnectionConfig {
private static final String RETRY_INTERVAL_MS_KEY = "mRetryIntervalsMs";
@NonNull private final long[] mRetryIntervalsMs;
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- public VcnGatewayConnectionConfig(
+ /** Builds a VcnGatewayConnectionConfig with the specified parameters. */
+ private VcnGatewayConnectionConfig(
@NonNull Set<Integer> exposedCapabilities,
@NonNull Set<Integer> underlyingCapabilities,
@NonNull long[] retryIntervalsMs,
@IntRange(from = MIN_MTU_V6) int maxMtu) {
- mExposedCapabilities = exposedCapabilities;
- mUnderlyingCapabilities = underlyingCapabilities;
+ mExposedCapabilities = new TreeSet(exposedCapabilities);
+ mUnderlyingCapabilities = new TreeSet(underlyingCapabilities);
mRetryIntervalsMs = retryIntervalsMs;
mMaxMtu = maxMtu;
@@ -165,9 +189,9 @@ public final class VcnGatewayConnectionConfig {
final PersistableBundle underlyingCapsBundle =
in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY);
- mExposedCapabilities = new ArraySet<>(PersistableBundleUtils.toList(
+ mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList(
exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
- mUnderlyingCapabilities = new ArraySet<>(PersistableBundleUtils.toList(
+ mUnderlyingCapabilities = new TreeSet<>(PersistableBundleUtils.toList(
underlyingCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY);
mMaxMtu = in.getInt(MAX_MTU_KEY);
@@ -221,52 +245,93 @@ public final class VcnGatewayConnectionConfig {
/**
* Returns all exposed capabilities.
*
+ * <p>The returned integer-value capabilities will not contain duplicates, and will be sorted in
+ * ascending numerical order.
+ *
+ * @see Builder#addExposedCapability(int)
+ * @see Builder#clearExposedCapability(int)
* @hide
*/
@NonNull
+ public int[] getExposedCapabilities() {
+ // Sorted set guarantees ordering
+ return ArrayUtils.convertToIntArray(new ArrayList<>(mExposedCapabilities));
+ }
+
+ /**
+ * Returns all exposed capabilities.
+ *
+ * <p>Left to prevent the need to make major changes while changes are actively in flight.
+ *
+ * @deprecated use getExposedCapabilities() instead
+ * @hide
+ */
+ @Deprecated
+ @NonNull
public Set<Integer> getAllExposedCapabilities() {
return Collections.unmodifiableSet(mExposedCapabilities);
}
/**
- * Checks if this config is configured to support/expose a specific capability.
+ * Returns all capabilities required of underlying networks.
+ *
+ * <p>The returned integer-value capabilities will be sorted in ascending numerical order.
*
- * @param capability the capability to check for
+ * @see Builder#addRequiredUnderlyingCapability(int)
+ * @see Builder#clearRequiredUnderlyingCapability(int)
+ * @hide
*/
- public boolean hasExposedCapability(@NetCapability int capability) {
- checkValidCapability(capability);
-
- return mExposedCapabilities.contains(capability);
+ @NonNull
+ public int[] getRequiredUnderlyingCapabilities() {
+ // Sorted set guarantees ordering
+ return ArrayUtils.convertToIntArray(new ArrayList<>(mUnderlyingCapabilities));
}
/**
* Returns all capabilities required of underlying networks.
*
+ * <p>Left to prevent the need to make major changes while changes are actively in flight.
+ *
+ * @deprecated use getRequiredUnderlyingCapabilities() instead
* @hide
*/
+ @Deprecated
@NonNull
public Set<Integer> getAllUnderlyingCapabilities() {
return Collections.unmodifiableSet(mUnderlyingCapabilities);
}
/**
- * Checks if this config requires an underlying network to have the specified capability.
+ * Retrieves the configured retry intervals.
*
- * @param capability the capability to check for
+ * @see Builder#setRetryInterval(long[])
+ * @hide
*/
- public boolean requiresUnderlyingCapability(@NetCapability int capability) {
- checkValidCapability(capability);
-
- return mUnderlyingCapabilities.contains(capability);
+ @NonNull
+ public long[] getRetryInterval() {
+ return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length);
}
- /** Retrieves the configured retry intervals. */
+ /**
+ * Retrieves the configured retry intervals.
+ *
+ * <p>Left to prevent the need to make major changes while changes are actively in flight.
+ *
+ * @deprecated use getRequiredUnderlyingCapabilities() instead
+ * @hide
+ */
+ @Deprecated
@NonNull
public long[] getRetryIntervalsMs() {
- return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length);
+ return getRetryInterval();
}
- /** Retrieves the maximum MTU allowed for this Gateway Connection. */
+ /**
+ * Retrieves the maximum MTU allowed for this Gateway Connection.
+ *
+ * @see Builder.setMaxMtu(int)
+ * @hide
+ */
@IntRange(from = MIN_MTU_V6)
public int getMaxMtu() {
return mMaxMtu;
@@ -321,8 +386,12 @@ public final class VcnGatewayConnectionConfig {
&& mMaxMtu == rhs.mMaxMtu;
}
- /** This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects. */
- public static class Builder {
+ /**
+ * This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects.
+ *
+ * @hide
+ */
+ public static final class Builder {
@NonNull private final Set<Integer> mExposedCapabilities = new ArraySet();
@NonNull private final Set<Integer> mUnderlyingCapabilities = new ArraySet();
@NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS;
@@ -340,8 +409,10 @@ public final class VcnGatewayConnectionConfig {
* @return this {@link Builder} instance, for chaining
* @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway
* Connection
+ * @hide
*/
- public Builder addExposedCapability(@NetCapability int exposedCapability) {
+ @NonNull
+ public Builder addExposedCapability(@VcnSupportedCapability int exposedCapability) {
checkValidCapability(exposedCapability);
mExposedCapabilities.add(exposedCapability);
@@ -356,8 +427,10 @@ public final class VcnGatewayConnectionConfig {
* @return this {@link Builder} instance, for chaining
* @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway
* Connection
+ * @hide
*/
- public Builder removeExposedCapability(@NetCapability int exposedCapability) {
+ @NonNull
+ public Builder clearExposedCapability(@VcnSupportedCapability int exposedCapability) {
checkValidCapability(exposedCapability);
mExposedCapabilities.remove(exposedCapability);
@@ -372,8 +445,11 @@ public final class VcnGatewayConnectionConfig {
* @return this {@link Builder} instance, for chaining
* @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
* networks
+ * @hide
*/
- public Builder addRequiredUnderlyingCapability(@NetCapability int underlyingCapability) {
+ @NonNull
+ public Builder addRequiredUnderlyingCapability(
+ @VcnSupportedCapability int underlyingCapability) {
checkValidCapability(underlyingCapability);
mUnderlyingCapabilities.add(underlyingCapability);
@@ -392,8 +468,11 @@ public final class VcnGatewayConnectionConfig {
* @return this {@link Builder} instance, for chaining
* @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
* networks
+ * @hide
*/
- public Builder removeRequiredUnderlyingCapability(@NetCapability int underlyingCapability) {
+ @NonNull
+ public Builder clearRequiredUnderlyingCapability(
+ @VcnSupportedCapability int underlyingCapability) {
checkValidCapability(underlyingCapability);
mUnderlyingCapabilities.remove(underlyingCapability);
@@ -422,6 +501,7 @@ public final class VcnGatewayConnectionConfig {
* 15m]}
* @return this {@link Builder} instance, for chaining
* @see VcnManager for additional discussion on fail-safe mode
+ * @hide
*/
@NonNull
public Builder setRetryInterval(@NonNull long[] retryIntervalsMs) {
@@ -443,6 +523,7 @@ public final class VcnGatewayConnectionConfig {
* @param maxMtu the maximum MTU allowed for this Gateway Connection. Must be greater than
* the IPv6 minimum MTU of 1280. Defaults to 1500.
* @return this {@link Builder} instance, for chaining
+ * @hide
*/
@NonNull
public Builder setMaxMtu(@IntRange(from = MIN_MTU_V6) int maxMtu) {
@@ -457,6 +538,7 @@ public final class VcnGatewayConnectionConfig {
* Builds and validates the VcnGatewayConnectionConfig.
*
* @return an immutable VcnGatewayConnectionConfig instance
+ * @hide
*/
@NonNull
public VcnGatewayConnectionConfig build() {
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index b881a339535b..33beb6a9d188 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -21,11 +21,18 @@ import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.content.Context;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
/**
* VcnManager publishes APIs for applications to configure and manage Virtual Carrier Networks.
@@ -57,9 +64,15 @@ import java.io.IOException;
* @hide
*/
@SystemService(Context.VCN_MANAGEMENT_SERVICE)
-public final class VcnManager {
+public class VcnManager {
@NonNull private static final String TAG = VcnManager.class.getSimpleName();
+ /** @hide */
+ @VisibleForTesting
+ public static final Map<
+ VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
+ REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>();
+
@NonNull private final Context mContext;
@NonNull private final IVcnManagementService mService;
@@ -136,4 +149,132 @@ public final class VcnManager {
throw e.rethrowFromSystemServer();
}
}
+
+ // TODO: make VcnUnderlyingNetworkPolicyListener @SystemApi
+ /**
+ * VcnUnderlyingNetworkPolicyListener is the interface through which internal system components
+ * can register to receive updates for VCN-underlying Network policies from the System Server.
+ *
+ * @hide
+ */
+ public interface VcnUnderlyingNetworkPolicyListener {
+ /**
+ * Notifies the implementation that the VCN's underlying Network policy has changed.
+ *
+ * <p>After receiving this callback, implementations MUST poll VcnManager for the updated
+ * VcnUnderlyingNetworkPolicy via VcnManager#getUnderlyingNetworkPolicy.
+ */
+ void onPolicyChanged();
+ }
+
+ /**
+ * Add a listener for VCN-underlying network policy updates.
+ *
+ * @param executor the Executor that will be used for invoking all calls to the specified
+ * Listener
+ * @param listener the VcnUnderlyingNetworkPolicyListener to be added
+ * @throws SecurityException if the caller does not have permission NETWORK_FACTORY
+ * @throws IllegalArgumentException if the specified VcnUnderlyingNetworkPolicyListener is
+ * already registered
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ public void addVcnUnderlyingNetworkPolicyListener(
+ @NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) {
+ requireNonNull(executor, "executor must not be null");
+ requireNonNull(listener, "listener must not be null");
+
+ VcnUnderlyingNetworkPolicyListenerBinder binder =
+ new VcnUnderlyingNetworkPolicyListenerBinder(executor, listener);
+ if (REGISTERED_POLICY_LISTENERS.putIfAbsent(listener, binder) != null) {
+ throw new IllegalArgumentException(
+ "Attempting to add a listener that is already in use");
+ }
+
+ try {
+ mService.addVcnUnderlyingNetworkPolicyListener(binder);
+ } catch (RemoteException e) {
+ REGISTERED_POLICY_LISTENERS.remove(listener);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Remove the specified VcnUnderlyingNetworkPolicyListener from VcnManager.
+ *
+ * <p>If the specified listener is not currently registered, this is a no-op.
+ *
+ * @param listener the VcnUnderlyingNetworkPolicyListener that will be removed
+ * @hide
+ */
+ public void removeVcnUnderlyingNetworkPolicyListener(
+ @NonNull VcnUnderlyingNetworkPolicyListener listener) {
+ requireNonNull(listener, "listener must not be null");
+
+ VcnUnderlyingNetworkPolicyListenerBinder binder =
+ REGISTERED_POLICY_LISTENERS.remove(listener);
+ if (binder == null) {
+ return;
+ }
+
+ try {
+ mService.removeVcnUnderlyingNetworkPolicyListener(binder);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Queries the underlying network policy for a network with the given parameters.
+ *
+ * <p>Prior to a new NetworkAgent being registered, or upon notification that Carrier VCN policy
+ * may have changed via {@link VcnUnderlyingNetworkPolicyListener#onPolicyChanged()}, a Network
+ * Provider MUST poll for the updated Network policy based on that Network's capabilities and
+ * properties.
+ *
+ * @param networkCapabilities the NetworkCapabilities to be used in determining the Network
+ * policy for this Network.
+ * @param linkProperties the LinkProperties to be used in determining the Network policy for
+ * this Network.
+ * @throws SecurityException if the caller does not have permission NETWORK_FACTORY
+ * @return the VcnUnderlyingNetworkPolicy to be used for this Network.
+ * @hide
+ */
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ public VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy(
+ @NonNull NetworkCapabilities networkCapabilities,
+ @NonNull LinkProperties linkProperties) {
+ requireNonNull(networkCapabilities, "networkCapabilities must not be null");
+ requireNonNull(linkProperties, "linkProperties must not be null");
+
+ try {
+ return mService.getUnderlyingNetworkPolicy(networkCapabilities, linkProperties);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Binder wrapper for added VcnUnderlyingNetworkPolicyListeners to receive signals from System
+ * Server.
+ *
+ * @hide
+ */
+ private static class VcnUnderlyingNetworkPolicyListenerBinder
+ extends IVcnUnderlyingNetworkPolicyListener.Stub {
+ @NonNull private final Executor mExecutor;
+ @NonNull private final VcnUnderlyingNetworkPolicyListener mListener;
+
+ private VcnUnderlyingNetworkPolicyListenerBinder(
+ Executor executor, VcnUnderlyingNetworkPolicyListener listener) {
+ mExecutor = executor;
+ mListener = listener;
+ }
+
+ @Override
+ public void onPolicyChanged() {
+ mExecutor.execute(() -> mListener.onPolicyChanged());
+ }
+ }
}
diff --git a/core/java/android/net/vcn/VcnTransportInfo.java b/core/java/android/net/vcn/VcnTransportInfo.java
new file mode 100644
index 000000000000..4d8cf91621ba
--- /dev/null
+++ b/core/java/android/net/vcn/VcnTransportInfo.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2021 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.vcn;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.TransportInfo;
+import android.net.wifi.WifiInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.SubscriptionManager;
+
+import java.util.Objects;
+
+/**
+ * VcnTransportInfo contains information about the VCN's underlying transports for SysUi.
+ *
+ * <p>Presence of this class in the NetworkCapabilities.TransportInfo implies that the network is a
+ * VCN.
+ *
+ * <p>VcnTransportInfo must exist on top of either an underlying Wifi or Cellular Network. If the
+ * underlying Network is WiFi, the subId will be {@link
+ * SubscriptionManager#INVALID_SUBSCRIPTION_ID}. If the underlying Network is Cellular, the WifiInfo
+ * will be {@code null}.
+ *
+ * @hide
+ */
+public class VcnTransportInfo implements TransportInfo, Parcelable {
+ @Nullable private final WifiInfo mWifiInfo;
+ private final int mSubId;
+
+ public VcnTransportInfo(@NonNull WifiInfo wifiInfo) {
+ this(wifiInfo, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ }
+
+ public VcnTransportInfo(int subId) {
+ this(null /* wifiInfo */, subId);
+ }
+
+ private VcnTransportInfo(@Nullable WifiInfo wifiInfo, int subId) {
+ if (wifiInfo == null && subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ throw new IllegalArgumentException(
+ "VcnTransportInfo requires either non-null WifiInfo or valid subId");
+ }
+
+ mWifiInfo = wifiInfo;
+ mSubId = subId;
+ }
+
+ /**
+ * Get the {@link WifiInfo} for this VcnTransportInfo.
+ *
+ * <p>If the underlying Network for the associated VCN is Cellular, returns null.
+ *
+ * @return the WifiInfo if there is an underlying WiFi connection, else null.
+ */
+ @Nullable
+ public WifiInfo getWifiInfo() {
+ return mWifiInfo;
+ }
+
+ /**
+ * Get the subId for the VCN Network associated with this VcnTransportInfo.
+ *
+ * <p>If the underlying Network for the associated VCN is WiFi, returns {@link
+ * SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
+ *
+ * @return the Subscription ID if a cellular underlying Network is present, else {@link
+ * android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID}.
+ */
+ public int getSubId() {
+ return mSubId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mWifiInfo, mSubId);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof VcnTransportInfo)) return false;
+ final VcnTransportInfo that = (VcnTransportInfo) o;
+
+ return Objects.equals(mWifiInfo, that.mWifiInfo) && mSubId == that.mSubId;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {}
+
+ /** Implement the Parcelable interface */
+ public static final @NonNull Creator<VcnTransportInfo> CREATOR =
+ new Creator<VcnTransportInfo>() {
+ public VcnTransportInfo createFromParcel(Parcel in) {
+ // return null instead of a default VcnTransportInfo to avoid leaking
+ // information about this being a VCN Network (instead of macro cellular, etc)
+ return null;
+ }
+
+ public VcnTransportInfo[] newArray(int size) {
+ return new VcnTransportInfo[size];
+ }
+ };
+}
diff --git a/apex/permission/framework/java/android/permission/PermissionState.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl
index e810db8ecbfe..6cb6ee685a64 100644
--- a/apex/permission/framework/java/android/permission/PermissionState.java
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl
@@ -14,9 +14,7 @@
* limitations under the License.
*/
-package android.permission;
+package android.net.vcn;
-/**
- * @hide
- */
-public class PermissionState {}
+/** @hide */
+parcelable VcnUnderlyingNetworkPolicy;
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
new file mode 100644
index 000000000000..dd7c86d87ff2
--- /dev/null
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn;
+
+import android.annotation.NonNull;
+import android.net.NetworkCapabilities;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * VcnUnderlyingNetworkPolicy represents the Network policy for a VCN-managed Network.
+ *
+ * <p>Transports that are bringing up networks capable of acting as a VCN's underlying network
+ * should query for policy state upon major capability changes (e.g. changing of TRUSTED bit), and
+ * when prompted by VcnManagementService via VcnUnderlyingNetworkPolicyListener.
+ *
+ * @hide
+ */
+public final class VcnUnderlyingNetworkPolicy implements Parcelable {
+ private final boolean mIsTearDownRequested;
+ private final NetworkCapabilities mMergedNetworkCapabilities;
+
+ /**
+ * Constructs a VcnUnderlyingNetworkPolicy with the specified parameters.
+ *
+ * @hide
+ */
+ public VcnUnderlyingNetworkPolicy(
+ boolean isTearDownRequested, @NonNull NetworkCapabilities mergedNetworkCapabilities) {
+ Objects.requireNonNull(
+ mergedNetworkCapabilities, "mergedNetworkCapabilities must be nonnull");
+
+ mIsTearDownRequested = isTearDownRequested;
+ mMergedNetworkCapabilities = mergedNetworkCapabilities;
+ }
+
+ /**
+ * Returns whether this Carrier VCN policy policy indicates that the underlying Network should
+ * be torn down.
+ */
+ public boolean isTeardownRequested() {
+ return mIsTearDownRequested;
+ }
+
+ /**
+ * Returns the NetworkCapabilities with Carrier VCN policy bits merged into the provided
+ * capabilities.
+ */
+ @NonNull
+ public NetworkCapabilities getMergedNetworkCapabilities() {
+ return mMergedNetworkCapabilities;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mIsTearDownRequested, mMergedNetworkCapabilities);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof VcnUnderlyingNetworkPolicy)) return false;
+ final VcnUnderlyingNetworkPolicy that = (VcnUnderlyingNetworkPolicy) o;
+
+ return mIsTearDownRequested == that.mIsTearDownRequested
+ && mMergedNetworkCapabilities.equals(that.mMergedNetworkCapabilities);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeBoolean(mIsTearDownRequested);
+ dest.writeParcelable(mMergedNetworkCapabilities, flags);
+ }
+
+ /** Implement the Parcelable interface */
+ public static final @NonNull Creator<VcnUnderlyingNetworkPolicy> CREATOR =
+ new Creator<VcnUnderlyingNetworkPolicy>() {
+ public VcnUnderlyingNetworkPolicy createFromParcel(Parcel in) {
+ return new VcnUnderlyingNetworkPolicy(
+ in.readBoolean(), in.readParcelable(null));
+ }
+
+ public VcnUnderlyingNetworkPolicy[] newArray(int size) {
+ return new VcnUnderlyingNetworkPolicy[size];
+ }
+ };
+}
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 0b2cfdd9ece3..bc3d5c4ab1ac 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -72,4 +72,7 @@ interface INfcAdapter
boolean deviceSupportsNfcSecure();
boolean setNfcSecure(boolean enable);
+ boolean setAlwaysOn(boolean value);
+ boolean isAlwaysOnEnabled();
+ boolean isAlwaysOnSupported();
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index a17a5370e787..e85eb935a8e7 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -350,6 +350,22 @@ public final class NfcAdapter {
"android.nfc.extra.HANDOVER_TRANSFER_STATUS";
/** @hide */
+ public static final String ACTION_ALWAYS_ON_STATE_CHANGED =
+ "android.nfc.action.ALWAYS_ON_STATE_CHANGED";
+
+ /**
+ * Used as an int extra field in {@link #ACTION_ALWAYS_ON_STATE_CHANGED}
+ * intents to request the current power state. Possible values are:
+ * {@link #STATE_OFF},
+ * {@link #STATE_TURNING_ON},
+ * {@link #STATE_ON},
+ * {@link #STATE_TURNING_OFF},
+ * @hide
+ */
+ public static final String EXTRA_ALWAYS_ON_STATE =
+ "android.nfc.extra.ALWAYS_ON_STATE";
+
+ /** @hide */
public static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0;
/** @hide */
public static final int HANDOVER_TRANSFER_STATUS_FAILURE = 1;
@@ -358,6 +374,14 @@ public final class NfcAdapter {
public static final String EXTRA_HANDOVER_TRANSFER_URI =
"android.nfc.extra.HANDOVER_TRANSFER_URI";
+ /**
+ * Broadcast Action: Notify possible NFC transaction blocked because device is locked.
+ * <p>An external NFC field detected when device locked and SecureNfc enabled.
+ * @hide
+ */
+ public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC =
+ "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC";
+
// Guarded by NfcAdapter.class
static boolean sIsInitialized = false;
static boolean sHasNfcFeature;
@@ -2211,4 +2235,106 @@ public final class NfcAdapter {
return mContext.getApplicationInfo().targetSdkVersion;
}
}
+
+ /**
+ * Sets NFC controller always on feature.
+ * <p>This API is for the NFCC internal state management. It allows to discriminate
+ * the controller function from the NFC function by keeping the NFC Controller on without
+ * any NFC RF enabled if necessary.
+ * <p>This call is asynchronous. Listen for {@link #ACTION_ALWAYS_ON_STATE_CHANGED}
+ * broadcasts to find out when the operation is complete.
+ * <p>If this returns true, then either NFCC is already on, or
+ * a {@link #ACTION_ALWAYS_ON_STATE_CHANGED} broadcast will be sent to indicate
+ * a state transition.
+ * If this returns false, then there is some problem that prevents an attempt to turn NFCC on.
+ * @param value if true the NFCC will be kept on (with no RF enabled if NFC adapter is
+ * disabled), if false the NFCC will follow completely the Nfc adapter state.
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ * @return void
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ public boolean setAlwaysOn(boolean value) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ try {
+ return sService.setAlwaysOn(value);
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ // Try one more time
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ return false;
+ }
+ try {
+ return sService.setAlwaysOn(value);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Checks NFC controller always on feature is enabled.
+ *
+ * @return True if NFC controller always on is enabled, false otherwise
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ * @hide
+ */
+
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ public boolean isAlwaysOnEnabled() {
+ try {
+ return sService.isAlwaysOnEnabled();
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ // Try one more time
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ return false;
+ }
+ try {
+ return sService.isAlwaysOnEnabled();
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the device supports NFC controller always on functionality.
+ *
+ * @return True if device supports NFC controller always on, false otherwise
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ * @hide
+ */
+
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ public boolean isAlwaysOnSupported() {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ try {
+ return sService.isAlwaysOnSupported();
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ // Try one more time
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ return false;
+ }
+ try {
+ return sService.isAlwaysOnSupported();
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ }
+ return false;
+ }
+ }
}
diff --git a/core/java/android/nfc/tech/Ndef.java b/core/java/android/nfc/tech/Ndef.java
index fdccaae9cb1b..225636565480 100644
--- a/core/java/android/nfc/tech/Ndef.java
+++ b/core/java/android/nfc/tech/Ndef.java
@@ -112,7 +112,7 @@ public final class Ndef extends BasicTagTechnology {
public static final String NFC_FORUM_TYPE_1 = "org.nfcforum.ndef.type1";
/** NFC Forum Tag Type 2 */
public static final String NFC_FORUM_TYPE_2 = "org.nfcforum.ndef.type2";
- /** NFC Forum Tag Type 4 */
+ /** NFC Forum Tag Type 3 */
public static final String NFC_FORUM_TYPE_3 = "org.nfcforum.ndef.type3";
/** NFC Forum Tag Type 4 */
public static final String NFC_FORUM_TYPE_4 = "org.nfcforum.ndef.type4";
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 46ad7b880a37..305c686f8657 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -22,11 +22,11 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressAutoDoc;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.ActivityManager;
import android.content.Context;
-import android.os.Handler;
import android.util.Log;
import android.widget.Toast;
@@ -41,12 +41,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.Executor;
-/**
- * Class that provides a privileged API to capture and consume bugreports.
- *
- * @hide
- */
-@SystemApi
+/** Class that provides a privileged API to capture and consume bugreports. */
@SystemService(Context.BUGREPORT_SERVICE)
public final class BugreportManager {
@@ -61,28 +56,30 @@ public final class BugreportManager {
mBinder = binder;
}
- /**
- * An interface describing the callback for bugreport progress and status.
- */
+ /** An interface describing the callback for bugreport progress and status. */
public abstract static class BugreportCallback {
- /** @hide */
+ /**
+ * Possible error codes taking a bugreport can encounter.
+ *
+ * @hide
+ */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "BUGREPORT_ERROR_" }, value = {
- BUGREPORT_ERROR_INVALID_INPUT,
- BUGREPORT_ERROR_RUNTIME,
- BUGREPORT_ERROR_USER_DENIED_CONSENT,
- BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT,
- BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS
- })
-
- /** Possible error codes taking a bugreport can encounter */
+ @IntDef(
+ prefix = {"BUGREPORT_ERROR_"},
+ value = {
+ BUGREPORT_ERROR_INVALID_INPUT,
+ BUGREPORT_ERROR_RUNTIME,
+ BUGREPORT_ERROR_USER_DENIED_CONSENT,
+ BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT,
+ BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS
+ })
public @interface BugreportErrorCode {}
/** The input options were invalid */
public static final int BUGREPORT_ERROR_INVALID_INPUT =
IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT;
- /** A runtime error occured */
+ /** A runtime error occurred */
public static final int BUGREPORT_ERROR_RUNTIME =
IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR;
@@ -100,6 +97,7 @@ public final class BugreportManager {
/**
* Called when there is a progress update.
+ *
* @param progress the progress in [0.0, 100.0]
*/
public void onProgress(@FloatRange(from = 0f, to = 100f) float progress) {}
@@ -114,14 +112,12 @@ public final class BugreportManager {
* out, but the bugreport could be available in the internal directory of dumpstate for
* manual retrieval.
*
- * <p> If {@code BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS} is passed, then the
- * caller should try later, as only one bugreport can be in progress at a time.
+ * <p>If {@code BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS} is passed, then the caller
+ * should try later, as only one bugreport can be in progress at a time.
*/
public void onError(@BugreportErrorCode int errorCode) {}
- /**
- * Called when taking bugreport finishes successfully.
- */
+ /** Called when taking bugreport finishes successfully. */
public void onFinished() {}
/**
@@ -138,20 +134,23 @@ public final class BugreportManager {
* seconds to return in the worst case. {@code callback} will receive progress and status
* updates.
*
- * <p>The bugreport artifacts will be copied over to the given file descriptors only if the
- * user consents to sharing with the calling app.
+ * <p>The bugreport artifacts will be copied over to the given file descriptors only if the user
+ * consents to sharing with the calling app.
*
* <p>{@link BugreportManager} takes ownership of {@code bugreportFd} and {@code screenshotFd}.
*
- * @param bugreportFd file to write the bugreport. This should be opened in write-only,
- * append mode.
- * @param screenshotFd file to write the screenshot, if necessary. This should be opened
- * in write-only, append mode.
+ * @param bugreportFd file to write the bugreport. This should be opened in write-only, append
+ * mode.
+ * @param screenshotFd file to write the screenshot, if necessary. This should be opened in
+ * write-only, append mode.
* @param params options that specify what kind of a bugreport should be taken
* @param callback callback for progress and status updates
+ * @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.DUMP)
- public void startBugreport(@NonNull ParcelFileDescriptor bugreportFd,
+ public void startBugreport(
+ @NonNull ParcelFileDescriptor bugreportFd,
@Nullable ParcelFileDescriptor screenshotFd,
@NonNull BugreportParams params,
@NonNull @CallbackExecutor Executor executor,
@@ -165,17 +164,21 @@ public final class BugreportManager {
boolean isScreenshotRequested = screenshotFd != null;
if (screenshotFd == null) {
// Binder needs a valid File Descriptor to be passed
- screenshotFd = ParcelFileDescriptor.open(new File("/dev/null"),
- ParcelFileDescriptor.MODE_READ_ONLY);
+ screenshotFd =
+ ParcelFileDescriptor.open(
+ new File("/dev/null"), ParcelFileDescriptor.MODE_READ_ONLY);
}
- DumpstateListener dsListener = new DumpstateListener(executor, callback,
- isScreenshotRequested);
+ DumpstateListener dsListener =
+ new DumpstateListener(executor, callback, isScreenshotRequested);
// Note: mBinder can get callingUid from the binder transaction.
- mBinder.startBugreport(-1 /* callingUid */,
+ mBinder.startBugreport(
+ -1 /* callingUid */,
mContext.getOpPackageName(),
bugreportFd.getFileDescriptor(),
screenshotFd.getFileDescriptor(),
- params.getMode(), dsListener, isScreenshotRequested);
+ params.getMode(),
+ dsListener,
+ isScreenshotRequested);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (FileNotFoundException e) {
@@ -189,13 +192,64 @@ public final class BugreportManager {
}
}
- /*
- * Cancels a currently running bugreport.
+ /**
+ * Starts a connectivity bugreport.
+ *
+ * <p>The connectivity bugreport is a specialized version of bugreport that only includes
+ * information specifically for debugging connectivity-related issues (e.g. telephony, wi-fi,
+ * and IP networking issues). It is intended primarily for use by OEMs and network providers
+ * such as mobile network operators. In addition to generally excluding information that isn't
+ * targeted to connectivity debugging, this type of bugreport excludes PII and sensitive
+ * information that isn't strictly necessary for connectivity debugging.
+ *
+ * <p>The calling app MUST have a context-specific reason for requesting a connectivity
+ * bugreport, such as detecting a connectivity-related issue. This API SHALL NOT be used to
+ * perform random sampling from a fleet of public end-user devices.
+ *
+ * <p>Calling this API will cause the system to ask the user for consent every single time. The
+ * bugreport artifacts will be copied over to the given file descriptors only if the user
+ * consents to sharing with the calling app.
+ *
+ * <p>This starts a bugreport in the background. However the call itself can take several
+ * seconds to return in the worst case. {@code callback} will receive progress and status
+ * updates.
+ *
+ * <p>Requires that the calling app has carrier privileges (see {@link
+ * android.telephony.TelephonyManager#hasCarrierPrivileges}) on any active subscription.
+ *
+ * @param bugreportFd file to write the bugreport. This should be opened in write-only, append
+ * mode.
+ * @param callback callback for progress and status updates.
*/
- @RequiresPermission(android.Manifest.permission.DUMP)
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ public void startConnectivityBugreport(
+ @NonNull ParcelFileDescriptor bugreportFd,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull BugreportCallback callback) {
+ startBugreport(
+ bugreportFd,
+ null /* screenshotFd */,
+ new BugreportParams(BugreportParams.BUGREPORT_MODE_TELEPHONY),
+ executor,
+ callback);
+ }
+
+ /**
+ * Cancels the currently running bugreport.
+ *
+ * <p>Apps are only able to cancel their own bugreports. App A cannot cancel a bugreport started
+ * by app B.
+ *
+ * <p>Requires permission: {@link android.Manifest.permission#DUMP} or that the calling app has
+ * carrier privileges (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on
+ * any active subscription.
+ *
+ * @throws SecurityException if trying to cancel another app's bugreport in progress
+ */
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
public void cancelBugreport() {
try {
- mBinder.cancelBugreport();
+ mBinder.cancelBugreport(-1 /* callingUid */, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -205,23 +259,26 @@ public final class BugreportManager {
* Requests a bugreport.
*
* <p>This requests the platform/system to take a bugreport and makes the final bugreport
- * available to the user. The user may choose to share it with another app, but the bugreport
- * is never given back directly to the app that requested it.
+ * available to the user. The user may choose to share it with another app, but the bugreport is
+ * never given back directly to the app that requested it.
*
- * @param params {@link BugreportParams} that specify what kind of a bugreport should
- * be taken, please note that not all kinds of bugreport allow for a
- * progress notification
- * @param shareTitle title on the final share notification
+ * @param params {@link BugreportParams} that specify what kind of a bugreport should be taken,
+ * please note that not all kinds of bugreport allow for a progress notification
+ * @param shareTitle title on the final share notification
* @param shareDescription description on the final share notification
+ * @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.DUMP)
- public void requestBugreport(@NonNull BugreportParams params, @Nullable CharSequence shareTitle,
+ public void requestBugreport(
+ @NonNull BugreportParams params,
+ @Nullable CharSequence shareTitle,
@Nullable CharSequence shareDescription) {
try {
String title = shareTitle == null ? null : shareTitle.toString();
String description = shareDescription == null ? null : shareDescription.toString();
- ActivityManager.getService().requestBugReportWithDescription(title, description,
- params.getMode());
+ ActivityManager.getService()
+ .requestBugReportWithDescription(title, description, params.getMode());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -232,8 +289,8 @@ public final class BugreportManager {
private final BugreportCallback mCallback;
private final boolean mIsScreenshotRequested;
- DumpstateListener(Executor executor, BugreportCallback callback,
- boolean isScreenshotRequested) {
+ DumpstateListener(
+ Executor executor, BugreportCallback callback, boolean isScreenshotRequested) {
mExecutor = executor;
mCallback = callback;
mIsScreenshotRequested = isScreenshotRequested;
@@ -243,9 +300,7 @@ public final class BugreportManager {
public void onProgress(int progress) throws RemoteException {
final long identity = Binder.clearCallingIdentity();
try {
- mExecutor.execute(() -> {
- mCallback.onProgress(progress);
- });
+ mExecutor.execute(() -> mCallback.onProgress(progress));
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -255,9 +310,7 @@ public final class BugreportManager {
public void onError(int errorCode) throws RemoteException {
final long identity = Binder.clearCallingIdentity();
try {
- mExecutor.execute(() -> {
- mCallback.onError(errorCode);
- });
+ mExecutor.execute(() -> mCallback.onError(errorCode));
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -267,9 +320,7 @@ public final class BugreportManager {
public void onFinished() throws RemoteException {
final long identity = Binder.clearCallingIdentity();
try {
- mExecutor.execute(() -> {
- mCallback.onFinished();
- });
+ mExecutor.execute(() -> mCallback.onFinished());
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -284,20 +335,19 @@ public final class BugreportManager {
Handler mainThreadHandler = new Handler(Looper.getMainLooper());
mainThreadHandler.post(
() -> {
- int message = success ? R.string.bugreport_screenshot_success_toast
- : R.string.bugreport_screenshot_failure_toast;
+ int message =
+ success
+ ? R.string.bugreport_screenshot_success_toast
+ : R.string.bugreport_screenshot_failure_toast;
Toast.makeText(mContext, message, Toast.LENGTH_LONG).show();
});
}
@Override
- public void onUiIntensiveBugreportDumpsFinished()
- throws RemoteException {
+ public void onUiIntensiveBugreportDumpsFinished() throws RemoteException {
final long identity = Binder.clearCallingIdentity();
try {
- mExecutor.execute(() -> {
- mCallback.onEarlyReportFinished();
- });
+ mExecutor.execute(() -> mCallback.onEarlyReportFinished());
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 0d8769e7635c..5ae53b502330 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -26,6 +26,7 @@ import android.app.ActivityThread;
import android.app.Application;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
+import android.sysprop.SocProperties;
import android.sysprop.TelephonyProperties;
import android.text.TextUtils;
import android.util.Slog;
@@ -87,6 +88,14 @@ public class Build {
/** The end-user-visible name for the end product. */
public static final String MODEL = getString("ro.product.model");
+ /** The manufacturer of the device's primary system-on-chip. */
+ @NonNull
+ public static final String SOC_MANUFACTURER = SocProperties.soc_manufacturer().orElse(UNKNOWN);
+
+ /** The model name of the device's primary system-on-chip. */
+ @NonNull
+ public static final String SOC_MODEL = SocProperties.soc_model().orElse(UNKNOWN);
+
/** The system bootloader version number. */
public static final String BOOTLOADER = getString("ro.bootloader");
@@ -317,6 +326,7 @@ public class Build {
* @see #SDK_INT
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@TestApi
public static final int FIRST_SDK_INT = SystemProperties
.getInt("ro.product.first_api_level", 0);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 67d5f5f205cc..59302afd5fb2 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1992,13 +1992,16 @@ public class UserManager {
}
/**
- * Checks if specified user can have restricted profile.
+ * Checks if the calling context user can have a restricted profile.
+ * @return whether the context user can have a restricted profile.
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_USERS)
- public boolean canHaveRestrictedProfile(@UserIdInt int userId) {
+ @UserHandleAware
+ public boolean canHaveRestrictedProfile() {
try {
- return mService.canHaveRestrictedProfile(userId);
+ return mService.canHaveRestrictedProfile(mUserId);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -2020,6 +2023,25 @@ public class UserManager {
}
/**
+ * Get the parent of a restricted profile.
+ *
+ * @return the parent of the user or {@code null} if the user is not restricted profile
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
+ Manifest.permission.CREATE_USERS})
+ @UserHandleAware
+ public @Nullable UserHandle getRestrictedProfileParent() {
+ final UserInfo info = getUserInfo(mUserId);
+ if (info == null) return null;
+ if (!info.isRestricted()) return null;
+ final int parent = info.restrictedProfileParentId;
+ if (parent == UserHandle.USER_NULL) return null;
+ return UserHandle.of(parent);
+ }
+
+ /**
* Checks if a user is a guest user.
* @return whether user is a guest user.
* @hide
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
index df3c4d55d979..51856d8bb723 100644
--- a/core/java/android/os/storage/DiskInfo.java
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -50,6 +50,8 @@ public class DiskInfo implements Parcelable {
public static final int FLAG_DEFAULT_PRIMARY = 1 << 1;
public static final int FLAG_SD = 1 << 2;
public static final int FLAG_USB = 1 << 3;
+ /** The FLAG_STUB_VISIBLE is set from vold, which gets the flag from outside (e.g., ChromeOS) */
+ public static final int FLAG_STUB_VISIBLE = 1 << 6;
public final String id;
@UnsupportedAppUsage
@@ -152,6 +154,10 @@ public class DiskInfo implements Parcelable {
return (flags & FLAG_USB) != 0;
}
+ public boolean isStubVisible() {
+ return (flags & FLAG_STUB_VISIBLE) != 0;
+ }
+
@Override
public String toString() {
final CharArrayWriter writer = new CharArrayWriter();
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 99bdfd1fc103..4669b208b163 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -195,4 +195,5 @@ interface IStorageManager {
void abortChanges(in String message, boolean retry) = 87;
void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88;
void fixupAppDir(in String path) = 89;
+ void disableAppDataIsolation(in String pkgName, int pid, int userId) = 90;
}
diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS
index 8af7de597294..ff126e12cf61 100644
--- a/core/java/android/os/storage/OWNERS
+++ b/core/java/android/os/storage/OWNERS
@@ -1,7 +1,10 @@
# Bug component: 95221
-narayan@google.com
-nandana@google.com
corinac@google.com
+nandana@google.com
zezeozue@google.com
maco@google.com
+sahanas@google.com
+abkaur@google.com
+chiangi@google.com
+narayan@google.com
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4086161603a4..0f7365dcfd90 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -999,6 +999,20 @@ public final class Settings {
"android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
/**
+ * Activity Action: Show settings to manage all SIM profiles.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_ALL_SUBSCRIPTIONS_SETTINGS =
+ "android.settings.MANAGE_ALL_SUBSCRIPTIONS_SETTINGS";
+
+ /**
* Activity Action: Show screen for controlling which apps can draw on top of other apps.
* <p>
* In some cases, a matching Activity may not exist, so ensure you safeguard against this.
diff --git a/core/java/android/se/OWNERS b/core/java/android/se/OWNERS
index f1539dc55d59..5682fd3281f4 100644
--- a/core/java/android/se/OWNERS
+++ b/core/java/android/se/OWNERS
@@ -1,4 +1,5 @@
# Bug component: 456592
-cbrubaker@google.com
-vishwath@google.com
+zachoverflow@google.com
+alisher@google.com
+jackcwyu@google.com
diff --git a/core/java/android/se/omapi/OWNERS b/core/java/android/se/omapi/OWNERS
index f1539dc55d59..5682fd3281f4 100644
--- a/core/java/android/se/omapi/OWNERS
+++ b/core/java/android/se/omapi/OWNERS
@@ -1,4 +1,5 @@
# Bug component: 456592
-cbrubaker@google.com
-vishwath@google.com
+zachoverflow@google.com
+alisher@google.com
+jackcwyu@google.com
diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index a5c5c613e1f2..333af91ac872 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -22,7 +22,10 @@
package android.se.omapi;
+import android.annotation.BroadcastBehavior;
import android.annotation.NonNull;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -71,6 +74,28 @@ public final class SEService {
}
/**
+ * Broadcast Action: Intent to notify if the secure element state is changed.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(registeredOnly = true, protectedBroadcast = true)
+ public static final String ACTION_SECURE_ELEMENT_STATE_CHANGED =
+ "android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED";
+
+ /**
+ * Mandatory extra containing the reader name of the state changed secure element.
+ *
+ * @see Reader#getName()
+ */
+ public static final String EXTRA_READER_NAME = "android.se.omapi.extra.READER_NAME";
+
+ /**
+ * Mandatory extra containing the connected state of the state changed secure element.
+ *
+ * True if the secure element is connected correctly, false otherwise.
+ */
+ public static final String EXTRA_READER_STATE = "android.se.omapi.extra.READER_STATE";
+
+ /**
* Listener object that allows the notification of the caller if this
* SEService could be bound to the backend.
*/
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 017f40521a81..f994d2930cd9 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -177,6 +177,7 @@ public final class KeymasterDefs {
public static final int KM_PURPOSE_SIGN = KeyPurpose.SIGN;
public static final int KM_PURPOSE_VERIFY = KeyPurpose.VERIFY;
public static final int KM_PURPOSE_WRAP = KeyPurpose.WRAP_KEY;
+ public static final int KM_PURPOSE_AGREE_KEY = KeyPurpose.AGREE_KEY;
// Key formats.
public static final int KM_KEY_FORMAT_X509 = KeyFormat.X509;
diff --git a/core/java/android/service/resumeonreboot/IResumeOnRebootService.aidl b/core/java/android/service/resumeonreboot/IResumeOnRebootService.aidl
new file mode 100644
index 000000000000..d9b403ca0609
--- /dev/null
+++ b/core/java/android/service/resumeonreboot/IResumeOnRebootService.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2021 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.service.resumeonreboot;
+
+import android.os.RemoteCallback;
+
+/** @hide */
+interface IResumeOnRebootService {
+ oneway void wrapSecret(in byte[] unwrappedBlob, in long lifeTimeInMillis, in RemoteCallback resultCallback);
+ oneway void unwrap(in byte[] wrappedBlob, in RemoteCallback resultCallback);
+} \ No newline at end of file
diff --git a/core/java/android/service/resumeonreboot/ResumeOnRebootService.java b/core/java/android/service/resumeonreboot/ResumeOnRebootService.java
new file mode 100644
index 000000000000..4ebaa96f4be2
--- /dev/null
+++ b/core/java/android/service/resumeonreboot/ResumeOnRebootService.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2021 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.service.resumeonreboot;
+
+import android.annotation.DurationMillisLong;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ParcelableException;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+
+import com.android.internal.os.BackgroundThread;
+
+import java.io.IOException;
+
+/**
+ * Base class for service that provides wrapping/unwrapping of the opaque blob needed for
+ * ResumeOnReboot operation. The package needs to provide a wrap/unwrap implementation for handling
+ * the opaque blob, that's secure even when on device keystore and clock is compromised. This can
+ * be achieved by using tamper-resistant hardware such as a secure element with a secure clock, or
+ * using a remote server to store and retrieve data and manage timing.
+ *
+ * <p>To extend this class, you must declare the service in your manifest file with the
+ * {@link android.Manifest.permission#BIND_RESUME_ON_REBOOT_SERVICE} permission,
+ * include an intent filter with the {@link #SERVICE_INTERFACE} action and mark the service as
+ * direct-boot aware. In addition, the package that contains the service must be granted
+ * {@link android.Manifest.permission#BIND_RESUME_ON_REBOOT_SERVICE}.
+ * For example:</p>
+ * <pre>
+ * &lt;service android:name=".FooResumeOnRebootService"
+ * android:exported="true"
+ * android:priority="100"
+ * android:directBootAware="true"
+ * android:permission="android.permission.BIND_RESUME_ON_REBOOT_SERVICE"&gt;
+ * &lt;intent-filter&gt;
+ * &lt;action android:name="android.service.resumeonreboot.ResumeOnRebootService" /&gt;
+ * &lt;/intent-filter&gt;
+ * &lt;/service&gt;
+ * </pre>
+ *
+ * //TODO: Replace this with public link when available.
+ *
+ * @hide
+ * @see
+ * <a href="https://goto.google.com/server-based-ror">https://goto.google.com/server-based-ror</a>
+ */
+@SystemApi
+public abstract class ResumeOnRebootService extends Service {
+
+ /**
+ * The intent that the service must respond to. Add it to the intent filter of the service.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE =
+ "android.service.resumeonreboot.ResumeOnRebootService";
+ /** @hide */
+ public static final String UNWRAPPED_BLOB_KEY = "unrwapped_blob_key";
+ /** @hide */
+ public static final String WRAPPED_BLOB_KEY = "wrapped_blob_key";
+ /** @hide */
+ public static final String EXCEPTION_KEY = "exception_key";
+
+ private final Handler mHandler = BackgroundThread.getHandler();
+
+ /**
+ * Implementation for wrapping the opaque blob used for resume-on-reboot prior to
+ * reboot. The service should not assume any structure of the blob to be wrapped. The
+ * implementation should wrap the opaque blob in a reasonable time or throw {@link IOException}
+ * if it's unable to complete the action.
+ *
+ * @param blob The opaque blob with size on the order of 100 bytes.
+ * @param lifeTimeInMillis The life time of the blob. This must be strictly enforced by the
+ * implementation and any attempt to unWrap the wrapped blob returned by
+ * this function after expiration should
+ * fail.
+ * @return Wrapped blob to be persisted across reboot with size on the order of 100 bytes.
+ * @throws IOException if the implementation is unable to wrap the blob successfully.
+ */
+ @NonNull
+ public abstract byte[] onWrap(@NonNull byte[] blob, @DurationMillisLong long lifeTimeInMillis)
+ throws IOException;
+
+ /**
+ * Implementation for unwrapping the wrapped blob used for resume-on-reboot after reboot. This
+ * operation would happen after reboot during direct boot mode (i.e before device is unlocked
+ * for the first time). The implementation should unwrap the wrapped blob in a reasonable time
+ * and returns the result or throw {@link IOException} if it's unable to complete the action
+ * and {@link IllegalArgumentException} if {@code unwrapBlob} fails because the wrappedBlob is
+ * stale.
+ *
+ * @param wrappedBlob The wrapped blob with size on the order of 100 bytes.
+ * @return Unwrapped blob used for resume-on-reboot with the size on the order of 100 bytes.
+ * @throws IOException if the implementation is unable to unwrap the wrapped blob successfully.
+ */
+ @NonNull
+ public abstract byte[] onUnwrap(@NonNull byte[] wrappedBlob) throws IOException;
+
+ private final android.service.resumeonreboot.IResumeOnRebootService mInterface =
+ new android.service.resumeonreboot.IResumeOnRebootService.Stub() {
+
+ @Override
+ public void wrapSecret(byte[] unwrappedBlob,
+ @DurationMillisLong long lifeTimeInMillis,
+ RemoteCallback resultCallback) throws RemoteException {
+ mHandler.post(() -> {
+ try {
+ byte[] wrappedBlob = onWrap(unwrappedBlob,
+ lifeTimeInMillis);
+ Bundle bundle = new Bundle();
+ bundle.putByteArray(WRAPPED_BLOB_KEY, wrappedBlob);
+ resultCallback.sendResult(bundle);
+ } catch (Throwable e) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(EXCEPTION_KEY, new ParcelableException(e));
+ resultCallback.sendResult(bundle);
+ }
+ });
+ }
+
+ @Override
+ public void unwrap(byte[] wrappedBlob, RemoteCallback resultCallback)
+ throws RemoteException {
+ mHandler.post(() -> {
+ try {
+ byte[] unwrappedBlob = onUnwrap(wrappedBlob);
+ Bundle bundle = new Bundle();
+ bundle.putByteArray(UNWRAPPED_BLOB_KEY, unwrappedBlob);
+ resultCallback.sendResult(bundle);
+ } catch (Throwable e) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(EXCEPTION_KEY, new ParcelableException(e));
+ resultCallback.sendResult(bundle);
+ }
+ });
+ }
+ };
+
+ @Nullable
+ @Override
+ public IBinder onBind(@Nullable Intent intent) {
+ return mInterface.asBinder();
+ }
+}
diff --git a/core/java/android/service/search/OWNERS b/core/java/android/service/search/OWNERS
new file mode 100644
index 000000000000..92835c2b0626
--- /dev/null
+++ b/core/java/android/service/search/OWNERS
@@ -0,0 +1,2 @@
+hyunyoungs@google.com
+sfufa@google.com
diff --git a/core/java/android/service/textservice/OWNERS b/core/java/android/service/textservice/OWNERS
index 10b8b7637431..0471e29a25cd 100644
--- a/core/java/android/service/textservice/OWNERS
+++ b/core/java/android/service/textservice/OWNERS
@@ -1,3 +1,3 @@
-# Bug component: 34867
+# Bug component: 816455
-include ../../inputmethodservice/OWNERS \ No newline at end of file
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index d6ae434af9d5..03d3755111aa 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -17,7 +17,10 @@
package android.telephony;
import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -29,9 +32,16 @@ import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.Looper;
import android.telephony.Annotation.CallState;
+import android.telephony.Annotation.DataActivityType;
+import android.telephony.Annotation.DisconnectCauses;
+import android.telephony.Annotation.NetworkType;
+import android.telephony.Annotation.PreciseDisconnectCauses;
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SimActivationState;
import android.telephony.Annotation.SrvccState;
+import android.telephony.NetworkRegistrationInfo.Domain;
+import android.telephony.TelephonyManager.DataEnabledReason;
+import android.telephony.TelephonyManager.DataState;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
@@ -40,6 +50,8 @@ import com.android.internal.telephony.IPhoneStateListener;
import dalvik.system.VMRuntime;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Map;
@@ -114,7 +126,9 @@ public class PhoneStateListener {
*
* @see #onServiceStateChanged
* @see ServiceState
+ * @deprecated Use {@link ServiceStateChangedListener} instead.
*/
+ @Deprecated
public static final int LISTEN_SERVICE_STATE = 0x00000001;
/**
@@ -122,8 +136,7 @@ public class PhoneStateListener {
* {@more}
*
* @see #onSignalStrengthChanged
- *
- * @deprecated by {@link #LISTEN_SIGNAL_STRENGTHS}
+ * @deprecated Use {@link SignalStrengthsChangedListener} instead.
*/
@Deprecated
public static final int LISTEN_SIGNAL_STRENGTH = 0x00000002;
@@ -139,7 +152,9 @@ public class PhoneStateListener {
* voicemail icon.
*
* @see #onMessageWaitingIndicatorChanged
+ * @deprecated Use {@link MessageWaitingIndicatorChangedListener} instead.
*/
+ @Deprecated
public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 0x00000004;
/**
@@ -150,7 +165,9 @@ public class PhoneStateListener {
* {@link TelephonyManager#hasCarrierPrivileges}).
*
* @see #onCallForwardingIndicatorChanged
+ * @deprecated Use {@link CallForwardingIndicatorChangedListener} instead.
*/
+ @Deprecated
public static final int LISTEN_CALL_FORWARDING_INDICATOR = 0x00000008;
/**
@@ -166,7 +183,9 @@ public class PhoneStateListener {
* instead.
*
* @see #onCellLocationChanged
+ * @deprecated Use {@link CellLocationChangedListener} instead.
*/
+ @Deprecated
public static final int LISTEN_CELL_LOCATION = 0x00000010;
/**
@@ -174,14 +193,18 @@ public class PhoneStateListener {
* {@more}
*
* @see #onCallStateChanged
+ * @deprecated Use {@link CallStateChangedListener} instead.
*/
+ @Deprecated
public static final int LISTEN_CALL_STATE = 0x00000020;
/**
* Listen for changes to the data connection state (cellular).
*
* @see #onDataConnectionStateChanged
+ * @deprecated Use {@link DataConnectionStateChangedListener} instead.
*/
+ @Deprecated
public static final int LISTEN_DATA_CONNECTION_STATE = 0x00000040;
/**
@@ -192,7 +215,9 @@ public class PhoneStateListener {
* data-traffic icon.
*
* @see #onDataActivity
+ * @deprecated Use {@link DataActivityListener} instead.
*/
+ @Deprecated
public static final int LISTEN_DATA_ACTIVITY = 0x00000080;
/**
@@ -202,7 +227,9 @@ public class PhoneStateListener {
* icon.
*
* @see #onSignalStrengthsChanged
+ * @deprecated Use {@link SignalStrengthsChangedListener} instead.
*/
+ @Deprecated
public static final int LISTEN_SIGNAL_STRENGTHS = 0x00000100;
/**
@@ -212,7 +239,9 @@ public class PhoneStateListener {
* @see #onSignalStrengthsChanged
*
* @hide
+ * @deprecated Use {@link AlwaysReportedSignalStrengthChangedListener} instead.
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
public static final int LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH = 0x00000200;
@@ -223,7 +252,9 @@ public class PhoneStateListener {
* permission.
*
* @see #onCellInfoChanged
+ * @deprecated Use {@link CellInfoChangedListener} instead.
*/
+ @Deprecated
public static final int LISTEN_CELL_INFO = 0x00000400;
/**
@@ -235,8 +266,10 @@ public class PhoneStateListener {
* (see {@link TelephonyManager#hasCarrierPrivileges}).
*
* @hide
+ * @deprecated Use {@link PreciseCallStateChangedListener} instead.
*/
- @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+ @Deprecated
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
@SystemApi
public static final int LISTEN_PRECISE_CALL_STATE = 0x00000800;
@@ -248,8 +281,10 @@ public class PhoneStateListener {
* (see {@link TelephonyManager#hasCarrierPrivileges}).
*
* @see #onPreciseDataConnectionStateChanged
+ * @deprecated Use {@link PreciseDataConnectionStateChangedListener} instead.
*/
- @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+ @Deprecated
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 0x00001000;
/**
@@ -259,7 +294,7 @@ public class PhoneStateListener {
* READ_PRECISE_PHONE_STATE}
* @see #onDataConnectionRealTimeInfoChanged(DataConnectionRealTimeInfo)
*
- * @deprecated Use {@link TelephonyManager#getModemActivityInfo()}
+ * @deprecated Use {@link TelephonyManager#requestModemActivityInfo} instead.
* @hide
*/
@Deprecated
@@ -272,7 +307,9 @@ public class PhoneStateListener {
*
* @see #onServiceStateChanged(ServiceState)
* @hide
+ * @deprecated Use {@link SrvccStateChangedListener} instead.
*/
+ @Deprecated
@SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public static final int LISTEN_SRVCC_STATE_CHANGED = 0x00004000;
@@ -290,10 +327,11 @@ public class PhoneStateListener {
/**
* Listen for carrier network changes indicated by a carrier app.
*
- * @see #onCarrierNetworkRequest
- * @see TelephonyManager#notifyCarrierNetworkChange(boolean)
+ * @see android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean)
* @hide
+ * @deprecated Use {@link CarrierNetworkChangeListener} instead.
*/
+ @Deprecated
public static final int LISTEN_CARRIER_NETWORK_CHANGE = 0x00010000;
/**
@@ -312,7 +350,9 @@ public class PhoneStateListener {
*
* @see #onVoiceActivationStateChanged
* @hide
+ * @deprecated Use {@link VoiceActivationStateChangedListener} instead.
*/
+ @Deprecated
@SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public static final int LISTEN_VOICE_ACTIVATION_STATE = 0x00020000;
@@ -324,20 +364,24 @@ public class PhoneStateListener {
* @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
* @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
* @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
- * {@more}
+ *
* Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates data service has been
* fully activated
*
* @see #onDataActivationStateChanged
* @hide
+ * @deprecated Use {@link DataActivationStateChangedListener} instead.
*/
+ @Deprecated
public static final int LISTEN_DATA_ACTIVATION_STATE = 0x00040000;
/**
* Listen for changes to the user mobile data state
*
* @see #onUserMobileDataStateChanged
+ * @deprecated Use {@link UserMobileDataStateChangedListener} instead.
*/
+ @Deprecated
public static final int LISTEN_USER_MOBILE_DATA_STATE = 0x00080000;
/**
@@ -348,7 +392,9 @@ public class PhoneStateListener {
* {@link TelephonyManager#hasCarrierPrivileges}).
*
* @see #onDisplayInfoChanged
+ * @deprecated Use {@link DisplayInfoChangedListener} instead.
*/
+ @Deprecated
public static final int LISTEN_DISPLAY_INFO_CHANGED = 0x00100000;
/**
@@ -356,7 +402,9 @@ public class PhoneStateListener {
*
* @see #onPhoneCapabilityChanged
* @hide
+ * @deprecated Use {@link PhoneCapabilityChangedListener} instead.
*/
+ @Deprecated
public static final int LISTEN_PHONE_CAPABILITY_CHANGE = 0x00200000;
/**
@@ -366,17 +414,19 @@ public class PhoneStateListener {
* subscription user selected as default data subscription in DSDS mode.
*
* @see #onActiveDataSubscriptionIdChanged
+ * @deprecated Use {@link ActiveDataSubscriptionIdChangedListener} instead.
*/
+ @Deprecated
public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 0x00400000;
/**
* Listen for changes to the radio power state.
*
- * <p>Requires permission {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
- *
* @see #onRadioPowerStateChanged
* @hide
+ * @deprecated Use {@link RadioPowerStateChangedListener} instead.
*/
+ @Deprecated
@SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 0x00800000;
@@ -386,7 +436,10 @@ public class PhoneStateListener {
*
* <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
* app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @deprecated Use {@link EmergencyNumberListChangedListener} instead.
*/
+ @Deprecated
public static final int LISTEN_EMERGENCY_NUMBER_LIST = 0x01000000;
/**
@@ -397,8 +450,10 @@ public class PhoneStateListener {
* or the calling app has carrier privileges
* (see {@link TelephonyManager#hasCarrierPrivileges}).
*
+ * @deprecated Use {@link CallDisconnectCauseChangedListener} instead.
*/
- @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+ @Deprecated
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
public static final int LISTEN_CALL_DISCONNECT_CAUSES = 0x02000000;
/**
@@ -410,9 +465,11 @@ public class PhoneStateListener {
*
* @see #onCallAttributesChanged
* @hide
+ * @deprecated Use {@link CallAttributesChangedListener} instead.
*/
+ @Deprecated
@SystemApi
- @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 0x04000000;
/**
@@ -424,18 +481,20 @@ public class PhoneStateListener {
* (see {@link TelephonyManager#hasCarrierPrivileges}).
*
* @see #onImsCallDisconnectCauseChanged(ImsReasonInfo)
+ * @deprecated Use {@link ImsCallDisconnectCauseChangedListener} instead.
*/
- @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+ @Deprecated
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 0x08000000;
/**
* Listen for the emergency number placed from an outgoing call.
*
- * <p>Requires permission {@link android.Manifest.permission#READ_ACTIVE_EMERGENCY_SESSION}
- *
* @see #onOutgoingEmergencyCall
* @hide
+ * @deprecated Use {@link OutgoingEmergencyCallListener} instead.
*/
+ @Deprecated
@SystemApi
@RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 0x10000000;
@@ -443,11 +502,11 @@ public class PhoneStateListener {
/**
* Listen for the emergency number placed from an outgoing SMS.
*
- * <p>Requires permission {@link android.Manifest.permission#READ_ACTIVE_EMERGENCY_SESSION}
- *
* @see #onOutgoingEmergencySms
* @hide
+ * @deprecated Use {@link OutgoingEmergencySmsListener} instead.
*/
+ @Deprecated
@SystemApi
@RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 0x20000000;
@@ -466,7 +525,9 @@ public class PhoneStateListener {
* of whether the calling app has carrier privileges.
*
* @see #onRegistrationFailed
+ * @deprecated Use {@link RegistrationFailedListener} instead.
*/
+ @Deprecated
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public static final int LISTEN_REGISTRATION_FAILURE = 0x40000000;
@@ -480,10 +541,525 @@ public class PhoneStateListener {
* of whether the calling app has carrier privileges.
*
* @see #onBarringInfoChanged
+ * @deprecated Use {@link BarringInfoChangedListener} instead.
*/
+ @Deprecated
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public static final int LISTEN_BARRING_INFO = 0x80000000;
+ /**
+ * Event for changes to the network service state (cellular).
+ *
+ * @see ServiceStateChangedListener#onServiceStateChanged
+ * @see ServiceState
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EVENT_SERVICE_STATE_CHANGED = 1;
+
+ /**
+ * Event for changes to the network signal strength (cellular).
+ *
+ * @see SignalStrengthsChangedListener#onSignalStrengthsChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EVENT_SIGNAL_STRENGTH_CHANGED = 2;
+
+ /**
+ * Event for changes to the message-waiting indicator.
+ *
+ * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE} or that
+ * the calling app has carrier privileges (see
+ * {@link TelephonyManager#hasCarrierPrivileges}).
+ * <p>
+ * Example: The status bar uses this to determine when to display the
+ * voicemail icon.
+ *
+ * @see MessageWaitingIndicatorChangedListener#onMessageWaitingIndicatorChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public static final int EVENT_MESSAGE_WAITING_INDICATOR_CHANGED = 3;
+
+ /**
+ * Event for changes to the call-forwarding indicator.
+ *
+ * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE} or that
+ * the calling app has carrier privileges (see
+ * {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @see CallForwardingIndicatorChangedListener#onCallForwardingIndicatorChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4;
+
+ /**
+ * Event for changes to the device's cell location. Note that
+ * this will result in frequent callbacks to the listener.
+ *
+ * If you need regular location updates but want more control over
+ * the update interval or location precision, you can set up a listener
+ * through the {@link android.location.LocationManager location manager}
+ * instead.
+ *
+ * @see CellLocationChangedListener#onCellLocationChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+ public static final int EVENT_CELL_LOCATION_CHANGED = 5;
+
+ /**
+ * Event for changes to the device call state.
+ *
+ * @see CallStateChangedListener#onCallStateChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_CALL_LOG)
+ public static final int EVENT_CALL_STATE_CHANGED = 6;
+
+ /**
+ * Event for changes to the data connection state (cellular).
+ *
+ * @see DataConnectionStateChangedListener#onDataConnectionStateChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EVENT_DATA_CONNECTION_STATE_CHANGED = 7;
+
+ /**
+ * Event for changes to the direction of data traffic on the data
+ * connection (cellular).
+ *
+ * Example: The status bar uses this to display the appropriate
+ * data-traffic icon.
+ *
+ * @see DataActivityListener#onDataActivity
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EVENT_DATA_ACTIVITY_CHANGED = 8;
+
+ /**
+ * Event for changes to the network signal strengths (cellular).
+ * <p>
+ * Example: The status bar uses this to control the signal-strength
+ * icon.
+ *
+ * @see SignalStrengthsChangedListener#onSignalStrengthsChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EVENT_SIGNAL_STRENGTHS_CHANGED = 9;
+
+ /**
+ * Event for changes of the network signal strengths (cellular) always reported from modem,
+ * even in some situations such as the screen of the device is off.
+ *
+ * @see AlwaysReportedSignalStrengthChangedListener#onSignalStrengthsChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
+ public static final int EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED = 10;
+
+ /**
+ * Event for changes to observed cell info.
+ *
+ * @see CellInfoChangedListener#onCellInfoChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+ public static final int EVENT_CELL_INFO_CHANGED = 11;
+
+ /**
+ * Event for {@link android.telephony.Annotation.PreciseCallStates} of ringing,
+ * background and foreground calls.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @see PreciseCallStateChangedListener#onPreciseCallStateChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_PRECISE_CALL_STATE_CHANGED = 12;
+
+ /**
+ * Event for {@link PreciseDataConnectionState} on the data connection (cellular).
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @see PreciseDataConnectionStateChangedListener#onPreciseDataConnectionStateChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED = 13;
+
+ /**
+ * Event for real time info for all data connections (cellular)).
+ *
+ * @see #onDataConnectionRealTimeInfoChanged(DataConnectionRealTimeInfo)
+ *
+ * @deprecated Use {@link TelephonyManager#requestModemActivityInfo}
+ * @hide
+ */
+ @Deprecated
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED = 14;
+
+ /**
+ * Event for OEM hook raw event
+ *
+ * @see #onOemHookRawEvent
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public static final int EVENT_OEM_HOOK_RAW = 15;
+
+ /**
+ * Event for changes to the SRVCC state of the active call.
+ *
+ * @see SrvccStateChangedListener#onSrvccStateChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public static final int EVENT_SRVCC_STATE_CHANGED = 16;
+
+ /**
+ * Event for carrier network changes indicated by a carrier app.
+ *
+ * @see android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean)
+ * @see CarrierNetworkChangeListener#onCarrierNetworkChange
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EVENT_CARRIER_NETWORK_CHANGED = 17;
+
+ /**
+ * Event for changes to the sim voice activation state
+ *
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
+ *
+ * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates voice service has been
+ * fully activated
+ *
+ * @see VoiceActivationStateChangedListener#onVoiceActivationStateChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public static final int EVENT_VOICE_ACTIVATION_STATE_CHANGED = 18;
+
+ /**
+ * Event for changes to the sim data activation state
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
+ *
+ * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates data service has been
+ * fully activated
+ *
+ * @see DataActivationStateChangedListener#onDataActivationStateChanged
+ * @hide
+ */
+ @SystemApi
+ public static final int EVENT_DATA_ACTIVATION_STATE_CHANGED = 19;
+
+ /**
+ * Event for changes to the user mobile data state
+ *
+ * @see UserMobileDataStateChangedListener#onUserMobileDataStateChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EVENT_USER_MOBILE_DATA_STATE_CHANGED = 20;
+
+ /**
+ * Event for display info changed event.
+ *
+ * @see DisplayInfoChangedListener#onDisplayInfoChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EVENT_DISPLAY_INFO_CHANGED = 21;
+
+ /**
+ * Event for changes to the phone capability.
+ *
+ * @see PhoneCapabilityChangedListener#onPhoneCapabilityChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EVENT_PHONE_CAPABILITY_CHANGED = 22;
+
+ /**
+ * Event for changes to active data subscription ID. Active data subscription is
+ * the current subscription used to setup Cellular Internet data. For example,
+ * it could be the current active opportunistic subscription in use, or the
+ * subscription user selected as default data subscription in DSDS mode.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
+ * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @see ActiveDataSubscriptionIdChangedListener#onActiveDataSubscriptionIdChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public static final int EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED = 23;
+
+ /**
+ * Event for changes to the radio power state.
+ *
+ * @see RadioPowerStateChangedListener#onRadioPowerStateChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public static final int EVENT_RADIO_POWER_STATE_CHANGED = 24;
+
+ /**
+ * Event for changes to emergency number list based on all active subscriptions.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
+ * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @see EmergencyNumberListChangedListener#onEmergencyNumberListChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public static final int EVENT_EMERGENCY_NUMBER_LIST_CHANGED = 25;
+
+ /**
+ * Event for call disconnect causes which contains {@link DisconnectCause} and
+ * {@link PreciseDisconnectCause}.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @see CallDisconnectCauseChangedListener#onCallDisconnectCauseChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_CALL_DISCONNECT_CAUSE_CHANGED = 26;
+
+ /**
+ * Event for changes to the call attributes of a currently active call.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @see CallAttributesChangedListener#onCallAttributesChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_CALL_ATTRIBUTES_CHANGED = 27;
+
+ /**
+ * Event for IMS call disconnect causes which contains
+ * {@link android.telephony.ims.ImsReasonInfo}
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @see ImsCallDisconnectCauseChangedListener#onImsCallDisconnectCauseChanged(ImsReasonInfo)
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = 28;
+
+ /**
+ * Event for the emergency number placed from an outgoing call.
+ *
+ * @see OutgoingEmergencyCallListener#onOutgoingEmergencyCall
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+ public static final int EVENT_OUTGOING_EMERGENCY_CALL = 29;
+
+ /**
+ * Event for the emergency number placed from an outgoing SMS.
+ *
+ * @see OutgoingEmergencySmsListener#onOutgoingEmergencySms
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+ public static final int EVENT_OUTGOING_EMERGENCY_SMS = 30;
+
+ /**
+ * Event for registration failures.
+ *
+ * Event for indications that a registration procedure has failed in either the CS or PS
+ * domain. This indication does not necessarily indicate a change of service state, which should
+ * be tracked via {@link #EVENT_SERVICE_STATE_CHANGED}.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or
+ * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * <p>Also requires the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission, regardless
+ * of whether the calling app has carrier privileges.
+ *
+ * @see RegistrationFailedListener#onRegistrationFailed
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PRECISE_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
+ public static final int EVENT_REGISTRATION_FAILURE = 31;
+
+ /**
+ * Event for Barring Information for the current registered / camped cell.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or
+ * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * <p>Also requires the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission, regardless
+ * of whether the calling app has carrier privileges.
+ *
+ * @see BarringInfoChangedListener#onBarringInfoChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PRECISE_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
+ public static final int EVENT_BARRING_INFO_CHANGED = 32;
+
+ /**
+ * Event for changes to the physical channel configuration.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @see PhysicalChannelConfigChangedListener#onPhysicalChannelConfigChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 33;
+
+ /**
+ * Event for changes to the data enabled.
+ *
+ * Event for indications that the enabled status of current data has changed.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @see DataEnabledChangedListener#onDataEnabledChanged
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_DATA_ENABLED_CHANGED = 34;
+
+ /** @hide */
+ @IntDef(prefix = { "EVENT_" }, value = {
+ EVENT_SERVICE_STATE_CHANGED,
+ EVENT_SIGNAL_STRENGTH_CHANGED,
+ EVENT_MESSAGE_WAITING_INDICATOR_CHANGED,
+ EVENT_CALL_FORWARDING_INDICATOR_CHANGED,
+ EVENT_CELL_LOCATION_CHANGED,
+ EVENT_CALL_STATE_CHANGED,
+ EVENT_DATA_CONNECTION_STATE_CHANGED,
+ EVENT_DATA_ACTIVITY_CHANGED,
+ EVENT_SIGNAL_STRENGTHS_CHANGED,
+ EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED,
+ EVENT_CELL_INFO_CHANGED,
+ EVENT_PRECISE_CALL_STATE_CHANGED,
+ EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED,
+ EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED,
+ EVENT_OEM_HOOK_RAW,
+ EVENT_SRVCC_STATE_CHANGED,
+ EVENT_CARRIER_NETWORK_CHANGED,
+ EVENT_VOICE_ACTIVATION_STATE_CHANGED,
+ EVENT_DATA_ACTIVATION_STATE_CHANGED,
+ EVENT_USER_MOBILE_DATA_STATE_CHANGED,
+ EVENT_DISPLAY_INFO_CHANGED,
+ EVENT_PHONE_CAPABILITY_CHANGED,
+ EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED,
+ EVENT_RADIO_POWER_STATE_CHANGED,
+ EVENT_EMERGENCY_NUMBER_LIST_CHANGED,
+ EVENT_CALL_DISCONNECT_CAUSE_CHANGED,
+ EVENT_CALL_ATTRIBUTES_CHANGED,
+ EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED,
+ EVENT_OUTGOING_EMERGENCY_CALL,
+ EVENT_OUTGOING_EMERGENCY_SMS,
+ EVENT_REGISTRATION_FAILURE,
+ EVENT_BARRING_INFO_CHANGED,
+ EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED,
+ EVENT_DATA_ENABLED_CHANGED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TelephonyEvent {}
+
/*
* Subscription used to listen to the phone state changes
* @hide
@@ -495,13 +1071,19 @@ public class PhoneStateListener {
/**
* @hide
*/
+ //TODO: The maxTargetSdk should be S if the build time tool updates it.
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- @UnsupportedAppUsage
- public final IPhoneStateListener callback;
+ @UnsupportedAppUsage(
+ maxTargetSdk = Build.VERSION_CODES.R,
+ publicAlternatives = "Use {@code TelephonyManager#registerPhoneStateListener(" +
+ "Executor, PhoneStateListener)} instead")
+ public IPhoneStateListener callback;
/**
* Create a PhoneStateListener for the Phone with the default subscription.
- * This class requires Looper.myLooper() not return null.
+ * If this is created for use with deprecated API
+ * {@link TelephonyManager#listen(PhoneStateListener, int)}, then this class requires
+ * Looper.myLooper() not return null.
*/
public PhoneStateListener() {
this(null, Looper.myLooper());
@@ -539,7 +1121,10 @@ public class PhoneStateListener {
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public PhoneStateListener(Integer subId, Looper looper) {
- this(subId, new HandlerExecutor(new Handler(looper)));
+ if (looper != null) {
+ setExecutor(new HandlerExecutor(new Handler(looper)));
+ }
+ mSubId = subId;
if (subId != null && VMRuntime.getRuntime().getTargetSdkVersion()
>= Build.VERSION_CODES.Q) {
throw new IllegalArgumentException("PhoneStateListener with subId: "
@@ -554,17 +1139,744 @@ public class PhoneStateListener {
* The Executor must not be null.
*
* @param executor a non-null Executor that will execute callbacks for the PhoneStateListener.
+ * @deprecated Use
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)} instead.
*/
+ @Deprecated
public PhoneStateListener(@NonNull Executor executor) {
- this(null, executor);
+ setExecutor(executor);
+ mSubId = null;
}
- private PhoneStateListener(Integer subId, Executor e) {
- if (e == null) {
+ private @NonNull Executor mExecutor;
+
+ /**
+ * @hide
+ */
+ public void setExecutor(@NonNull @CallbackExecutor Executor executor) {
+ if (executor == null) {
throw new IllegalArgumentException("PhoneStateListener Executor must be non-null");
}
- mSubId = subId;
- callback = new IPhoneStateListenerStub(this, e);
+ mExecutor = executor;
+ callback = new IPhoneStateListenerStub(this, mExecutor);
+ }
+
+ /**
+ * @hide
+ */
+ public boolean isExecutorSet() {
+ return mExecutor != null;
+ }
+
+ /**
+ * Interface for service state listener.
+ */
+ public interface ServiceStateChangedListener {
+ /**
+ * Callback invoked when device service state changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * The instance of {@link ServiceState} passed as an argument here will have various
+ * levels of location information stripped from it depending on the location permissions
+ * that your app holds.
+ * Only apps holding the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission will
+ * receive all the information in {@link ServiceState}.
+ *
+ * @see ServiceState#STATE_EMERGENCY_ONLY
+ * @see ServiceState#STATE_IN_SERVICE
+ * @see ServiceState#STATE_OUT_OF_SERVICE
+ * @see ServiceState#STATE_POWER_OFF
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void onServiceStateChanged(@NonNull ServiceState serviceState);
+ }
+
+ /**
+ * Interface for message waiting indicator listener.
+ */
+ public interface MessageWaitingIndicatorChangedListener {
+ /**
+ * Callback invoked when the message-waiting indicator changes on the registered
+ * subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void onMessageWaitingIndicatorChanged(boolean mwi);
+ }
+
+ /**
+ * Interface for call-forwarding indicator listener.
+ */
+ public interface CallForwardingIndicatorChangedListener {
+ /**
+ * Callback invoked when the call-forwarding indicator changes on the registered
+ * subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void onCallForwardingIndicatorChanged(boolean cfi);
+ }
+
+ /**
+ * Interface for device cell location listener.
+ */
+ public interface CellLocationChangedListener {
+ /**
+ * Callback invoked when device cell location changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+ public void onCellLocationChanged(@NonNull CellLocation location);
+ }
+
+ /**
+ * Interface for call state listener.
+ */
+ public interface CallStateChangedListener {
+ /**
+ * Callback invoked when device call state changes.
+ * <p>
+ * Reports the state of Telephony (mobile) calls on the device for the registered s
+ * ubscription.
+ * <p>
+ * Note: the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to all subIds.
+ * <p>
+ * Note: The state returned here may differ from that returned by
+ * {@link TelephonyManager#getCallState()}. Receivers of this callback should be aware that
+ * calling {@link TelephonyManager#getCallState()} from within this callback may return a
+ * different state than the callback reports.
+ *
+ * @param state call state
+ * @param phoneNumber call phone number. If application does not have
+ * {@link android.Manifest.permission#READ_CALL_LOG} permission or carrier
+ * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), an empty string will be
+ * passed as an argument.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_CALL_LOG)
+ public void onCallStateChanged(@CallState int state, @Nullable String phoneNumber);
+ }
+
+ /**
+ * Interface for data connection state listener.
+ */
+ public interface DataConnectionStateChangedListener {
+ /**
+ * Callback invoked when connection state changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @see TelephonyManager#DATA_DISCONNECTED
+ * @see TelephonyManager#DATA_CONNECTING
+ * @see TelephonyManager#DATA_CONNECTED
+ * @see TelephonyManager#DATA_SUSPENDED
+ *
+ * @param state is the current state of data connection.
+ * @param networkType is the current network type of data connection.
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void onDataConnectionStateChanged(@DataState int state,
+ @NetworkType int networkType);
+ }
+
+ /**
+ * Interface for data activity state listener.
+ */
+ public interface DataActivityListener {
+ /**
+ * Callback invoked when data activity state changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @see TelephonyManager#DATA_ACTIVITY_NONE
+ * @see TelephonyManager#DATA_ACTIVITY_IN
+ * @see TelephonyManager#DATA_ACTIVITY_OUT
+ * @see TelephonyManager#DATA_ACTIVITY_INOUT
+ * @see TelephonyManager#DATA_ACTIVITY_DORMANT
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void onDataActivity(@DataActivityType int direction);
+ }
+
+ /**
+ * Interface for network signal strengths listener.
+ */
+ public interface SignalStrengthsChangedListener {
+ /**
+ * Callback invoked when network signal strengths changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength);
+ }
+
+ /**
+ * Interface for network signal strengths listener which always reported from modem.
+ */
+ public interface AlwaysReportedSignalStrengthChangedListener {
+ /**
+ * Callback always invoked from modem when network signal strengths changes on the
+ * registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ */
+ @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
+ public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength);
+ }
+
+ /**
+ * Interface for cell info listener.
+ */
+ public interface CellInfoChangedListener {
+ /**
+ * Callback invoked when a observed cell info has changed or new cells have been added
+ * or removed on the registered subscription.
+ * Note, the registration subscription ID s from {@link TelephonyManager} object
+ * which registersPhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param cellInfo is the list of currently visible cells.
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+ public void onCellInfoChanged(@NonNull List<CellInfo> cellInfo);
+ }
+
+ /**
+ * Interface for precise device call state listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface PreciseCallStateChangedListener {
+ /**
+ * Callback invoked when precise device call state changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param callState {@link PreciseCallState}
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public void onPreciseCallStateChanged(@NonNull PreciseCallState callState);
+ }
+
+ /**
+ * Interface for call disconnect cause listener.
+ */
+ public interface CallDisconnectCauseChangedListener {
+ /**
+ * Callback invoked when call disconnect cause changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param disconnectCause {@link DisconnectCause}.
+ * @param preciseDisconnectCause {@link PreciseDisconnectCause}.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public void onCallDisconnectCauseChanged(@DisconnectCauses int disconnectCause,
+ @PreciseDisconnectCauses int preciseDisconnectCause);
+ }
+
+ /**
+ * Interface for IMS call disconnect cause listener.
+ */
+ public interface ImsCallDisconnectCauseChangedListener {
+ /**
+ * Callback invoked when IMS call disconnect cause changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param imsReasonInfo {@link ImsReasonInfo} contains details on why IMS call failed.
+ *
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo);
+ }
+
+ /**
+ * Interface for precise data connection state listener.
+ */
+ public interface PreciseDataConnectionStateChangedListener {
+ /**
+ * Callback providing update about the default/internet data connection on the registered
+ * subscription.
+ *
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @param dataConnectionState {@link PreciseDataConnectionState}
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public void onPreciseDataConnectionStateChanged(
+ @NonNull PreciseDataConnectionState dataConnectionState);
+ }
+
+ /**
+ * Interface for Single Radio Voice Call Continuity listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface SrvccStateChangedListener {
+ /**
+ * Callback invoked when there has been a change in the Single Radio Voice Call Continuity
+ * (SRVCC) state for the currently active call on the registered subscription.
+ *
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void onSrvccStateChanged(@SrvccState int srvccState);
+ }
+
+ /**
+ * Interface for SIM voice activation state listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface VoiceActivationStateChangedListener {
+ /**
+ * Callback invoked when the SIM voice activation state has changed on the registered
+ * subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param state is the current SIM voice activation state
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void onVoiceActivationStateChanged(@SimActivationState int state);
+
+ }
+
+ /**
+ * Interface for SIM data activation state listener.
+ */
+ public interface DataActivationStateChangedListener {
+ /**
+ * Callback invoked when the SIM data activation state has changed on the registered
+ * subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param state is the current SIM data activation state
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void onDataActivationStateChanged(@SimActivationState int state);
+ }
+
+ /**
+ * Interface for user mobile data state listener.
+ */
+ public interface UserMobileDataStateChangedListener {
+ /**
+ * Callback invoked when the user mobile data state has changed on the registered
+ * subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param enabled indicates whether the current user mobile data state is enabled or
+ * disabled.
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void onUserMobileDataStateChanged(boolean enabled);
+ }
+
+ /**
+ * Interface for display info listener.
+ */
+ public interface DisplayInfoChangedListener {
+ /**
+ * Callback invoked when the display info has changed on the registered subscription.
+ * <p> The {@link TelephonyDisplayInfo} contains status information shown to the user
+ * based on carrier policy.
+ *
+ * @param telephonyDisplayInfo The display information.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo);
+ }
+
+ /**
+ * Interface for the current emergency number list listener.
+ */
+ public interface EmergencyNumberListChangedListener {
+ /**
+ * Callback invoked when the current emergency number list has changed on the registered
+ * subscription.
+ *
+ * Note, the registered subscription is associated with {@link TelephonyManager} object
+ * on which
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}
+ * was called.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * given subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param emergencyNumberList Map associating all active subscriptions on the device with
+ * the list of emergency numbers originating from that
+ * subscription.
+ * If there are no active subscriptions, the map will contain a
+ * single entry with
+ * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} as
+ * the key and a list of emergency numbers as the value. If no
+ * emergency number information is available, the value will be
+ * empty.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void onEmergencyNumberListChanged(
+ @NonNull Map<Integer, List<EmergencyNumber>> emergencyNumberList);
+ }
+
+ /**
+ * Interface for outgoing emergency call listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface OutgoingEmergencyCallListener {
+ /**
+ * Callback invoked when an outgoing call is placed to an emergency number.
+ *
+ * This method will be called when an emergency call is placed on any subscription
+ * (including the no-SIM case), regardless of which subscription this listener was
+ * registered on.
+ *
+ * The default implementation of this method calls
+ * {@link #onOutgoingEmergencyCall(EmergencyNumber)} for backwards compatibility purposes.
+ * Do not call {@code super(...)} from within your implementation unless you want
+ * {@link #onOutgoingEmergencyCall(EmergencyNumber)} to be called as well.
+ *
+ * @param placedEmergencyNumber The {@link EmergencyNumber} the emergency call was
+ * placed to.
+ * @param subscriptionId The subscription ID used to place the emergency call. If the
+ * emergency call was placed without a valid subscription
+ * (e.g. when there are no SIM cards in the device), this will be
+ * equal to {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
+ */
+ @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+ public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber,
+ int subscriptionId);
+ }
+
+ /**
+ * Interface for outgoing emergency sms listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface OutgoingEmergencySmsListener {
+ /**
+ * Smsback invoked when an outgoing sms is sent to an emergency number.
+ *
+ * This method will be called when an emergency sms is sent on any subscription,
+ * regardless of which subscription this listener was registered on.
+ *
+ * The default implementation of this method calls
+ * {@link #onOutgoingEmergencySms(EmergencyNumber)} for backwards compatibility purposes. Do
+ * not call {@code super(...)} from within your implementation unless you want
+ * {@link #onOutgoingEmergencySms(EmergencyNumber)} to be called as well.
+ *
+ * @param sentEmergencyNumber The {@link EmergencyNumber} the emergency sms was sent to.
+ * @param subscriptionId The subscription ID used to send the emergency sms.
+ */
+ @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+ public void onOutgoingEmergencySms(@NonNull EmergencyNumber sentEmergencyNumber,
+ int subscriptionId);
+ }
+
+ /**
+ * Interface for phone capability listener.
+ *
+ */
+ public interface PhoneCapabilityChangedListener {
+ /**
+ * Callback invoked when phone capability changes.
+ * Note, this callback triggers regardless of registered subscription.
+ *
+ * @param capability the new phone capability
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void onPhoneCapabilityChanged(@NonNull PhoneCapability capability);
+ }
+
+ /**
+ * Interface for active data subscription ID listener.
+ */
+ public interface ActiveDataSubscriptionIdChangedListener {
+ /**
+ * Callback invoked when active data subscription ID changes.
+ * Note, this callback triggers regardless of registered subscription.
+ *
+ * @param subId current subscription used to setup Cellular Internet data.
+ * For example, it could be the current active opportunistic subscription
+ * in use, or the subscription user selected as default data subscription in
+ * DSDS mode.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void onActiveDataSubscriptionIdChanged(int subId);
+ }
+
+ /**
+ * Interface for modem radio power state listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface RadioPowerStateChangedListener {
+ /**
+ * Callback invoked when modem radio power state changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param state the modem radio power state
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void onRadioPowerStateChanged(@RadioPowerState int state);
+ }
+
+ /**
+ * Interface for carrier network listener.
+ */
+ public interface CarrierNetworkChangeListener {
+ /**
+ * Callback invoked when telephony has received notice from a carrier
+ * app that a network action that could result in connectivity loss
+ * has been requested by an app using
+ * {@link android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean)}
+ *
+ * This is optional and is only used to allow the system to provide alternative UI while
+ * telephony is performing an action that may result in intentional, temporary network
+ * lack of connectivity.
+ *
+ * Note, this callback is pinned to the registered subscription and will be invoked when
+ * the notifying carrier app has carrier privilege rule on the registered
+ * subscription. {@link android.telephony.TelephonyManager#hasCarrierPrivileges}
+ *
+ * @param active If the carrier network change is or shortly will be active,
+ * {@code true} indicate that showing alternative UI, {@code false} otherwise.
+ */
+ public void onCarrierNetworkChange(boolean active);
+ }
+
+ /**
+ * Interface for registration failures listener.
+ */
+ public interface RegistrationFailedListener {
+ /**
+ * Report that Registration or a Location/Routing/Tracking Area update has failed.
+ *
+ * <p>Indicate whenever a registration procedure, including a location, routing, or tracking
+ * area update fails. This includes procedures that do not necessarily result in a change of
+ * the modem's registration status. If the modem's registration status changes, that is
+ * reflected in the onNetworkStateChanged() and subsequent
+ * get{Voice/Data}RegistrationState().
+ *
+ * <p>Because registration failures are ephemeral, this callback is not sticky.
+ * Registrants will not receive the most recent past value when registering.
+ *
+ * @param cellIdentity the CellIdentity, which must include the globally unique identifier
+ * for the cell (for example, all components of the CGI or ECGI).
+ * @param chosenPlmn a 5 or 6 digit alphanumeric PLMN (MCC|MNC) among those broadcast by the
+ * cell that was chosen for the failed registration attempt.
+ * @param domain DOMAIN_CS, DOMAIN_PS or both in case of a combined procedure.
+ * @param causeCode the primary failure cause code of the procedure.
+ * For GSM/UMTS (MM), values are in TS 24.008 Sec 10.5.95
+ * For GSM/UMTS (GMM), values are in TS 24.008 Sec 10.5.147
+ * For LTE (EMM), cause codes are TS 24.301 Sec 9.9.3.9
+ * For NR (5GMM), cause codes are TS 24.501 Sec 9.11.3.2
+ * Integer.MAX_VALUE if this value is unused.
+ * @param additionalCauseCode the cause code of any secondary/combined procedure
+ * if appropriate. For UMTS, if a combined attach succeeds for
+ * PS only, then the GMM cause code shall be included as an
+ * additionalCauseCode. For LTE (ESM), cause codes are in
+ * TS 24.301 9.9.4.4. Integer.MAX_VALUE if this value is unused.
+ */
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PRECISE_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
+ public void onRegistrationFailed(@NonNull CellIdentity cellIdentity,
+ @NonNull String chosenPlmn, @Domain int domain,
+ int causeCode, int additionalCauseCode);
+ }
+
+ /**
+ * Interface for call attributes listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface CallAttributesChangedListener {
+ /**
+ * Callback invoked when the call attributes changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param callAttributes the call attributes
+ */
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+ void onCallAttributesChanged(@NonNull CallAttributes callAttributes);
+ }
+
+ /**
+ * Interface for barring information listener.
+ */
+ public interface BarringInfoChangedListener {
+ /**
+ * Report updated barring information for the current camped/registered cell.
+ *
+ * <p>Barring info is provided for all services applicable to the current camped/registered
+ * cell, for the registered PLMN and current access class/access category.
+ *
+ * @param barringInfo for all services on the current cell.
+ * @see android.telephony.BarringInfo
+ */
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PRECISE_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
+ public void onBarringInfoChanged(@NonNull BarringInfo barringInfo);
+ }
+
+ /**
+ * Interface for current physical channel configuration listener.
+ * @hide
+ */
+ @SystemApi
+ public interface PhysicalChannelConfigChangedListener {
+ /**
+ * Callback invoked when the current physical channel configuration has changed
+ *
+ * @param configs List of the current {@link PhysicalChannelConfig}s
+ */
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public void onPhysicalChannelConfigChanged(@NonNull List<PhysicalChannelConfig> configs);
+ }
+
+ /**
+ * Interface for data enabled listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface DataEnabledChangedListener {
+ /**
+ * Callback invoked when the data enabled changes.
+ *
+ * @param enabled {@code true} if data is enabled, otherwise disabled.
+ * @param reason Reason for data enabled/disabled.
+ * See {@link TelephonyManager.DataEnabledReason}.
+ */
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public void onDataEnabledChanged(boolean enabled,
+ @DataEnabledReason int reason);
}
/**
@@ -658,8 +1970,7 @@ public class PhoneStateListener {
* PhoneStateListener by {@link TelephonyManager#listen(PhoneStateListener, int)}.
* If this TelephonyManager object was created with
* {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subId. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ * subId. Otherwise, this callback applies to all subIds.
* <p>
* Note: The state returned here may differ from that returned by
* {@link TelephonyManager#getCallState()}. Receivers of this callback should be aware that
@@ -698,6 +2009,7 @@ public class PhoneStateListener {
* same as above, but with the network type. Both called.
*/
public void onDataConnectionStateChanged(int state, int networkType) {
+ // default implementation empty
}
/**
@@ -745,6 +2057,7 @@ public class PhoneStateListener {
* @param cellInfo is the list of currently visible cells.
*/
public void onCellInfoChanged(List<CellInfo> cellInfo) {
+ // default implementation empty
}
/**
@@ -758,7 +2071,7 @@ public class PhoneStateListener {
* @param callState {@link PreciseCallState}
* @hide
*/
- @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
@SystemApi
public void onPreciseCallStateChanged(@NonNull PreciseCallState callState) {
// default implementation empty
@@ -777,9 +2090,9 @@ public class PhoneStateListener {
* @param preciseDisconnectCause {@link PreciseDisconnectCause}.
*
*/
- @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
- public void onCallDisconnectCauseChanged(@Annotation.DisconnectCauses int disconnectCause,
- int preciseDisconnectCause) {
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public void onCallDisconnectCauseChanged(@DisconnectCauses int disconnectCause,
+ @PreciseDisconnectCauses int preciseDisconnectCause) {
// default implementation empty
}
@@ -795,7 +2108,7 @@ public class PhoneStateListener {
* @param imsReasonInfo {@link ImsReasonInfo} contains details on why IMS call failed.
*
*/
- @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
public void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo) {
// default implementation empty
}
@@ -817,7 +2130,7 @@ public class PhoneStateListener {
*
* @param dataConnectionState {@link PreciseDataConnectionState}
*/
- @RequiresPermission((android.Manifest.permission.MODIFY_PHONE_STATE))
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void onPreciseDataConnectionStateChanged(
@NonNull PreciseDataConnectionState dataConnectionState) {
// default implementation empty
@@ -855,6 +2168,7 @@ public class PhoneStateListener {
*/
@SystemApi
public void onSrvccStateChanged(@SrvccState int srvccState) {
+ // default implementation empty
}
@@ -873,6 +2187,7 @@ public class PhoneStateListener {
*/
@SystemApi
public void onVoiceActivationStateChanged(@SimActivationState int state) {
+ // default implementation empty
}
/**
@@ -889,6 +2204,7 @@ public class PhoneStateListener {
* @hide
*/
public void onDataActivationStateChanged(@SimActivationState int state) {
+ // default implementation empty
}
/**
@@ -916,7 +2232,7 @@ public class PhoneStateListener {
*
* @param telephonyDisplayInfo The display information.
*/
- @RequiresPermission((android.Manifest.permission.READ_PHONE_STATE))
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo) {
// default implementation empty
}
@@ -1030,7 +2346,8 @@ public class PhoneStateListener {
/**
* Callback invoked when OEM hook raw event is received on the registered subscription.
* Note, the registration subId comes from {@link TelephonyManager} object which registers
- * PhoneStateListener by {@link TelephonyManager#listen(PhoneStateListener, int)}.
+ * PhoneStateListener by
+ * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
* If this TelephonyManager object was created with
* {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
* subId. Otherwise, this callback applies to
@@ -1052,7 +2369,7 @@ public class PhoneStateListener {
* @param capability the new phone capability
* @hide
*/
- public void onPhoneCapabilityChanged(PhoneCapability capability) {
+ public void onPhoneCapabilityChanged(@NonNull PhoneCapability capability) {
// default implementation empty
}
@@ -1096,7 +2413,8 @@ public class PhoneStateListener {
* subId. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
- * @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE}
+ * Requires permission {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
+ *
* @param state the modem radio power state
* @hide
*/
@@ -1453,18 +2771,16 @@ public class PhoneStateListener {
Binder.withCleanCallingIdentity(
() -> mExecutor.execute(
() -> psl.onImsCallDisconnectCauseChanged(disconnectCause)));
-
}
public void onRegistrationFailed(@NonNull CellIdentity cellIdentity,
- @NonNull String chosenPlmn, int domain,
- int causeCode, int additionalCauseCode) {
+ @NonNull String chosenPlmn, int domain, int causeCode, int additionalCauseCode) {
PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
if (psl == null) return;
Binder.withCleanCallingIdentity(
() -> mExecutor.execute(() -> psl.onRegistrationFailed(
- cellIdentity, chosenPlmn, domain, causeCode, additionalCauseCode)));
+ cellIdentity, chosenPlmn, domain, causeCode, additionalCauseCode)));
// default implementation empty
}
@@ -1475,8 +2791,27 @@ public class PhoneStateListener {
Binder.withCleanCallingIdentity(
() -> mExecutor.execute(() -> psl.onBarringInfoChanged(barringInfo)));
}
- }
+ public void onPhysicalChannelConfigChanged(List<PhysicalChannelConfig> configs) {
+ PhysicalChannelConfigChangedListener listener =
+ (PhysicalChannelConfigChangedListener) mPhoneStateListenerWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onPhysicalChannelConfigChanged(
+ configs)));
+ }
+
+ public void onDataEnabledChanged(boolean enabled, @DataEnabledReason int reason) {
+ DataEnabledChangedListener listener =
+ (DataEnabledChangedListener) mPhoneStateListenerWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onDataEnabledChanged(
+ enabled, reason)));
+ }
+ }
private void log(String s) {
Rlog.d(LOG_TAG, s);
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 3673ae7f7a37..a9548b0a42b4 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -15,6 +15,7 @@
*/
package android.telephony;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -24,6 +25,9 @@ import android.compat.annotation.EnabledAfter;
import android.content.Context;
import android.os.Binder;
import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.Annotation.CallState;
@@ -37,6 +41,7 @@ import android.telephony.Annotation.SimActivationState;
import android.telephony.Annotation.SrvccState;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
+import android.util.ArraySet;
import android.util.Log;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
@@ -45,6 +50,7 @@ import com.android.internal.telephony.ITelephonyRegistry;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.Executor;
/**
@@ -206,7 +212,7 @@ public class TelephonyRegistryManager {
}
/**
- * To check the SDK version for {@link #listenForSubscriber}.
+ * To check the SDK version for {@link #listenWithEventList}.
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.P)
@@ -218,23 +224,23 @@ public class TelephonyRegistryManager {
* @param pkg Package name
* @param featureId Feature ID
* @param listener Listener providing callback
- * @param events Events
+ * @param events List events
* @param notifyNow Whether to notify instantly
*/
- public void listenForSubscriber(int subId, @NonNull String pkg, @NonNull String featureId,
- @NonNull PhoneStateListener listener, int events, boolean notifyNow) {
+ public void listenWithEventList(int subId, @NonNull String pkg, @NonNull String featureId,
+ @NonNull PhoneStateListener listener, @NonNull int[] events, boolean notifyNow) {
try {
// subId from PhoneStateListener is deprecated Q on forward, use the subId from
// TelephonyManager instance. Keep using subId from PhoneStateListener for pre-Q.
if (Compatibility.isChangeEnabled(LISTEN_CODE_CHANGE)) {
// Since mSubId in PhoneStateListener is deprecated from Q on forward, this is
// the only place to set mSubId and its for "informational" only.
- listener.mSubId = (events == PhoneStateListener.LISTEN_NONE)
+ listener.mSubId = (events.length == 0)
? SubscriptionManager.INVALID_SUBSCRIPTION_ID : subId;
} else if (listener.mSubId != null) {
subId = listener.mSubId;
}
- sRegistry.listenForSubscriber(
+ sRegistry.listenWithEventList(
subId, pkg, featureId, listener.callback, events, notifyNow);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -765,4 +771,366 @@ public class TelephonyRegistryManager {
}
}
+ /**
+ * Notify {@link PhysicalChannelConfig} has changed for a specific subscription.
+ *
+ * @param subId the subId
+ * @param configs a list of {@link PhysicalChannelConfig}, the configs of physical channel.
+ */
+ public void notifyPhysicalChannelConfigForSubscriber(
+ int subId, List<PhysicalChannelConfig> configs) {
+ try {
+ sRegistry.notifyPhysicalChannelConfigForSubscriber(subId, configs);
+ } catch (RemoteException ex) {
+ // system server crash
+ }
+ }
+
+ /**
+ * Notify that the data enabled has changed.
+ *
+ * @param enabled True if data is enabled, otherwise disabled.
+ * @param reason Reason for data enabled/disabled. See {@code REASON_*} in
+ * {@link TelephonyManager}.
+ */
+ public void notifyDataEnabled(boolean enabled, @TelephonyManager.DataEnabledReason int reason) {
+ try {
+ sRegistry.notifyDataEnabled(enabled, reason);
+ } catch (RemoteException ex) {
+ // system server crash
+ }
+ }
+
+ public @NonNull Set<Integer> getEventsFromListener(@NonNull PhoneStateListener listener) {
+
+ Set<Integer> eventList = new ArraySet<>();
+
+ if (listener instanceof PhoneStateListener.ServiceStateChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.MessageWaitingIndicatorChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.CallForwardingIndicatorChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.CellLocationChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_CELL_LOCATION_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.CallStateChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_CALL_STATE_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.DataConnectionStateChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.DataActivityListener) {
+ eventList.add(PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.SignalStrengthsChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.AlwaysReportedSignalStrengthChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.CellInfoChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_CELL_INFO_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.PreciseCallStateChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.CallDisconnectCauseChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.ImsCallDisconnectCauseChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.PreciseDataConnectionStateChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.SrvccStateChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.VoiceActivationStateChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.DataActivationStateChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.UserMobileDataStateChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.DisplayInfoChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.EmergencyNumberListChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.OutgoingEmergencyCallListener) {
+ eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL);
+ }
+
+ if (listener instanceof PhoneStateListener.OutgoingEmergencySmsListener) {
+ eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS);
+ }
+
+ if (listener instanceof PhoneStateListener.PhoneCapabilityChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.ActiveDataSubscriptionIdChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.RadioPowerStateChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.CarrierNetworkChangeListener) {
+ eventList.add(PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.RegistrationFailedListener) {
+ eventList.add(PhoneStateListener.EVENT_REGISTRATION_FAILURE);
+ }
+
+ if (listener instanceof PhoneStateListener.CallAttributesChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.BarringInfoChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_BARRING_INFO_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.PhysicalChannelConfigChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED);
+ }
+
+ if (listener instanceof PhoneStateListener.DataEnabledChangedListener) {
+ eventList.add(PhoneStateListener.EVENT_DATA_ENABLED_CHANGED);
+ }
+
+ return eventList;
+ }
+
+ private @NonNull Set<Integer> getEventsFromBitmask(int eventMask) {
+
+ Set<Integer> eventList = new ArraySet<>();
+
+ if ((eventMask & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
+ eventList.add(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
+ eventList.add(PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
+ eventList.add(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
+ eventList.add(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
+ eventList.add(PhoneStateListener.EVENT_CELL_LOCATION_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
+ eventList.add(PhoneStateListener.EVENT_CALL_STATE_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
+ eventList.add(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
+ eventList.add(PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
+ eventList.add(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
+ eventList.add(PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_CELL_INFO) != 0) {
+ eventList.add(PhoneStateListener.EVENT_CELL_INFO_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
+ eventList.add(PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
+ eventList.add(PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO) != 0) {
+ eventList.add(PhoneStateListener.EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT) != 0) {
+ eventList.add(PhoneStateListener.EVENT_OEM_HOOK_RAW);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) != 0) {
+ eventList.add(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) != 0) {
+ eventList.add(PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) != 0) {
+ eventList.add(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) != 0) {
+ eventList.add(PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) {
+ eventList.add(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) != 0) {
+ eventList.add(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE) != 0) {
+ eventList.add(PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE) != 0) {
+ eventList.add(PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED) != 0) {
+ eventList.add(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST) != 0) {
+ eventList.add(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES) != 0) {
+ eventList.add(PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED) != 0) {
+ eventList.add(PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) != 0) {
+ eventList.add(PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL) != 0) {
+ eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS) != 0) {
+ eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_REGISTRATION_FAILURE) != 0) {
+ eventList.add(PhoneStateListener.EVENT_REGISTRATION_FAILURE);
+ }
+
+ if ((eventMask & PhoneStateListener.LISTEN_BARRING_INFO) != 0) {
+ eventList.add(PhoneStateListener.EVENT_BARRING_INFO_CHANGED);
+ }
+ return eventList;
+
+ }
+
+ /**
+ * Registers a listener object to receive notification of changes
+ * in specified telephony states.
+ * <p>
+ * To register a listener, pass a {@link PhoneStateListener} which implements
+ * interfaces of events. For example,
+ * FakeServiceStateChangedListener extends {@link PhoneStateListener} implements
+ * {@link PhoneStateListener.ServiceStateChangedListener}.
+ *
+ * At registration, and when a specified telephony state changes, the telephony manager invokes
+ * the appropriate callback method on the listener object and passes the current (updated)
+ * values.
+ * <p>
+ *
+ * If this TelephonyManager object has been created with
+ * {@link TelephonyManager#createForSubscriptionId}, applies to the given subId.
+ * Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ * To listen events for multiple subIds, pass a separate listener object to
+ * each TelephonyManager object created with {@link TelephonyManager#createForSubscriptionId}.
+ *
+ * Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
+ * call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
+ * {@link SecurityException} will be thrown otherwise.
+ *
+ * This API should be used sparingly -- large numbers of listeners will cause system
+ * instability. If a process has registered too many listeners without unregistering them, it
+ * may encounter an {@link IllegalStateException} when trying to register more listeners.
+ *
+ * @param listener The {@link PhoneStateListener} object to register.
+ */
+ public void registerPhoneStateListener(@NonNull @CallbackExecutor Executor executor, int subId,
+ String pkgName, String attributionTag, @NonNull PhoneStateListener listener,
+ boolean notifyNow) {
+ listener.setExecutor(executor);
+ registerPhoneStateListener(subId, pkgName, attributionTag, listener,
+ getEventsFromListener(listener), notifyNow);
+ }
+
+ public void registerPhoneStateListenerWithEvents(int subId, String pkgName,
+ String attributionTag, @NonNull PhoneStateListener listener, int events,
+ boolean notifyNow) {
+ registerPhoneStateListener(
+ subId, pkgName, attributionTag, listener, getEventsFromBitmask(events), notifyNow);
+ }
+
+ private void registerPhoneStateListener(int subId,
+ String pkgName, String attributionTag, @NonNull PhoneStateListener listener,
+ @NonNull Set<Integer> events, boolean notifyNow) {
+ if (listener == null) {
+ throw new IllegalStateException("telephony service is null.");
+ }
+
+ listenWithEventList(subId, pkgName, attributionTag, listener,
+ events.stream().mapToInt(i -> i).toArray(), notifyNow);
+ }
+
+ /**
+ * Unregister an existing {@link PhoneStateListener}.
+ *
+ * @param listener The {@link PhoneStateListener} object to unregister.
+ */
+ public void unregisterPhoneStateListener(int subId, String pkgName, String attributionTag,
+ @NonNull PhoneStateListener listener,
+ boolean notifyNow) {
+ listenWithEventList(subId, pkgName, attributionTag, listener, new int[0], notifyNow);
+ }
}
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index 17d3ae4a7ff0..471f2c2aecae 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -24,11 +24,12 @@ import android.content.res.Resources;
import android.icu.text.MeasureFormat;
import android.icu.util.Measure;
import android.icu.util.MeasureUnit;
-import android.net.NetworkUtils;
import android.text.BidiFormatter;
import android.text.TextUtils;
import android.view.View;
+import com.android.net.module.util.Inet4AddressUtils;
+
import java.util.Locale;
/**
@@ -207,7 +208,7 @@ public final class Formatter {
*/
@Deprecated
public static String formatIpAddress(int ipv4Address) {
- return NetworkUtils.intToInetAddress(ipv4Address).getHostAddress();
+ return Inet4AddressUtils.intToInet4AddressHTL(ipv4Address).getHostAddress();
}
private static final int SECONDS_PER_MINUTE = 60;
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 537498c44d5e..9d0ae30f1420 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -39,7 +39,6 @@ public class FeatureFlagUtils {
public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer";
public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
- public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
/** @hide */
@@ -53,7 +52,6 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put("settings_audio_switcher", "true");
DEFAULT_FLAGS.put("settings_systemui_theme", "true");
DEFAULT_FLAGS.put(SETTINGS_FUSE_FLAG, "true");
- DEFAULT_FLAGS.put(DYNAMIC_SYSTEM, "false");
DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
diff --git a/core/java/android/util/OWNERS b/core/java/android/util/OWNERS
index 8f3d9f6f5881..14aa38682d2b 100644
--- a/core/java/android/util/OWNERS
+++ b/core/java/android/util/OWNERS
@@ -1,3 +1,6 @@
per-file FeatureFlagUtils.java = sbasi@google.com
per-file FeatureFlagUtils.java = tmfang@google.com
per-file FeatureFlagUtils.java = asapperstein@google.com
+
+per-file TypedValue.java = file:/core/java/android/content/res/OWNERS
+per-file AttributeSet.java = file:/core/java/android/content/res/OWNERS
diff --git a/core/java/android/uwb/AngleMeasurement.java b/core/java/android/uwb/AngleMeasurement.java
index 93b5fd4cd4b6..9df213b2092f 100644
--- a/core/java/android/uwb/AngleMeasurement.java
+++ b/core/java/android/uwb/AngleMeasurement.java
@@ -18,6 +18,7 @@ package android.uwb;
import android.annotation.FloatRange;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -31,6 +32,7 @@ import java.util.Objects;
*
* @hide
*/
+@SystemApi
public final class AngleMeasurement implements Parcelable {
private final double mRadians;
private final double mErrorRadians;
diff --git a/core/java/android/uwb/AngleOfArrivalMeasurement.java b/core/java/android/uwb/AngleOfArrivalMeasurement.java
index 20a1c7aa72d0..3d8626b98bed 100644
--- a/core/java/android/uwb/AngleOfArrivalMeasurement.java
+++ b/core/java/android/uwb/AngleOfArrivalMeasurement.java
@@ -18,6 +18,7 @@ package android.uwb;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -28,6 +29,7 @@ import java.util.Objects;
*
* @hide
*/
+@SystemApi
public final class AngleOfArrivalMeasurement implements Parcelable {
private final AngleMeasurement mAzimuthAngleMeasurement;
private final AngleMeasurement mAltitudeAngleMeasurement;
@@ -53,7 +55,7 @@ public final class AngleOfArrivalMeasurement implements Parcelable {
* @return the azimuth {@link AngleMeasurement}
*/
@NonNull
- public AngleMeasurement getAzimuthAngleMeasurement() {
+ public AngleMeasurement getAzimuth() {
return mAzimuthAngleMeasurement;
}
@@ -70,7 +72,7 @@ public final class AngleOfArrivalMeasurement implements Parcelable {
* @return altitude {@link AngleMeasurement} or null when this is not available
*/
@Nullable
- public AngleMeasurement getAltitudeAngleMeasurement() {
+ public AngleMeasurement getAltitude() {
return mAltitudeAngleMeasurement;
}
@@ -85,8 +87,8 @@ public final class AngleOfArrivalMeasurement implements Parcelable {
if (obj instanceof AngleOfArrivalMeasurement) {
AngleOfArrivalMeasurement other = (AngleOfArrivalMeasurement) obj;
- return mAzimuthAngleMeasurement.equals(other.getAzimuthAngleMeasurement())
- && mAltitudeAngleMeasurement.equals(other.getAltitudeAngleMeasurement());
+ return mAzimuthAngleMeasurement.equals(other.getAzimuth())
+ && mAltitudeAngleMeasurement.equals(other.getAltitude());
}
return false;
}
@@ -116,11 +118,9 @@ public final class AngleOfArrivalMeasurement implements Parcelable {
public AngleOfArrivalMeasurement createFromParcel(Parcel in) {
Builder builder = new Builder();
- builder.setAzimuthAngleMeasurement(
- in.readParcelable(AngleMeasurement.class.getClassLoader()));
+ builder.setAzimuth(in.readParcelable(AngleMeasurement.class.getClassLoader()));
- builder.setAltitudeAngleMeasurement(
- in.readParcelable(AngleMeasurement.class.getClassLoader()));
+ builder.setAltitude(in.readParcelable(AngleMeasurement.class.getClassLoader()));
return builder.build();
}
@@ -144,7 +144,7 @@ public final class AngleOfArrivalMeasurement implements Parcelable {
* @param azimuthAngle azimuth angle
*/
@NonNull
- public Builder setAzimuthAngleMeasurement(@NonNull AngleMeasurement azimuthAngle) {
+ public Builder setAzimuth(@NonNull AngleMeasurement azimuthAngle) {
mAzimuthAngleMeasurement = azimuthAngle;
return this;
}
@@ -155,7 +155,7 @@ public final class AngleOfArrivalMeasurement implements Parcelable {
* @param altitudeAngle altitude angle
*/
@NonNull
- public Builder setAltitudeAngleMeasurement(@NonNull AngleMeasurement altitudeAngle) {
+ public Builder setAltitude(@NonNull AngleMeasurement altitudeAngle) {
mAltitudeAngleMeasurement = altitudeAngle;
return this;
}
diff --git a/core/java/android/uwb/DistanceMeasurement.java b/core/java/android/uwb/DistanceMeasurement.java
index 10c2172d5a6b..2a9bbdf3ec5d 100644
--- a/core/java/android/uwb/DistanceMeasurement.java
+++ b/core/java/android/uwb/DistanceMeasurement.java
@@ -19,6 +19,7 @@ package android.uwb;
import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -32,6 +33,7 @@ import java.util.Objects;
*
* @hide
*/
+@SystemApi
public final class DistanceMeasurement implements Parcelable {
private final double mMeters;
private final double mErrorMeters;
diff --git a/core/java/android/uwb/RangingMeasurement.java b/core/java/android/uwb/RangingMeasurement.java
index 50e5f0d8d554..249e2b746d0d 100644
--- a/core/java/android/uwb/RangingMeasurement.java
+++ b/core/java/android/uwb/RangingMeasurement.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -33,6 +34,7 @@ import java.util.Objects;
*
* @hide
*/
+@SystemApi
public final class RangingMeasurement implements Parcelable {
private final UwbAddress mRemoteDeviceAddress;
private final @Status int mStatus;
diff --git a/core/java/android/uwb/RangingReport.java b/core/java/android/uwb/RangingReport.java
index 5b5f084914ab..7a2df8617700 100644
--- a/core/java/android/uwb/RangingReport.java
+++ b/core/java/android/uwb/RangingReport.java
@@ -18,6 +18,7 @@ package android.uwb;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -30,6 +31,7 @@ import java.util.Objects;
*
* @hide
*/
+@SystemApi
public final class RangingReport implements Parcelable {
private final List<RangingMeasurement> mRangingMeasurements;
diff --git a/core/java/android/uwb/RangingSession.java b/core/java/android/uwb/RangingSession.java
index 0f87af415825..bfa8bf21ec6a 100644
--- a/core/java/android/uwb/RangingSession.java
+++ b/core/java/android/uwb/RangingSession.java
@@ -18,6 +18,7 @@ package android.uwb;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Binder;
import android.os.PersistableBundle;
import android.os.RemoteException;
@@ -42,6 +43,7 @@ import java.util.concurrent.Executor;
*
* @hide
*/
+@SystemApi
public final class RangingSession implements AutoCloseable {
private static final String TAG = "Uwb.RangingSession";
private final SessionHandle mSessionHandle;
diff --git a/core/java/android/uwb/UwbAddress.java b/core/java/android/uwb/UwbAddress.java
index b9523a307c42..22883be88760 100644
--- a/core/java/android/uwb/UwbAddress.java
+++ b/core/java/android/uwb/UwbAddress.java
@@ -18,6 +18,7 @@ package android.uwb;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -28,6 +29,7 @@ import java.util.Arrays;
*
* @hide
*/
+@SystemApi
public final class UwbAddress implements Parcelable {
public static final int SHORT_ADDRESS_BYTE_LENGTH = 2;
public static final int EXTENDED_ADDRESS_BYTE_LENGTH = 8;
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index 15ee5b5f22eb..8adfe0601b14 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -20,6 +20,7 @@ import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
import android.os.IBinder;
@@ -44,6 +45,7 @@ import java.util.concurrent.Executor;
*
* @hide
*/
+@SystemApi
@SystemService(Context.UWB_SERVICE)
public final class UwbManager {
private IUwbAdapter mUwbAdapter;
diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS
index 93b5a2e8bc28..b1d3967a8b04 100644
--- a/core/java/android/view/accessibility/OWNERS
+++ b/core/java/android/view/accessibility/OWNERS
@@ -9,3 +9,4 @@ sumir@google.com
ogunwale@google.com
jjaggi@google.com
pweaver@google.com
+ryanlwlin@google.com
diff --git a/core/java/android/view/textclassifier/OWNERS b/core/java/android/view/textclassifier/OWNERS
index ac80d9f4cdd0..4bcdeea472e3 100644
--- a/core/java/android/view/textclassifier/OWNERS
+++ b/core/java/android/view/textclassifier/OWNERS
@@ -6,3 +6,5 @@ svetoslavganov@android.com
svetoslavganov@google.com
augale@google.com
joannechung@google.com
+tonymak@google.com
+licha@google.com
diff --git a/core/java/android/view/textservice/OWNERS b/core/java/android/view/textservice/OWNERS
index 582be8dc4594..0471e29a25cd 100644
--- a/core/java/android/view/textservice/OWNERS
+++ b/core/java/android/view/textservice/OWNERS
@@ -1,3 +1,3 @@
-# Bug component: 34867
+# Bug component: 816455
-include ../inputmethod/OWNERS
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index b9ff26b7d9ff..6281ee9d05d1 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -39,6 +39,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.view.inspector.InspectableProperty;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.util.ArrayList;
@@ -776,17 +777,23 @@ public abstract class AbsSeekBar extends ProgressBar {
/**
* Grows {@code r} from its center such that each dimension is at least {@code minimumSize}.
+ *
+ * The result will still have the same {@link Rect#centerX()} and {@link Rect#centerY()} as the
+ * input.
+ *
+ * @hide
*/
- private void growRectTo(Rect r, int minimumSize) {
- int dy = (minimumSize - r.height()) / 2;
+ @VisibleForTesting
+ public void growRectTo(Rect r, int minimumSize) {
+ int dy = minimumSize - r.height();
if (dy > 0) {
- r.top -= dy;
- r.bottom += dy;
+ r.top -= (dy + 1) / 2;
+ r.bottom += dy / 2;
}
- int dx = (minimumSize - r.width()) / 2;
+ int dx = minimumSize - r.width();
if (dx > 0) {
- r.left -= dx;
- r.right += dx;
+ r.left -= (dx + 1) / 2;
+ r.right += dx / 2;
}
}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index e6a166140d89..beef9825b72a 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -129,7 +129,7 @@ interface IBatteryStats {
void noteWifiBatchedScanStartedFromSource(in WorkSource ws, int csph);
void noteWifiBatchedScanStoppedFromSource(in WorkSource ws);
void noteWifiRadioPowerState(int powerState, long timestampNs, int uid);
- void noteNetworkInterfaceType(String iface, int type);
+ void noteNetworkInterfaceForTransports(String iface, in int[] transportTypes);
void noteNetworkStatsEnabled();
void noteDeviceIdleMode(int mode, String activeReason, int activeUid);
void setBatteryState(int status, int health, int plugType, int level, int temp, int volt,
diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS
index c5a956a81d8d..99692d0736c2 100644
--- a/core/java/com/android/internal/app/OWNERS
+++ b/core/java/com/android/internal/app/OWNERS
@@ -3,3 +3,5 @@ per-file *Resolver* = file:/packages/SystemUI/OWNERS
per-file *Chooser* = file:/packages/SystemUI/OWNERS
per-file SimpleIconFactory.java = file:/packages/SystemUI/OWNERS
per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS
+per-file IVoice* = file:/core/java/android/service/voice/OWNERS
+per-file *Hotword* = file:/core/java/android/service/voice/OWNERS
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index cc266d60465e..a5eb5f607c12 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -22,17 +22,16 @@ import java.util.Map;
parcelable CompatibilityChangeConfig;
parcelable CompatibilityChangeInfo;
-
/**
* 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.
+ * <p>Should be used for gating and logging from non-app processes.
+ *
+ * <p>Note: for app processes please use {@code android.compat.Compatibility} API.
*
* {@hide}
*/
-interface IPlatformCompat
-{
+interface IPlatformCompat {
/**
* Reports that a compatibility change is affecting an app process now.
@@ -40,8 +39,9 @@ interface IPlatformCompat
* <p>Note: for changes that are gated using {@link #isChangeEnabled(long, ApplicationInfo)},
* you do not need to call this API directly. The change will be reported for you.
*
- * @param changeId The ID of the compatibility change taking effect.
- * @param appInfo Representing the affected app.
+ * @param changeId the ID of the compatibility change taking effect
+ * @param appInfo representing the affected app
+ * @throws SecurityException if logging is not allowed
*/
void reportChange(long changeId, in ApplicationInfo appInfo);
@@ -51,11 +51,12 @@ interface IPlatformCompat
* <p>Note: for changes that are gated using {@link #isChangeEnabled(long, String)},
* you do not need to call this API directly. The change will be reported for you.
*
- * @param changeId The ID of the compatibility change taking effect.
- * @param userId The ID of the user that the operation is done for.
- * @param packageName The package name of the app in question.
+ * @param changeId the ID of the compatibility change taking effect
+ * @param userId the ID of the user that the operation is done for
+ * @param packageName the package name of the app in question
+ * @throws SecurityException if logging is not allowed
*/
- void reportChangeByPackageName(long changeId, in String packageName, int userId);
+ void reportChangeByPackageName(long changeId, in String packageName, int userId);
/**
* Reports that a compatibility change is affecting an app process now.
@@ -63,13 +64,14 @@ interface IPlatformCompat
* <p>Note: for changes that are gated using {@link #isChangeEnabled(long, int)},
* you do not need to call this API directly. The change will be reported for you.
*
- * @param changeId The ID of the compatibility change taking effect.
- * @param uid The UID of the app in question.
+ * @param changeId the ID of the compatibility change taking effect
+ * @param uid the UID of the app in question
+ * @throws SecurityException if logging is not allowed
*/
void reportChangeByUid(long changeId, int uid);
/**
- * Query if a given compatibility change is enabled for an app process. This method should
+ * Queries if a given compatibility change is enabled for an app process. This method should
* be called when implementing functionality on behalf of the affected app.
*
* <p>If this method returns {@code true}, the calling code should implement the compatibility
@@ -79,14 +81,15 @@ interface IPlatformCompat
* <p>It will also report the change as {@link #reportChange(long, ApplicationInfo)} would, so
* there is no need to call that method directly.
*
- * @param changeId The ID of the compatibility change in question.
- * @param appInfo Representing the app in question.
- * @return {@code true} if the change is enabled for the current app.
+ * @param changeId the ID of the compatibility change in question
+ * @param appInfo representing the app in question
+ * @return {@code true} if the change is enabled for the current app
+ * @throws SecurityException if logging or reading compat confis is not allowed
*/
boolean isChangeEnabled(long changeId, in ApplicationInfo appInfo);
/**
- * Query if a given compatibility change is enabled for an app process. This method should
+ * Queries if a given compatibility change is enabled for an app process. This method should
* be called when implementing functionality on behalf of the affected app.
*
* <p>Same as {@link #isChangeEnabled(long, ApplicationInfo)}, except it receives a package name
@@ -102,15 +105,16 @@ interface IPlatformCompat
* <p>It will also report the change as {@link #reportChange(long, String)} would, so there is
* no need to call that method directly.
*
- * @param changeId The ID of the compatibility change in question.
- * @param packageName The package name of the app in question.
- * @param userId The ID of the user that the operation is done for.
- * @return {@code true} if the change is enabled for the current app.
+ * @param changeId the ID of the compatibility change in question
+ * @param packageName the package name of the app in question
+ * @param userId the ID of the user that the operation is done for
+ * @return {@code true} if the change is enabled for the current app
+ * @throws SecurityException if logging or reading compat confis is not allowed
*/
boolean isChangeEnabledByPackageName(long changeId, in String packageName, int userId);
/**
- * Query if a given compatibility change is enabled for an app process. This method should
+ * Queries if a given compatibility change is enabled for an app process. This method should
* be called when implementing functionality on behalf of the affected app.
*
* <p>Same as {@link #isChangeEnabled(long, ApplicationInfo)}, except it receives a uid
@@ -127,110 +131,132 @@ interface IPlatformCompat
* <p>It will also report the change as {@link #reportChange(long, int)} would, so there is
* no need to call that method directly.
*
- * @param changeId The ID of the compatibility change in question.
- * @param uid The UID of the app in question.
- * @return {@code true} if the change is enabled for the current app.
+ * @param changeId the ID of the compatibility change in question
+ * @param uid the UID of the app in question
+ * @return {@code true} if the change is enabled for the current app
+ * @throws SecurityException if logging or reading compat confis is not allowed
*/
boolean isChangeEnabledByUid(long changeId, int uid);
/**
- * Add overrides to compatibility changes. Kills the app to allow the changes to take effect.
+ * Adds overrides to compatibility changes.
*
- * @param overrides Parcelable containing the compat change overrides to be applied.
- * @param packageName The package name of the app whose changes will be overridden.
+ * <p>Kills the app to allow the changes to take effect.
*
+ * @param overrides parcelable containing the compat change overrides to be applied
+ * @param packageName the package name of the app whose changes will be overridden
+ * @throws SecurityException if overriding changes is not permitted
*/
void setOverrides(in CompatibilityChangeConfig overrides, in String packageName);
/**
- * Add overrides to compatibility changes. Doesn't kill the app, to be only used in tests.
+ * Adds overrides to compatibility changes.
*
- * @param overrides Parcelable containing the compat change overrides to be applied.
- * @param packageName The package name of the app whose changes will be overridden.
+ * <p>Does not kill the app, to be only used in tests.
*
+ * @param overrides parcelable containing the compat change overrides to be applied
+ * @param packageName the package name of the app whose changes will be overridden
+ * @throws SecurityException if overriding changes is not permitted.
*/
void setOverridesForTest(in CompatibilityChangeConfig overrides, in String packageName);
/**
- * Removes an override previously added via {@link #setOverrides(CompatibilityChangeConfig,
- * String)}. This restores the default behaviour for the given change and app, once any app
- * processes have been restarted.
- * Kills the app to allow the changes to take effect.
+ * Restores the default behaviour for the given change and app.
*
- * @param changeId The ID of the change that was overridden.
- * @param packageName The app package name that was overridden.
- * @return {@code true} if an override existed;
+ * <p>Kills the app to allow the changes to take effect.
+ *
+ * @param changeId the ID of the change that was overridden
+ * @param packageName the app package name that was overridden
+ * @return {@code true} if an override existed
+ * @throws SecurityException if overriding changes is not permitted
*/
boolean clearOverride(long changeId, String packageName);
/**
- * Enable all compatibility changes which have enabledSinceTargetSdk ==
- * {@param targetSdkVersion} for an app, subject to the policy. Kills the app to allow the
- * changes to take effect.
+ * Restores the default behaviour for the given change and app.
*
- * @param packageName The package name of the app whose compatibility changes will be enabled.
- * @param targetSdkVersion The targetSdkVersion for filtering the changes to be enabled.
+ * <p>Does not kill the app; to be only used in tests.
+ *
+ * @param changeId the ID of the change that was overridden
+ * @param packageName the app package name that was overridden
+ * @throws SecurityException if overriding changes is not permitted
+ */
+ void clearOverrideForTest(long changeId, String packageName);
+
+ /**
+ * Enables all compatibility changes that have enabledSinceTargetSdk ==
+ * {@param targetSdkVersion} for an app, subject to the policy.
+ *
+ * <p>Kills the app to allow the changes to take effect.
*
+ * @param packageName The package name of the app whose compatibility changes will be
+ * enabled.
+ * @param targetSdkVersion The targetSdkVersion for filtering the changes to be enabled.
* @return The number of changes that were enabled.
+ * @throws SecurityException if overriding changes is not permitted.
*/
int enableTargetSdkChanges(in String packageName, int targetSdkVersion);
/**
- * Disable all compatibility changes which have enabledAfterTargetSdk ==
- * {@param targetSdkVersion} for an app, subject to the policy. Kills the app to allow the
- * changes to take effect.
+ * Disables all compatibility changes that have enabledAfterTargetSdk ==
+ * {@param targetSdkVersion} for an app, subject to the policy.
*
- * @param packageName The package name of the app whose compatibility changes will be disabled.
- * @param targetSdkVersion The targetSdkVersion for filtering the changes to be disabled.
+ * <p>Kills the app to allow the changes to take effect.
*
- * @return The number of changes that were disabled.
+ * @param packageName the package name of the app whose compatibility changes will be
+ * disabled
+ * @param targetSdkVersion the targetSdkVersion for filtering the changes to be disabled
+ * @return the number of changes that were disabled
+ * @throws SecurityException if overriding changes is not permitted.
*/
int disableTargetSdkChanges(in String packageName, int targetSdkVersion);
/**
- * Revert overrides to compatibility changes. Kills the app to allow the changes to take effect.
+ * Restores the default behaviour for the given app.
*
- * @param packageName The package name of the app whose overrides will be cleared.
+ * <p>Kills the app to allow the changes to take effect.
*
+ * @param packageName the package name of the app whose overrides will be cleared
+ * @throws SecurityException if overriding changes is not permitted
*/
void clearOverrides(in String packageName);
/**
- * Revert overrides to compatibility changes. Doesn't kill the app, to be only used in tests.
+ * Restores the default behaviour for the given app.
*
- * @param packageName The package name of the app whose overrides will be cleared.
+ * <p>Does not kill the app; to be only used in tests.
*
+ * @param packageName the package name of the app whose overrides will be cleared
+ * @throws SecurityException if overriding changes is not permitted
*/
void clearOverridesForTest(in String packageName);
-
/**
* Get configs for an application.
*
- * @param appInfo The application whose config will be returned.
- *
- * @return A {@link CompatibilityChangeConfig}, representing whether a change is enabled for
- * the given app or not.
+ * @param appInfo the application whose config will be returned
+ * @return a {@link CompatibilityChangeConfig}, representing whether a change is enabled for
+ * the given app or not
*/
CompatibilityChangeConfig getAppConfig(in ApplicationInfo appInfo);
/**
* List all compatibility changes.
*
- * @return An array of {@link CompatChangeInfo} known to the service.
+ * @return an array of {@link CompatibilityChangeInfo} known to the service
*/
CompatibilityChangeInfo[] listAllChanges();
/**
- * List the compatibility changes that should be present in the UI.
- * Filters out certain changes like e.g. logging only.
- *
- * @return An array of {@link CompatChangeInfo}.
- */
+ * List the compatibility changes that should be present in the UI.
+ * Filters out certain changes like e.g. logging only.
+ *
+ * @return an array of {@link CompatibilityChangeInfo}
+ */
CompatibilityChangeInfo[] listUIChanges();
/**
- * Get an instance that can determine whether a changeid can be overridden for a package name.
+ * Gets an instance that can determine whether a changeid can be overridden for a package name.
*/
IOverrideValidator getOverrideValidator();
}
diff --git a/core/java/com/android/internal/graphics/fonts/OWNERS b/core/java/com/android/internal/graphics/fonts/OWNERS
new file mode 100644
index 000000000000..18486af9d12c
--- /dev/null
+++ b/core/java/com/android/internal/graphics/fonts/OWNERS
@@ -0,0 +1 @@
+include /graphics/java/android/graphics/fonts/OWNERS
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index c0648ab89c41..2e7629a76dee 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -129,7 +129,7 @@ public class VpnConfig implements Parcelable {
String[] routes = routesStr.trim().split(" ");
for (String route : routes) {
//each route is ip/prefix
- RouteInfo info = new RouteInfo(new IpPrefix(route), null);
+ RouteInfo info = new RouteInfo(new IpPrefix(route), null, null, RouteInfo.RTN_UNICAST);
this.routes.add(info);
updateAllowedFamilies(info.getDestination().getAddress());
}
diff --git a/core/java/com/android/internal/net/VpnInfo.java b/core/java/com/android/internal/net/VpnInfo.java
deleted file mode 100644
index e74af5eb50de..000000000000
--- a/core/java/com/android/internal/net/VpnInfo.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.internal.net;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Arrays;
-
-/**
- * A lightweight container used to carry information of the ongoing VPN.
- * Internal use only..
- *
- * @hide
- */
-public class VpnInfo implements Parcelable {
- public int ownerUid;
- public String vpnIface;
- public String[] underlyingIfaces;
-
- @Override
- public String toString() {
- return "VpnInfo{"
- + "ownerUid=" + ownerUid
- + ", vpnIface='" + vpnIface + '\''
- + ", underlyingIfaces='" + Arrays.toString(underlyingIfaces) + '\''
- + '}';
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(ownerUid);
- dest.writeString(vpnIface);
- dest.writeStringArray(underlyingIfaces);
- }
-
- public static final Parcelable.Creator<VpnInfo> CREATOR = new Parcelable.Creator<VpnInfo>() {
- @Override
- public VpnInfo createFromParcel(Parcel source) {
- VpnInfo info = new VpnInfo();
- info.ownerUid = source.readInt();
- info.vpnIface = source.readString();
- info.underlyingIfaces = source.readStringArray();
- return info;
- }
-
- @Override
- public VpnInfo[] newArray(int size) {
- return new VpnInfo[size];
- }
- };
-}
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 8bfc28ed5e52..ae680e0febac 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -23,7 +23,6 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.hardware.SensorManager;
-import android.net.ConnectivityManager;
import android.os.BatteryStats;
import android.os.BatteryStats.Uid;
import android.os.Build;
@@ -37,6 +36,7 @@ import android.os.SELinux;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.telephony.TelephonyManager;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -148,12 +148,11 @@ public class BatteryStatsHelper {
boolean mHasBluetoothPowerReporting = false;
public static boolean checkWifiOnly(Context context) {
- ConnectivityManager cm = (ConnectivityManager) context.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- if (cm == null) {
+ final TelephonyManager tm = context.getSystemService(TelephonyManager.class);
+ if (tm == null) {
return false;
}
- return !cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+ return !tm.isDataCapable();
}
public static boolean checkHasWifiPowerReporting(BatteryStats stats, PowerProfile profile) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 1071d9f2a918..2d75b70333f2 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -16,6 +16,8 @@
package com.android.internal.os;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.os.BatteryStatsManager.NUM_WIFI_STATES;
import static android.os.BatteryStatsManager.NUM_WIFI_SUPPL_STATES;
@@ -32,7 +34,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.hardware.usb.UsbManager;
-import android.net.ConnectivityManager;
import android.net.INetworkStatsService;
import android.net.NetworkStats;
import android.net.Uri;
@@ -101,6 +102,7 @@ import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.XmlUtils;
+import com.android.net.module.util.NetworkCapabilitiesUtils;
import libcore.util.EmptyArray;
@@ -6099,11 +6101,12 @@ public class BatteryStatsImpl extends BatteryStats {
}
/** @hide */
- public void noteNetworkInterfaceType(String iface, int networkType) {
+ public void noteNetworkInterfaceForTransports(String iface, int[] transportTypes) {
if (TextUtils.isEmpty(iface)) return;
+ final int displayTransport = NetworkCapabilitiesUtils.getDisplayTransport(transportTypes);
synchronized (mModemNetworkLock) {
- if (ConnectivityManager.isNetworkTypeMobile(networkType)) {
+ if (displayTransport == TRANSPORT_CELLULAR) {
mModemIfaces = includeInStringArray(mModemIfaces, iface);
if (DEBUG) Slog.d(TAG, "Note mobile iface " + iface + ": " + mModemIfaces);
} else {
@@ -6113,7 +6116,7 @@ public class BatteryStatsImpl extends BatteryStats {
}
synchronized (mWifiNetworkLock) {
- if (ConnectivityManager.isNetworkTypeWifi(networkType)) {
+ if (displayTransport == TRANSPORT_WIFI) {
mWifiIfaces = includeInStringArray(mWifiIfaces, iface);
if (DEBUG) Slog.d(TAG, "Note wifi iface " + iface + ": " + mWifiIfaces);
} else {
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 790d7f7ab694..6860759eea8a 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -69,15 +69,16 @@ public class WrapperInit {
// Tell the Zygote what our actual PID is (since it only knows about the
// wrapper that it directly forked).
if (fdNum != 0) {
+ FileDescriptor fd = new FileDescriptor();
try {
- FileDescriptor fd = new FileDescriptor();
fd.setInt$(fdNum);
DataOutputStream os = new DataOutputStream(new FileOutputStream(fd));
os.writeInt(Process.myPid());
os.close();
- IoUtils.closeQuietly(fd);
} catch (IOException ex) {
Slog.d(TAG, "Could not write pid of wrapped process to Zygote pipe.", ex);
+ } finally {
+ IoUtils.closeQuietly(fd);
}
}
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index d2dc7c283ff7..854fb17e692b 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -23,6 +23,7 @@ import android.telephony.CellInfo;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.TelephonyDisplayInfo;
import android.telephony.PhoneCapability;
+import android.telephony.PhysicalChannelConfig;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
import android.telephony.ServiceState;
@@ -68,4 +69,6 @@ oneway interface IPhoneStateListener {
void onRegistrationFailed(in CellIdentity cellIdentity,
String chosenPlmn, int domain, int causeCode, int additionalCauseCode);
void onBarringInfoChanged(in BarringInfo barringInfo);
+ void onPhysicalChannelConfigChanged(in List<PhysicalChannelConfig> configs);
+ void onDataEnabledChanged(boolean enabled, int reason);
}
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 5f2dcc3d22e1..2a73dacbc94a 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -41,16 +41,8 @@ interface ITelephonyRegistry {
IOnSubscriptionsChangedListener callback);
void removeOnSubscriptionsChangedListener(String pkg,
IOnSubscriptionsChangedListener callback);
- /**
- * @deprecated Use {@link #listenWithFeature(String, String, IPhoneStateListener, int,
- * boolean) instead
- */
- @UnsupportedAppUsage
- void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow);
- void listenWithFeature(String pkg, String featureId, IPhoneStateListener callback, int events,
- boolean notifyNow);
- void listenForSubscriber(in int subId, String pkg, String featureId,
- IPhoneStateListener callback, int events, boolean notifyNow);
+ void listenWithEventList(in int subId, String pkg, String featureId,
+ IPhoneStateListener callback, in int[] events, boolean notifyNow);
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
void notifyCallStateForAllSubs(int state, String incomingNumber);
void notifyCallState(in int phoneId, in int subId, int state, String incomingNumber);
@@ -99,4 +91,7 @@ interface ITelephonyRegistry {
void notifyRegistrationFailed(int slotIndex, int subId, in CellIdentity cellIdentity,
String chosenPlmn, int domain, int causeCode, int additionalCauseCode);
void notifyBarringInfoChanged(int slotIndex, int subId, in BarringInfo barringInfo);
+ void notifyPhysicalChannelConfigForSubscriber(in int subId,
+ in List<PhysicalChannelConfig> configs);
+ void notifyDataEnabled(boolean enabled, int reason);
}
diff --git a/core/java/com/android/internal/textservice/OWNERS b/core/java/com/android/internal/textservice/OWNERS
new file mode 100644
index 000000000000..0471e29a25cd
--- /dev/null
+++ b/core/java/com/android/internal/textservice/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 816455
+
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/core/java/com/android/internal/util/LocationPermissionChecker.java b/core/java/com/android/internal/util/LocationPermissionChecker.java
index cd8fc350362d..c583d5a5be37 100644
--- a/core/java/com/android/internal/util/LocationPermissionChecker.java
+++ b/core/java/com/android/internal/util/LocationPermissionChecker.java
@@ -24,6 +24,7 @@ import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.LocationManager;
+import android.net.NetworkStack;
import android.os.Binder;
import android.os.Build;
import android.os.UserHandle;
@@ -147,6 +148,13 @@ public class LocationPermissionChecker {
int uid, @Nullable String message) {
checkPackage(uid, pkgName);
+ // Apps with NETWORK_SETTINGS, NETWORK_SETUP_WIZARD, NETWORK_STACK & MAINLINE_NETWORK_STACK
+ // are granted a bypass.
+ if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid)
+ || checkNetworkStackPermission(uid) || checkMainlineNetworkStackPermission(uid)) {
+ return SUCCEEDED;
+ }
+
// Location mode must be enabled
if (!isLocationModeEnabled()) {
return ERROR_LOCATION_MODE_OFF;
@@ -259,4 +267,37 @@ public class LocationPermissionChecker {
// We don't care about pid, pass in -1
return mContext.checkPermission(permissionType, -1, uid);
}
+
+ /**
+ * Returns true if the |uid| holds NETWORK_SETTINGS permission.
+ */
+ public boolean checkNetworkSettingsPermission(int uid) {
+ return getUidPermission(android.Manifest.permission.NETWORK_SETTINGS, uid)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
+ * Returns true if the |uid| holds NETWORK_SETUP_WIZARD permission.
+ */
+ public boolean checkNetworkSetupWizardPermission(int uid) {
+ return getUidPermission(android.Manifest.permission.NETWORK_SETUP_WIZARD, uid)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
+ * Returns true if the |uid| holds NETWORK_STACK permission.
+ */
+ public boolean checkNetworkStackPermission(int uid) {
+ return getUidPermission(android.Manifest.permission.NETWORK_STACK, uid)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
+ * Returns true if the |uid| holds MAINLINE_NETWORK_STACK permission.
+ */
+ public boolean checkMainlineNetworkStackPermission(int uid) {
+ return getUidPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, uid)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
}
diff --git a/core/java/com/android/internal/widget/OWNERS b/core/java/com/android/internal/widget/OWNERS
index cca39ea3287d..ae566c3988cd 100644
--- a/core/java/com/android/internal/widget/OWNERS
+++ b/core/java/com/android/internal/widget/OWNERS
@@ -1 +1,7 @@
per-file PointerLocationView.java = michaelwr@google.com, svv@google.com
+
+# LockSettings related
+per-file *LockPattern* = file:/services/core/java/com/android/server/locksettings/OWNERS
+per-file *LockScreen* = file:/services/core/java/com/android/server/locksettings/OWNERS
+per-file *Lockscreen* = file:/services/core/java/com/android/server/locksettings/OWNERS
+per-file *LockSettings* = file:/services/core/java/com/android/server/locksettings/OWNERS
diff --git a/core/jni/android_media_AudioErrors.h b/core/jni/android_media_AudioErrors.h
index c17a020f74fc..13c9115c1e56 100644
--- a/core/jni/android_media_AudioErrors.h
+++ b/core/jni/android_media_AudioErrors.h
@@ -35,7 +35,7 @@ enum {
AUDIO_JAVA_WOULD_BLOCK = -7,
};
-static inline jint nativeToJavaStatus(status_t status) {
+static constexpr inline jint nativeToJavaStatus(status_t status) {
switch (status) {
case NO_ERROR:
return AUDIO_JAVA_SUCCESS;
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 7a5c38385f32..065c79b8601f 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -263,18 +263,7 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we
return (jint) AUDIO_JAVA_ERROR;
}
- // TODO: replace when we land matching AudioTrack::set() in frameworks/av in r or r-tv-dev.
- if (tunerConfiguration != nullptr) {
- const TunerConfigurationHelper tunerHelper(env, tunerConfiguration);
- ALOGE("Error creating AudioTrack: unsupported tuner contentId:%d syncId:%d",
- tunerHelper.getContentId(), tunerHelper.getSyncId());
- return (jint)AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
- }
- // TODO: replace when we land matching AudioTrack::set() in frameworks/av in r or r-tv-dev.
- if (encapsulationMode != 0 /* ENCAPSULATION_MODE_NONE */) {
- ALOGE("Error creating AudioTrack: unsupported encapsulationMode %d", encapsulationMode);
- return (jint)AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
- }
+ const TunerConfigurationHelper tunerHelper(env, tunerConfiguration);
jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
if (nSession == NULL) {
@@ -369,6 +358,18 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we
offloadInfo.stream_type = AUDIO_STREAM_MUSIC; //required for offload
}
+ if (encapsulationMode != 0) {
+ offloadInfo = AUDIO_INFO_INITIALIZER;
+ offloadInfo.format = format;
+ offloadInfo.sample_rate = sampleRateInHertz;
+ offloadInfo.channel_mask = nativeChannelMask;
+ offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
+ offloadInfo.encapsulation_mode =
+ static_cast<audio_encapsulation_mode_t>(encapsulationMode);
+ offloadInfo.content_id = tunerHelper.getContentId();
+ offloadInfo.sync_id = tunerHelper.getSyncId();
+ }
+
// initialize the native AudioTrack object
status_t status = NO_ERROR;
switch (memoryMode) {
@@ -389,7 +390,8 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we
sessionId, // audio session ID
offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK
: AudioTrack::TRANSFER_SYNC,
- offload ? &offloadInfo : NULL, -1, -1, // default uid, pid values
+ (offload || encapsulationMode) ? &offloadInfo : NULL, -1,
+ -1, // default uid, pid values
paa.get());
break;
@@ -1364,8 +1366,7 @@ static jint android_media_AudioTrack_setAudioDescriptionMixLeveldB(JNIEnv *env,
return (jint)AUDIO_JAVA_ERROR;
}
- // TODO: replace in r-dev or r-tv-dev with code if HW is able to set audio mix level.
- return (jint)AUDIO_JAVA_ERROR;
+ return nativeToJavaStatus(lpTrack->setAudioDescriptionMixLevel(level));
}
static jint android_media_AudioTrack_getAudioDescriptionMixLeveldB(JNIEnv *env, jobject thiz,
@@ -1381,12 +1382,10 @@ static jint android_media_AudioTrack_getAudioDescriptionMixLeveldB(JNIEnv *env,
return (jint)AUDIO_JAVA_ERROR;
}
- // TODO: replace in r-dev or r-tv-dev with code if HW is able to set audio mix level.
- // By contract we can return -infinity if unsupported.
- *nativeLevel = -std::numeric_limits<float>::infinity();
+ status_t status = lpTrack->getAudioDescriptionMixLevel(reinterpret_cast<float *>(nativeLevel));
env->ReleasePrimitiveArrayCritical(level, nativeLevel, 0 /* mode */);
- nativeLevel = nullptr;
- return (jint)AUDIO_JAVA_SUCCESS;
+
+ return nativeToJavaStatus(status);
}
static jint android_media_AudioTrack_setDualMonoMode(JNIEnv *env, jobject thiz, jint dualMonoMode) {
@@ -1396,8 +1395,8 @@ static jint android_media_AudioTrack_setDualMonoMode(JNIEnv *env, jobject thiz,
return (jint)AUDIO_JAVA_ERROR;
}
- // TODO: replace in r-dev or r-tv-dev with code if HW is able to set audio mix level.
- return (jint)AUDIO_JAVA_ERROR;
+ return nativeToJavaStatus(
+ lpTrack->setDualMonoMode(static_cast<audio_dual_mono_mode_t>(dualMonoMode)));
}
static jint android_media_AudioTrack_getDualMonoMode(JNIEnv *env, jobject thiz,
@@ -1407,18 +1406,17 @@ static jint android_media_AudioTrack_getDualMonoMode(JNIEnv *env, jobject thiz,
ALOGE("%s: AudioTrack not initialized", __func__);
return (jint)AUDIO_JAVA_ERROR;
}
- jfloat *nativeDualMonoMode = (jfloat *)env->GetPrimitiveArrayCritical(dualMonoMode, NULL);
+ jint *nativeDualMonoMode = (jint *)env->GetPrimitiveArrayCritical(dualMonoMode, NULL);
if (nativeDualMonoMode == nullptr) {
ALOGE("%s: Cannot retrieve dualMonoMode pointer", __func__);
return (jint)AUDIO_JAVA_ERROR;
}
- // TODO: replace in r-dev or r-tv-dev with code if HW is able to select dual mono mode.
- // By contract we can return DUAL_MONO_MODE_OFF if unsupported.
- *nativeDualMonoMode = 0; // DUAL_MONO_MODE_OFF for now.
+ status_t status = lpTrack->getDualMonoMode(
+ reinterpret_cast<audio_dual_mono_mode_t *>(nativeDualMonoMode));
env->ReleasePrimitiveArrayCritical(dualMonoMode, nativeDualMonoMode, 0 /* mode */);
- nativeDualMonoMode = nullptr;
- return (jint)AUDIO_JAVA_SUCCESS;
+
+ return nativeToJavaStatus(status);
}
// ----------------------------------------------------------------------------
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 2155246cd544..e2af87ee1adf 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -18,6 +18,7 @@
#include <vector>
+#include <android/file_descriptor_jni.h>
#include <arpa/inet.h>
#include <linux/filter.h>
#include <linux/if_arp.h>
@@ -83,7 +84,7 @@ static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jobject clazz,
filter_code,
};
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ int fd = AFileDescriptor_getFD(env, javaFd);
if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
jniThrowExceptionFmt(env, "java/net/SocketException",
"setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
@@ -93,7 +94,7 @@ static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jobject clazz,
static void android_net_utils_detachBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
{
int optval_ignored = 0;
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ int fd = AFileDescriptor_getFD(env, javaFd);
if (setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, &optval_ignored, sizeof(optval_ignored)) !=
0) {
jniThrowExceptionFmt(env, "java/net/SocketException",
@@ -117,10 +118,9 @@ static jboolean android_net_utils_bindProcessToNetworkForHostResolution(JNIEnv *
return (jboolean) !setNetworkForResolv(netId);
}
-static jint android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, jint socket,
- jint netId)
-{
- return setNetworkForSocket(netId, socket);
+static jint android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, jobject javaFd,
+ jint netId) {
+ return setNetworkForSocket(netId, AFileDescriptor_getFD(env, javaFd));
}
static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint socket)
@@ -128,6 +128,10 @@ static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint
return (jboolean) !protectFromVpn(socket);
}
+static jboolean android_net_utils_protectFromVpnWithFd(JNIEnv *env, jobject thiz, jobject javaFd) {
+ return android_net_utils_protectFromVpn(env, thiz, AFileDescriptor_getFD(env, javaFd));
+}
+
static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jint uid, jint netId)
{
return (jboolean) !queryUserAccess(uid, netId);
@@ -178,7 +182,7 @@ static jobject android_net_utils_resNetworkSend(JNIEnv *env, jobject thiz, jint
}
static jobject android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) {
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ int fd = AFileDescriptor_getFD(env, javaFd);
int rcode;
std::vector<uint8_t> buf(MAXPACKETSIZE, 0);
@@ -205,7 +209,7 @@ static jobject android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, job
}
static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) {
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ int fd = AFileDescriptor_getFD(env, javaFd);
resNetworkCancel(fd);
jniSetFileDescriptorOfFD(env, javaFd, -1);
}
@@ -231,7 +235,7 @@ static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, j
return NULL;
}
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ int fd = AFileDescriptor_getFD(env, javaFd);
struct tcp_repair_window trw = {};
socklen_t size = sizeof(trw);
@@ -271,8 +275,9 @@ static const JNINativeMethod gNetworkUtilMethods[] = {
{ "bindProcessToNetwork", "(I)Z", (void*) android_net_utils_bindProcessToNetwork },
{ "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
{ "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
- { "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork },
- { "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn },
+ { "bindSocketToNetwork", "(Ljava/io/FileDescriptor;I)I", (void*) android_net_utils_bindSocketToNetwork },
+ { "protectFromVpn", "(I)Z", (void*) android_net_utils_protectFromVpn },
+ { "protectFromVpn", "(Ljava/io/FileDescriptor;)Z", (void*) android_net_utils_protectFromVpnWithFd },
{ "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
{ "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter },
{ "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter },
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index 0fb29111d043..a9db91be1d5b 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -257,7 +257,17 @@ jobject JHwBlob::NewObject(JNIEnv *env, size_t size) {
// XXX Again cannot refer to gFields.constructID because InitClass may
// not have been called yet.
- return env->NewObject(clazz.get(), constructID, size);
+ // Cases:
+ // - this originates from another process (something so large should not fit
+ // in the binder buffer, and it should be rejected by the binder driver)
+ // - if this is used in process, this code makes too many heap copies (in
+ // order to retrofit HIDL's scatter-gather format to java types) to
+ // justify passing such a large amount of data over this path. So the
+ // alternative (updating the constructor and other code to accept other
+ // types, should also probably not be taken in this case).
+ CHECK_LE(size, std::numeric_limits<jint>::max());
+
+ return env->NewObject(clazz.get(), constructID, static_cast<jint>(size));
}
} // namespace android
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 22dd765f2526..b2e562c9650e 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1559,7 +1559,6 @@ static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list,
jobjectArray whitelisted_data_info_list, uid_t uid, const char* process_name,
jstring managed_nice_name, fail_fn_t fail_fn) {
- ensureInAppMountNamespace(fail_fn);
std::vector<std::string> merged_data_info_list;
insertPackagesToMergedList(env, merged_data_info_list, pkg_data_info_list,
process_name, managed_nice_name, fail_fn);
@@ -1706,10 +1705,11 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
MountEmulatedStorage(uid, mount_external, need_pre_initialize_native_bridge, fail_fn);
- // System services, isolated process, webview/app zygote, old target sdk app, should
- // give a null in same_uid_pkgs and private_volumes so they don't need app data isolation.
- // Isolated process / webview / app zygote should be gated by SELinux and file permission
- // so they can't even traverse CE / DE directories.
+ // Make sure app is running in its own mount namespace before isolating its data directories.
+ ensureInAppMountNamespace(fail_fn);
+
+ // Sandbox data and jit profile directories by overlaying a tmpfs on those dirs and bind
+ // mount all related packages separately.
if (mount_data_dirs) {
isolateAppData(env, pkg_data_info_list, whitelisted_data_info_list,
uid, process_name, managed_nice_name, fail_fn);
@@ -1810,7 +1810,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
break;
}
- android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &heap_tagging_level, sizeof(heap_tagging_level));
+ mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level);
// Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime.
runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 714a09d02264..24dabfc02454 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -309,9 +309,14 @@
<protected-broadcast android:name="android.net.nsd.STATE_CHANGED" />
+ <!-- For OMAPI -->
+ <protected-broadcast android:name="android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED" />
+
<protected-broadcast android:name="android.nfc.action.ADAPTER_STATE_CHANGED" />
+ <protected-broadcast android:name="android.nfc.action.ALWAYS_ON_STATE_CHANGED" />
<protected-broadcast android:name="android.nfc.action.PREFERRED_PAYMENT_CHANGED" />
<protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
+ <protected-broadcast android:name="android.nfc.action.REQUIRE_UNLOCK_FOR_NFC" />
<protected-broadcast android:name="com.android.nfc.action.LLCP_UP" />
<protected-broadcast android:name="com.android.nfc.action.LLCP_DOWN" />
<protected-broadcast android:name="com.android.nfc.cardemulation.action.CLOSE_TAP_DIALOG" />
@@ -1622,7 +1627,7 @@
<permission android:name="android.permission.MANAGE_IPSEC_TUNNELS"
android:protectionLevel="signature|appop" />
- <!-- @hide Allows apps to create and manage Test Networks.
+ <!-- @SystemApi @hide Allows apps to create and manage Test Networks.
<p>Granted only to shell. CTS tests will use
UiAutomation.AdoptShellPermissionIdentity() to gain access.
-->
@@ -1664,6 +1669,12 @@
<permission android:name="android.permission.REQUEST_NETWORK_SCORES"
android:protectionLevel="signature|setup" />
+ <!-- Allows applications to restart the Wi-Fi subsystem.
+ @SystemApi
+ <p>Not for use by third-party applications. @hide -->
+ <permission android:name="android.permission.RESTART_WIFI_SUBSYSTEM"
+ android:protectionLevel="signature|setup" />
+
<!-- @SystemApi @hide Allows applications to toggle airplane mode.
<p>Not for use by third-party or privileged applications.
-->
@@ -2979,6 +2990,12 @@
<permission android:name="android.permission.RECOVERY"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application to do certain operations needed for
+ resume on reboot feature.
+ @hide -->
+ <permission android:name="android.permission.BIND_RESUME_ON_REBOOT_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows an application to read system update info.
@hide -->
<permission android:name="android.permission.READ_SYSTEM_UPDATE_INFO"
diff --git a/core/res/OWNERS b/core/res/OWNERS
index 02cf0b71ff69..a30111b44382 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -1,7 +1,9 @@
adamp@google.com
alanv@google.com
+asc@google.com
dsandler@android.com
dsandler@google.com
+dupin@google.com
hackbod@android.com
hackbod@google.com
jsharkey@android.com
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 2f1bcdc76afb..4b3d82a04b8b 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8968,6 +8968,11 @@
changed at runtime by calling
{@link android.media.tv.TvInputManager#updateTvInputInfo(android.media.tv.TvInputInfo)}. -->
<attr name="tunerCount" format="integer" />
+ <!-- Attribute whether the TV input service can pause recording programs.
+ This value can be changed at runtime by calling
+ {@link android.media.tv.TvInputManager#updateTvInputInfo(android.media.tv.TvInputInfo)}
+ . -->
+ <attr name="canPauseRecording" format="boolean" />
</declare-styleable>
<!-- Attributes that can be used with <code>rating-system-definition</code> tags inside of the
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d30efa95edff..20cb27085661 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4411,4 +4411,7 @@
<!-- Component names of the services which will keep critical code path warm -->
<string-array name="config_keep_warming_services" translatable="false" />
+
+ <!-- Whether to select voice/data/sms preference without user confirmation -->
+ <bool name="config_voice_data_sms_auto_fallback">false</bool>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e00aff1af37b..a0be0681bd38 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3043,6 +3043,7 @@
=============================================================== -->
<public-group type="attr" first-id="0x01010617">
+ <public name="canPauseRecording" />
<!-- attribute definitions go here -->
</public-group>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1143467425af..8ac00dceea9e 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -110,7 +110,7 @@
<!-- Displayed as the title for a success/failure report enabling/disabling caller ID. -->
<string name="ClipMmi">Incoming Caller ID</string>
<!-- Displayed as the title for a success/failure report enabling/disabling caller ID. -->
- <string name="ClirMmi">Outgoing Caller ID</string>
+ <string name="ClirMmi">Hide Outgoing Caller ID</string>
<!-- Displayed as the title for a success/failure report enabling/disabling connected line ID. -->
<string name="ColpMmi">Connected Line ID</string>
<!-- Displayed as the title for a success/failure report enabling/disabling connected line ID restriction. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 937716dbcf74..4509b4e0b3f9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4057,4 +4057,6 @@
<java-symbol type="array" name="config_notificationMsgPkgsAllowedAsConvos" />
<java-symbol type="array" name="config_keep_warming_services" />
+
+ <java-symbol type="bool" name="config_voice_data_sms_auto_fallback" />
</resources>
diff --git a/core/sysprop/WatchdogProperties.sysprop b/core/sysprop/WatchdogProperties.sysprop
index 1bcc773a9a5d..93e8b788aed9 100644
--- a/core/sysprop/WatchdogProperties.sysprop
+++ b/core/sysprop/WatchdogProperties.sysprop
@@ -16,7 +16,7 @@ module: "android.sysprop.WatchdogProperties"
owner: Platform
# To escape the watchdog timeout loop, fatal reboot the system when
-# watchdog timed out 'fatal_count' times in 'fatal_window_second'
+# watchdog timed out 'fatal_count' times in 'fatal_window_seconds'
# seconds, if both values are not 0. Default value of both is 0.
prop {
api_name: "fatal_count"
@@ -26,8 +26,9 @@ prop {
access: Readonly
}
+# See 'fatal_count' for documentation.
prop {
- api_name: "fatal_window_second"
+ api_name: "fatal_window_seconds"
type: Integer
prop_name: "framework_watchdog.fatal_window.second"
scope: Internal
@@ -35,9 +36,9 @@ prop {
}
# The fatal counting can be disabled by setting property
-# 'is_fatal_ignore' to true.
+# 'should_ignore_fatal_count' to true.
prop {
- api_name: "is_fatal_ignore"
+ api_name: "should_ignore_fatal_count"
type: Boolean
prop_name: "persist.debug.framework_watchdog.fatal_ignore"
scope: Internal
diff --git a/core/sysprop/api/com.android.sysprop.watchdog-latest.txt b/core/sysprop/api/com.android.sysprop.watchdog-latest.txt
index d901aef945c9..c8462111fa94 100644
--- a/core/sysprop/api/com.android.sysprop.watchdog-latest.txt
+++ b/core/sysprop/api/com.android.sysprop.watchdog-latest.txt
@@ -7,13 +7,13 @@ props {
prop_name: "framework_watchdog.fatal_count"
}
prop {
- api_name: "fatal_window_second"
+ api_name: "fatal_window_seconds"
type: Integer
scope: Internal
prop_name: "framework_watchdog.fatal_window.second"
}
prop {
- api_name: "is_fatal_ignore"
+ api_name: "should_ignore_fatal_count"
scope: Internal
prop_name: "persist.debug.framework_watchdog.fatal_ignore"
}
diff --git a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
index f9e3bc60561c..09f16a82cd7f 100644
--- a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
+++ b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
@@ -23,7 +23,10 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.Manifest;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.os.BugreportManager;
import android.os.BugreportManager.BugreportCallback;
import android.os.BugreportParams;
@@ -31,7 +34,9 @@ import android.os.FileUtils;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.StrictMode;
+import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -53,10 +58,11 @@ import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
-
/**
* Tests for BugreportManager API.
*/
@@ -67,8 +73,22 @@ public class BugreportManagerTest {
private static final String TAG = "BugreportManagerTest";
private static final long BUGREPORT_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(10);
+ private static final long DUMPSTATE_STARTUP_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
private static final long UIAUTOMATOR_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
+
+ // A small timeout used when waiting for the result of a BugreportCallback to be received.
+ // This value must be at least 1000ms since there is an intentional delay in
+ // BugreportManagerServiceImpl in the error case.
+ private static final long CALLBACK_RESULT_TIMEOUT_MS = 1500;
+
+ // Sent by Shell when its bugreport finishes (contains final bugreport/screenshot file name
+ // associated with the bugreport).
+ private static final String INTENT_BUGREPORT_FINISHED =
+ "com.android.internal.intent.action.BUGREPORT_FINISHED";
+ private static final String EXTRA_BUGREPORT = "android.intent.extra.BUGREPORT";
+ private static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
+
private Handler mHandler;
private Executor mExecutor;
private BugreportManager mBrm;
@@ -171,7 +191,7 @@ public class BugreportManagerTest {
ParcelFileDescriptor bugreportFd2 = parcelFd(bugreportFile2);
ParcelFileDescriptor screenshotFd2 = parcelFd(screenshotFile2);
mBrm.startBugreport(bugreportFd2, screenshotFd2, wifi(), mExecutor, callback2);
- Thread.sleep(500 /* .5s */);
+ Thread.sleep(CALLBACK_RESULT_TIMEOUT_MS);
// Verify #2 encounters an error.
assertThat(callback2.getErrorCode()).isEqualTo(
@@ -180,7 +200,7 @@ public class BugreportManagerTest {
// Cancel #1 so we can move on to the next test.
mBrm.cancelBugreport();
- Thread.sleep(500 /* .5s */);
+ waitTillDoneOrTimeout(callback);
assertThat(callback.isDone()).isTrue();
assertFdsAreClosed(mBugreportFd, mScreenshotFd);
}
@@ -206,12 +226,54 @@ public class BugreportManagerTest {
// Try again, with DUMP permission.
getPermissions();
mBrm.cancelBugreport();
- Thread.sleep(500 /* .5s */);
+ waitTillDoneOrTimeout(callback);
assertThat(callback.isDone()).isTrue();
assertFdsAreClosed(mBugreportFd, mScreenshotFd);
}
@Test
+ public void cancelBugreport_noReportStarted() throws Exception {
+ // Without the native DumpstateService running, we don't get a SecurityException.
+ mBrm.cancelBugreport();
+ }
+
+ @LargeTest
+ @Test
+ public void cancelBugreport_fromDifferentUid() throws Exception {
+ assertThat(Process.myUid()).isNotEqualTo(Process.SHELL_UID);
+
+ // Start a bugreport through ActivityManager's shell command - this starts a BR from the
+ // shell UID rather than our own.
+ BugreportBroadcastReceiver br = new BugreportBroadcastReceiver();
+ InstrumentationRegistry.getContext()
+ .registerReceiver(br, new IntentFilter(INTENT_BUGREPORT_FINISHED));
+ UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+ .executeShellCommand("am bug-report");
+
+ // The command triggers the report through a broadcast, so wait until dumpstate actually
+ // starts up, which may take a bit.
+ waitTillDumpstateRunningOrTimeout();
+
+ try {
+ mBrm.cancelBugreport();
+ fail("Expected cancelBugreport to throw SecurityException when report started by "
+ + "different UID");
+ } catch (SecurityException expected) {
+ } finally {
+ // Do this in the finally block so that even if this test case fails, we don't break
+ // other test cases unexpectedly due to the still-running shell report.
+ try {
+ // The shell's BR is still running and should complete successfully.
+ br.waitForBugreportFinished();
+ } finally {
+ // The latch may fail for a number of reasons but we still need to unregister the
+ // BroadcastReceiver.
+ InstrumentationRegistry.getContext().unregisterReceiver(br);
+ }
+ }
+ }
+
+ @Test
public void insufficientPermissions_throwsException() throws Exception {
dropPermissions();
@@ -346,6 +408,28 @@ public class BugreportManagerTest {
.adoptShellPermissionIdentity(Manifest.permission.DUMP);
}
+ private static boolean isDumpstateRunning() {
+ String[] output;
+ try {
+ output =
+ UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+ .executeShellCommand("ps -A -o NAME | grep dumpstate")
+ .trim()
+ .split("\n");
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to check if dumpstate is running", e);
+ return false;
+ }
+ for (String line : output) {
+ // Check for an exact match since there may be other things that contain "dumpstate" as
+ // a substring (e.g. the dumpstate HAL).
+ if (TextUtils.equals("dumpstate", line)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private static void assertFdIsClosed(ParcelFileDescriptor pfd) {
try {
int fd = pfd.getFd();
@@ -364,18 +448,25 @@ public class BugreportManagerTest {
return System.currentTimeMillis();
}
- private static boolean shouldTimeout(long startTimeMs) {
- return now() - startTimeMs >= BUGREPORT_TIMEOUT_MS;
+ private static void waitTillDumpstateRunningOrTimeout() throws Exception {
+ long startTimeMs = now();
+ while (!isDumpstateRunning()) {
+ Thread.sleep(500 /* .5s */);
+ if (now() - startTimeMs >= DUMPSTATE_STARTUP_TIMEOUT_MS) {
+ break;
+ }
+ Log.d(TAG, "Waited " + (now() - startTimeMs) + "ms for dumpstate to start");
+ }
}
private static void waitTillDoneOrTimeout(BugreportCallbackImpl callback) throws Exception {
long startTimeMs = now();
while (!callback.isDone()) {
Thread.sleep(1000 /* 1s */);
- if (shouldTimeout(startTimeMs)) {
+ if (now() - startTimeMs >= BUGREPORT_TIMEOUT_MS) {
break;
}
- Log.d(TAG, "Waited " + (now() - startTimeMs) + "ms");
+ Log.d(TAG, "Waited " + (now() - startTimeMs) + "ms for bugreport to finish");
}
}
@@ -450,6 +541,36 @@ public class BugreportManagerTest {
assertTrue(device.wait(Until.gone(consentTitleObj), UIAUTOMATOR_TIMEOUT_MS));
}
+ private class BugreportBroadcastReceiver extends BroadcastReceiver {
+ Intent mBugreportFinishedIntent = null;
+ final CountDownLatch mLatch;
+
+ BugreportBroadcastReceiver() {
+ mLatch = new CountDownLatch(1);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ setBugreportFinishedIntent(intent);
+ mLatch.countDown();
+ }
+
+ private void setBugreportFinishedIntent(Intent intent) {
+ mBugreportFinishedIntent = intent;
+ }
+
+ public Intent getBugreportFinishedIntent() {
+ return mBugreportFinishedIntent;
+ }
+
+ public void waitForBugreportFinished() throws Exception {
+ if (!mLatch.await(BUGREPORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ throw new Exception("Failed to receive BUGREPORT_FINISHED in "
+ + BUGREPORT_TIMEOUT_MS + " ms.");
+ }
+ }
+ }
+
/**
* A rule to change strict mode vm policy temporarily till test method finished.
*
diff --git a/core/tests/coretests/src/android/app/OWNERS b/core/tests/coretests/src/android/app/OWNERS
index bd7da0c3f209..b3f399363aef 100644
--- a/core/tests/coretests/src/android/app/OWNERS
+++ b/core/tests/coretests/src/android/app/OWNERS
@@ -1 +1,6 @@
per-file Window*.java = file:/services/core/java/com/android/server/wm/OWNERS
+
+# Notification, DND, Status bar
+per-file *Notification* = file:/packages/SystemUI/OWNERS
+per-file *Zen* = file:/packages/SystemUI/OWNERS
+per-file *StatusBar* = file:/packages/SystemUI/OWNERS
diff --git a/core/tests/coretests/src/android/app/people/OWNERS b/core/tests/coretests/src/android/app/people/OWNERS
new file mode 100644
index 000000000000..6ec8e6aa8d81
--- /dev/null
+++ b/core/tests/coretests/src/android/app/people/OWNERS
@@ -0,0 +1 @@
+file:/core/java/android/app/people/OWNERS \ No newline at end of file
diff --git a/core/tests/coretests/src/android/content/OWNERS b/core/tests/coretests/src/android/content/OWNERS
index 912db1e835dc..c61a4b538a44 100644
--- a/core/tests/coretests/src/android/content/OWNERS
+++ b/core/tests/coretests/src/android/content/OWNERS
@@ -1,3 +1,4 @@
+per-file AssetTest.java = file:/core/java/android/content/res/OWNERS
per-file ContextTest.java = file:/services/core/java/com/android/server/wm/OWNERS
-per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS
+per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
diff --git a/core/tests/coretests/src/android/content/integrity/OWNERS b/core/tests/coretests/src/android/content/integrity/OWNERS
new file mode 100644
index 000000000000..4ffc7041a527
--- /dev/null
+++ b/core/tests/coretests/src/android/content/integrity/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/integrity/OWNERS
diff --git a/core/tests/coretests/src/android/content/pm/OWNERS b/core/tests/coretests/src/android/content/pm/OWNERS
new file mode 100644
index 000000000000..867336515ce3
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/OWNERS
@@ -0,0 +1,5 @@
+include /core/java/android/content/pm/OWNERS
+
+per-file AppSearchPersonTest.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS
+per-file SigningDetailsTest.java = cbrubaker@google.com
+per-file SigningDetailsTest.java = mpgroover@google.com
diff --git a/core/tests/coretests/src/android/content/res/OWNERS b/core/tests/coretests/src/android/content/res/OWNERS
new file mode 100644
index 000000000000..3e79d8ff0bbe
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/res/OWNERS
diff --git a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
index 0f17d27048f3..6be9306bbd2d 100644
--- a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
+++ b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
@@ -254,7 +254,7 @@ public class DateIntervalFormatTest {
assertEquals("19–22 de ene. de 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 de ene. – jue., 22 de ene. de 2009",
+ assertEquals("lun, 19 de ene. – jue, 22 de ene. de 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009",
@@ -265,7 +265,7 @@ public class DateIntervalFormatTest {
assertEquals("19 de ene. – 22 de abr. 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 de ene. – mié., 22 de abr. de 2009",
+ assertEquals("lun, 19 de ene. – mié, 22 de abr. de 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH,
FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("enero–abril de 2009",
@@ -286,9 +286,9 @@ public class DateIntervalFormatTest {
assertEquals("19–22 de enero de 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, 0));
- assertEquals("19–22 ene. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
+ assertEquals("19–22 ene 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 ene. – jue., 22 ene. 2009",
+ assertEquals("lun, 19 ene – jue, 22 ene 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009",
@@ -296,19 +296,19 @@ public class DateIntervalFormatTest {
assertEquals("19 de enero–22 de abril de 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, 0));
- assertEquals("19 ene. – 22 abr. 2009",
+ assertEquals("19 ene – 22 abr 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 ene. – mié., 22 abr. 2009",
+ assertEquals("lun, 19 ene – mié, 22 abr 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH,
FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("enero–abril de 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
- assertEquals("19 ene. 2009 – 9 feb. 2012",
+ assertEquals("19 ene 2009 – 9 feb 2012",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("ene. 2009 – feb. 2012",
+ assertEquals("ene 2009 – feb 2012",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR,
FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
assertEquals("19 de enero de 2009–9 de febrero de 2012",
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
index 068d04798858..5612833e5ddd 100644
--- a/core/tests/coretests/src/android/text/format/FormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -212,7 +212,7 @@ public class FormatterTest {
// Make sure it works on different locales.
setLocale(new Locale("ru", "RU"));
- assertEquals("1 мин.", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
+ assertEquals("1 мин", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
mContext, 1 * SECOND));
}
diff --git a/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java b/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
index 4b3b5735b4f3..b3425162f48f 100644
--- a/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
@@ -755,8 +755,8 @@ public class RelativeDateTimeFormatterTest {
final Locale locale = new Locale("fr");
android.icu.text.RelativeDateTimeFormatter icuFormatter =
android.icu.text.RelativeDateTimeFormatter.getInstance(locale);
- assertEquals("D à T", icuFormatter.combineDateAndTime("D", "T"));
+ assertEquals("D, T", icuFormatter.combineDateAndTime("D", "T"));
// Ensure single quote ' and curly braces {} are not interpreted in input values.
- assertEquals("D'x' à T{0}", icuFormatter.combineDateAndTime("D'x'", "T{0}"));
+ assertEquals("D'x', T{0}", icuFormatter.combineDateAndTime("D'x'", "T{0}"));
}
}
diff --git a/core/tests/coretests/src/android/view/autofill/OWNERS b/core/tests/coretests/src/android/view/autofill/OWNERS
new file mode 100644
index 000000000000..9a30e826a24f
--- /dev/null
+++ b/core/tests/coretests/src/android/view/autofill/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 351486
+
+include /core/java/android/view/autofill/OWNERS
diff --git a/core/tests/coretests/src/android/view/contentcapture/OWNERS b/core/tests/coretests/src/android/view/contentcapture/OWNERS
new file mode 100644
index 000000000000..24561c59bba6
--- /dev/null
+++ b/core/tests/coretests/src/android/view/contentcapture/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 544200
+
+include /core/java/android/view/contentcapture/OWNERS
diff --git a/core/tests/coretests/src/android/view/textclassifier/OWNERS b/core/tests/coretests/src/android/view/textclassifier/OWNERS
new file mode 100644
index 000000000000..46b3cb8824a0
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/textclassifier/OWNERS
diff --git a/core/tests/coretests/src/android/view/textservice/OWNERS b/core/tests/coretests/src/android/view/textservice/OWNERS
new file mode 100644
index 000000000000..0471e29a25cd
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textservice/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 816455
+
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/core/tests/coretests/src/android/widget/AbsSeekBarTest.java b/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
index 5371a0f8d9d7..ccd873dc390e 100644
--- a/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
+++ b/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
@@ -30,7 +30,6 @@ import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
import android.platform.test.annotations.Presubmit;
-import android.view.View;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -48,6 +47,7 @@ import java.util.List;
@Presubmit
public class AbsSeekBarTest {
+ public static final int PADDING = 10;
private Context mContext;
private AbsSeekBar mBar;
@@ -59,34 +59,42 @@ public class AbsSeekBarTest {
@Test
public void testExclusionForThumb_limitedTo48dp() {
- mBar.setPadding(10, 10, 10, 10);
+ mBar.setPadding(PADDING, PADDING, PADDING, PADDING);
mBar.setThumb(newThumb(dpToPxSize(20)));
mBar.setMin(0);
mBar.setMax(100);
mBar.setProgress(50);
+
+ final int thumbOffset = mBar.getThumbOffset();
+
measureAndLayout(dpToPxSize(200), dpToPxSize(100));
List<Rect> exclusions = mBar.getSystemGestureExclusionRects();
assertEquals("exclusions should be size 1, but was " + exclusions, 1, exclusions.size());
assertEquals("exclusion should be centered on thumb",
- center(mBar), center(exclusions.get(0)));
+ center(offset(mBar.getThumb().getBounds(), PADDING - thumbOffset, PADDING)),
+ center(exclusions.get(0)));
assertEquals("exclusion should be 48dp high", dpToPxSize(48), exclusions.get(0).height());
assertEquals("exclusion should be 48dp wide", dpToPxSize(48), exclusions.get(0).width());
}
@Test
public void testExclusionForThumb_limitedToHeight() {
- mBar.setPadding(10, 10, 10, 10);
+ mBar.setPadding(PADDING, PADDING, PADDING, PADDING);
mBar.setThumb(newThumb(dpToPxSize(20)));
mBar.setMin(0);
mBar.setMax(100);
mBar.setProgress(50);
+
+ final int thumbOffset = mBar.getThumbOffset();
+
measureAndLayout(dpToPxSize(200), dpToPxSize(32));
List<Rect> exclusions = mBar.getSystemGestureExclusionRects();
assertEquals("exclusions should be size 1, but was " + exclusions, 1, exclusions.size());
assertEquals("exclusion should be centered on thumb",
- center(mBar), center(exclusions.get(0)));
+ center(offset(mBar.getThumb().getBounds(), PADDING - thumbOffset, PADDING)),
+ center(exclusions.get(0)));
assertEquals("exclusion should be 32dp high", dpToPxSize(32), exclusions.get(0).height());
assertEquals("exclusion should be 32dp wide", dpToPxSize(32), exclusions.get(0).width());
}
@@ -95,7 +103,7 @@ public class AbsSeekBarTest {
public void testExclusionForThumb_passesThroughUserExclusions() {
mBar.setSystemGestureExclusionRects(Arrays.asList(new Rect(1, 2, 3, 4)));
- mBar.setPadding(10, 10, 10, 10);
+ mBar.setPadding(PADDING, PADDING, PADDING, PADDING);
mBar.setThumb(newThumb(dpToPxSize(20)));
mBar.setMin(0);
mBar.setMax(100);
@@ -110,12 +118,37 @@ public class AbsSeekBarTest {
assertThat(mBar.getSystemGestureExclusionRects(), hasSize(2));
}
+ @Test
+ public void testGrowRectTo_evenInitialDifference() {
+ doGrowRectTest(new Rect(0, 0, 0, 0), 10, new Rect(-5, -5, 5, 5));
+ }
+
+ @Test
+ public void testGrowRectTo_unevenInitialDifference() {
+ doGrowRectTest(new Rect(0, 0, 1, 1), 10, new Rect(-5, -5, 5, 5));
+ }
+
+ @Test
+ public void testGrowRectTo_unevenInitialDifference_unevenSize() {
+ doGrowRectTest(new Rect(0, 0, 0, 0), 9, new Rect(-5, -5, 4, 4));
+ }
+
+ public void doGrowRectTest(Rect in, int minimumSize, Rect expected) {
+ Rect result = new Rect(in);
+ mBar.growRectTo(result, minimumSize);
+
+ assertEquals("grown rect", expected, result);
+ assertEquals("grown rect center point", center(expected), center(result));
+ }
+
private Point center(Rect rect) {
return new Point(rect.centerX(), rect.centerY());
}
- private Point center(View view) {
- return center(new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
+ private Rect offset(Rect rect, int dx, int dy) {
+ Rect result = new Rect(rect);
+ result.offset(dx, dy);
+ return result;
}
private ShapeDrawable newThumb(int size) {
diff --git a/core/tests/mockingcoretests/src/android/view/OWNERS b/core/tests/mockingcoretests/src/android/view/OWNERS
new file mode 100644
index 000000000000..9c9f824ba12b
--- /dev/null
+++ b/core/tests/mockingcoretests/src/android/view/OWNERS
@@ -0,0 +1,2 @@
+# Display
+per-file Display*.java = file:/services/core/java/com/android/server/display/OWNERS
diff --git a/core/tests/overlaytests/device/Android.bp b/core/tests/overlaytests/device/Android.bp
index 12a2b0815050..f86ac9ce37e1 100644
--- a/core/tests/overlaytests/device/Android.bp
+++ b/core/tests/overlaytests/device/Android.bp
@@ -16,7 +16,11 @@ android_test {
name: "OverlayDeviceTests",
srcs: ["src/**/*.java"],
platform_apis: true,
- static_libs: ["androidx.test.rules"],
+ certificate: "platform",
+ static_libs: [
+ "androidx.test.rules",
+ "testng",
+ ],
test_suites: ["device-tests"],
data: [
":OverlayDeviceTests_AppOverlayOne",
diff --git a/core/tests/overlaytests/device/AndroidManifest.xml b/core/tests/overlaytests/device/AndroidManifest.xml
index 4881636c7095..a69911f8d827 100644
--- a/core/tests/overlaytests/device/AndroidManifest.xml
+++ b/core/tests/overlaytests/device/AndroidManifest.xml
@@ -19,6 +19,8 @@
<uses-sdk android:minSdkVersion="21" />
+ <uses-permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES" />
+
<application>
<uses-library android:name="android.test.runner"/>
</application>
diff --git a/core/tests/overlaytests/device/AndroidTest.xml b/core/tests/overlaytests/device/AndroidTest.xml
index 6507839a4288..ebbdda559ed2 100644
--- a/core/tests/overlaytests/device/AndroidTest.xml
+++ b/core/tests/overlaytests/device/AndroidTest.xml
@@ -19,9 +19,20 @@
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-instrumentation" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="remount-system" value="true" />
+ <option name="push" value="OverlayDeviceTests.apk->/system/app/OverlayDeviceTests.apk" />
+ </target_preparer>
+
+ <!-- Reboot to have the test APK scanned by PM and reboot after to remove the test APK. -->
+ <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer">
+ <option name="pre-reboot" value="true" />
+ <option name="post-reboot" value="true" />
+ </target_preparer>
+
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="OverlayDeviceTests.apk" />
<option name="test-file-name" value="OverlayDeviceTests_AppOverlayOne.apk" />
<option name="test-file-name" value="OverlayDeviceTests_AppOverlayTwo.apk" />
<option name="test-file-name" value="OverlayDeviceTests_FrameworkOverlay.apk" />
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java b/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java
index 390bb766ab81..76c01a7e1125 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java
@@ -18,60 +18,76 @@ package com.android.overlaytest;
import static java.util.concurrent.TimeUnit.SECONDS;
-import android.app.UiAutomation;
-import android.content.res.Resources;
-import android.os.ParcelFileDescriptor;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.om.OverlayManager;
+import android.content.om.OverlayManagerTransaction;
+import android.os.UserHandle;
import androidx.test.InstrumentationRegistry;
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;
class LocalOverlayManager {
private static final long TIMEOUT = 30;
- public static void setEnabledAndWait(Executor executor, final String packageName,
- boolean enable) throws Exception {
- final String pattern = (enable ? "[x]" : "[ ]") + " " + packageName;
- if (executeShellCommand("cmd overlay list").contains(pattern)) {
- // nothing to do, overlay already in the requested state
- return;
+ public static void toggleOverlaysAndWait(@NonNull final String[] overlaysToEnable,
+ @NonNull final String[] overlaysToDisable) throws Exception {
+ final int userId = UserHandle.myUserId();
+ OverlayManagerTransaction.Builder builder = new OverlayManagerTransaction.Builder();
+ for (String pkg : overlaysToEnable) {
+ builder.setEnabled(pkg, true, userId);
}
+ for (String pkg : overlaysToDisable) {
+ builder.setEnabled(pkg, false, userId);
+ }
+ OverlayManagerTransaction transaction = builder.build();
- final Resources res = InstrumentationRegistry.getContext().getResources();
- final String[] oldApkPaths = res.getAssets().getApkPaths();
+ final Context ctx = InstrumentationRegistry.getTargetContext();
FutureTask<Boolean> task = new FutureTask<>(() -> {
while (true) {
- if (!Arrays.equals(oldApkPaths, res.getAssets().getApkPaths())) {
+ final String[] paths = ctx.getResources().getAssets().getApkPaths();
+ if (arrayTailContains(paths, overlaysToEnable)
+ && arrayDoesNotContain(paths, overlaysToDisable)) {
return true;
}
Thread.sleep(10);
}
});
+
+ OverlayManager om = ctx.getSystemService(OverlayManager.class);
+ om.commit(transaction);
+
+ Executor executor = (cmd) -> new Thread(cmd).start();
executor.execute(task);
- executeShellCommand("cmd overlay " + (enable ? "enable " : "disable ") + packageName);
task.get(TIMEOUT, SECONDS);
}
- private static String executeShellCommand(final String command)
- throws Exception {
- final UiAutomation uiAutomation =
- InstrumentationRegistry.getInstrumentation().getUiAutomation();
- final ParcelFileDescriptor pfd = uiAutomation.executeShellCommand(command);
- try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
- final BufferedReader reader = new BufferedReader(
- new InputStreamReader(in, StandardCharsets.UTF_8));
- StringBuilder str = new StringBuilder();
- String line;
- while ((line = reader.readLine()) != null) {
- str.append(line);
+ private static boolean arrayTailContains(@NonNull final String[] array,
+ @NonNull final String[] substrings) {
+ if (array.length < substrings.length) {
+ return false;
+ }
+ for (int i = 0; i < substrings.length; i++) {
+ String a = array[array.length - substrings.length + i];
+ String s = substrings[i];
+ if (!a.contains(s)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean arrayDoesNotContain(@NonNull final String[] array,
+ @NonNull final String[] substrings) {
+ for (String s : substrings) {
+ for (String a : array) {
+ if (a.contains(s)) {
+ return false;
+ }
}
- return str.toString();
}
+ return true;
}
}
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/TransactionTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/TransactionTest.java
new file mode 100644
index 000000000000..0b4f5e227169
--- /dev/null
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/TransactionTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.overlaytest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
+import android.content.om.OverlayInfo;
+import android.content.om.OverlayManager;
+import android.content.om.OverlayManagerTransaction;
+import android.content.res.Resources;
+import android.os.UserHandle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.List;
+
+@RunWith(JUnit4.class)
+@MediumTest
+public class TransactionTest {
+ static final String APP_OVERLAY_ONE_PKG = "com.android.overlaytest.app_overlay_one";
+ static final String APP_OVERLAY_TWO_PKG = "com.android.overlaytest.app_overlay_two";
+
+ private Context mContext;
+ private Resources mResources;
+ private OverlayManager mOverlayManager;
+ private int mUserId;
+ private UserHandle mUserHandle;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ mResources = mContext.getResources();
+ mOverlayManager = mContext.getSystemService(OverlayManager.class);
+ mUserId = UserHandle.myUserId();
+ mUserHandle = UserHandle.of(mUserId);
+
+ LocalOverlayManager.toggleOverlaysAndWait(
+ new String[]{},
+ new String[]{APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG});
+ }
+
+ @Test
+ public void testValidTransaction() throws Exception {
+ assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, false, mUserId);
+ assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId);
+
+ OverlayManagerTransaction t = new OverlayManagerTransaction.Builder()
+ .setEnabled(APP_OVERLAY_ONE_PKG, true)
+ .setEnabled(APP_OVERLAY_TWO_PKG, true)
+ .build();
+ mOverlayManager.commit(t);
+
+ assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, true, mUserId);
+ assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, true, mUserId);
+ List<OverlayInfo> ois =
+ mOverlayManager.getOverlayInfosForTarget("com.android.overlaytest", mUserHandle);
+ assertEquals(ois.size(), 2);
+ assertEquals(ois.get(0).packageName, APP_OVERLAY_ONE_PKG);
+ assertEquals(ois.get(1).packageName, APP_OVERLAY_TWO_PKG);
+
+ OverlayManagerTransaction t2 = new OverlayManagerTransaction.Builder()
+ .setEnabled(APP_OVERLAY_TWO_PKG, true)
+ .setEnabled(APP_OVERLAY_ONE_PKG, true)
+ .build();
+ mOverlayManager.commit(t2);
+
+ assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, true, mUserId);
+ assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, true, mUserId);
+ List<OverlayInfo> ois2 =
+ mOverlayManager.getOverlayInfosForTarget("com.android.overlaytest", mUserHandle);
+ assertEquals(ois2.size(), 2);
+ assertEquals(ois2.get(0).packageName, APP_OVERLAY_TWO_PKG);
+ assertEquals(ois2.get(1).packageName, APP_OVERLAY_ONE_PKG);
+
+ OverlayManagerTransaction t3 = new OverlayManagerTransaction.Builder()
+ .setEnabled(APP_OVERLAY_TWO_PKG, false)
+ .build();
+ mOverlayManager.commit(t3);
+
+ assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, true, mUserId);
+ assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId);
+ List<OverlayInfo> ois3 =
+ mOverlayManager.getOverlayInfosForTarget("com.android.overlaytest", mUserHandle);
+ assertEquals(ois3.size(), 2);
+ assertEquals(ois3.get(0).packageName, APP_OVERLAY_TWO_PKG);
+ assertEquals(ois3.get(1).packageName, APP_OVERLAY_ONE_PKG);
+ }
+
+ @Test
+ public void testInvalidRequestHasNoEffect() {
+ assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, false, mUserId);
+ assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId);
+
+ OverlayManagerTransaction t = new OverlayManagerTransaction.Builder()
+ .setEnabled(APP_OVERLAY_ONE_PKG, true)
+ .setEnabled("does-not-exist", true)
+ .setEnabled(APP_OVERLAY_TWO_PKG, true)
+ .build();
+ assertThrows(SecurityException.class, () -> mOverlayManager.commit(t));
+
+ assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, false, mUserId);
+ assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId);
+ }
+
+ private void assertOverlayIsEnabled(final String packageName, boolean enabled, int userId) {
+ final OverlayInfo oi = mOverlayManager.getOverlayInfo(packageName, UserHandle.of(userId));
+ assertNotNull(oi);
+ assertEquals(oi.isEnabled(), enabled);
+ }
+}
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
index d28c47d9c922..420f755c5251 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
@@ -22,8 +22,6 @@ import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.util.concurrent.Executor;
-
@RunWith(JUnit4.class)
@MediumTest
public class WithMultipleOverlaysTest extends OverlayBaseTest {
@@ -33,9 +31,8 @@ public class WithMultipleOverlaysTest extends OverlayBaseTest {
@BeforeClass
public static void enableOverlay() throws Exception {
- Executor executor = (cmd) -> new Thread(cmd).start();
- LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, true);
- LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, true);
- LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, true);
+ LocalOverlayManager.toggleOverlaysAndWait(
+ new String[]{FRAMEWORK_OVERLAY_PKG, APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG},
+ new String[]{});
}
}
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
index 6566ad304c1c..a86255e96388 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
@@ -22,8 +22,6 @@ import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.util.concurrent.Executor;
-
@RunWith(JUnit4.class)
@MediumTest
public class WithOverlayTest extends OverlayBaseTest {
@@ -32,10 +30,9 @@ public class WithOverlayTest extends OverlayBaseTest {
}
@BeforeClass
- public static void enableOverlay() throws Exception {
- Executor executor = (cmd) -> new Thread(cmd).start();
- LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, true);
- LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, false);
- LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, true);
+ public static void enableOverlays() throws Exception {
+ LocalOverlayManager.toggleOverlaysAndWait(
+ new String[]{FRAMEWORK_OVERLAY_PKG, APP_OVERLAY_ONE_PKG},
+ new String[]{APP_OVERLAY_TWO_PKG});
}
}
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
index 48cfeab2fbff..51c411819b87 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
@@ -22,8 +22,6 @@ import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.util.concurrent.Executor;
-
@RunWith(JUnit4.class)
@MediumTest
public class WithoutOverlayTest extends OverlayBaseTest {
@@ -33,9 +31,8 @@ public class WithoutOverlayTest extends OverlayBaseTest {
@BeforeClass
public static void disableOverlays() throws Exception {
- Executor executor = (cmd) -> new Thread(cmd).start();
- LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, false);
- LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, false);
- LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, false);
+ LocalOverlayManager.toggleOverlaysAndWait(
+ new String[]{},
+ new String[]{FRAMEWORK_OVERLAY_PKG, APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG});
}
}
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp
index da3aa007135a..847b4915530b 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp
@@ -15,6 +15,6 @@
android_test {
name: "OverlayDeviceTests_AppOverlayOne",
sdk_version: "current",
-
+ certificate: "platform",
aaptflags: ["--no-resource-removal"],
}
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp
index 215b66da36dc..7d5f82a71b44 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp
@@ -15,6 +15,6 @@
android_test {
name: "OverlayDeviceTests_AppOverlayTwo",
sdk_version: "current",
-
+ certificate: "platform",
aaptflags: ["--no-resource-removal"],
}
diff --git a/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
index 4c3eaeb1730b..7175f562d7ef 100644
--- a/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.util;
+import static android.Manifest.permission.NETWORK_SETTINGS;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -82,6 +84,7 @@ public class LocationPermissionCheckerTest {
private int mAllowCoarseLocationApps;
private int mFineLocationPermission;
private int mAllowFineLocationApps;
+ private int mNetworkSettingsPermission;
private int mCurrentUser;
private boolean mIsLocationEnabled;
private boolean mThrowSecurityException;
@@ -138,6 +141,7 @@ public class LocationPermissionCheckerTest {
mFineLocationPermission = PackageManager.PERMISSION_DENIED;
mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED;
mAllowFineLocationApps = AppOpsManager.MODE_ERRORED;
+ mNetworkSettingsPermission = PackageManager.PERMISSION_DENIED;
}
private void setupMockInterface() {
@@ -151,6 +155,8 @@ public class LocationPermissionCheckerTest {
.thenReturn(mCoarseLocationPermission);
when(mMockContext.checkPermission(mManifestStringFine, -1, mUid))
.thenReturn(mFineLocationPermission);
+ when(mMockContext.checkPermission(NETWORK_SETTINGS, -1, mUid))
+ .thenReturn(mNetworkSettingsPermission);
when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(mIsLocationEnabled);
}
@@ -264,6 +270,21 @@ public class LocationPermissionCheckerTest {
assertEquals(LocationPermissionChecker.ERROR_LOCATION_MODE_OFF, result);
}
+ @Test
+ public void testenforceCanAccessScanResults_LocationModeDisabledHasNetworkSettings()
+ throws Exception {
+ mThrowSecurityException = false;
+ mIsLocationEnabled = false;
+ mNetworkSettingsPermission = PackageManager.PERMISSION_GRANTED;
+ setupTestCase();
+
+ final int result =
+ mChecker.checkLocationPermissionWithDetailInfo(
+ TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
+ assertEquals(LocationPermissionChecker.SUCCEEDED, result);
+ }
+
+
private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) {
try {
r.run();
diff --git a/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
index e0884e3e1c28..9394dec7f46f 100644
--- a/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
+++ b/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
@@ -42,14 +42,14 @@ public class AngleOfArrivalMeasurementTest {
AngleOfArrivalMeasurement.Builder builder = new AngleOfArrivalMeasurement.Builder();
tryBuild(builder, false);
- builder.setAltitudeAngleMeasurement(altitude);
+ builder.setAltitude(altitude);
tryBuild(builder, false);
- builder.setAzimuthAngleMeasurement(azimuth);
+ builder.setAzimuth(azimuth);
AngleOfArrivalMeasurement measurement = tryBuild(builder, true);
- assertEquals(azimuth, measurement.getAzimuthAngleMeasurement());
- assertEquals(altitude, measurement.getAltitudeAngleMeasurement());
+ assertEquals(azimuth, measurement.getAzimuth());
+ assertEquals(altitude, measurement.getAltitude());
}
private AngleMeasurement getAngleMeasurement(double radian, double error, double confidence) {
diff --git a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
index b4b2e303443e..8e7f7c562ade 100644
--- a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
+++ b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
@@ -42,8 +42,8 @@ public class UwbTestUtils {
public static AngleOfArrivalMeasurement getAngleOfArrivalMeasurement() {
return new AngleOfArrivalMeasurement.Builder()
- .setAltitudeAngleMeasurement(getAngleMeasurement())
- .setAzimuthAngleMeasurement(getAngleMeasurement())
+ .setAltitude(getAngleMeasurement())
+ .setAzimuth(getAngleMeasurement())
.build();
}
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index 9867d810dba2..65d3a012b129 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -1,3 +1,4 @@
+alanstokes@google.com
cbrubaker@google.com
hackbod@android.com
hackbod@google.com
@@ -12,4 +13,4 @@ toddke@android.com
toddke@google.com
yamasani@google.com
-per-file preinstalled-packages* = file:/MULTIUSER_OWNERS \ No newline at end of file
+per-file preinstalled-packages* = file:/MULTIUSER_OWNERS
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index a185da19e71b..365acf2c1fb9 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -344,7 +344,7 @@ applications that come with the platform
<permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<permission name="android.permission.MOVE_PACKAGE"/>
<!-- Needed for test only -->
- <permission name="android.permission.NETWORK_AIRPLANE_MODE"/>
+ <permission name="android.permission.RESTART_WIFI_SUBSYSTEM"/>
<permission name="android.permission.OBSERVE_APP_USAGE"/>
<permission name="android.permission.NETWORK_SCAN"/>
<permission name="android.permission.PACKAGE_USAGE_STATS" />
diff --git a/identity/java/android/security/identity/CredstoreIdentityCredential.java b/identity/java/android/security/identity/CredstoreIdentityCredential.java
index 7c0af6def696..6398cee74cba 100644
--- a/identity/java/android/security/identity/CredstoreIdentityCredential.java
+++ b/identity/java/android/security/identity/CredstoreIdentityCredential.java
@@ -37,6 +37,7 @@ import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.time.Instant;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Map;
@@ -237,12 +238,18 @@ class CredstoreIdentityCredential extends IdentityCredential {
}
private boolean mAllowUsingExhaustedKeys = true;
+ private boolean mAllowUsingExpiredKeys = false;
@Override
public void setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys) {
mAllowUsingExhaustedKeys = allowUsingExhaustedKeys;
}
+ @Override
+ public void setAllowUsingExpiredKeys(boolean allowUsingExpiredKeys) {
+ mAllowUsingExpiredKeys = allowUsingExpiredKeys;
+ }
+
private boolean mOperationHandleSet = false;
private long mOperationHandle = 0;
@@ -256,7 +263,8 @@ class CredstoreIdentityCredential extends IdentityCredential {
public long getCredstoreOperationHandle() {
if (!mOperationHandleSet) {
try {
- mOperationHandle = mBinder.selectAuthKey(mAllowUsingExhaustedKeys);
+ mOperationHandle = mBinder.selectAuthKey(mAllowUsingExhaustedKeys,
+ mAllowUsingExpiredKeys);
mOperationHandleSet = true;
} catch (android.os.RemoteException e) {
throw new RuntimeException("Unexpected RemoteException ", e);
@@ -306,7 +314,8 @@ class CredstoreIdentityCredential extends IdentityCredential {
rnsParcels,
sessionTranscript != null ? sessionTranscript : new byte[0],
readerSignature != null ? readerSignature : new byte[0],
- mAllowUsingExhaustedKeys);
+ mAllowUsingExhaustedKeys,
+ mAllowUsingExpiredKeys);
} catch (android.os.RemoteException e) {
throw new RuntimeException("Unexpected RemoteException ", e);
} catch (android.os.ServiceSpecificException e) {
@@ -410,6 +419,34 @@ class CredstoreIdentityCredential extends IdentityCredential {
}
@Override
+ public void storeStaticAuthenticationData(X509Certificate authenticationKey,
+ Instant expirationDate,
+ byte[] staticAuthData)
+ throws UnknownAuthenticationKeyException {
+ try {
+ AuthKeyParcel authKeyParcel = new AuthKeyParcel();
+ authKeyParcel.x509cert = authenticationKey.getEncoded();
+ long millisSinceEpoch = (expirationDate.getEpochSecond() * 1000)
+ + (expirationDate.getNano() / 1000000);
+ mBinder.storeStaticAuthenticationDataWithExpiration(authKeyParcel,
+ millisSinceEpoch, staticAuthData);
+ } catch (CertificateEncodingException e) {
+ throw new RuntimeException("Error encoding authenticationKey", e);
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ if (e.errorCode == ICredentialStore.ERROR_NOT_SUPPORTED) {
+ throw new UnsupportedOperationException("Not supported", e);
+ } else if (e.errorCode == ICredentialStore.ERROR_AUTHENTICATION_KEY_NOT_FOUND) {
+ throw new UnknownAuthenticationKeyException(e.getMessage(), e);
+ } else {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+ }
+
+ @Override
public @NonNull int[] getAuthenticationDataUsageCount() {
try {
int[] usageCount = mBinder.getAuthenticationDataUsageCount();
@@ -421,4 +458,49 @@ class CredstoreIdentityCredential extends IdentityCredential {
+ e.errorCode, e);
}
}
+
+ @Override
+ public @NonNull byte[] proveOwnership(@NonNull byte[] challenge) {
+ try {
+ byte[] proofOfOwnership = mBinder.proveOwnership(challenge);
+ return proofOfOwnership;
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ if (e.errorCode == ICredentialStore.ERROR_NOT_SUPPORTED) {
+ throw new UnsupportedOperationException("Not supported", e);
+ } else {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+ }
+
+ @Override
+ public @NonNull byte[] delete(@NonNull byte[] challenge) {
+ try {
+ byte[] proofOfDeletion = mBinder.deleteWithChallenge(challenge);
+ return proofOfDeletion;
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+
+ @Override
+ public @NonNull byte[] update(@NonNull PersonalizationData personalizationData) {
+ try {
+ IWritableCredential binder = mBinder.update();
+ byte[] proofOfProvision =
+ CredstoreWritableIdentityCredential.personalize(binder, personalizationData);
+ return proofOfProvision;
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
}
diff --git a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
index 129063361b35..d8d47424e2e8 100644
--- a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
+++ b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
@@ -162,5 +162,4 @@ class CredstoreIdentityCredentialStore extends IdentityCredentialStore {
+ e.errorCode, e);
}
}
-
}
diff --git a/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
index 725e3d8e429a..d2e7984ce19f 100644
--- a/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
+++ b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
@@ -76,7 +76,14 @@ class CredstoreWritableIdentityCredential extends WritableIdentityCredential {
@NonNull @Override
public byte[] personalize(@NonNull PersonalizationData personalizationData) {
+ return personalize(mBinder, personalizationData);
+ }
+ // Used by both personalize() and CredstoreIdentityCredential.update().
+ //
+ @NonNull
+ static byte[] personalize(IWritableCredential binder,
+ @NonNull PersonalizationData personalizationData) {
Collection<AccessControlProfile> accessControlProfiles =
personalizationData.getAccessControlProfiles();
@@ -144,7 +151,7 @@ class CredstoreWritableIdentityCredential extends WritableIdentityCredential {
secureUserId = getRootSid();
}
try {
- byte[] personalizationReceipt = mBinder.personalize(acpParcels, ensParcels,
+ byte[] personalizationReceipt = binder.personalize(acpParcels, ensParcels,
secureUserId);
return personalizationReceipt;
} catch (android.os.RemoteException e) {
@@ -164,5 +171,4 @@ class CredstoreWritableIdentityCredential extends WritableIdentityCredential {
return rootSid;
}
-
}
diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java
index 4eb6e420c07f..8f175bb63edb 100644
--- a/identity/java/android/security/identity/IdentityCredential.java
+++ b/identity/java/android/security/identity/IdentityCredential.java
@@ -23,6 +23,7 @@ import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
+import java.time.Instant;
import java.util.Collection;
import java.util.Map;
@@ -114,6 +115,25 @@ public abstract class IdentityCredential {
public abstract void setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys);
/**
+ * Sets whether to allow using an authentication key which has been expired if no
+ * other key is available. This must be called prior to calling
+ * {@link #getEntries(byte[], Map, byte[], byte[])}.
+ *
+ * <p>By default this is set to false.
+ *
+ * <p>This is only implemented in feature version 202101 or later. If not implemented, the call
+ * fails with {@link UnsupportedOperationException}. See
+ * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known
+ * feature versions.
+ *
+ * @param allowUsingExpiredKeys whether to allow using an authentication key which use count
+ * has been exceeded if no other key is available.
+ */
+ public void setAllowUsingExpiredKeys(boolean allowUsingExpiredKeys) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
* Called by android.hardware.biometrics.CryptoObject#getOpId() to get an
* operation handle.
*
@@ -289,6 +309,21 @@ public abstract class IdentityCredential {
*
* <p>Each X.509 certificate is signed by CredentialKey. The certificate chain for CredentialKey
* can be obtained using the {@link #getCredentialKeyCertificateChain()} method.
+
+ * <p>If the implementation is feature version 202101 or later,
+ * each X.509 certificate contains an X.509 extension at OID 1.3.6.1.4.1.11129.2.1.26 which
+ * contains a DER encoded OCTET STRING with the bytes of the CBOR with the following CDDL:
+ * <pre>
+ * ProofOfBinding = [
+ * "ProofOfBinding",
+ * bstr, // Contains SHA-256(ProofOfProvisioning)
+ * ]
+ * </pre>
+ * <p>This CBOR enables an issuer to determine the exact state of the credential it
+ * returns issuer-signed data for.
+ *
+ * <p> See {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for
+ * known feature versions.
*
* @return A collection of X.509 certificates for dynamic authentication keys that need issuer
* certification.
@@ -308,16 +343,136 @@ public abstract class IdentityCredential {
* the authenticity
* and integrity of the credential data fields.
* @throws UnknownAuthenticationKeyException If the given authentication key is not recognized.
+ * @deprecated Use {@link #storeStaticAuthenticationData(X509Certificate, Instant, byte[])}
+ * instead.
*/
+ @Deprecated
public abstract void storeStaticAuthenticationData(
@NonNull X509Certificate authenticationKey,
@NonNull byte[] staticAuthData)
throws UnknownAuthenticationKeyException;
/**
+ * Store authentication data associated with a dynamic authentication key.
+ *
+ * This should only be called for an authenticated key returned by
+ * {@link #getAuthKeysNeedingCertification()}.
+ *
+ * <p>This is only implemented in feature version 202101 or later. If not implemented, the call
+ * fails with {@link UnsupportedOperationException}. See
+ * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known
+ * feature versions.
+ *
+ * @param authenticationKey The dynamic authentication key for which certification and
+ * associated static
+ * authentication data is being provided.
+ * @param expirationDate The expiration date of the static authentication data.
+ * @param staticAuthData Static authentication data provided by the issuer that validates
+ * the authenticity
+ * and integrity of the credential data fields.
+ * @throws UnknownAuthenticationKeyException If the given authentication key is not recognized.
+ */
+ public void storeStaticAuthenticationData(
+ @NonNull X509Certificate authenticationKey,
+ @NonNull Instant expirationDate,
+ @NonNull byte[] staticAuthData)
+ throws UnknownAuthenticationKeyException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
* Get the number of times the dynamic authentication keys have been used.
*
* @return int array of dynamic authentication key usage counts.
*/
public @NonNull abstract int[] getAuthenticationDataUsageCount();
+
+ /**
+ * Proves ownership of a credential.
+ *
+ * <p>This method returns a COSE_Sign1 data structure signed by the CredentialKey
+ * with payload set to {@code ProofOfDeletion} as defined below.</p>
+ *
+ * <p>The returned CBOR is the following:</p>
+ * <pre>
+ * ProofOfOwnership = [
+ * "ProofOfOwnership", ; tstr
+ * tstr, ; DocType
+ * bstr, ; Challenge
+ * bool ; true if this is a test credential, should
+ * ; always be false.
+ * ]
+ * </pre>
+ *
+ * <p>This is only implemented in feature version 202101 or later. If not implemented, the call
+ * fails with {@link UnsupportedOperationException}. See
+ * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known
+ * feature versions.
+ *
+ * @param challenge is a non-empty byte array whose contents should be unique, fresh and
+ * provided by the issuing authority. The value provided is embedded in the
+ * generated CBOR and enables the issuing authority to verify that the
+ * returned proof is fresh.
+ * @return the COSE_Sign1 data structure above
+ */
+ public @NonNull byte[] proveOwnership(@NonNull byte[] challenge) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Deletes a credential.
+ *
+ * <p>This method returns a COSE_Sign1 data structure signed by the CredentialKey
+ * with payload set to {@code ProofOfDeletion} as defined below.</p>
+ *
+ * <pre>
+ * ProofOfDeletion = [
+ * "ProofOfDeletion", ; tstr
+ * tstr, ; DocType
+ * bstr, ; Challenge
+ * bool ; true if this is a test credential, should
+ * ; always be false.
+ * ]
+ * </pre>
+ *
+ * <p>This is only implemented in feature version 202101 or later. If not implemented, the call
+ * fails with {@link UnsupportedOperationException}. See
+ * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known
+ * feature versions.
+ *
+ * @param challenge is a non-empty byte array whose contents should be unique, fresh and
+ * provided by the issuing authority. The value provided is embedded in the
+ * generated CBOR and enables the issuing authority to verify that the
+ * returned proof is fresh.
+ * @return the COSE_Sign1 data structure above
+ */
+ public @NonNull byte[] delete(@NonNull byte[] challenge) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Updates the credential with new access control profiles and data items.
+ *
+ * <p>This method is similar to
+ * {@link WritableIdentityCredential#personalize(PersonalizationData)} except that it operates
+ * on an existing credential, see the documentation for that method for the format of the
+ * returned data.
+ *
+ * <p>If this call succeeds an side-effect is that all dynamic authentication keys for the
+ * credential are deleted. The application will need to use
+ * {@link #getAuthKeysNeedingCertification()} to generate replacement keys and return
+ * them for issuer certification.
+ *
+ * <p>This is only implemented in feature version 202101 or later. If not implemented, the call
+ * fails with {@link UnsupportedOperationException}. See
+ * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known
+ * feature versions.
+ *
+ * @param personalizationData The data to update, including access control profiles
+ * and data elements and their values, grouped into namespaces.
+ * @return A COSE_Sign1 data structure, see above.
+ */
+ public @NonNull byte[] update(@NonNull PersonalizationData personalizationData) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/identity/java/android/security/identity/IdentityCredentialStore.java b/identity/java/android/security/identity/IdentityCredentialStore.java
index 3843d9279900..6ccd0e892141 100644
--- a/identity/java/android/security/identity/IdentityCredentialStore.java
+++ b/identity/java/android/security/identity/IdentityCredentialStore.java
@@ -72,6 +72,17 @@ import java.lang.annotation.RetentionPolicy;
* <p>Credentials provisioned to the direct access store should <strong>always</strong> use reader
* authentication to protect data elements. The reason for this is user authentication or user
* approval of data release is not possible when the device is off.
+ *
+ * <p>The Identity Credential API is designed to be able to evolve and change over time
+ * but still provide 100% backwards compatibility. This is complicated by the fact that
+ * there may be a version skew between the API used by the application and the version
+ * implemented in secure hardware. To solve this problem, the API provides for a way
+ * for the application to query which feature version the hardware implements (if any
+ * at all) using
+ * {@link android.content.pm#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} and
+ * {@link android.content.pm#FEATURE_IDENTITY_CREDENTIAL_HARDWARE_DIRECT_ACCESS}.
+ * Methods which only work on certain feature versions are clearly documented as
+ * such.
*/
public abstract class IdentityCredentialStore {
IdentityCredentialStore() {}
@@ -193,7 +204,9 @@ public abstract class IdentityCredentialStore {
* @param credentialName the name of the credential to delete.
* @return {@code null} if the credential was not found, the COSE_Sign1 data structure above
* if the credential was found and deleted.
+ * @deprecated Use {@link IdentityCredential#delete(byte[])} instead.
*/
+ @Deprecated
public abstract @Nullable byte[] deleteCredentialByName(@NonNull String credentialName);
/** @hide */
@@ -201,5 +214,4 @@ public abstract class IdentityCredentialStore {
@Retention(RetentionPolicy.SOURCE)
public @interface Ciphersuite {
}
-
}
diff --git a/keystore/java/android/security/AuthTokenUtils.java b/keystore/java/android/security/AuthTokenUtils.java
new file mode 100644
index 000000000000..e6376000673b
--- /dev/null
+++ b/keystore/java/android/security/AuthTokenUtils.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.annotation.NonNull;
+import android.hardware.security.keymint.HardwareAuthToken;
+import android.hardware.security.secureclock.Timestamp;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * @hide This Utils class provides method(s) for AuthToken conversion.
+ */
+public class AuthTokenUtils {
+
+ private AuthTokenUtils(){
+ }
+
+ /**
+ * Build a HardwareAuthToken from a byte array
+ * @param array byte array representing an auth token
+ * @return HardwareAuthToken representation of an auth token
+ */
+ public static @NonNull HardwareAuthToken toHardwareAuthToken(@NonNull byte[] array) {
+ final HardwareAuthToken hardwareAuthToken = new HardwareAuthToken();
+
+ // First byte is version, which does not exist in HardwareAuthToken anymore
+ // Next 8 bytes is the challenge.
+ hardwareAuthToken.challenge =
+ ByteBuffer.wrap(array, 1, 8).order(ByteOrder.nativeOrder()).getLong();
+
+ // Next 8 bytes is the userId
+ hardwareAuthToken.userId =
+ ByteBuffer.wrap(array, 9, 8).order(ByteOrder.nativeOrder()).getLong();
+
+ // Next 8 bytes is the authenticatorId.
+ hardwareAuthToken.authenticatorId =
+ ByteBuffer.wrap(array, 17, 8).order(ByteOrder.nativeOrder()).getLong();
+
+ // while the other fields are in machine byte order, authenticatorType and timestamp
+ // are in network byte order.
+ // Next 4 bytes is the authenticatorType.
+ hardwareAuthToken.authenticatorType =
+ ByteBuffer.wrap(array, 25, 4).order(ByteOrder.BIG_ENDIAN).getInt();
+ // Next 8 bytes is the timestamp.
+ final Timestamp timestamp = new Timestamp();
+ timestamp.milliSeconds =
+ ByteBuffer.wrap(array, 29, 8).order(ByteOrder.BIG_ENDIAN).getLong();
+ hardwareAuthToken.timestamp = timestamp;
+
+ // Last 32 bytes is the mac, 37:69
+ hardwareAuthToken.mac = new byte[32];
+ System.arraycopy(array, 37 /* srcPos */,
+ hardwareAuthToken.mac,
+ 0 /* destPos */,
+ 32 /* length */);
+
+ return hardwareAuthToken;
+ }
+}
diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java
new file mode 100644
index 000000000000..21d23b1b2575
--- /dev/null
+++ b/keystore/java/android/security/Authorization.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.security.keymint.HardwareAuthToken;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
+import android.security.authorization.IKeystoreAuthorization;
+import android.security.authorization.LockScreenEvent;
+import android.system.keystore2.ResponseCode;
+import android.util.Log;
+
+/**
+ * @hide This is the client side for IKeystoreAuthorization AIDL.
+ * It shall only be used by biometric authentication providers and Gatekeeper.
+ */
+public class Authorization {
+ private static final String TAG = "KeystoreAuthorization";
+ private static IKeystoreAuthorization sIKeystoreAuthorization;
+
+ public static final int SYSTEM_ERROR = ResponseCode.SYSTEM_ERROR;
+
+ public Authorization() {
+ sIKeystoreAuthorization = null;
+ }
+
+ private static synchronized IKeystoreAuthorization getService() {
+ if (sIKeystoreAuthorization == null) {
+ sIKeystoreAuthorization = IKeystoreAuthorization.Stub.asInterface(
+ ServiceManager.checkService("android.security.authorization"));
+ }
+ return sIKeystoreAuthorization;
+ }
+
+ /**
+ * Adds an auth token to keystore2.
+ *
+ * @param authToken created by Android authenticators.
+ * @return 0 if successful or {@code ResponseCode.SYSTEM_ERROR}.
+ */
+ public int addAuthToken(@NonNull HardwareAuthToken authToken) {
+ if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
+ try {
+ getService().addAuthToken(authToken);
+ return 0;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Can not connect to keystore", e);
+ return SYSTEM_ERROR;
+ } catch (ServiceSpecificException e) {
+ return e.errorCode;
+ }
+ }
+
+ /**
+ * Add an auth token to Keystore 2.0 in the legacy serialized auth token format.
+ * @param authToken
+ * @return 0 if successful or a {@code ResponseCode}.
+ */
+ public int addAuthToken(@NonNull byte[] authToken) {
+ return addAuthToken(AuthTokenUtils.toHardwareAuthToken(authToken));
+ }
+
+ /**
+ * Informs keystore2 about lock screen event.
+ *
+ * @param locked - whether it is a lock (true) or unlock (false) event
+ * @param syntheticPassword - if it is an unlock event with the password, pass the synthetic
+ * password provided by the LockSettingService
+ *
+ * @return 0 if successful or a {@code ResponseCode}.
+ */
+ public int onLockScreenEvent(@NonNull boolean locked, @NonNull int userId,
+ @Nullable byte[] syntheticPassword) {
+ if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
+ try {
+ if (locked) {
+ getService().onLockScreenEvent(LockScreenEvent.LOCK, userId, null);
+ } else {
+ getService().onLockScreenEvent(LockScreenEvent.UNLOCK, userId, syntheticPassword);
+ }
+ return 0;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Can not connect to keystore", e);
+ return SYSTEM_ERROR;
+ } catch (ServiceSpecificException e) {
+ return e.errorCode;
+ }
+ }
+
+}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index c70c986fcd6b..4a67135227dd 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -996,6 +996,7 @@ public class KeyStore {
*/
public int addAuthToken(byte[] authToken) {
try {
+ new Authorization().addAuthToken(authToken);
return mBinder.addAuthToken(authToken);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java
index 92d87aa0fed6..f7477bf92c81 100644
--- a/keystore/java/android/security/KeyStore2.java
+++ b/keystore/java/android/security/KeyStore2.java
@@ -23,6 +23,7 @@ import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
+import android.security.keymaster.KeymasterDefs;
import android.system.keystore2.IKeystoreService;
import android.system.keystore2.KeyDescriptor;
import android.system.keystore2.KeyEntryResponse;
@@ -107,7 +108,7 @@ public class KeyStore2 {
return request.execute(service);
} catch (ServiceSpecificException e) {
Log.e(TAG, "KeyStore exception", e);
- throw new KeyStoreException(e.errorCode, "");
+ throw getKeyStoreException(e.errorCode);
} catch (RemoteException e) {
if (firstTry) {
Log.w(TAG, "Looks like we may have lost connection to the Keystore "
@@ -274,4 +275,40 @@ public class KeyStore2 {
}
}
+ static KeyStoreException getKeyStoreException(int errorCode) {
+ if (errorCode > 0) {
+ // KeyStore layer error
+ switch (errorCode) {
+ case ResponseCode.LOCKED:
+ return new KeyStoreException(errorCode, "User authentication required");
+ case ResponseCode.UNINITIALIZED:
+ return new KeyStoreException(errorCode, "Keystore not initialized");
+ case ResponseCode.SYSTEM_ERROR:
+ return new KeyStoreException(errorCode, "System error");
+ case ResponseCode.PERMISSION_DENIED:
+ return new KeyStoreException(errorCode, "Permission denied");
+ case ResponseCode.KEY_NOT_FOUND:
+ return new KeyStoreException(errorCode, "Key not found");
+ case ResponseCode.VALUE_CORRUPTED:
+ return new KeyStoreException(errorCode, "Key blob corrupted");
+ case ResponseCode.KEY_PERMANENTLY_INVALIDATED:
+ return new KeyStoreException(errorCode, "Key permanently invalidated");
+ default:
+ return new KeyStoreException(errorCode, String.valueOf(errorCode));
+ }
+ } else {
+ // Keymaster layer error
+ switch (errorCode) {
+ case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
+ // The name of this parameter significantly differs between Keymaster and
+ // framework APIs. Use the framework wording to make life easier for developers.
+ return new KeyStoreException(errorCode,
+ "Invalid user authentication validity duration");
+ default:
+ return new KeyStoreException(errorCode,
+ KeymasterDefs.getErrorMessage(errorCode));
+ }
+ }
+ }
+
}
diff --git a/keystore/java/android/security/KeyStoreOperation.java b/keystore/java/android/security/KeyStoreOperation.java
index 7ea9e1438845..a6552dddc630 100644
--- a/keystore/java/android/security/KeyStoreOperation.java
+++ b/keystore/java/android/security/KeyStoreOperation.java
@@ -73,8 +73,7 @@ public class KeyStoreOperation {
);
}
default:
- // TODO Human readable string. Use something like KeyStore.getKeyStoreException
- throw new KeyStoreException(e.errorCode, "");
+ throw KeyStore2.getKeyStoreException(e.errorCode);
}
} catch (RemoteException e) {
// Log exception and report invalid operation handle.
diff --git a/keystore/java/android/security/KeyStoreSecurityLevel.java b/keystore/java/android/security/KeyStoreSecurityLevel.java
index 3ef4aa5b7ec3..372add9b7ecb 100644
--- a/keystore/java/android/security/KeyStoreSecurityLevel.java
+++ b/keystore/java/android/security/KeyStoreSecurityLevel.java
@@ -52,7 +52,7 @@ public class KeyStoreSecurityLevel {
try {
return request.execute();
} catch (ServiceSpecificException e) {
- throw new KeyStoreException(e.errorCode, "");
+ throw KeyStore2.getKeyStoreException(e.errorCode);
} catch (RemoteException e) {
// Log exception and report invalid operation handle.
// This should prompt the caller drop the reference to this operation and retry.
@@ -96,25 +96,26 @@ public class KeyStoreSecurityLevel {
} catch (ServiceSpecificException e) {
switch (e.errorCode) {
case ResponseCode.BACKEND_BUSY: {
+ long backOffHint = (long) (Math.random() * 80 + 20);
if (CompatChanges.isChangeEnabled(
KeyStore2.KEYSTORE_OPERATION_CREATION_MAY_FAIL)) {
// Starting with Android S we inform the caller about the
// backend being busy.
- throw new BackendBusyException();
+ throw new BackendBusyException(backOffHint);
} else {
// Before Android S operation creation must always succeed. So we
// just have to retry. We do so with a randomized back-off between
- // 50 and 250ms.
+ // 20 and 100ms.
// It is a little awkward that we cannot break out of this loop
// by interrupting this thread. But that is the expected behavior.
// There is some comfort in the fact that interrupting a thread
// also does not unblock a thread waiting for a binder transaction.
- interruptedPreservingSleep((long) (Math.random() * 200 + 50));
+ interruptedPreservingSleep(backOffHint);
}
break;
}
default:
- throw new KeyStoreException(e.errorCode, "");
+ throw KeyStore2.getKeyStoreException(e.errorCode);
}
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
diff --git a/keystore/java/android/security/keystore/BackendBusyException.java b/keystore/java/android/security/keystore/BackendBusyException.java
index 1a88469d7e54..a813e939a720 100644
--- a/keystore/java/android/security/keystore/BackendBusyException.java
+++ b/keystore/java/android/security/keystore/BackendBusyException.java
@@ -16,37 +16,66 @@
package android.security.keystore;
+import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
import java.security.ProviderException;
/**
* Indicates a transient error that prevented a key operation from being created.
- * Callers should try again with a back-off period of 10-30 milliseconds.
+ * Callers should try again with a back-off period of {@link #getBackOffHintMillis()}
+ * milliseconds.
*/
public class BackendBusyException extends ProviderException {
+ private final long mBackOffHintMillis;
+
/**
* Constructs a new {@code BackendBusyException} without detail message and cause.
+ *
*/
- public BackendBusyException() {
+ public BackendBusyException(@DurationMillisLong long backOffHintMillis) {
super("The keystore backend has no operation slots available. Retry later.");
+ if (backOffHintMillis < 0) {
+ throw new IllegalArgumentException("Back-off hint cannot be negative.");
+ }
+ mBackOffHintMillis = backOffHintMillis;
}
/**
* Constructs a new {@code BackendBusyException} with the provided detail message and
* no cause.
*/
- public BackendBusyException(@NonNull String message) {
+ public BackendBusyException(@DurationMillisLong long backOffHintMillis,
+ @NonNull String message) {
super(message);
+ if (backOffHintMillis < 0) {
+ throw new IllegalArgumentException("Back-off hint cannot be negative.");
+ }
+ mBackOffHintMillis = backOffHintMillis;
}
/**
* Constructs a new {@code BackendBusyException} with the provided detail message and
* cause.
*/
- public BackendBusyException(@NonNull String message, @NonNull Throwable cause) {
+ public BackendBusyException(@DurationMillisLong long backOffHintMillis,
+ @NonNull String message, @NonNull Throwable cause) {
super(message, cause);
+ if (backOffHintMillis < 0) {
+ throw new IllegalArgumentException("Back-off hint cannot be negative.");
+ }
+ mBackOffHintMillis = backOffHintMillis;
}
+ /**
+ * When retrying to start a Keystore operation after receiving this exception, this can be
+ * used to determine how long to wait before retrying. It is not guaranteed that the operation
+ * will succeeds after this time. Multiple retries may be necessary if the system is congested.
+ *
+ * @return Number of milliseconds to back off before retrying.
+ */
+ public @DurationMillisLong long getBackOffHintMillis() {
+ return mBackOffHintMillis;
+ }
}
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index 5928540b19bf..014d6882be8d 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -67,6 +67,7 @@ public abstract class KeyProperties {
PURPOSE_SIGN,
PURPOSE_VERIFY,
PURPOSE_WRAP_KEY,
+ PURPOSE_AGREE_KEY,
})
public @interface PurposeEnum {}
@@ -96,6 +97,11 @@ public abstract class KeyProperties {
public static final int PURPOSE_WRAP_KEY = 1 << 5;
/**
+ * Purpose of key: creating a shared ECDH secret through key agreement.
+ */
+ public static final int PURPOSE_AGREE_KEY = 1 << 6;
+
+ /**
* @hide
*/
public static abstract class Purpose {
@@ -113,6 +119,8 @@ public abstract class KeyProperties {
return KeymasterDefs.KM_PURPOSE_VERIFY;
case PURPOSE_WRAP_KEY:
return KeymasterDefs.KM_PURPOSE_WRAP;
+ case PURPOSE_AGREE_KEY:
+ return KeymasterDefs.KM_PURPOSE_AGREE_KEY;
default:
throw new IllegalArgumentException("Unknown purpose: " + purpose);
}
@@ -130,6 +138,8 @@ public abstract class KeyProperties {
return PURPOSE_VERIFY;
case KeymasterDefs.KM_PURPOSE_WRAP:
return PURPOSE_WRAP_KEY;
+ case KeymasterDefs.KM_PURPOSE_AGREE_KEY:
+ return PURPOSE_AGREE_KEY;
default:
throw new IllegalArgumentException("Unknown purpose: " + purpose);
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java
index 6ddaa704afa8..b631999c2c54 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java
@@ -38,9 +38,10 @@ public class AndroidKeyStoreECPublicKey extends AndroidKeyStorePublicKey impleme
public AndroidKeyStoreECPublicKey(@NonNull KeyDescriptor descriptor,
@NonNull KeyMetadata metadata,
+ @NonNull byte[] x509EncodedForm,
@NonNull KeyStoreSecurityLevel securityLevel,
@NonNull ECParameterSpec params, @NonNull ECPoint w) {
- super(descriptor, metadata, KeyProperties.KEY_ALGORITHM_EC, securityLevel);
+ super(descriptor, metadata, x509EncodedForm, KeyProperties.KEY_ALGORITHM_EC, securityLevel);
mParams = params;
mW = w;
}
@@ -48,7 +49,7 @@ public class AndroidKeyStoreECPublicKey extends AndroidKeyStorePublicKey impleme
public AndroidKeyStoreECPublicKey(@NonNull KeyDescriptor descriptor,
@NonNull KeyMetadata metadata,
@NonNull KeyStoreSecurityLevel securityLevel, @NonNull ECPublicKey info) {
- this(descriptor, metadata, securityLevel, info.getParams(), info.getW());
+ this(descriptor, metadata, info.getEncoded(), securityLevel, info.getParams(), info.getW());
if (!"X.509".equalsIgnoreCase(info.getFormat())) {
throw new IllegalArgumentException(
"Unsupported key export format: " + info.getFormat());
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java
new file mode 100644
index 000000000000..fc963a88c4d1
--- /dev/null
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2021 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.security.keystore2;
+
+import android.hardware.security.keymint.Algorithm;
+import android.hardware.security.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyPurpose;
+import android.hardware.security.keymint.Tag;
+import android.security.KeyStoreException;
+import android.security.KeyStoreOperation;
+import android.security.keystore.KeyStoreCryptoOperation;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.ProviderException;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.crypto.KeyAgreementSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * {@link KeyAgreementSpi} which provides an ECDH implementation backed by Android KeyStore.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreKeyAgreementSpi extends KeyAgreementSpi
+ implements KeyStoreCryptoOperation {
+
+ private static final String TAG = "AndroidKeyStoreKeyAgreementSpi";
+
+ /**
+ * ECDH implementation.
+ *
+ * @hide
+ */
+ public static class ECDH extends AndroidKeyStoreKeyAgreementSpi {
+ public ECDH() {
+ super(Algorithm.EC);
+ }
+ }
+
+ private final int mKeymintAlgorithm;
+
+ // Fields below are populated by engineInit and should be preserved after engineDoFinal.
+ private AndroidKeyStorePrivateKey mKey;
+ private PublicKey mOtherPartyKey;
+
+ // Fields below are reset when engineDoFinal succeeds.
+ private KeyStoreOperation mOperation;
+ private long mOperationHandle;
+
+ protected AndroidKeyStoreKeyAgreementSpi(int keymintAlgorithm) {
+ resetAll();
+
+ mKeymintAlgorithm = keymintAlgorithm;
+ }
+
+ @Override
+ protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException {
+ resetAll();
+
+ if (key == null) {
+ throw new InvalidKeyException("key == null");
+ } else if (!(key instanceof AndroidKeyStorePrivateKey)) {
+ throw new InvalidKeyException(
+ "Only Android KeyStore private keys supported. Key: " + key);
+ }
+ // Checking the correct KEY_PURPOSE and algorithm is done by the Keymint implementation in
+ // ensureKeystoreOperationInitialized() below.
+ mKey = (AndroidKeyStorePrivateKey) key;
+
+ boolean success = false;
+ try {
+ ensureKeystoreOperationInitialized();
+ success = true;
+ } finally {
+ if (!success) {
+ resetAll();
+ }
+ }
+ }
+
+ @Override
+ protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (params != null) {
+ throw new InvalidAlgorithmParameterException(
+ "Unsupported algorithm parameters: " + params);
+ }
+ engineInit(key, random);
+ }
+
+ @Override
+ protected Key engineDoPhase(Key key, boolean lastPhase)
+ throws InvalidKeyException, IllegalStateException {
+ ensureKeystoreOperationInitialized();
+
+ if (key == null) {
+ throw new InvalidKeyException("key == null");
+ } else if (!(key instanceof PublicKey)) {
+ throw new InvalidKeyException("Only public keys supported. Key: " + key);
+ } else if (!lastPhase) {
+ throw new IllegalStateException(
+ "Only one other party supported. lastPhase must be set to true.");
+ } else if (mOtherPartyKey != null) {
+ throw new IllegalStateException(
+ "Only one other party supported. doPhase() must only be called exactly once.");
+ }
+ // The other party key will be passed as part of the doFinal() call, to prevent an
+ // additional IPC.
+ mOtherPartyKey = (PublicKey) key;
+
+ return null; // No intermediate key
+ }
+
+ @Override
+ protected byte[] engineGenerateSecret() throws IllegalStateException {
+ try {
+ ensureKeystoreOperationInitialized();
+ } catch (InvalidKeyException e) {
+ throw new IllegalStateException("Not initialized", e);
+ }
+
+ if (mOtherPartyKey == null) {
+ throw new IllegalStateException("Other party key not provided. Call doPhase() first.");
+ }
+ byte[] otherPartyKeyEncoded = mOtherPartyKey.getEncoded();
+
+ try {
+ return mOperation.finish(otherPartyKeyEncoded, null);
+ } catch (KeyStoreException e) {
+ throw new ProviderException("Keystore operation failed", e);
+ } finally {
+ resetWhilePreservingInitState();
+ }
+ }
+
+ @Override
+ protected SecretKey engineGenerateSecret(String algorithm)
+ throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException {
+ byte[] generatedSecret = engineGenerateSecret();
+
+ return new SecretKeySpec(generatedSecret, algorithm);
+ }
+
+ @Override
+ protected int engineGenerateSecret(byte[] sharedSecret, int offset)
+ throws IllegalStateException, ShortBufferException {
+ byte[] generatedSecret = engineGenerateSecret();
+
+ if (generatedSecret.length > sharedSecret.length - offset) {
+ throw new ShortBufferException("Needed: " + generatedSecret.length);
+ }
+ System.arraycopy(generatedSecret, 0, sharedSecret, offset, generatedSecret.length);
+ return generatedSecret.length;
+ }
+
+ @Override
+ public long getOperationHandle() {
+ return mOperationHandle;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ resetAll();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private void resetWhilePreservingInitState() {
+ KeyStoreCryptoOperationUtils.abortOperation(mOperation);
+ mOperationHandle = 0;
+ mOperation = null;
+ mOtherPartyKey = null;
+ }
+
+ private void resetAll() {
+ resetWhilePreservingInitState();
+ mKey = null;
+ }
+
+ private void ensureKeystoreOperationInitialized()
+ throws InvalidKeyException, IllegalStateException {
+ if (mKey == null) {
+ throw new IllegalStateException("Not initialized");
+ }
+ if (mOperation != null) {
+ return;
+ }
+
+ // We don't need to explicitly pass in any other parameters here, as they're part of the
+ // private key that is available to Keymint.
+ List<KeyParameter> parameters = new ArrayList<>();
+ parameters.add(KeyStore2ParameterUtils.makeEnum(
+ Tag.PURPOSE, KeyPurpose.AGREE_KEY
+ ));
+
+ try {
+ mOperation =
+ mKey.getSecurityLevel().createOperation(mKey.getKeyIdDescriptor(), parameters);
+ } catch (KeyStoreException keyStoreException) {
+ // If necessary, throw an exception due to KeyStore operation having failed.
+ InvalidKeyException e =
+ KeyStoreCryptoOperationUtils.getInvalidKeyException(mKey, keyStoreException);
+ if (e != null) {
+ throw e;
+ }
+ }
+
+ // Set the operation handle. This will be a random number, or the operation challenge if
+ // user authentication is required. If we got a challenge we check if the authorization can
+ // possibly succeed.
+ mOperationHandle =
+ KeyStoreCryptoOperationUtils.getOrMakeOperationChallenge(mOperation, mKey);
+ }
+}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index 403da189262d..164bc8669525 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -94,6 +94,9 @@ public class AndroidKeyStoreProvider extends Provider {
put("KeyGenerator.DESede", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$DESede");
}
+ // javax.crypto.KeyAgreement
+ put("KeyAgreement.ECDH", PACKAGE_NAME + ".AndroidKeyStoreKeyAgreementSpi$ECDH");
+
// java.security.SecretKeyFactory
putSecretKeyFactoryImpl("AES");
if (supports3DES) {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java
index 49dd77e3a3db..db3e567cb6b4 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java
@@ -32,13 +32,15 @@ import java.security.PublicKey;
public abstract class AndroidKeyStorePublicKey extends AndroidKeyStoreKey implements PublicKey {
private final byte[] mCertificate;
private final byte[] mCertificateChain;
+ private final byte[] mEncoded;
public AndroidKeyStorePublicKey(@NonNull KeyDescriptor descriptor,
- @NonNull KeyMetadata metadata, @NonNull String algorithm,
- @NonNull KeyStoreSecurityLevel securityLevel) {
+ @NonNull KeyMetadata metadata, @NonNull byte[] x509EncodedForm,
+ @NonNull String algorithm, @NonNull KeyStoreSecurityLevel securityLevel) {
super(descriptor, metadata.key.nspace, metadata.authorizations, algorithm, securityLevel);
mCertificate = metadata.certificate;
mCertificateChain = metadata.certificateChain;
+ mEncoded = x509EncodedForm;
}
abstract AndroidKeyStorePrivateKey getPrivateKey();
@@ -50,7 +52,7 @@ public abstract class AndroidKeyStorePublicKey extends AndroidKeyStoreKey implem
@Override
public byte[] getEncoded() {
- return ArrayUtils.cloneIfNotEmpty(mCertificate);
+ return ArrayUtils.cloneIfNotEmpty(mEncoded);
}
@Override
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSAPublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSAPublicKey.java
index b578ea9baa06..9fe6cf3c113f 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSAPublicKey.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSAPublicKey.java
@@ -36,9 +36,11 @@ public class AndroidKeyStoreRSAPublicKey extends AndroidKeyStorePublicKey implem
public AndroidKeyStoreRSAPublicKey(@NonNull KeyDescriptor descriptor,
@NonNull KeyMetadata metadata,
+ @NonNull byte[] x509EncodedForm,
@NonNull KeyStoreSecurityLevel securityLevel, @NonNull BigInteger modulus,
@NonNull BigInteger publicExponent) {
- super(descriptor, metadata, KeyProperties.KEY_ALGORITHM_RSA, securityLevel);
+ super(descriptor, metadata, x509EncodedForm, KeyProperties.KEY_ALGORITHM_RSA,
+ securityLevel);
mModulus = modulus;
mPublicExponent = publicExponent;
}
@@ -46,7 +48,8 @@ public class AndroidKeyStoreRSAPublicKey extends AndroidKeyStorePublicKey implem
public AndroidKeyStoreRSAPublicKey(@NonNull KeyDescriptor descriptor,
@NonNull KeyMetadata metadata,
@NonNull KeyStoreSecurityLevel securityLevel, @NonNull RSAPublicKey info) {
- this(descriptor, metadata, securityLevel, info.getModulus(), info.getPublicExponent());
+ this(descriptor, metadata, info.getEncoded(), securityLevel, info.getModulus(),
+ info.getPublicExponent());
if (!"X.509".equalsIgnoreCase(info.getFormat())) {
throw new IllegalArgumentException(
"Unsupported key export format: " + info.getFormat());
diff --git a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java
index 6c733ba712d5..33e8dede9f5c 100644
--- a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java
+++ b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java
@@ -139,7 +139,9 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS
int inputConsumed = ArrayUtils.copy(input, inputOffset, mChunk, mChunkLength,
inputLength);
inputLength -= inputConsumed;
- inputOffset += inputOffset;
+ inputOffset += inputConsumed;
+ mChunkLength += inputConsumed;
+ if (mChunkLength < mChunkSizeMax) return output;
byte[] o = mKeyStoreStream.update(mChunk);
if (o != null) {
output = ArrayUtils.concat(output, o);
diff --git a/libs/androidfw/LocaleDataTables.cpp b/libs/androidfw/LocaleDataTables.cpp
index 6c6c5c9f4e22..8a10599b498f 100644
--- a/libs/androidfw/LocaleDataTables.cpp
+++ b/libs/androidfw/LocaleDataTables.cpp
@@ -64,42 +64,43 @@ const char SCRIPT_CODES[][4] = {
/* 60 */ {'N', 'k', 'o', 'o'},
/* 61 */ {'N', 's', 'h', 'u'},
/* 62 */ {'O', 'g', 'a', 'm'},
- /* 63 */ {'O', 'r', 'k', 'h'},
- /* 64 */ {'O', 'r', 'y', 'a'},
- /* 65 */ {'O', 's', 'g', 'e'},
- /* 66 */ {'P', 'a', 'u', 'c'},
- /* 67 */ {'P', 'h', 'l', 'i'},
- /* 68 */ {'P', 'h', 'n', 'x'},
- /* 69 */ {'P', 'l', 'r', 'd'},
- /* 70 */ {'P', 'r', 't', 'i'},
- /* 71 */ {'R', 'u', 'n', 'r'},
- /* 72 */ {'S', 'a', 'm', 'r'},
- /* 73 */ {'S', 'a', 'r', 'b'},
- /* 74 */ {'S', 'a', 'u', 'r'},
- /* 75 */ {'S', 'g', 'n', 'w'},
- /* 76 */ {'S', 'i', 'n', 'h'},
- /* 77 */ {'S', 'o', 'g', 'd'},
- /* 78 */ {'S', 'o', 'r', 'a'},
- /* 79 */ {'S', 'o', 'y', 'o'},
- /* 80 */ {'S', 'y', 'r', 'c'},
- /* 81 */ {'T', 'a', 'l', 'e'},
- /* 82 */ {'T', 'a', 'l', 'u'},
- /* 83 */ {'T', 'a', 'm', 'l'},
- /* 84 */ {'T', 'a', 'n', 'g'},
- /* 85 */ {'T', 'a', 'v', 't'},
- /* 86 */ {'T', 'e', 'l', 'u'},
- /* 87 */ {'T', 'f', 'n', 'g'},
- /* 88 */ {'T', 'h', 'a', 'a'},
- /* 89 */ {'T', 'h', 'a', 'i'},
- /* 90 */ {'T', 'i', 'b', 't'},
- /* 91 */ {'U', 'g', 'a', 'r'},
- /* 92 */ {'V', 'a', 'i', 'i'},
- /* 93 */ {'W', 'c', 'h', 'o'},
- /* 94 */ {'X', 'p', 'e', 'o'},
- /* 95 */ {'X', 's', 'u', 'x'},
- /* 96 */ {'Y', 'i', 'i', 'i'},
- /* 97 */ {'~', '~', '~', 'A'},
- /* 98 */ {'~', '~', '~', 'B'},
+ /* 63 */ {'O', 'l', 'c', 'k'},
+ /* 64 */ {'O', 'r', 'k', 'h'},
+ /* 65 */ {'O', 'r', 'y', 'a'},
+ /* 66 */ {'O', 's', 'g', 'e'},
+ /* 67 */ {'P', 'a', 'u', 'c'},
+ /* 68 */ {'P', 'h', 'l', 'i'},
+ /* 69 */ {'P', 'h', 'n', 'x'},
+ /* 70 */ {'P', 'l', 'r', 'd'},
+ /* 71 */ {'P', 'r', 't', 'i'},
+ /* 72 */ {'R', 'u', 'n', 'r'},
+ /* 73 */ {'S', 'a', 'm', 'r'},
+ /* 74 */ {'S', 'a', 'r', 'b'},
+ /* 75 */ {'S', 'a', 'u', 'r'},
+ /* 76 */ {'S', 'g', 'n', 'w'},
+ /* 77 */ {'S', 'i', 'n', 'h'},
+ /* 78 */ {'S', 'o', 'g', 'd'},
+ /* 79 */ {'S', 'o', 'r', 'a'},
+ /* 80 */ {'S', 'o', 'y', 'o'},
+ /* 81 */ {'S', 'y', 'r', 'c'},
+ /* 82 */ {'T', 'a', 'l', 'e'},
+ /* 83 */ {'T', 'a', 'l', 'u'},
+ /* 84 */ {'T', 'a', 'm', 'l'},
+ /* 85 */ {'T', 'a', 'n', 'g'},
+ /* 86 */ {'T', 'a', 'v', 't'},
+ /* 87 */ {'T', 'e', 'l', 'u'},
+ /* 88 */ {'T', 'f', 'n', 'g'},
+ /* 89 */ {'T', 'h', 'a', 'a'},
+ /* 90 */ {'T', 'h', 'a', 'i'},
+ /* 91 */ {'T', 'i', 'b', 't'},
+ /* 92 */ {'U', 'g', 'a', 'r'},
+ /* 93 */ {'V', 'a', 'i', 'i'},
+ /* 94 */ {'W', 'c', 'h', 'o'},
+ /* 95 */ {'X', 'p', 'e', 'o'},
+ /* 96 */ {'X', 's', 'u', 'x'},
+ /* 97 */ {'Y', 'i', 'i', 'i'},
+ /* 98 */ {'~', '~', '~', 'A'},
+ /* 99 */ {'~', '~', '~', 'B'},
};
@@ -120,7 +121,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x80600000u, 46u}, // ada -> Latn
{0x90600000u, 46u}, // ade -> Latn
{0xA4600000u, 46u}, // adj -> Latn
- {0xBC600000u, 90u}, // adp -> Tibt
+ {0xBC600000u, 91u}, // adp -> Tibt
{0xE0600000u, 17u}, // ady -> Cyrl
{0xE4600000u, 46u}, // adz -> Latn
{0x61650000u, 4u}, // ae -> Avst
@@ -138,7 +139,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xB8E00000u, 0u}, // aho -> Ahom
{0x99200000u, 46u}, // ajg -> Latn
{0x616B0000u, 46u}, // ak -> Latn
- {0xA9400000u, 95u}, // akk -> Xsux
+ {0xA9400000u, 96u}, // akk -> Xsux
{0x81600000u, 46u}, // ala -> Latn
{0xA1600000u, 46u}, // ali -> Latn
{0xB5600000u, 46u}, // aln -> Latn
@@ -163,7 +164,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xC9E00000u, 46u}, // aps -> Latn
{0xE5E00000u, 46u}, // apz -> Latn
{0x61720000u, 1u}, // ar -> Arab
- {0x61725842u, 98u}, // ar-XB -> ~~~B
+ {0x61725842u, 99u}, // ar-XB -> ~~~B
{0x8A200000u, 2u}, // arc -> Armi
{0x9E200000u, 46u}, // arh -> Latn
{0xB6200000u, 46u}, // arn -> Latn
@@ -174,7 +175,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xE6200000u, 1u}, // arz -> Arab
{0x61730000u, 7u}, // as -> Beng
{0x82400000u, 46u}, // asa -> Latn
- {0x92400000u, 75u}, // ase -> Sgnw
+ {0x92400000u, 76u}, // ase -> Sgnw
{0x9A400000u, 46u}, // asg -> Latn
{0xBA400000u, 46u}, // aso -> Latn
{0xCE400000u, 46u}, // ast -> Latn
@@ -231,7 +232,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xDC810000u, 46u}, // bex -> Latn
{0xE4810000u, 46u}, // bez -> Latn
{0x8CA10000u, 46u}, // bfd -> Latn
- {0xC0A10000u, 83u}, // bfq -> Taml
+ {0xC0A10000u, 84u}, // bfq -> Taml
{0xCCA10000u, 1u}, // bft -> Arab
{0xE0A10000u, 18u}, // bfy -> Deva
{0x62670000u, 17u}, // bg -> Cyrl
@@ -265,7 +266,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xC1410000u, 46u}, // bkq -> Latn
{0xD1410000u, 46u}, // bku -> Latn
{0xD5410000u, 46u}, // bkv -> Latn
- {0xCD610000u, 85u}, // blt -> Tavt
+ {0xCD610000u, 86u}, // blt -> Tavt
{0x626D0000u, 46u}, // bm -> Latn
{0x9D810000u, 46u}, // bmh -> Latn
{0xA9810000u, 46u}, // bmk -> Latn
@@ -275,7 +276,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x99A10000u, 46u}, // bng -> Latn
{0xB1A10000u, 46u}, // bnm -> Latn
{0xBDA10000u, 46u}, // bnp -> Latn
- {0x626F0000u, 90u}, // bo -> Tibt
+ {0x626F0000u, 91u}, // bo -> Tibt
{0xA5C10000u, 46u}, // boj -> Latn
{0xB1C10000u, 46u}, // bom -> Latn
{0xB5C10000u, 46u}, // bon -> Latn
@@ -322,6 +323,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x9F210000u, 46u}, // bzh -> Latn
{0xDB210000u, 46u}, // bzw -> Latn
{0x63610000u, 46u}, // ca -> Latn
+ {0x8C020000u, 46u}, // cad -> Latn
{0xB4020000u, 46u}, // can -> Latn
{0xA4220000u, 46u}, // cbj -> Latn
{0x9C420000u, 46u}, // cch -> Latn
@@ -346,7 +348,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xE1420000u, 46u}, // cky -> Latn
{0x81620000u, 46u}, // cla -> Latn
{0x91820000u, 46u}, // cme -> Latn
- {0x99820000u, 79u}, // cmg -> Soyo
+ {0x99820000u, 80u}, // cmg -> Soyo
{0x636F0000u, 46u}, // co -> Latn
{0xBDC20000u, 15u}, // cop -> Copt
{0xC9E20000u, 46u}, // cps -> Latn
@@ -360,7 +362,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x63730000u, 46u}, // cs -> Latn
{0x86420000u, 46u}, // csb -> Latn
{0xDA420000u, 10u}, // csw -> Cans
- {0x8E620000u, 66u}, // ctd -> Pauc
+ {0x8E620000u, 67u}, // ctd -> Pauc
{0x63750000u, 17u}, // cu -> Cyrl
{0x63760000u, 17u}, // cv -> Cyrl
{0x63790000u, 46u}, // cy -> Latn
@@ -389,7 +391,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x91230000u, 46u}, // dje -> Latn
{0xA5A30000u, 46u}, // dnj -> Latn
{0x85C30000u, 46u}, // dob -> Latn
- {0xA1C30000u, 1u}, // doi -> Arab
+ {0xA1C30000u, 18u}, // doi -> Deva
{0xBDC30000u, 46u}, // dop -> Latn
{0xD9C30000u, 46u}, // dow -> Latn
{0x9E230000u, 56u}, // drh -> Mong
@@ -404,12 +406,12 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x8A830000u, 46u}, // duc -> Latn
{0x8E830000u, 46u}, // dud -> Latn
{0x9A830000u, 46u}, // dug -> Latn
- {0x64760000u, 88u}, // dv -> Thaa
+ {0x64760000u, 89u}, // dv -> Thaa
{0x82A30000u, 46u}, // dva -> Latn
{0xDAC30000u, 46u}, // dww -> Latn
{0xBB030000u, 46u}, // dyo -> Latn
{0xD3030000u, 46u}, // dyu -> Latn
- {0x647A0000u, 90u}, // dz -> Tibt
+ {0x647A0000u, 91u}, // dz -> Tibt
{0x9B230000u, 46u}, // dzg -> Latn
{0xD0240000u, 46u}, // ebu -> Latn
{0x65650000u, 46u}, // ee -> Latn
@@ -422,7 +424,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x81840000u, 46u}, // ema -> Latn
{0xA1840000u, 46u}, // emi -> Latn
{0x656E0000u, 46u}, // en -> Latn
- {0x656E5841u, 97u}, // en-XA -> ~~~A
+ {0x656E5841u, 98u}, // en-XA -> ~~~A
{0xB5A40000u, 46u}, // enn -> Latn
{0xC1A40000u, 46u}, // enq -> Latn
{0x656F0000u, 46u}, // eo -> Latn
@@ -438,6 +440,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x65750000u, 46u}, // eu -> Latn
{0xBAC40000u, 46u}, // ewo -> Latn
{0xCEE40000u, 46u}, // ext -> Latn
+ {0x83240000u, 46u}, // eza -> Latn
{0x66610000u, 1u}, // fa -> Arab
{0x80050000u, 46u}, // faa -> Latn
{0x84050000u, 46u}, // fab -> Latn
@@ -521,7 +524,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x95C60000u, 20u}, // gof -> Ethi
{0xA1C60000u, 46u}, // goi -> Latn
{0xB1C60000u, 18u}, // gom -> Deva
- {0xB5C60000u, 86u}, // gon -> Telu
+ {0xB5C60000u, 87u}, // gon -> Telu
{0xC5C60000u, 46u}, // gor -> Latn
{0xC9C60000u, 46u}, // gos -> Latn
{0xCDC60000u, 24u}, // got -> Goth
@@ -566,7 +569,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xAD070000u, 46u}, // hil -> Latn
{0x81670000u, 46u}, // hla -> Latn
{0xD1670000u, 32u}, // hlu -> Hluw
- {0x8D870000u, 69u}, // hmd -> Plrd
+ {0x8D870000u, 70u}, // hmd -> Plrd
{0xCD870000u, 46u}, // hmt -> Latn
{0x8DA70000u, 1u}, // hnd -> Arab
{0x91A70000u, 18u}, // hne -> Deva
@@ -601,7 +604,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x69670000u, 46u}, // ig -> Latn
{0x84C80000u, 46u}, // igb -> Latn
{0x90C80000u, 46u}, // ige -> Latn
- {0x69690000u, 96u}, // ii -> Yiii
+ {0x69690000u, 97u}, // ii -> Yiii
{0xA5280000u, 46u}, // ijj -> Latn
{0x696B0000u, 46u}, // ik -> Latn
{0xA9480000u, 46u}, // ikk -> Latn
@@ -626,6 +629,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x6A610000u, 36u}, // ja -> Jpan
{0x84090000u, 46u}, // jab -> Latn
{0xB0090000u, 46u}, // jam -> Latn
+ {0xC4090000u, 46u}, // jar -> Latn
{0xB8290000u, 46u}, // jbo -> Latn
{0xD0290000u, 46u}, // jbu -> Latn
{0xB4890000u, 46u}, // jen -> Latn
@@ -661,7 +665,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x906A0000u, 46u}, // kde -> Latn
{0x9C6A0000u, 1u}, // kdh -> Arab
{0xAC6A0000u, 46u}, // kdl -> Latn
- {0xCC6A0000u, 89u}, // kdt -> Thai
+ {0xCC6A0000u, 90u}, // kdt -> Thai
{0x808A0000u, 46u}, // kea -> Latn
{0xB48A0000u, 46u}, // ken -> Latn
{0xE48A0000u, 46u}, // kez -> Latn
@@ -673,7 +677,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x94CA0000u, 46u}, // kgf -> Latn
{0xBCCA0000u, 46u}, // kgp -> Latn
{0x80EA0000u, 46u}, // kha -> Latn
- {0x84EA0000u, 82u}, // khb -> Talu
+ {0x84EA0000u, 83u}, // khb -> Talu
{0xB4EA0000u, 18u}, // khn -> Deva
{0xC0EA0000u, 46u}, // khq -> Latn
{0xC8EA0000u, 46u}, // khs -> Latn
@@ -766,7 +770,8 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x82EA0000u, 46u}, // kxa -> Latn
{0x8AEA0000u, 20u}, // kxc -> Ethi
{0x92EA0000u, 46u}, // kxe -> Latn
- {0xB2EA0000u, 89u}, // kxm -> Thai
+ {0xAEEA0000u, 18u}, // kxl -> Deva
+ {0xB2EA0000u, 90u}, // kxm -> Thai
{0xBEEA0000u, 1u}, // kxp -> Arab
{0xDAEA0000u, 46u}, // kxw -> Latn
{0xE6EA0000u, 46u}, // kxz -> Latn
@@ -775,6 +780,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x6B795452u, 46u}, // ky-TR -> Latn
{0x930A0000u, 46u}, // kye -> Latn
{0xDF0A0000u, 46u}, // kyx -> Latn
+ {0x9F2A0000u, 1u}, // kzh -> Arab
{0xA72A0000u, 46u}, // kzj -> Latn
{0xC72A0000u, 46u}, // kzr -> Latn
{0xCF2A0000u, 46u}, // kzt -> Latn
@@ -790,7 +796,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xD02B0000u, 46u}, // lbu -> Latn
{0xD82B0000u, 46u}, // lbw -> Latn
{0xB04B0000u, 46u}, // lcm -> Latn
- {0xBC4B0000u, 89u}, // lcp -> Thai
+ {0xBC4B0000u, 90u}, // lcp -> Thai
{0x846B0000u, 46u}, // ldb -> Latn
{0x8C8B0000u, 46u}, // led -> Latn
{0x908B0000u, 46u}, // lee -> Latn
@@ -814,7 +820,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xCD4B0000u, 46u}, // lkt -> Latn
{0x916B0000u, 46u}, // lle -> Latn
{0xB56B0000u, 46u}, // lln -> Latn
- {0xB58B0000u, 86u}, // lmn -> Telu
+ {0xB58B0000u, 87u}, // lmn -> Telu
{0xB98B0000u, 46u}, // lmo -> Latn
{0xBD8B0000u, 46u}, // lmp -> Latn
{0x6C6E0000u, 46u}, // ln -> Latn
@@ -836,7 +842,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xE28B0000u, 46u}, // luy -> Latn
{0xE68B0000u, 1u}, // luz -> Arab
{0x6C760000u, 46u}, // lv -> Latn
- {0xAECB0000u, 89u}, // lwl -> Thai
+ {0xAECB0000u, 90u}, // lwl -> Thai
{0x9F2B0000u, 28u}, // lzh -> Hans
{0xE72B0000u, 46u}, // lzz -> Latn
{0x8C0C0000u, 46u}, // mad -> Latn
@@ -927,7 +933,6 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xBA2C0000u, 57u}, // mro -> Mroo
{0x6D730000u, 46u}, // ms -> Latn
{0x6D734343u, 1u}, // ms-CC -> Arab
- {0x6D734944u, 1u}, // ms-ID -> Arab
{0x6D740000u, 46u}, // mt -> Latn
{0x8A6C0000u, 46u}, // mtc -> Latn
{0x966C0000u, 46u}, // mtf -> Latn
@@ -1006,11 +1011,11 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x9DAD0000u, 46u}, // nnh -> Latn
{0xA9AD0000u, 46u}, // nnk -> Latn
{0xB1AD0000u, 46u}, // nnm -> Latn
- {0xBDAD0000u, 93u}, // nnp -> Wcho
+ {0xBDAD0000u, 94u}, // nnp -> Wcho
{0x6E6F0000u, 46u}, // no -> Latn
{0x8DCD0000u, 44u}, // nod -> Lana
{0x91CD0000u, 18u}, // noe -> Deva
- {0xB5CD0000u, 71u}, // non -> Runr
+ {0xB5CD0000u, 72u}, // non -> Runr
{0xBDCD0000u, 46u}, // nop -> Latn
{0xD1CD0000u, 46u}, // nou -> Latn
{0xBA0D0000u, 60u}, // nqo -> Nkoo
@@ -1044,18 +1049,18 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xB5AE0000u, 46u}, // onn -> Latn
{0xC9AE0000u, 46u}, // ons -> Latn
{0xB1EE0000u, 46u}, // opm -> Latn
- {0x6F720000u, 64u}, // or -> Orya
+ {0x6F720000u, 65u}, // or -> Orya
{0xBA2E0000u, 46u}, // oro -> Latn
{0xD22E0000u, 1u}, // oru -> Arab
{0x6F730000u, 17u}, // os -> Cyrl
- {0x824E0000u, 65u}, // osa -> Osge
+ {0x824E0000u, 66u}, // osa -> Osge
{0x826E0000u, 1u}, // ota -> Arab
- {0xAA6E0000u, 63u}, // otk -> Orkh
+ {0xAA6E0000u, 64u}, // otk -> Orkh
{0xB32E0000u, 46u}, // ozm -> Latn
{0x70610000u, 27u}, // pa -> Guru
{0x7061504Bu, 1u}, // pa-PK -> Arab
{0x980F0000u, 46u}, // pag -> Latn
- {0xAC0F0000u, 67u}, // pal -> Phli
+ {0xAC0F0000u, 68u}, // pal -> Phli
{0xB00F0000u, 46u}, // pam -> Latn
{0xBC0F0000u, 46u}, // pap -> Latn
{0xD00F0000u, 46u}, // pau -> Latn
@@ -1065,11 +1070,11 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x886F0000u, 46u}, // pdc -> Latn
{0xCC6F0000u, 46u}, // pdt -> Latn
{0x8C8F0000u, 46u}, // ped -> Latn
- {0xB88F0000u, 94u}, // peo -> Xpeo
+ {0xB88F0000u, 95u}, // peo -> Xpeo
{0xDC8F0000u, 46u}, // pex -> Latn
{0xACAF0000u, 46u}, // pfl -> Latn
{0xACEF0000u, 1u}, // phl -> Arab
- {0xB4EF0000u, 68u}, // phn -> Phnx
+ {0xB4EF0000u, 69u}, // phn -> Phnx
{0xAD0F0000u, 46u}, // pil -> Latn
{0xBD0F0000u, 46u}, // pip -> Latn
{0x814F0000u, 8u}, // pka -> Brah
@@ -1105,7 +1110,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xB4D10000u, 46u}, // rgn -> Latn
{0x98F10000u, 1u}, // rhg -> Arab
{0x81110000u, 46u}, // ria -> Latn
- {0x95110000u, 87u}, // rif -> Tfng
+ {0x95110000u, 88u}, // rif -> Tfng
{0x95114E4Cu, 46u}, // rif-NL -> Latn
{0xC9310000u, 18u}, // rjs -> Deva
{0xCD510000u, 7u}, // rkt -> Beng
@@ -1135,9 +1140,9 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x9C120000u, 17u}, // sah -> Cyrl
{0xC0120000u, 46u}, // saq -> Latn
{0xC8120000u, 46u}, // sas -> Latn
- {0xCC120000u, 46u}, // sat -> Latn
+ {0xCC120000u, 63u}, // sat -> Olck
{0xD4120000u, 46u}, // sav -> Latn
- {0xE4120000u, 74u}, // saz -> Saur
+ {0xE4120000u, 75u}, // saz -> Saur
{0x80320000u, 46u}, // sba -> Latn
{0x90320000u, 46u}, // sbe -> Latn
{0xBC320000u, 46u}, // sbp -> Latn
@@ -1161,11 +1166,11 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xD8D20000u, 20u}, // sgw -> Ethi
{0xE4D20000u, 46u}, // sgz -> Latn
{0x73680000u, 46u}, // sh -> Latn
- {0xA0F20000u, 87u}, // shi -> Tfng
+ {0xA0F20000u, 88u}, // shi -> Tfng
{0xA8F20000u, 46u}, // shk -> Latn
{0xB4F20000u, 58u}, // shn -> Mymr
{0xD0F20000u, 1u}, // shu -> Arab
- {0x73690000u, 76u}, // si -> Sinh
+ {0x73690000u, 77u}, // si -> Sinh
{0x8D120000u, 46u}, // sid -> Latn
{0x99120000u, 46u}, // sig -> Latn
{0xAD120000u, 46u}, // sil -> Latn
@@ -1184,7 +1189,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x81920000u, 46u}, // sma -> Latn
{0xA5920000u, 46u}, // smj -> Latn
{0xB5920000u, 46u}, // smn -> Latn
- {0xBD920000u, 72u}, // smp -> Samr
+ {0xBD920000u, 73u}, // smp -> Samr
{0xC1920000u, 46u}, // smq -> Latn
{0xC9920000u, 46u}, // sms -> Latn
{0x736E0000u, 46u}, // sn -> Latn
@@ -1194,10 +1199,10 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xDDB20000u, 46u}, // snx -> Latn
{0xE1B20000u, 46u}, // sny -> Latn
{0x736F0000u, 46u}, // so -> Latn
- {0x99D20000u, 77u}, // sog -> Sogd
+ {0x99D20000u, 78u}, // sog -> Sogd
{0xA9D20000u, 46u}, // sok -> Latn
{0xC1D20000u, 46u}, // soq -> Latn
- {0xD1D20000u, 89u}, // sou -> Thai
+ {0xD1D20000u, 90u}, // sou -> Thai
{0xE1D20000u, 46u}, // soy -> Latn
{0x8DF20000u, 46u}, // spd -> Latn
{0xADF20000u, 46u}, // spl -> Latn
@@ -1208,7 +1213,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x7372524Fu, 46u}, // sr-RO -> Latn
{0x73725255u, 46u}, // sr-RU -> Latn
{0x73725452u, 46u}, // sr-TR -> Latn
- {0x86320000u, 78u}, // srb -> Sora
+ {0x86320000u, 79u}, // srb -> Sora
{0xB6320000u, 46u}, // srn -> Latn
{0xC6320000u, 46u}, // srr -> Latn
{0xDE320000u, 18u}, // srx -> Deva
@@ -1235,9 +1240,9 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xB6F20000u, 46u}, // sxn -> Latn
{0xDAF20000u, 46u}, // sxw -> Latn
{0xAF120000u, 7u}, // syl -> Beng
- {0xC7120000u, 80u}, // syr -> Syrc
+ {0xC7120000u, 81u}, // syr -> Syrc
{0xAF320000u, 46u}, // szl -> Latn
- {0x74610000u, 83u}, // ta -> Taml
+ {0x74610000u, 84u}, // ta -> Taml
{0xA4130000u, 18u}, // taj -> Deva
{0xAC130000u, 46u}, // tal -> Latn
{0xB4130000u, 46u}, // tan -> Latn
@@ -1251,11 +1256,11 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xE4330000u, 46u}, // tbz -> Latn
{0xA0530000u, 46u}, // tci -> Latn
{0xE0530000u, 42u}, // tcy -> Knda
- {0x8C730000u, 81u}, // tdd -> Tale
+ {0x8C730000u, 82u}, // tdd -> Tale
{0x98730000u, 18u}, // tdg -> Deva
{0x9C730000u, 18u}, // tdh -> Deva
{0xD0730000u, 46u}, // tdu -> Latn
- {0x74650000u, 86u}, // te -> Telu
+ {0x74650000u, 87u}, // te -> Telu
{0x8C930000u, 46u}, // ted -> Latn
{0xB0930000u, 46u}, // tem -> Latn
{0xB8930000u, 46u}, // teo -> Latn
@@ -1266,7 +1271,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x88D30000u, 46u}, // tgc -> Latn
{0xB8D30000u, 46u}, // tgo -> Latn
{0xD0D30000u, 46u}, // tgu -> Latn
- {0x74680000u, 89u}, // th -> Thai
+ {0x74680000u, 90u}, // th -> Thai
{0xACF30000u, 18u}, // thl -> Deva
{0xC0F30000u, 18u}, // thq -> Deva
{0xC4F30000u, 18u}, // thr -> Deva
@@ -1305,14 +1310,14 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x8E530000u, 25u}, // tsd -> Grek
{0x96530000u, 18u}, // tsf -> Deva
{0x9A530000u, 46u}, // tsg -> Latn
- {0xA6530000u, 90u}, // tsj -> Tibt
+ {0xA6530000u, 91u}, // tsj -> Tibt
{0xDA530000u, 46u}, // tsw -> Latn
{0x74740000u, 17u}, // tt -> Cyrl
{0x8E730000u, 46u}, // ttd -> Latn
{0x92730000u, 46u}, // tte -> Latn
{0xA6730000u, 46u}, // ttj -> Latn
{0xC6730000u, 46u}, // ttr -> Latn
- {0xCA730000u, 89u}, // tts -> Thai
+ {0xCA730000u, 90u}, // tts -> Thai
{0xCE730000u, 46u}, // ttt -> Latn
{0x9E930000u, 46u}, // tuh -> Latn
{0xAE930000u, 46u}, // tul -> Latn
@@ -1323,7 +1328,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xD2B30000u, 46u}, // tvu -> Latn
{0x9ED30000u, 46u}, // twh -> Latn
{0xC2D30000u, 46u}, // twq -> Latn
- {0x9AF30000u, 84u}, // txg -> Tang
+ {0x9AF30000u, 85u}, // txg -> Tang
{0x74790000u, 46u}, // ty -> Latn
{0x83130000u, 46u}, // tya -> Latn
{0xD7130000u, 17u}, // tyv -> Cyrl
@@ -1333,7 +1338,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x75670000u, 1u}, // ug -> Arab
{0x75674B5Au, 17u}, // ug-KZ -> Cyrl
{0x75674D4Eu, 17u}, // ug-MN -> Cyrl
- {0x80D40000u, 91u}, // uga -> Ugar
+ {0x80D40000u, 92u}, // uga -> Ugar
{0x756B0000u, 17u}, // uk -> Cyrl
{0xA1740000u, 46u}, // uli -> Latn
{0x85940000u, 46u}, // umb -> Latn
@@ -1346,6 +1351,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xCE340000u, 46u}, // urt -> Latn
{0xDA340000u, 46u}, // urw -> Latn
{0x82540000u, 46u}, // usa -> Latn
+ {0x9E740000u, 46u}, // uth -> Latn
{0xC6740000u, 46u}, // utr -> Latn
{0x9EB40000u, 46u}, // uvh -> Latn
{0xAEB40000u, 46u}, // uvl -> Latn
@@ -1353,7 +1359,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x757A4146u, 1u}, // uz-AF -> Arab
{0x757A434Eu, 17u}, // uz-CN -> Cyrl
{0x98150000u, 46u}, // vag -> Latn
- {0xA0150000u, 92u}, // vai -> Vaii
+ {0xA0150000u, 93u}, // vai -> Vaii
{0xB4150000u, 46u}, // van -> Latn
{0x76650000u, 46u}, // ve -> Latn
{0x88950000u, 46u}, // vec -> Latn
@@ -1376,7 +1382,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xB4160000u, 46u}, // wan -> Latn
{0xC4160000u, 46u}, // war -> Latn
{0xBC360000u, 46u}, // wbp -> Latn
- {0xC0360000u, 86u}, // wbq -> Telu
+ {0xC0360000u, 87u}, // wbq -> Telu
{0xC4360000u, 18u}, // wbr -> Deva
{0xA0560000u, 46u}, // wci -> Latn
{0xC4960000u, 46u}, // wer -> Latn
@@ -1418,9 +1424,9 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0xC5B70000u, 18u}, // xnr -> Deva
{0x99D70000u, 46u}, // xog -> Latn
{0xB5D70000u, 46u}, // xon -> Latn
- {0xC5F70000u, 70u}, // xpr -> Prti
+ {0xC5F70000u, 71u}, // xpr -> Prti
{0x86370000u, 46u}, // xrb -> Latn
- {0x82570000u, 73u}, // xsa -> Sarb
+ {0x82570000u, 74u}, // xsa -> Sarb
{0xA2570000u, 46u}, // xsi -> Latn
{0xB2570000u, 46u}, // xsm -> Latn
{0xC6570000u, 18u}, // xsr -> Deva
@@ -1461,7 +1467,7 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x98190000u, 46u}, // zag -> Latn
{0xA4790000u, 1u}, // zdj -> Arab
{0x80990000u, 46u}, // zea -> Latn
- {0x9CD90000u, 87u}, // zgh -> Tfng
+ {0x9CD90000u, 88u}, // zgh -> Tfng
{0x7A680000u, 28u}, // zh -> Hans
{0x7A684155u, 29u}, // zh-AU -> Hant
{0x7A68424Eu, 29u}, // zh-BN -> Hant
@@ -1470,7 +1476,6 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
{0x7A68484Bu, 29u}, // zh-HK -> Hant
{0x7A684944u, 29u}, // zh-ID -> Hant
{0x7A684D4Fu, 29u}, // zh-MO -> Hant
- {0x7A684D59u, 29u}, // zh-MY -> Hant
{0x7A685041u, 29u}, // zh-PA -> Hant
{0x7A685046u, 29u}, // zh-PF -> Hant
{0x7A685048u, 29u}, // zh-PH -> Hant
@@ -1592,6 +1597,7 @@ std::unordered_set<uint64_t> REPRESENTATIVE_LOCALES({
0xD701434D4C61746ELLU, // byv_Latn_CM
0x93214D4C4C61746ELLU, // bze_Latn_ML
0x636145534C61746ELLU, // ca_Latn_ES
+ 0x8C0255534C61746ELLU, // cad_Latn_US
0x9C424E474C61746ELLU, // cch_Latn_NG
0xBC42424443616B6DLLU, // ccp_Cakm_BD
0x636552554379726CLLU, // ce_Cyrl_RU
@@ -1627,6 +1633,7 @@ std::unordered_set<uint64_t> REPRESENTATIVE_LOCALES({
0x637652554379726CLLU, // cv_Cyrl_RU
0x637947424C61746ELLU, // cy_Latn_GB
0x6461444B4C61746ELLU, // da_Latn_DK
+ 0x940343494C61746ELLU, // daf_Latn_CI
0xA80355534C61746ELLU, // dak_Latn_US
0xC40352554379726CLLU, // dar_Cyrl_RU
0xD4034B454C61746ELLU, // dav_Latn_KE
@@ -1636,7 +1643,7 @@ std::unordered_set<uint64_t> REPRESENTATIVE_LOCALES({
0xC4C343414C61746ELLU, // dgr_Latn_CA
0x91234E454C61746ELLU, // dje_Latn_NE
0xA5A343494C61746ELLU, // dnj_Latn_CI
- 0xA1C3494E41726162LLU, // doi_Arab_IN
+ 0xA1C3494E44657661LLU, // doi_Deva_IN
0x9E23434E4D6F6E67LLU, // drh_Mong_CN
0x864344454C61746ELLU, // dsb_Latn_DE
0xB2634D4C4C61746ELLU, // dtm_Latn_ML
@@ -1839,6 +1846,7 @@ std::unordered_set<uint64_t> REPRESENTATIVE_LOCALES({
0xC6AA49444C61746ELLU, // kvr_Latn_ID
0xDEAA504B41726162LLU, // kvx_Arab_PK
0x6B7747424C61746ELLU, // kw_Latn_GB
+ 0xAEEA494E44657661LLU, // kxl_Deva_IN
0xB2EA544854686169LLU, // kxm_Thai_TH
0xBEEA504B41726162LLU, // kxp_Arab_PK
0x6B79434E41726162LLU, // ky_Arab_CN
@@ -2047,7 +2055,7 @@ std::unordered_set<uint64_t> REPRESENTATIVE_LOCALES({
0x9C1252554379726CLLU, // sah_Cyrl_RU
0xC0124B454C61746ELLU, // saq_Latn_KE
0xC81249444C61746ELLU, // sas_Latn_ID
- 0xCC12494E4C61746ELLU, // sat_Latn_IN
+ 0xCC12494E4F6C636BLLU, // sat_Olck_IN
0xD412534E4C61746ELLU, // sav_Latn_SN
0xE412494E53617572LLU, // saz_Saur_IN
0xBC32545A4C61746ELLU, // sbp_Latn_TZ
@@ -2149,6 +2157,7 @@ std::unordered_set<uint64_t> REPRESENTATIVE_LOCALES({
0x747254524C61746ELLU, // tr_Latn_TR
0xD23354524C61746ELLU, // tru_Latn_TR
0xD63354574C61746ELLU, // trv_Latn_TW
+ 0xDA33504B41726162LLU, // trw_Arab_PK
0x74735A414C61746ELLU, // ts_Latn_ZA
0x8E5347524772656BLLU, // tsd_Grek_GR
0x96534E5044657661LLU, // tsf_Deva_NP
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index bce70e2aae9e..223382731bc0 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -30,6 +30,7 @@
#include <memory>
#include <set>
#include <type_traits>
+#include <vector>
#include <android-base/macros.h>
#include <androidfw/ByteBucketArray.h>
@@ -1029,7 +1030,7 @@ base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_
// But we don't want to hit the cache, so instead we will have a
// local temporary allocation for the conversions.
size_t convBufferLen = strLen + 4;
- char16_t* convBuffer = (char16_t*)calloc(convBufferLen, sizeof(char16_t));
+ std::vector<char16_t> convBuffer(convBufferLen);
ssize_t l = 0;
ssize_t h = mHeader->stringCount-1;
@@ -1043,8 +1044,8 @@ base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_
}
if (s.has_value()) {
char16_t* end = utf8_to_utf16(reinterpret_cast<const uint8_t*>(s->data()),
- s->size(), convBuffer, convBufferLen);
- c = strzcmp16(convBuffer, end-convBuffer, str, strLen);
+ s->size(), convBuffer.data(), convBufferLen);
+ c = strzcmp16(convBuffer.data(), end-convBuffer.data(), str, strLen);
}
if (kDebugStringPoolNoisy) {
ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
@@ -1054,7 +1055,6 @@ base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_
if (kDebugStringPoolNoisy) {
ALOGI("MATCH!");
}
- free(convBuffer);
return mid;
} else if (c < 0) {
l = mid + 1;
@@ -1062,7 +1062,6 @@ base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_
h = mid - 1;
}
}
- free(convBuffer);
} else {
// It is unusual to get the ID from an unsorted string block...
// most often this happens because we want to get IDs for style
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 7dff0c2b9380..d22e97c231fd 100755
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -5434,8 +5434,12 @@ public class AudioManager {
public boolean setAdditionalOutputDeviceDelay(
@NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) {
Objects.requireNonNull(device);
- // Implement the setter in r-dev or r-tv-dev as needed.
- return false;
+ try {
+ return getService().setAdditionalOutputDeviceDelay(
+ new AudioDeviceAttributes(device), delayMillis);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -5450,8 +5454,11 @@ public class AudioManager {
@IntRange(from = 0)
public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Objects.requireNonNull(device);
- // Implement the getter in r-dev or r-tv-dev as needed.
- return 0;
+ try {
+ return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -5468,8 +5475,12 @@ public class AudioManager {
@IntRange(from = 0)
public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Objects.requireNonNull(device);
- // Implement the getter in r-dev or r-tv-dev as needed.
- return 0;
+ try {
+ return getService().getMaxAdditionalOutputDeviceDelay(
+ new AudioDeviceAttributes(device));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index b2c2c4b1bbb4..d7ef4549ca3f 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1269,10 +1269,12 @@ public class AudioTrack extends PlayerBase
// native code figure out the minimum buffer size.
if (mMode == MODE_STREAM && mBufferSizeInBytes == 0) {
int bytesPerSample = 1;
- try {
- bytesPerSample = mFormat.getBytesPerSample(mFormat.getEncoding());
- } catch (IllegalArgumentException e) {
- // do nothing
+ if (AudioFormat.isEncodingLinearFrames(mFormat.getEncoding())) {
+ try {
+ bytesPerSample = mFormat.getBytesPerSample(mFormat.getEncoding());
+ } catch (IllegalArgumentException e) {
+ // do nothing
+ }
}
mBufferSizeInBytes = mFormat.getChannelCount() * bytesPerSample;
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index ebaa3162d0e4..ed48b569b166 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -330,4 +330,10 @@ interface IAudioService {
oneway void unregisterCommunicationDeviceDispatcher(
ICommunicationDeviceDispatcher dispatcher);
+
+ boolean setAdditionalOutputDeviceDelay(in AudioDeviceAttributes device, long delayMillis);
+
+ long getAdditionalOutputDeviceDelay(in AudioDeviceAttributes device);
+
+ long getMaxAdditionalOutputDeviceDelay(in AudioDeviceAttributes device);
}
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 068f9689d06f..4b8a8adade1f 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -73,6 +73,8 @@ interface IMediaRouterService {
void unregisterManager(IMediaRouter2Manager manager);
void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
in MediaRoute2Info route, int volume);
+ void startScan(IMediaRouter2Manager manager);
+ void stopScan(IMediaRouter2Manager manager);
void requestCreateSessionWithManager(IMediaRouter2Manager manager, int requestId,
in RoutingSessionInfo oldSession, in @nullable MediaRoute2Info route);
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 4b09a5f19fb0..68237de2ca98 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -147,6 +147,36 @@ public final class MediaRouter2Manager {
}
/**
+ * Starts scanning remote routes.
+ * @see #stopScan(String)
+ */
+ public void startScan() {
+ Client client = getOrCreateClient();
+ if (client != null) {
+ try {
+ mMediaRouterService.startScan(client);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Unable to get sessions. Service probably died.", ex);
+ }
+ }
+ }
+
+ /**
+ * Stops scanning remote routes to reduce resource consumption.
+ * @see #startScan(String)
+ */
+ public void stopScan() {
+ Client client = getOrCreateClient();
+ if (client != null) {
+ try {
+ mMediaRouterService.stopScan(client);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Unable to get sessions. Service probably died.", ex);
+ }
+ }
+ }
+
+ /**
* Gets a {@link android.media.session.MediaController} associated with the
* given routing session.
* If there is no matching media session, {@code null} is returned.
diff --git a/media/java/android/media/RouteDiscoveryPreference.java b/media/java/android/media/RouteDiscoveryPreference.java
index 68f2964dbeb2..2f952474b7f0 100644
--- a/media/java/android/media/RouteDiscoveryPreference.java
+++ b/media/java/android/media/RouteDiscoveryPreference.java
@@ -153,6 +153,7 @@ public final class RouteDiscoveryPreference implements Parcelable {
return false;
}
RouteDiscoveryPreference other = (RouteDiscoveryPreference) o;
+ //TODO: Make this order-free
return Objects.equals(mPreferredFeatures, other.mPreferredFeatures)
&& mShouldPerformActiveScan == other.mShouldPerformActiveScan;
}
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 1fbb67260895..5d7fdff70f5c 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -91,6 +91,8 @@ interface ITvInputManager {
// For the recording session
void startRecording(in IBinder sessionToken, in Uri programUri, in Bundle params, int userId);
void stopRecording(in IBinder sessionToken, int userId);
+ void pauseRecording(in IBinder sessionToken, in Bundle params, int userId);
+ void resumeRecording(in IBinder sessionToken, in Bundle params, int userId);
// For TV input hardware binding
List<TvInputHardwareInfo> getHardwareList();
diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl
index 24b87d50b33e..158cf211d9f0 100644
--- a/media/java/android/media/tv/ITvInputSession.aidl
+++ b/media/java/android/media/tv/ITvInputSession.aidl
@@ -58,4 +58,6 @@ oneway interface ITvInputSession {
// For the recording session
void startRecording(in Uri programUri, in Bundle params);
void stopRecording();
+ void pauseRecording(in Bundle params);
+ void resumeRecording(in Bundle params);
}
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index e89d33d70d5c..abccf8da9cfc 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -68,6 +68,8 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
private static final int DO_TIME_SHIFT_ENABLE_POSITION_TRACKING = 19;
private static final int DO_START_RECORDING = 20;
private static final int DO_STOP_RECORDING = 21;
+ private static final int DO_PAUSE_RECORDING = 22;
+ private static final int DO_RESUME_RECORDING = 23;
private final boolean mIsRecordingSession;
private final HandlerCaller mCaller;
@@ -224,6 +226,14 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
mTvInputRecordingSessionImpl.stopRecording();
break;
}
+ case DO_PAUSE_RECORDING: {
+ mTvInputRecordingSessionImpl.pauseRecording((Bundle) msg.obj);
+ break;
+ }
+ case DO_RESUME_RECORDING: {
+ mTvInputRecordingSessionImpl.resumeRecording((Bundle) msg.obj);
+ break;
+ }
default: {
Log.w(TAG, "Unhandled message code: " + msg.what);
break;
@@ -363,6 +373,16 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_STOP_RECORDING));
}
+ @Override
+ public void pauseRecording(@Nullable Bundle params) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_PAUSE_RECORDING, params));
+ }
+
+ @Override
+ public void resumeRecording(@Nullable Bundle params) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_RESUME_RECORDING, params));
+ }
+
private final class TvInputEventReceiver extends InputEventReceiver {
public TvInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
diff --git a/media/java/android/media/tv/TvInputHardwareInfo.java b/media/java/android/media/tv/TvInputHardwareInfo.java
index b12f7c551288..0bedbd3c1f46 100644
--- a/media/java/android/media/tv/TvInputHardwareInfo.java
+++ b/media/java/android/media/tv/TvInputHardwareInfo.java
@@ -188,6 +188,20 @@ public final class TvInputHardwareInfo implements Parcelable {
mCableConnectionStatus = source.readInt();
}
+ /** @hide */
+ public Builder toBuilder() {
+ Builder newBuilder = new Builder()
+ .deviceId(mDeviceId)
+ .type(mType)
+ .audioType(mAudioType)
+ .audioAddress(mAudioAddress)
+ .cableConnectionStatus(mCableConnectionStatus);
+ if (mType == TV_INPUT_TYPE_HDMI) {
+ newBuilder.hdmiPortId(mHdmiPortId);
+ }
+ return newBuilder;
+ }
+
public static final class Builder {
private Integer mDeviceId = null;
private Integer mType = null;
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 195ad5bc10f9..54cb2bff5566 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -143,6 +143,7 @@ public final class TvInputInfo implements Parcelable {
// Attributes from XML meta data.
private final String mSetupActivity;
private final boolean mCanRecord;
+ private final boolean mCanPauseRecording;
private final int mTunerCount;
// Attributes specific to HDMI
@@ -264,8 +265,8 @@ public final class TvInputInfo implements Parcelable {
private TvInputInfo(ResolveInfo service, String id, int type, boolean isHardwareInput,
CharSequence label, int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected,
- String setupActivity, boolean canRecord, int tunerCount, HdmiDeviceInfo hdmiDeviceInfo,
- boolean isConnectedToHdmiSwitch,
+ String setupActivity, boolean canRecord, boolean canPauseRecording, int tunerCount,
+ HdmiDeviceInfo hdmiDeviceInfo, boolean isConnectedToHdmiSwitch,
@HdmiAddressRelativePosition int hdmiConnectionRelativePosition, String parentId,
Bundle extras) {
mService = service;
@@ -279,6 +280,7 @@ public final class TvInputInfo implements Parcelable {
mIconDisconnected = iconDisconnected;
mSetupActivity = setupActivity;
mCanRecord = canRecord;
+ mCanPauseRecording = canPauseRecording;
mTunerCount = tunerCount;
mHdmiDeviceInfo = hdmiDeviceInfo;
mIsConnectedToHdmiSwitch = isConnectedToHdmiSwitch;
@@ -386,6 +388,14 @@ public final class TvInputInfo implements Parcelable {
}
/**
+ * Returns {@code true} if this TV input can pause recording TV programs,
+ * {@code false} otherwise.
+ */
+ public boolean canPauseRecording() {
+ return mCanPauseRecording;
+ }
+
+ /**
* Returns domain-specific extras associated with this TV input.
*/
public Bundle getExtras() {
@@ -571,6 +581,7 @@ public final class TvInputInfo implements Parcelable {
&& Objects.equals(mIconDisconnected, obj.mIconDisconnected)
&& TextUtils.equals(mSetupActivity, obj.mSetupActivity)
&& mCanRecord == obj.mCanRecord
+ && mCanPauseRecording == obj.mCanPauseRecording
&& mTunerCount == obj.mTunerCount
&& Objects.equals(mHdmiDeviceInfo, obj.mHdmiDeviceInfo)
&& mIsConnectedToHdmiSwitch == obj.mIsConnectedToHdmiSwitch
@@ -606,6 +617,7 @@ public final class TvInputInfo implements Parcelable {
dest.writeParcelable(mIconDisconnected, flags);
dest.writeString(mSetupActivity);
dest.writeByte(mCanRecord ? (byte) 1 : 0);
+ dest.writeByte(mCanPauseRecording ? (byte) 1 : 0);
dest.writeInt(mTunerCount);
dest.writeParcelable(mHdmiDeviceInfo, flags);
dest.writeByte(mIsConnectedToHdmiSwitch ? (byte) 1 : 0);
@@ -648,6 +660,7 @@ public final class TvInputInfo implements Parcelable {
mIconDisconnected = in.readParcelable(null);
mSetupActivity = in.readString();
mCanRecord = in.readByte() == 1;
+ mCanPauseRecording = in.readByte() == 1;
mTunerCount = in.readInt();
mHdmiDeviceInfo = in.readParcelable(null);
mIsConnectedToHdmiSwitch = in.readByte() == 1;
@@ -695,6 +708,7 @@ public final class TvInputInfo implements Parcelable {
private Icon mIconDisconnected;
private String mSetupActivity;
private Boolean mCanRecord;
+ private Boolean mCanPauseRecording;
private Integer mTunerCount;
private TvInputHardwareInfo mTvInputHardwareInfo;
private HdmiDeviceInfo mHdmiDeviceInfo;
@@ -879,6 +893,18 @@ public final class TvInputInfo implements Parcelable {
}
/**
+ * Sets whether this TV input can pause recording TV programs or not.
+ *
+ * @param canPauseRecording Whether this TV input can pause recording TV programs.
+ * @return This Builder object to allow for chaining of calls to builder methods.
+ */
+ @NonNull
+ public Builder setCanPauseRecording(boolean canPauseRecording) {
+ this.mCanPauseRecording = canPauseRecording;
+ return this;
+ }
+
+ /**
* Sets domain-specific extras associated with this TV input.
*
* @param extras Domain-specific extras associated with this TV input. Keys <em>must</em> be
@@ -927,7 +953,9 @@ public final class TvInputInfo implements Parcelable {
parseServiceMetadata(type);
return new TvInputInfo(mResolveInfo, id, type, isHardwareInput, mLabel, mLabelResId,
mIcon, mIconStandby, mIconDisconnected, mSetupActivity,
- mCanRecord == null ? false : mCanRecord, mTunerCount == null ? 0 : mTunerCount,
+ mCanRecord == null ? false : mCanRecord,
+ mCanPauseRecording == null ? false : mCanPauseRecording,
+ mTunerCount == null ? 0 : mTunerCount,
mHdmiDeviceInfo, isConnectedToHdmiSwitch, hdmiConnectionRelativePosition,
mParentId, mExtras);
}
@@ -997,6 +1025,12 @@ public final class TvInputInfo implements Parcelable {
mTunerCount = sa.getInt(
com.android.internal.R.styleable.TvInputService_tunerCount, 1);
}
+ if (mCanPauseRecording == null) {
+ mCanPauseRecording = sa.getBoolean(
+ com.android.internal.R.styleable.TvInputService_canPauseRecording,
+ false);
+ }
+
sa.recycle();
} catch (IOException | XmlPullParserException e) {
throw new IllegalStateException("Failed reading meta-data for " + si.packageName, e);
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 98a01a4cb449..6341dc263efd 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -2476,6 +2476,40 @@ public final class TvInputManager {
}
/**
+ * Pauses TV program recording in the current recording session.
+ *
+ * @param params A set of extra parameters which might be handled with this event.
+ */
+ void pauseRecording(@NonNull Bundle params) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.pauseRecording(mToken, params, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Resumes TV program recording in the current recording session.
+ *
+ * @param params A set of extra parameters which might be handled with this event.
+ */
+ void resumeRecording(@NonNull Bundle params) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.resumeRecording(mToken, params, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Calls {@link TvInputService.Session#appPrivateCommand(String, Bundle)
* TvInputService.Session.appPrivateCommand()} on the current TvView.
*
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index abbf4780bcc1..0fe9d504b951 100755
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -1852,6 +1852,28 @@ public abstract class TvInputService extends Service {
/**
+ * Called when the application requests to pause TV program recording. Recording must pause
+ * immediately when this method is called.
+ *
+ * If the pause request cannot be fulfilled, the session must call
+ * {@link #notifyError(int)}.
+ *
+ * @param params Domain-specific data for recording request.
+ */
+ public void onPauseRecording(@NonNull Bundle params) { }
+
+ /**
+ * Called when the application requests to resume TV program recording. Recording must
+ * resume immediately when this method is called.
+ *
+ * If the resume request cannot be fulfilled, the session must call
+ * {@link #notifyError(int)}.
+ *
+ * @param params Domain-specific data for recording request.
+ */
+ public void onResumeRecording(@NonNull Bundle params) { }
+
+ /**
* Called when the application requests to release all the resources held by this recording
* session.
*/
@@ -1903,6 +1925,22 @@ public abstract class TvInputService extends Service {
}
/**
+ * Calls {@link #onPauseRecording(Bundle)}.
+ *
+ */
+ void pauseRecording(@NonNull Bundle params) {
+ onPauseRecording(params);
+ }
+
+ /**
+ * Calls {@link #onResumeRecording(Bundle)}.
+ *
+ */
+ void resumeRecording(@NonNull Bundle params) {
+ onResumeRecording(params);
+ }
+
+ /**
* Calls {@link #onAppPrivateCommand(String, Bundle)}.
*/
void appPrivateCommand(String action, Bundle data) {
diff --git a/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java
index 23fadac8a72b..180e2bd6845b 100644
--- a/media/java/android/media/tv/TvRecordingClient.java
+++ b/media/java/android/media/tv/TvRecordingClient.java
@@ -30,6 +30,7 @@ import android.util.Log;
import android.util.Pair;
import java.util.ArrayDeque;
+import java.util.Objects;
import java.util.Queue;
/**
@@ -49,6 +50,8 @@ public class TvRecordingClient {
private boolean mIsRecordingStarted;
private boolean mIsTuned;
+ private boolean mIsPaused;
+ private boolean mIsRecordingStopping;
private final Queue<Pair<String, Bundle>> mPendingAppPrivateCommands = new ArrayDeque<>();
/**
@@ -113,17 +116,22 @@ public class TvRecordingClient {
if (TextUtils.isEmpty(inputId)) {
throw new IllegalArgumentException("inputId cannot be null or an empty string");
}
- if (mIsRecordingStarted) {
+ if (mIsRecordingStarted && !mIsPaused) {
throw new IllegalStateException("tune failed - recording already started");
}
if (mSessionCallback != null && TextUtils.equals(mSessionCallback.mInputId, inputId)) {
if (mSession != null) {
+ mSessionCallback.mChannelUri = channelUri;
mSession.tune(channelUri, params);
} else {
mSessionCallback.mChannelUri = channelUri;
mSessionCallback.mConnectionParams = params;
}
+ mIsTuned = false;
} else {
+ if (mIsPaused) {
+ throw new IllegalStateException("tune failed - inputId is changed during pause");
+ }
resetInternal();
mSessionCallback = new MySessionCallback(inputId, channelUri, params);
if (mTvInputManager != null) {
@@ -148,6 +156,8 @@ public class TvRecordingClient {
mSession.release();
mIsTuned = false;
mIsRecordingStarted = false;
+ mIsPaused = false;
+ mIsRecordingStopping = false;
mSession = null;
}
}
@@ -169,7 +179,8 @@ public class TvRecordingClient {
*
* @param programUri The URI for the TV program to record, built by
* {@link TvContract#buildProgramUri(long)}. Can be {@code null}.
- * @throws IllegalStateException If {@link #tune} request hasn't been handled yet.
+ * @throws IllegalStateException If {@link #tune} request hasn't been handled yet or during
+ * pause.
*/
public void startRecording(@Nullable Uri programUri) {
startRecording(programUri, Bundle.EMPTY);
@@ -195,11 +206,16 @@ public class TvRecordingClient {
* @param params Domain-specific data for this request. Keys <em>must</em> be a scoped
* name, i.e. prefixed with a package name you own, so that different developers will
* not create conflicting keys.
- * @throws IllegalStateException If {@link #tune} request hasn't been handled yet.
+ * @throws IllegalStateException If {@link #tune} request hasn't been handled yet or during
+ * pause.
*/
public void startRecording(@Nullable Uri programUri, @NonNull Bundle params) {
- if (!mIsTuned) {
- throw new IllegalStateException("startRecording failed - not yet tuned");
+ if (mIsRecordingStopping || !mIsTuned || mIsPaused) {
+ throw new IllegalStateException("startRecording failed -"
+ + "recording not yet stopped or not yet tuned or paused");
+ }
+ if (mIsRecordingStarted) {
+ Log.w(TAG, "startRecording failed - recording already started");
}
if (mSession != null) {
mSession.startRecording(programUri, params);
@@ -225,6 +241,103 @@ public class TvRecordingClient {
}
if (mSession != null) {
mSession.stopRecording();
+ if (mIsRecordingStarted) {
+ mIsRecordingStopping = true;
+ }
+ }
+ }
+
+ /**
+ * Pause TV program recording in the current recording session. Recording is expected to pause
+ * immediately when this method is called. If recording has not yet started in the current
+ * recording session, this method does nothing.
+ *
+ * <p>In pause status, the application can tune during recording. To continue recording,
+ * please call {@link TvRecordingClient#resumeRecording()} to resume instead of
+ * {@link TvRecordingClient#startRecording(Uri)}. Application can stop
+ * the recording with {@link TvRecordingClient#stopRecording()} in recording pause status.
+ *
+ * <p>If the pause request cannot be fulfilled, the recording session will respond by calling
+ * {@link RecordingCallback#onError(int)}.
+ */
+ public void pauseRecording() {
+ pauseRecording(Bundle.EMPTY);
+ }
+
+ /**
+ * Pause TV program recording in the current recording session. Recording is expected to pause
+ * immediately when this method is called. If recording has not yet started in the current
+ * recording session, this method does nothing.
+ *
+ * <p>In pause status, the application can tune during recording. To continue recording,
+ * please call {@link TvRecordingClient#resumeRecording()} to resume instead of
+ * {@link TvRecordingClient#startRecording(Uri)}. Application can stop
+ * the recording with {@link TvRecordingClient#stopRecording()} in recording pause status.
+ *
+ * <p>If the pause request cannot be fulfilled, the recording session will respond by calling
+ * {@link RecordingCallback#onError(int)}.
+ *
+ * @param params Domain-specific data for this request.
+ */
+ public void pauseRecording(@NonNull Bundle params) {
+ if (!mIsRecordingStarted || mIsRecordingStopping) {
+ throw new IllegalStateException(
+ "pauseRecording failed - recording not yet started or stopping");
+ }
+ TvInputInfo info = mTvInputManager.getTvInputInfo(mSessionCallback.mInputId);
+ if (info == null || !info.canPauseRecording()) {
+ throw new UnsupportedOperationException(
+ "pauseRecording failed - operation not supported");
+ }
+ if (mIsPaused) {
+ Log.w(TAG, "pauseRecording failed - recording already paused");
+ }
+ if (mSession != null) {
+ mSession.pauseRecording(params);
+ mIsPaused = true;
+ }
+ }
+
+ /**
+ * Resume TV program recording only in recording pause status in the current recording session.
+ * Recording is expected to resume immediately when this method is called. If recording has not
+ * yet paused in the current recording session, this method does nothing.
+ *
+ * <p>When record is resumed, the recording is continue and can not re-tune. Application can
+ * stop the recording with {@link TvRecordingClient#stopRecording()} after record resumed.
+ *
+ * <p>If the pause request cannot be fulfilled, the recording session will respond by calling
+ * {@link RecordingCallback#onError(int)}.
+ */
+ public void resumeRecording() {
+ resumeRecording(Bundle.EMPTY);
+ }
+
+ /**
+ * Resume TV program recording only in recording pause status in the current recording session.
+ * Recording is expected to resume immediately when this method is called. If recording has not
+ * yet paused in the current recording session, this method does nothing.
+ *
+ * <p>When record is resumed, the recording is continues and can not re-tune. Application can
+ * stop the recording with {@link TvRecordingClient#stopRecording()} after record resumed.
+ *
+ * <p>If the resume request cannot be fulfilled, the recording session will respond by calling
+ * {@link RecordingCallback#onError(int)}.
+ *
+ * @param params Domain-specific data for this request.
+ */
+ public void resumeRecording(@NonNull Bundle params) {
+ if (!mIsRecordingStarted || mIsRecordingStopping || !mIsTuned) {
+ throw new IllegalStateException(
+ "resumeRecording failed - recording not yet started or stopping or "
+ + "not yet tuned");
+ }
+ if (!mIsPaused) {
+ Log.w(TAG, "resumeRecording failed - recording not yet paused");
+ }
+ if (mSession != null) {
+ mSession.resumeRecording(params);
+ mIsPaused = false;
}
}
@@ -367,6 +480,10 @@ public class TvRecordingClient {
Log.w(TAG, "onTuned - session not created");
return;
}
+ if (mIsTuned || !Objects.equals(mChannelUri, channelUri)) {
+ Log.w(TAG, "onTuned - already tuned or not yet tuned to last channel");
+ return;
+ }
mIsTuned = true;
mCallback.onTuned(channelUri);
}
@@ -382,6 +499,8 @@ public class TvRecordingClient {
}
mIsTuned = false;
mIsRecordingStarted = false;
+ mIsPaused = false;
+ mIsRecordingStopping = false;
mSessionCallback = null;
mSession = null;
if (mCallback != null) {
@@ -398,7 +517,13 @@ public class TvRecordingClient {
Log.w(TAG, "onRecordingStopped - session not created");
return;
}
+ if (!mIsRecordingStarted) {
+ Log.w(TAG, "onRecordingStopped - recording not yet started");
+ return;
+ }
mIsRecordingStarted = false;
+ mIsPaused = false;
+ mIsRecordingStopping = false;
mCallback.onRecordingStopped(recordedProgramUri);
}
diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
index 887116725961..c4b622d0fba9 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
@@ -47,6 +47,7 @@ public class DvrRecorder implements AutoCloseable {
private static int sInstantId = 0;
private int mSegmentId = 0;
private int mOverflow;
+ private Boolean mIsStopped = null;
private native int nativeAttachFilter(Filter filter);
private native int nativeDetachFilter(Filter filter);
@@ -135,7 +136,13 @@ public class DvrRecorder implements AutoCloseable {
.write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD,
FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STARTED, mSegmentId, 0);
- return nativeStartDvr();
+ synchronized (mIsStopped) {
+ int result = nativeStartDvr();
+ if (result == Tuner.RESULT_SUCCESS) {
+ mIsStopped = false;
+ }
+ return result;
+ }
}
/**
@@ -152,7 +159,13 @@ public class DvrRecorder implements AutoCloseable {
.write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD,
FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STOPPED, mSegmentId, mOverflow);
- return nativeStopDvr();
+ synchronized (mIsStopped) {
+ int result = nativeStopDvr();
+ if (result == Tuner.RESULT_SUCCESS) {
+ mIsStopped = true;
+ }
+ return result;
+ }
}
/**
@@ -164,7 +177,13 @@ public class DvrRecorder implements AutoCloseable {
*/
@Result
public int flush() {
- return nativeFlushDvr();
+ synchronized (mIsStopped) {
+ if (mIsStopped) {
+ return nativeFlushDvr();
+ }
+ Log.w(TAG, "Cannot flush non-stopped Record DVR.");
+ return Tuner.RESULT_INVALID_STATE;
+ }
}
/**
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 5daf8b0f88f8..694b93919cde 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -169,8 +169,9 @@ static fields_t gFields;
static int IP_V4_LENGTH = 4;
static int IP_V6_LENGTH = 16;
-void DestroyCallback(const C2Buffer * /* buf */, void *arg) {
+void DestroyCallback(const C2Buffer * buf, void *arg) {
android::sp<android::MediaEvent> event = (android::MediaEvent *)arg;
+ android::Mutex::Autolock autoLock(event->mLock);
if (event->mLinearBlockObj != NULL) {
JNIEnv *env = android::AndroidRuntime::getJNIEnv();
env->DeleteWeakGlobalRef(event->mLinearBlockObj);
@@ -179,6 +180,7 @@ void DestroyCallback(const C2Buffer * /* buf */, void *arg) {
event->mAvHandleRefCnt--;
event->finalize();
+ event->decStrong(buf);
}
namespace android {
@@ -369,6 +371,7 @@ jobject MediaEvent::getLinearBlock() {
pC2Buffer->setInfo(info);
}
pC2Buffer->registerOnDestroyNotify(&DestroyCallback, this);
+ incStrong(pC2Buffer.get());
jobject linearBlock =
env->NewObject(
env->FindClass("android/media/MediaCodec$LinearBlock"),
@@ -3646,6 +3649,7 @@ static jobject android_media_tv_Tuner_media_event_get_linear_block(
ALOGD("Failed get MediaEvent");
return NULL;
}
+ android::Mutex::Autolock autoLock(mediaEventSp->mLock);
return mediaEventSp->getLinearBlock();
}
diff --git a/apex/permission/testing/Android.bp b/packages/Connectivity/framework/Android.bp
index 63bf0a08e956..8db8d7699a1e 100644
--- a/apex/permission/testing/Android.bp
+++ b/packages/Connectivity/framework/Android.bp
@@ -1,25 +1,29 @@
-// Copyright (C) 2019 The Android Open Source Project
+//
+// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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.
+//
-apex_test {
- name: "test_com.android.permission",
+// TODO: use a java_library in the bootclasspath instead
+filegroup {
+ name: "framework-connectivity-sources",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.aidl",
+ ],
+ path: "src",
visibility: [
- "//system/apex/tests",
+ "//frameworks/base",
+ "//packages/modules/Connectivity:__subpackages__",
],
- defaults: ["com.android.permission-defaults"],
- manifest: "test_manifest.json",
- file_contexts: ":com.android.permission-file_contexts",
- // Test APEX, should never be installed
- installable: false,
-}
+} \ No newline at end of file
diff --git a/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl b/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl
new file mode 100644
index 000000000000..64b556720cd2
--- /dev/null
+++ b/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+package com.android.connectivity.aidl;
+
+import android.net.NattKeepalivePacketData;
+import android.net.QosFilterParcelable;
+import android.net.TcpKeepalivePacketData;
+
+import com.android.connectivity.aidl.INetworkAgentRegistry;
+
+/**
+ * Interface to notify NetworkAgent of connectivity events.
+ * @hide
+ */
+oneway interface INetworkAgent {
+ void onRegistered(in INetworkAgentRegistry registry);
+ void onDisconnected();
+ void onBandwidthUpdateRequested();
+ void onValidationStatusChanged(int validationStatus,
+ in @nullable String captivePortalUrl);
+ void onSaveAcceptUnvalidated(boolean acceptUnvalidated);
+ void onStartNattSocketKeepalive(int slot, int intervalDurationMs,
+ in NattKeepalivePacketData packetData);
+ void onStartTcpSocketKeepalive(int slot, int intervalDurationMs,
+ in TcpKeepalivePacketData packetData);
+ void onStopSocketKeepalive(int slot);
+ void onSignalStrengthThresholdsUpdated(in int[] thresholds);
+ void onPreventAutomaticReconnect();
+ void onAddNattKeepalivePacketFilter(int slot,
+ in NattKeepalivePacketData packetData);
+ void onAddTcpKeepalivePacketFilter(int slot,
+ in TcpKeepalivePacketData packetData);
+ void onRemoveKeepalivePacketFilter(int slot);
+ void onQosFilterCallbackRegistered(int qosCallbackId, in QosFilterParcelable filterParcel);
+ void onQosCallbackUnregistered(int qosCallbackId);
+}
diff --git a/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl b/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl
new file mode 100644
index 000000000000..f0193db5c2e2
--- /dev/null
+++ b/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+package com.android.connectivity.aidl;
+
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.QosSession;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+
+/**
+ * Interface for NetworkAgents to send network network properties.
+ * @hide
+ */
+oneway interface INetworkAgentRegistry {
+ void sendNetworkCapabilities(in NetworkCapabilities nc);
+ void sendLinkProperties(in LinkProperties lp);
+ // TODO: consider replacing this by "markConnected()" and removing
+ void sendNetworkInfo(in NetworkInfo info);
+ void sendScore(int score);
+ void sendExplicitlySelected(boolean explicitlySelected, boolean acceptPartial);
+ void sendSocketKeepaliveEvent(int slot, int reason);
+ void sendUnderlyingNetworks(in @nullable List<Network> networks);
+ void sendEpsQosSessionAvailable(int callbackId, in QosSession session, in EpsBearerQosSessionAttributes attributes);
+ void sendQosSessionLost(int qosCallbackId, in QosSession session);
+ void sendQosCallbackError(int qosCallbackId, int exceptionType);
+}
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java
index 06c52942e671..fcee98d0bd0b 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java
@@ -19,11 +19,8 @@ package com.android.dynsystem;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.image.DynamicSystemClient;
-import android.os.image.DynamicSystemManager;
-import android.util.FeatureFlagUtils;
/**
@@ -43,24 +40,10 @@ public class BootCompletedReceiver extends BroadcastReceiver {
return;
}
- DynamicSystemManager dynSystem =
- (DynamicSystemManager) context.getSystemService(Context.DYNAMIC_SYSTEM_SERVICE);
-
- boolean isInUse = (dynSystem != null) && dynSystem.isInUse();
-
- if (!isInUse && !featureFlagEnabled()) {
- return;
- }
-
Intent startServiceIntent = new Intent(
context, DynamicSystemInstallationService.class);
startServiceIntent.setAction(DynamicSystemClient.ACTION_NOTIFY_IF_IN_USE);
context.startServiceAsUser(startServiceIntent, UserHandle.SYSTEM);
}
-
- private boolean featureFlagEnabled() {
- return SystemProperties.getBoolean(
- FeatureFlagUtils.PERSIST_PREFIX + FeatureFlagUtils.DYNAMIC_SYSTEM, false);
- }
}
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
index 82ea7449bf6d..64e42cc595ec 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
@@ -22,10 +22,8 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.image.DynamicSystemClient;
-import android.util.FeatureFlagUtils;
import android.util.Log;
/**
@@ -46,12 +44,6 @@ public class VerificationActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (!featureFlagEnabled()) {
- Log.w(TAG, FeatureFlagUtils.DYNAMIC_SYSTEM + " not enabled; activity aborted.");
- finish();
- return;
- }
-
KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
if (km != null) {
@@ -101,11 +93,6 @@ public class VerificationActivity extends Activity {
startServiceAsUser(intent, UserHandle.SYSTEM);
}
- private boolean featureFlagEnabled() {
- return SystemProperties.getBoolean(
- FeatureFlagUtils.PERSIST_PREFIX + FeatureFlagUtils.DYNAMIC_SYSTEM, false);
- }
-
static boolean isVerified(String url) {
if (url == null) return true;
return sVerifiedUrl != null && sVerifiedUrl.equals(url);
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index c63cf06cf75c..2b5e9cdc017d 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -291,7 +291,7 @@
<item>256K</item>
<item>1M</item>
<item>4M</item>
- <item>16M</item>
+ <item>8M</item>
</string-array>
<!-- Titles for logd limit size lowram selection preference. [CHAR LIMIT=14] -->
@@ -309,7 +309,7 @@
<item>262144</item>
<item>1048576</item>
<item>4194304</item>
- <item>16777216</item>
+ <item>8388608</item>
</string-array>
<!-- Summaries for logd limit size selection preference. [CHAR LIMIT=50]-->
@@ -319,7 +319,7 @@
<item>256K per log buffer</item>
<item>1M per log buffer</item>
<item>4M per log buffer</item>
- <item>16M per log buffer</item>
+ <item>8M per log buffer</item>
</string-array>
<!-- Values for logpersist state selection preference. -->
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 741a6803a1e3..e222b3bf7921 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -156,6 +156,7 @@
<uses-permission android:name="android.permission.MANAGE_CONTENT_SUGGESTIONS" />
<uses-permission android:name="android.permission.MANAGE_APP_PREDICTIONS" />
<uses-permission android:name="android.permission.MANAGE_SEARCH_UI" />
+ <uses-permission android:name="android.permission.MANAGE_SMARTSPACE" />
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.SET_TIME" />
@@ -291,8 +292,8 @@
<!-- Permission needed to test mainline permission module rollback -->
<uses-permission android:name="android.permission.UPGRADE_RUNTIME_PERMISSIONS" />
- <!-- Permission needed to read wifi network credentials for CtsNetTestCases -->
- <uses-permission android:name="android.permission.NETWORK_AIRPLANE_MODE" />
+ <!-- Permission needed to restart WiFi Subsystem -->
+ <uses-permission android:name="android.permission.RESTART_WIFI_SUBSYSTEM" />
<!-- Permission needed to read wifi network credentials for CtsNetTestCases -->
<uses-permission android:name="android.permission.READ_WIFI_CREDENTIAL" />
@@ -345,6 +346,9 @@
<uses-permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
<uses-permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
+ <!-- Permission required for CTS test - CtsSensorPrivacyTestCases -->
+ <uses-permission android:name="android.permission.MANAGE_SENSOR_PRIVACY" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 6ecf303c6dc8..249b1946d435 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -45,7 +45,7 @@ android_library {
"WindowManager-Shell",
"SystemUIPluginLib",
"SystemUISharedLib",
- "SystemUI-statsd",
+ "SystemUI-statsd",
"SettingsLib",
"androidx.viewpager2_viewpager2",
"androidx.legacy_legacy-support-v4",
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index 5a7c5c9b5ebc..f65f97a3a450 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -271,7 +271,7 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout {
float contentStart = getPaddingStart();
int childCount = getChildCount();
// Underflow === don't show content until that index
- if (DEBUG) android.util.Log.d(TAG, "calculateIconTranslations: start=" + translationX
+ if (DEBUG) Log.d(TAG, "calculateIconTranslations: start=" + translationX
+ " width=" + width + " underflow=" + mNeedsUnderflow);
// Collect all of the states which want to be visible
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 309d4b04ebbf..c5a35eaf3e6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -29,7 +29,6 @@ import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.IConnectivityManager;
import android.net.Network;
-import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.os.Handler;
import android.os.RemoteException;
@@ -66,12 +65,8 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi
private static final String TAG = "SecurityController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private static final NetworkRequest REQUEST = new NetworkRequest.Builder()
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
- .setUids(null)
- .build();
+ private static final NetworkRequest REQUEST =
+ new NetworkRequest.Builder().clearCapabilities().build();
private static final int NO_NETWORK = -1;
private static final String VPN_BRANDED_META_DATA = "com.android.systemui.IS_BRANDED";
diff --git a/packages/services/CameraExtensionsProxy/OWNERS b/packages/services/CameraExtensionsProxy/OWNERS
new file mode 100644
index 000000000000..f48a95c5b3a3
--- /dev/null
+++ b/packages/services/CameraExtensionsProxy/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/av:/camera/OWNERS
diff --git a/services/Android.bp b/services/Android.bp
index ef52c2aff002..a13dbe612528 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -139,7 +139,7 @@ droidstubs {
last_released: {
api_file: ":android.api.system-server.latest",
removed_api_file: ":removed.api.system-server.latest",
- baseline_file: ":system-server-api-incompatibilities-with-last-released"
+ baseline_file: ":android-incompatibilities.api.system-server.latest"
},
api_lint: {
enabled: true,
@@ -147,11 +147,20 @@ droidstubs {
baseline_file: "api/lint-baseline.txt",
},
},
- dist: {
- targets: ["sdk", "win_sdk"],
- dir: "apistubs/android/system-server/api",
- dest: "android.txt",
- },
+ dists: [
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/system-server/api",
+ dest: "android.txt",
+ tag: ".api.txt"
+ },
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/system-server/api",
+ dest: "removed.txt",
+ tag: ".removed-api.txt",
+ },
+ ]
}
java_library {
diff --git a/services/OWNERS b/services/OWNERS
index 88d0b61a2ab6..03e0807eea62 100644
--- a/services/OWNERS
+++ b/services/OWNERS
@@ -1 +1,6 @@
per-file Android.bp = file:platform/build/soong:/OWNERS
+
+# art-team@ manages the system server profile
+per-file art-profile* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+
+per-file java/com/android/server/* = toddke@google.com
diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS
index c6f42f719caa..a31cfae995b2 100644
--- a/services/accessibility/OWNERS
+++ b/services/accessibility/OWNERS
@@ -1,4 +1,4 @@
svetoslavganov@google.com
pweaver@google.com
rhedjao@google.com
-qasid@google.com
+ryanlwlin@google.com
diff --git a/services/appwidget/java/com/android/server/appwidget/OWNERS b/services/appwidget/java/com/android/server/appwidget/OWNERS
new file mode 100644
index 000000000000..d724cac4aa3e
--- /dev/null
+++ b/services/appwidget/java/com/android/server/appwidget/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/appwidget/OWNERS
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 307d344bffa7..4bebe399b8bc 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -84,6 +84,7 @@ java_library_static {
":storaged_aidl",
":vold_aidl",
":platform-compat-config",
+ ":platform-compat-overrides",
":display-device-config",
"java/com/android/server/EventLogTags.logtags",
"java/com/android/server/am/EventLogTags.logtags",
@@ -112,6 +113,9 @@ java_library_static {
"time_zone_distro",
"time_zone_distro_installer",
"android.hardware.authsecret-V1.0-java",
+ "android.hardware.boot-V1.0-java",
+ "android.hardware.boot-V1.1-java",
+ "android.hardware.boot-V1.2-java",
"android.hardware.broadcastradio-V2.0-java",
"android.hardware.health-V1.0-java",
"android.hardware.health-V2.0-java",
@@ -200,6 +204,8 @@ filegroup {
"java/com/android/server/connectivity/NetworkRanker.java",
"java/com/android/server/connectivity/PermissionMonitor.java",
"java/com/android/server/connectivity/ProxyTracker.java",
+ "java/com/android/server/connectivity/QosCallbackAgentConnection.java",
+ "java/com/android/server/connectivity/QosCallbackTracker.java",
"java/com/android/server/connectivity/TcpKeepaliveController.java",
"java/com/android/server/connectivity/Vpn.java",
"java/com/android/server/connectivity/VpnIkev2Utils.java",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d0a5f33a28e9..554edc6d74bd 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -94,6 +94,7 @@ import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener;
import android.net.INetworkStatsService;
+import android.net.IQosCallback;
import android.net.ISocketKeepaliveCallback;
import android.net.InetAddresses;
import android.net.IpMemoryStore;
@@ -121,12 +122,17 @@ import android.net.NetworkUtils;
import android.net.NetworkWatchlistManager;
import android.net.PrivateDnsConfigParcel;
import android.net.ProxyInfo;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosSocketFilter;
+import android.net.QosSocketInfo;
import android.net.RouteInfo;
import android.net.RouteInfoParcel;
import android.net.SocketKeepalive;
import android.net.TetheringManager;
import android.net.UidRange;
import android.net.UidRangeParcel;
+import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
import android.net.VpnManager;
import android.net.VpnService;
@@ -179,7 +185,6 @@ import com.android.internal.app.IBatteryStats;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.AsyncChannel;
@@ -194,7 +199,6 @@ import com.android.server.connectivity.AutodestructReference;
import com.android.server.connectivity.DataConnectionStats;
import com.android.server.connectivity.DnsManager;
import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
-import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.connectivity.KeepaliveTracker;
import com.android.server.connectivity.LingerMonitor;
import com.android.server.connectivity.MockableSystemProperties;
@@ -205,6 +209,7 @@ import com.android.server.connectivity.NetworkNotificationManager.NotificationTy
import com.android.server.connectivity.NetworkRanker;
import com.android.server.connectivity.PermissionMonitor;
import com.android.server.connectivity.ProxyTracker;
+import com.android.server.connectivity.QosCallbackTracker;
import com.android.server.connectivity.Vpn;
import com.android.server.net.BaseNetworkObserver;
import com.android.server.net.LockdownVpnTracker;
@@ -280,6 +285,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Default to 30s linger time-out. Modifiable only for testing.
private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger";
private static final int DEFAULT_LINGER_DELAY_MS = 30_000;
+
+ // The maximum number of network request allowed per uid before an exception is thrown.
+ private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
+
@VisibleForTesting
protected int mLingerDelayMs; // Can't be final, or test subclass constructors can't change it.
@@ -292,6 +301,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
@VisibleForTesting
protected final PermissionMonitor mPermissionMonitor;
+ private final PerUidCounter mNetworkRequestCounter;
+
private KeyStore mKeyStore;
@VisibleForTesting
@@ -314,6 +325,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
private boolean mRestrictBackground;
private final Context mContext;
+ // The Context is created for UserHandle.ALL.
+ private final Context mUserAllContext;
private final Dependencies mDeps;
// 0 is full bad, 100 is full good
private int mDefaultInetConditionPublished = 0;
@@ -615,6 +628,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private final LocationPermissionChecker mLocationPermissionChecker;
private KeepaliveTracker mKeepaliveTracker;
+ private QosCallbackTracker mQosCallbackTracker;
private NetworkNotificationManager mNotifier;
private LingerMonitor mLingerMonitor;
@@ -859,6 +873,66 @@ public class ConnectivityService extends IConnectivityManager.Stub
};
/**
+ * Keeps track of the number of requests made under different uids.
+ */
+ public static class PerUidCounter {
+ private final int mMaxCountPerUid;
+
+ // Map from UID to number of NetworkRequests that UID has filed.
+ @GuardedBy("mUidToNetworkRequestCount")
+ private final SparseIntArray mUidToNetworkRequestCount = new SparseIntArray();
+
+ /**
+ * Constructor
+ *
+ * @param maxCountPerUid the maximum count per uid allowed
+ */
+ public PerUidCounter(final int maxCountPerUid) {
+ mMaxCountPerUid = maxCountPerUid;
+ }
+
+ /**
+ * Increments the request count of the given uid. Throws an exception if the number
+ * of open requests for the uid exceeds the value of maxCounterPerUid which is the value
+ * passed into the constructor. see: {@link #PerUidCounter(int)}.
+ *
+ * @throws ServiceSpecificException with
+ * {@link ConnectivityManager.Errors.TOO_MANY_REQUESTS} if the number of requests for
+ * the uid exceed the allowed number.
+ *
+ * @param uid the uid that the request was made under
+ */
+ public void incrementCountOrThrow(final int uid) {
+ synchronized (mUidToNetworkRequestCount) {
+ final int networkRequests = mUidToNetworkRequestCount.get(uid, 0) + 1;
+ if (networkRequests >= mMaxCountPerUid) {
+ throw new ServiceSpecificException(
+ ConnectivityManager.Errors.TOO_MANY_REQUESTS);
+ }
+ mUidToNetworkRequestCount.put(uid, networkRequests);
+ }
+ }
+
+ /**
+ * Decrements the request count of the given uid.
+ *
+ * @param uid the uid that the request was made under
+ */
+ public void decrementCount(final int uid) {
+ synchronized (mUidToNetworkRequestCount) {
+ final int requests = mUidToNetworkRequestCount.get(uid, 0);
+ if (requests < 1) {
+ logwtf("BUG: too small request count " + requests + " for UID " + uid);
+ } else if (requests == 1) {
+ mUidToNetworkRequestCount.delete(uid);
+ } else {
+ mUidToNetworkRequestCount.put(uid, requests - 1);
+ }
+ }
+ }
+ }
+
+ /**
* Dependencies of ConnectivityService, for injection in tests.
*/
@VisibleForTesting
@@ -889,6 +963,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
/**
+ * Get a reference to the system keystore.
+ */
+ public KeyStore getKeyStore() {
+ return KeyStore.getInstance();
+ }
+
+ /**
* @see ProxyTracker
*/
public ProxyTracker makeProxyTracker(@NonNull Context context,
@@ -918,14 +999,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
return new MultinetworkPolicyTracker(c, h, r);
}
- /**
- * @see IpConnectivityMetrics.Logger
- */
- public IpConnectivityMetrics.Logger getMetricsLogger() {
- return Objects.requireNonNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
- "no IpConnectivityMetrics service");
- }
-
public IBatteryStats getBatteryStatsService() {
return BatteryStatsService.getService();
}
@@ -947,6 +1020,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mSystemProperties = mDeps.getSystemProperties();
mNetIdManager = mDeps.makeNetIdManager();
mContext = Objects.requireNonNull(context, "missing Context");
+ mNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_UID);
mMetricsLog = logger;
mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
@@ -990,7 +1064,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
mNetd = netd;
- mKeyStore = KeyStore.getInstance();
+ mKeyStore = mDeps.getKeyStore();
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mLocationPermissionChecker = new LocationPermissionChecker(mContext);
@@ -1088,8 +1162,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
- final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
- userAllContext.registerReceiver(
+ mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
+ mUserAllContext.registerReceiver(
mIntentReceiver,
intentFilter,
null /* broadcastPermission */,
@@ -1105,7 +1179,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
- userAllContext.registerReceiver(
+ mUserAllContext.registerReceiver(
mIntentReceiver,
intentFilter,
null /* broadcastPermission */,
@@ -1114,14 +1188,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Listen to lockdown VPN reset.
intentFilter = new IntentFilter();
intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET);
- userAllContext.registerReceiver(
+ mUserAllContext.registerReceiver(
mIntentReceiver, intentFilter, NETWORK_STACK, mHandler);
- try {
- mNMS.registerObserver(mDataActivityObserver);
- } catch (RemoteException e) {
- loge("Error registering observer :" + e);
- }
+ mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mNMS);
mSettingsObserver = new SettingsObserver(mContext, mHandler);
registerSettingsCallbacks();
@@ -1131,6 +1201,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mKeepaliveTracker = new KeepaliveTracker(mContext, mHandler);
mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager);
+ mQosCallbackTracker = new QosCallbackTracker(mHandler, mNetworkRequestCounter);
final int dailyLimit = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
@@ -1387,9 +1458,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
return;
}
final String action = blocked ? "BLOCKED" : "UNBLOCKED";
- final NetworkRequest satisfiedRequest = nri.getSatisfiedRequest();
- final int requestId = satisfiedRequest != null
- ? satisfiedRequest.requestId : nri.mRequests.get(0).requestId;
+ final int requestId = nri.getActiveRequest() != null
+ ? nri.getActiveRequest().requestId : nri.mRequests.get(0).requestId;
mNetworkInfoBlockingLogs.log(String.format(
"%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId()));
}
@@ -1569,7 +1639,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (nc != null) {
result.put(
nai.network,
- maybeSanitizeLocationInfoForCaller(
+ createWithLocationInfoSanitizedIfNecessaryWhenParceled(
nc, mDeps.getCallingUid(), callingPackageName));
}
@@ -1579,7 +1649,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
for (Network network : networks) {
nc = getNetworkCapabilitiesInternal(network);
if (nc != null) {
- result.put(network, maybeSanitizeLocationInfoForCaller(
+ result.put(
+ network,
+ createWithLocationInfoSanitizedIfNecessaryWhenParceled(
nc, mDeps.getCallingUid(), callingPackageName));
}
}
@@ -1651,7 +1723,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
if (nai == null) return null;
synchronized (nai) {
- if (nai.networkCapabilities == null) return null;
return networkCapabilitiesRestrictedForCallerPermissions(
nai.networkCapabilities, Binder.getCallingPid(), mDeps.getCallingUid());
}
@@ -1661,7 +1732,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
public NetworkCapabilities getNetworkCapabilities(Network network, String callingPackageName) {
mAppOpsManager.checkPackage(mDeps.getCallingUid(), callingPackageName);
enforceAccessPermission();
- return maybeSanitizeLocationInfoForCaller(
+ return createWithLocationInfoSanitizedIfNecessaryWhenParceled(
getNetworkCapabilitiesInternal(network),
mDeps.getCallingUid(), callingPackageName);
}
@@ -1682,37 +1753,51 @@ public class ConnectivityService extends IConnectivityManager.Stub
return newNc;
}
+ private boolean hasLocationPermission(int callerUid, @NonNull String callerPkgName) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return mLocationPermissionChecker.checkLocationPermission(
+ callerPkgName, null /* featureId */, callerUid, null /* message */);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
@VisibleForTesting
@Nullable
- NetworkCapabilities maybeSanitizeLocationInfoForCaller(
+ NetworkCapabilities createWithLocationInfoSanitizedIfNecessaryWhenParceled(
@Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName) {
if (nc == null) {
return null;
}
- final NetworkCapabilities newNc = new NetworkCapabilities(nc);
- if (callerUid != newNc.getOwnerUid()) {
+ Boolean hasLocationPermission = null;
+ final NetworkCapabilities newNc;
+ // Avoid doing location permission check if the transport info has no location sensitive
+ // data.
+ if (nc.getTransportInfo() != null && nc.getTransportInfo().hasLocationSensitiveFields()) {
+ hasLocationPermission = hasLocationPermission(callerUid, callerPkgName);
+ newNc = new NetworkCapabilities(nc, hasLocationPermission);
+ } else {
+ newNc = new NetworkCapabilities(nc, false /* parcelLocationSensitiveFields */);
+ }
+ // Reset owner uid if not destined for the owner app.
+ if (callerUid != nc.getOwnerUid()) {
newNc.setOwnerUid(INVALID_UID);
return newNc;
}
-
// Allow VPNs to see ownership of their own VPN networks - not location sensitive.
if (nc.hasTransport(TRANSPORT_VPN)) {
// Owner UIDs already checked above. No need to re-check.
return newNc;
}
-
- final long token = Binder.clearCallingIdentity();
- try {
- if (!mLocationPermissionChecker.checkLocationPermission(
- callerPkgName, null /* featureId */, callerUid, null /* message */)) {
- // Caller does not have the requisite location permissions. Reset the
- // owner's UID in the NetworkCapabilities.
- newNc.setOwnerUid(INVALID_UID);
- }
- } finally {
- Binder.restoreCallingIdentity(token);
+ if (hasLocationPermission == null) {
+ // Location permission not checked yet, check now for masking owner UID.
+ hasLocationPermission = hasLocationPermission(callerUid, callerPkgName);
+ }
+ // Reset owner uid if the app has no location permission.
+ if (!hasLocationPermission) {
+ newNc.setOwnerUid(INVALID_UID);
}
-
return newNc;
}
@@ -1789,30 +1874,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() {
- @Override
- public void interfaceClassDataActivityChanged(int transportType, boolean active,
- long tsNanos, int uid) {
- sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active, tsNanos);
- }
- };
-
- // This is deprecated and only to support legacy use cases.
- private int transportTypeToLegacyType(int type) {
- switch (type) {
- case NetworkCapabilities.TRANSPORT_CELLULAR:
- return ConnectivityManager.TYPE_MOBILE;
- case NetworkCapabilities.TRANSPORT_WIFI:
- return ConnectivityManager.TYPE_WIFI;
- case NetworkCapabilities.TRANSPORT_BLUETOOTH:
- return ConnectivityManager.TYPE_BLUETOOTH;
- case NetworkCapabilities.TRANSPORT_ETHERNET:
- return ConnectivityManager.TYPE_ETHERNET;
- default:
- loge("Unexpected transport in transportTypeToLegacyType: " + type);
- }
- return ConnectivityManager.TYPE_NONE;
- }
/**
* Ensures that the system cannot call a particular method.
*/
@@ -2261,20 +2322,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
sendStickyBroadcast(makeGeneralIntent(info, bcastType));
}
- private void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) {
- Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
- intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
- intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active);
- intent.putExtra(ConnectivityManager.EXTRA_REALTIME_NS, tsNanos);
- final long ident = Binder.clearCallingIdentity();
- try {
- mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL,
- RECEIVE_DATA_ACTIVITY_CHANGE, null, null, 0, null, null);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
private void sendStickyBroadcast(Intent intent) {
synchronized (this) {
if (!mSystemReady
@@ -2304,7 +2351,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
intent.addFlags(Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
}
try {
- mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL, options);
+ mUserAllContext.sendStickyBroadcast(intent, options);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -2380,74 +2427,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
/**
- * Setup data activity tracking for the given network.
- *
- * Every {@code setupDataActivityTracking} should be paired with a
- * {@link #removeDataActivityTracking} for cleanup.
- */
- private void setupDataActivityTracking(NetworkAgentInfo networkAgent) {
- final String iface = networkAgent.linkProperties.getInterfaceName();
-
- final int timeout;
- final int type;
-
- if (networkAgent.networkCapabilities.hasTransport(
- NetworkCapabilities.TRANSPORT_CELLULAR)) {
- timeout = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
- 10);
- type = NetworkCapabilities.TRANSPORT_CELLULAR;
- } else if (networkAgent.networkCapabilities.hasTransport(
- NetworkCapabilities.TRANSPORT_WIFI)) {
- timeout = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
- 15);
- type = NetworkCapabilities.TRANSPORT_WIFI;
- } else {
- return; // do not track any other networks
- }
-
- if (timeout > 0 && iface != null) {
- try {
- mNMS.addIdleTimer(iface, timeout, type);
- } catch (Exception e) {
- // You shall not crash!
- loge("Exception in setupDataActivityTracking " + e);
- }
- }
- }
-
- /**
- * Remove data activity tracking when network disconnects.
- */
- private void removeDataActivityTracking(NetworkAgentInfo networkAgent) {
- final String iface = networkAgent.linkProperties.getInterfaceName();
- final NetworkCapabilities caps = networkAgent.networkCapabilities;
-
- if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
- caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) {
- try {
- // the call fails silently if no idle timer setup for this interface
- mNMS.removeIdleTimer(iface);
- } catch (Exception e) {
- loge("Exception in removeDataActivityTracking " + e);
- }
- }
- }
-
- /**
- * Update data activity tracking when network state is updated.
- */
- private void updateDataActivityTracking(NetworkAgentInfo newNetwork,
- NetworkAgentInfo oldNetwork) {
- if (newNetwork != null) {
- setupDataActivityTracking(newNetwork);
- }
- if (oldNetwork != null) {
- removeDataActivityTracking(oldNetwork);
- }
- }
- /**
* Reads the network specific MTU size from resources.
* and set it on it's iface.
*/
@@ -2750,7 +2729,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
@VisibleForTesting
NetworkRequestInfo[] requestsSortedById() {
NetworkRequestInfo[] requests = new NetworkRequestInfo[0];
- requests = mNetworkRequests.values().toArray(requests);
+ requests = getNrisFromGlobalRequests().toArray(requests);
// Sort the array based off the NRI containing the min requestId in its requests.
Arrays.sort(requests,
Comparator.comparingInt(nri -> Collections.min(nri.mRequests,
@@ -2761,7 +2740,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
private boolean isLiveNetworkAgent(NetworkAgentInfo nai, int what) {
- if (nai.network == null) return false;
final NetworkAgentInfo officialNai = getNetworkAgentInfoForNetwork(nai.network);
if (officialNai != null && officialNai.equals(nai)) return true;
if (officialNai != null || VDBG) {
@@ -2862,13 +2840,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
Log.wtf(TAG, "Non-virtual networks cannot have underlying networks");
break;
}
- final ArrayList<Network> underlying;
- try {
- underlying = ((Bundle) arg.second).getParcelableArrayList(
- NetworkAgent.UNDERLYING_NETWORKS_KEY);
- } catch (NullPointerException | ClassCastException e) {
- break;
- }
+ final List<Network> underlying = (List<Network>) arg.second;
final Network[] oldUnderlying = nai.declaredUnderlyingNetworks;
nai.declaredUnderlyingNetworks = (underlying != null)
? underlying.toArray(new Network[0]) : null;
@@ -2881,6 +2853,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
updateCapabilitiesForNetwork(nai);
notifyIfacesChangedForNetworkStats();
}
+ break;
}
}
}
@@ -3442,6 +3415,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// of rematchAllNetworksAndRequests
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
mKeepaliveTracker.handleStopAllKeepalives(nai, SocketKeepalive.ERROR_INVALID_NETWORK);
+
+ mQosCallbackTracker.handleNetworkReleased(nai.network);
for (String iface : nai.linkProperties.getAllInterfaceNames()) {
// Disable wakeup packet monitoring for each interface.
wakeupModifyInterface(iface, nai.networkCapabilities, false);
@@ -3454,22 +3429,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
// available until we've told netd to delete it below.
mNetworkForNetId.remove(nai.network.getNetId());
}
+ propagateUnderlyingNetworkCapabilities(nai.network);
// Remove all previously satisfied requests.
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest request = nai.requestAt(i);
final NetworkRequestInfo nri = mNetworkRequests.get(request);
- final NetworkAgentInfo currentNetwork = nri.mSatisfier;
+ final NetworkAgentInfo currentNetwork = nri.getSatisfier();
if (currentNetwork != null
&& currentNetwork.network.getNetId() == nai.network.getNetId()) {
- nri.mSatisfier = null;
+ nri.setSatisfier(null, null);
sendUpdatedScoreToFactories(request, null);
}
}
nai.clearLingerState();
- propagateUnderlyingNetworkCapabilities(nai.network);
+ // TODO: this loop, and the mLegacyTypeTracker.remove just below it, seem redundant given
+ // there's a full rematch right after. Currently, deleting it breaks tests that check for
+ // the default network disconnecting. Find out why, fix the rematch code, and delete this.
if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
mDefaultNetworkNai = null;
- updateDataActivityTracking(null /* newNetwork */, nai);
+ mNetworkActivityTracker.updateDataActivityTracking(null /* newNetwork */, nai);
notifyLockdownVpn(nai);
ensureNetworkTransitionWakelock(nai.toShortString());
}
@@ -3537,42 +3515,63 @@ public class ConnectivityService extends IConnectivityManager.Stub
return null;
}
- private void handleRegisterNetworkRequestWithIntent(Message msg) {
+ private void handleRegisterNetworkRequestWithIntent(@NonNull final Message msg) {
final NetworkRequestInfo nri = (NetworkRequestInfo) (msg.obj);
-
- NetworkRequestInfo existingRequest = findExistingNetworkRequestInfo(nri.mPendingIntent);
+ // handleRegisterNetworkRequestWithIntent() doesn't apply to multilayer requests.
+ ensureNotMultilayerRequest(nri, "handleRegisterNetworkRequestWithIntent");
+ final NetworkRequestInfo existingRequest =
+ findExistingNetworkRequestInfo(nri.mPendingIntent);
if (existingRequest != null) { // remove the existing request.
- if (DBG) log("Replacing " + existingRequest.request + " with "
- + nri.request + " because their intents matched.");
- handleReleaseNetworkRequest(existingRequest.request, getCallingUid(),
+ if (DBG) {
+ log("Replacing " + existingRequest.mRequests.get(0) + " with "
+ + nri.mRequests.get(0) + " because their intents matched.");
+ }
+ handleReleaseNetworkRequest(existingRequest.mRequests.get(0), getCallingUid(),
/* callOnUnavailable */ false);
}
handleRegisterNetworkRequest(nri);
}
- private void handleRegisterNetworkRequest(NetworkRequestInfo nri) {
+ private void handleRegisterNetworkRequest(@NonNull final NetworkRequestInfo nri) {
ensureRunningOnConnectivityServiceThread();
- mNetworkRequests.put(nri.request, nri);
mNetworkRequestInfoLogs.log("REGISTER " + nri);
- if (nri.request.isListen()) {
- for (NetworkAgentInfo network : mNetworkAgentInfos) {
- if (nri.request.networkCapabilities.hasSignalStrength() &&
- network.satisfiesImmutableCapabilitiesOf(nri.request)) {
- updateSignalStrengthThresholds(network, "REGISTER", nri.request);
+ for (final NetworkRequest req : nri.mRequests) {
+ mNetworkRequests.put(req, nri);
+ if (req.isListen()) {
+ for (final NetworkAgentInfo network : mNetworkAgentInfos) {
+ if (req.networkCapabilities.hasSignalStrength()
+ && network.satisfiesImmutableCapabilitiesOf(req)) {
+ updateSignalStrengthThresholds(network, "REGISTER", req);
+ }
}
}
}
rematchAllNetworksAndRequests();
- if (nri.request.isRequest() && nri.mSatisfier == null) {
- sendUpdatedScoreToFactories(nri.request, null);
+ // If an active request exists, return as its score has already been sent if needed.
+ if (null != nri.getActiveRequest()) {
+ return;
+ }
+
+ // As this request was not satisfied on rematch and thus never had any scores sent to the
+ // factories, send null now for each request of type REQUEST.
+ for (final NetworkRequest req : nri.mRequests) {
+ if (!req.isRequest()) {
+ continue;
+ }
+ sendUpdatedScoreToFactories(req, null);
}
}
- private void handleReleaseNetworkRequestWithIntent(PendingIntent pendingIntent,
- int callingUid) {
- NetworkRequestInfo nri = findExistingNetworkRequestInfo(pendingIntent);
+ private void handleReleaseNetworkRequestWithIntent(@NonNull final PendingIntent pendingIntent,
+ final int callingUid) {
+ final NetworkRequestInfo nri = findExistingNetworkRequestInfo(pendingIntent);
if (nri != null) {
- handleReleaseNetworkRequest(nri.request, callingUid, /* callOnUnavailable */ false);
+ // handleReleaseNetworkRequestWithIntent() paths don't apply to multilayer requests.
+ ensureNotMultilayerRequest(nri, "handleReleaseNetworkRequestWithIntent");
+ handleReleaseNetworkRequest(
+ nri.mRequests.get(0),
+ callingUid,
+ /* callOnUnavailable */ false);
}
}
@@ -3626,6 +3625,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
return false;
}
for (final NetworkRequest req : nri.mRequests) {
+ // This multilayer listen request is satisfied therefore no further requests need to be
+ // evaluated deeming this network not a potential satisfier.
+ if (req.isListen() && nri.getActiveRequest() == req) {
+ return false;
+ }
// As non-multilayer listen requests have already returned, the below would only happen
// for a multilayer request therefore continue to the next request if available.
if (req.isListen()) {
@@ -3646,7 +3650,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// 2. Unvalidated WiFi will not be reaped when validated cellular
// is currently satisfying the request. This is desirable when
// WiFi ends up validating and out scoring cellular.
- || nri.mSatisfier.getCurrentScore()
+ || nri.getSatisfier().getCurrentScore()
< candidate.getCurrentScoreAsValidated();
return isNetworkNeeded;
}
@@ -3671,30 +3675,45 @@ public class ConnectivityService extends IConnectivityManager.Stub
return nri;
}
- private void handleTimedOutNetworkRequest(final NetworkRequestInfo nri) {
+ private void ensureNotMultilayerRequest(@NonNull final NetworkRequestInfo nri,
+ final String callingMethod) {
+ if (nri.isMultilayerRequest()) {
+ throw new IllegalStateException(
+ callingMethod + " does not support multilayer requests.");
+ }
+ }
+
+ private void handleTimedOutNetworkRequest(@NonNull final NetworkRequestInfo nri) {
ensureRunningOnConnectivityServiceThread();
- if (mNetworkRequests.get(nri.request) == null) {
+ // handleTimedOutNetworkRequest() is part of the requestNetwork() flow which works off of a
+ // single NetworkRequest and thus does not apply to multilayer requests.
+ ensureNotMultilayerRequest(nri, "handleTimedOutNetworkRequest");
+ if (mNetworkRequests.get(nri.mRequests.get(0)) == null) {
return;
}
- if (nri.mSatisfier != null) {
+ if (nri.getSatisfier() != null) {
return;
}
- if (VDBG || (DBG && nri.request.isRequest())) {
- log("releasing " + nri.request + " (timeout)");
+ if (VDBG || (DBG && nri.mRequests.get(0).isRequest())) {
+ log("releasing " + nri.mRequests.get(0) + " (timeout)");
}
handleRemoveNetworkRequest(nri);
- callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0);
+ callCallbackForRequest(
+ nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0);
}
- private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid,
- boolean callOnUnavailable) {
+ private void handleReleaseNetworkRequest(@NonNull final NetworkRequest request,
+ final int callingUid,
+ final boolean callOnUnavailable) {
final NetworkRequestInfo nri =
getNriForAppRequest(request, callingUid, "release NetworkRequest");
if (nri == null) {
return;
}
- if (VDBG || (DBG && nri.request.isRequest())) {
- log("releasing " + nri.request + " (release request)");
+ // handleReleaseNetworkRequest() paths don't apply to multilayer requests.
+ ensureNotMultilayerRequest(nri, "handleReleaseNetworkRequest");
+ if (VDBG || (DBG && request.isRequest())) {
+ log("releasing " + request + " (release request)");
}
handleRemoveNetworkRequest(nri);
if (callOnUnavailable) {
@@ -3702,42 +3721,88 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void handleRemoveNetworkRequest(final NetworkRequestInfo nri) {
+ private void handleRemoveNetworkRequest(@NonNull final NetworkRequestInfo nri) {
ensureRunningOnConnectivityServiceThread();
nri.unlinkDeathRecipient();
- mNetworkRequests.remove(nri.request);
+ for (final NetworkRequest req : nri.mRequests) {
+ mNetworkRequests.remove(req);
+ if (req.isListen()) {
+ removeListenRequestFromNetworks(req);
+ }
+ }
+ mNetworkRequestCounter.decrementCount(nri.mUid);
+ mNetworkRequestInfoLogs.log("RELEASE " + nri);
- decrementNetworkRequestPerUidCount(nri);
+ if (null != nri.getActiveRequest()) {
+ if (nri.getActiveRequest().isRequest()) {
+ removeSatisfiedNetworkRequestFromNetwork(nri);
+ } else {
+ nri.setSatisfier(null, null);
+ }
+ }
- mNetworkRequestInfoLogs.log("RELEASE " + nri);
- if (nri.request.isRequest()) {
- boolean wasKept = false;
- final NetworkAgentInfo nai = nri.mSatisfier;
- if (nai != null) {
- boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
- nai.removeRequest(nri.request.requestId);
- if (VDBG || DDBG) {
- log(" Removing from current network " + nai.toShortString()
- + ", leaving " + nai.numNetworkRequests() + " requests.");
- }
- // If there are still lingered requests on this network, don't tear it down,
- // but resume lingering instead.
- final long now = SystemClock.elapsedRealtime();
- if (updateLingerState(nai, now)) {
- notifyNetworkLosing(nai, now);
- }
- if (unneeded(nai, UnneededFor.TEARDOWN)) {
- if (DBG) log("no live requests for " + nai.toShortString() + "; disconnecting");
- teardownUnneededNetwork(nai);
- } else {
- wasKept = true;
- }
- nri.mSatisfier = null;
- if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) {
- // Went from foreground to background.
- updateCapabilitiesForNetwork(nai);
- }
+ cancelNpiRequests(nri);
+ }
+
+ private void cancelNpiRequests(@NonNull final NetworkRequestInfo nri) {
+ for (final NetworkRequest req : nri.mRequests) {
+ cancelNpiRequest(req);
+ }
+ }
+
+ private void cancelNpiRequest(@NonNull final NetworkRequest req) {
+ if (req.isRequest()) {
+ for (final NetworkProviderInfo npi : mNetworkProviderInfos.values()) {
+ npi.cancelRequest(req);
+ }
+ }
+ }
+
+ private void removeListenRequestFromNetworks(@NonNull final NetworkRequest req) {
+ // listens don't have a singular affected Network. Check all networks to see
+ // if this listen request applies and remove it.
+ for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
+ nai.removeRequest(req.requestId);
+ if (req.networkCapabilities.hasSignalStrength()
+ && nai.satisfiesImmutableCapabilitiesOf(req)) {
+ updateSignalStrengthThresholds(nai, "RELEASE", req);
+ }
+ }
+ }
+
+ /**
+ * Remove a NetworkRequestInfo's satisfied request from its 'satisfier' (NetworkAgentInfo) and
+ * manage the necessary upkeep (linger, teardown networks, etc.) when doing so.
+ * @param nri the NetworkRequestInfo to disassociate from its current NetworkAgentInfo
+ */
+ private void removeSatisfiedNetworkRequestFromNetwork(@NonNull final NetworkRequestInfo nri) {
+ boolean wasKept = false;
+ final NetworkAgentInfo nai = nri.getSatisfier();
+ if (nai != null) {
+ final int requestLegacyType = nri.getActiveRequest().legacyType;
+ final boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
+ nai.removeRequest(nri.getActiveRequest().requestId);
+ if (VDBG || DDBG) {
+ log(" Removing from current network " + nai.toShortString()
+ + ", leaving " + nai.numNetworkRequests() + " requests.");
+ }
+ // If there are still lingered requests on this network, don't tear it down,
+ // but resume lingering instead.
+ final long now = SystemClock.elapsedRealtime();
+ if (updateLingerState(nai, now)) {
+ notifyNetworkLosing(nai, now);
+ }
+ if (unneeded(nai, UnneededFor.TEARDOWN)) {
+ if (DBG) log("no live requests for " + nai.toShortString() + "; disconnecting");
+ teardownUnneededNetwork(nai);
+ } else {
+ wasKept = true;
+ }
+ nri.setSatisfier(null, null);
+ if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) {
+ // Went from foreground to background.
+ updateCapabilitiesForNetwork(nai);
}
// Maintain the illusion. When this request arrived, we might have pretended
@@ -3745,15 +3810,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
// connected. Now that this request has gone away, we might have to pretend
// that the network disconnected. LegacyTypeTracker will generate that
// phantom disconnect for this type.
- if (nri.request.legacyType != TYPE_NONE && nai != null) {
+ if (requestLegacyType != TYPE_NONE) {
boolean doRemove = true;
if (wasKept) {
// check if any of the remaining requests for this network are for the
// same legacy type - if so, don't remove the nai
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest otherRequest = nai.requestAt(i);
- if (otherRequest.legacyType == nri.request.legacyType &&
- otherRequest.isRequest()) {
+ if (otherRequest.legacyType == requestLegacyType
+ && otherRequest.isRequest()) {
if (DBG) log(" still have other legacy request - leaving");
doRemove = false;
}
@@ -3761,39 +3826,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
if (doRemove) {
- mLegacyTypeTracker.remove(nri.request.legacyType, nai, false);
- }
- }
-
- for (NetworkProviderInfo npi : mNetworkProviderInfos.values()) {
- npi.cancelRequest(nri.request);
- }
- } else {
- // listens don't have a singular affectedNetwork. Check all networks to see
- // if this listen request applies and remove it.
- for (NetworkAgentInfo nai : mNetworkAgentInfos) {
- nai.removeRequest(nri.request.requestId);
- if (nri.request.networkCapabilities.hasSignalStrength() &&
- nai.satisfiesImmutableCapabilitiesOf(nri.request)) {
- updateSignalStrengthThresholds(nai, "RELEASE", nri.request);
+ mLegacyTypeTracker.remove(requestLegacyType, nai, false);
}
}
}
}
- private void decrementNetworkRequestPerUidCount(final NetworkRequestInfo nri) {
- synchronized (mUidToNetworkRequestCount) {
- final int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
- if (requests < 1) {
- Log.wtf(TAG, "BUG: too small request count " + requests + " for UID " + nri.mUid);
- } else if (requests == 1) {
- mUidToNetworkRequestCount.removeAt(mUidToNetworkRequestCount.indexOfKey(nri.mUid));
- } else {
- mUidToNetworkRequestCount.put(nri.mUid, requests - 1);
- }
- }
- }
-
@Override
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
enforceNetworkStackSettingsOrSetup();
@@ -4620,6 +4658,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
Log.w(TAG, s);
}
+ private static void logwtf(String s) {
+ Log.wtf(TAG, s);
+ }
+
private static void loge(String s) {
Log.e(TAG, s);
}
@@ -4812,28 +4854,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
*
* <p>Must be called on the handler thread.
*/
- private VpnInfo[] getAllVpnInfo() {
+ private UnderlyingNetworkInfo[] getAllVpnInfo() {
ensureRunningOnConnectivityServiceThread();
synchronized (mVpns) {
if (mLockdownEnabled) {
- return new VpnInfo[0];
+ return new UnderlyingNetworkInfo[0];
}
}
- List<VpnInfo> infoList = new ArrayList<>();
+ List<UnderlyingNetworkInfo> infoList = new ArrayList<>();
for (NetworkAgentInfo nai : mNetworkAgentInfos) {
- VpnInfo info = createVpnInfo(nai);
+ UnderlyingNetworkInfo info = createVpnInfo(nai);
if (info != null) {
infoList.add(info);
}
}
- return infoList.toArray(new VpnInfo[infoList.size()]);
+ return infoList.toArray(new UnderlyingNetworkInfo[infoList.size()]);
}
/**
* @return VPN information for accounting, or null if we can't retrieve all required
* information, e.g underlying ifaces.
*/
- private VpnInfo createVpnInfo(NetworkAgentInfo nai) {
+ private UnderlyingNetworkInfo createVpnInfo(NetworkAgentInfo nai) {
if (!nai.isVPN()) return null;
Network[] underlyingNetworks = nai.declaredUnderlyingNetworks;
@@ -4862,16 +4904,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (interfaces.isEmpty()) return null;
- VpnInfo info = new VpnInfo();
- info.ownerUid = nai.networkCapabilities.getOwnerUid();
- info.vpnIface = nai.linkProperties.getInterfaceName();
// Must be non-null or NetworkStatsService will crash.
// Cannot happen in production code because Vpn only registers the NetworkAgent after the
// tun or ipsec interface is created.
- if (info.vpnIface == null) return null;
- info.underlyingIfaces = interfaces.toArray(new String[0]);
+ // TODO: Remove this check.
+ if (nai.linkProperties.getInterfaceName() == null) return null;
- return info;
+ return new UnderlyingNetworkInfo(nai.networkCapabilities.getOwnerUid(),
+ nai.linkProperties.getInterfaceName(), interfaces);
}
/**
@@ -4977,16 +5017,23 @@ public class ConnectivityService extends IConnectivityManager.Stub
mVpnBlockedUidRanges = newVpnBlockedUidRanges;
}
+ private boolean isLockdownVpnEnabled() {
+ return mKeyStore.contains(Credentials.LOCKDOWN_VPN);
+ }
+
@Override
public boolean updateLockdownVpn() {
- if (mDeps.getCallingUid() != Process.SYSTEM_UID) {
- logw("Lockdown VPN only available to AID_SYSTEM");
+ // Allow the system UID for the system server and for Settings.
+ // Also, for unit tests, allow the process that ConnectivityService is running in.
+ if (mDeps.getCallingUid() != Process.SYSTEM_UID
+ && Binder.getCallingPid() != Process.myPid()) {
+ logw("Lockdown VPN only available to system process or AID_SYSTEM");
return false;
}
synchronized (mVpns) {
// Tear down existing lockdown if profile was removed
- mLockdownEnabled = LockdownVpnTracker.isEnabled();
+ mLockdownEnabled = isLockdownVpnEnabled();
if (mLockdownEnabled) {
byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
if (profileTag == null) {
@@ -5007,7 +5054,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
logw("VPN for user " + user + " not ready yet. Skipping lockdown");
return false;
}
- setLockdownTracker(new LockdownVpnTracker(mContext, this, mHandler, vpn, profile));
+ setLockdownTracker(
+ new LockdownVpnTracker(mContext, this, mHandler, mKeyStore, vpn, profile));
} else {
setLockdownTracker(null);
}
@@ -5095,7 +5143,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
synchronized (mVpns) {
// Can't set always-on VPN if legacy VPN is already in lockdown mode.
- if (LockdownVpnTracker.isEnabled()) {
+ if (isLockdownVpnEnabled()) {
return false;
}
@@ -5201,7 +5249,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore);
mVpns.put(userId, userVpn);
- if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
+ if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
updateLockdownVpn();
}
}
@@ -5285,7 +5333,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void onUserUnlocked(int userId) {
synchronized (mVpns) {
// User present may be sent because of an unlock, which might mean an unlocked keystore.
- if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
+ if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
updateLockdownVpn();
} else {
startAlwaysOnVpn(userId);
@@ -5354,11 +5402,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
private final HashMap<Messenger, NetworkProviderInfo> mNetworkProviderInfos = new HashMap<>();
private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>();
- private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
- // Map from UID to number of NetworkRequests that UID has filed.
- @GuardedBy("mUidToNetworkRequestCount")
- private final SparseIntArray mUidToNetworkRequestCount = new SparseIntArray();
-
private static class NetworkProviderInfo {
public final String name;
public final Messenger messenger;
@@ -5444,18 +5487,38 @@ public class ConnectivityService extends IConnectivityManager.Stub
/**
* Tracks info about the requester.
- * Also used to notice when the calling process dies so we can self-expire
+ * Also used to notice when the calling process dies so as to self-expire
*/
@VisibleForTesting
protected class NetworkRequestInfo implements IBinder.DeathRecipient {
final List<NetworkRequest> mRequests;
- final NetworkRequest request;
+
+ // mSatisfier and mActiveRequest rely on one another therefore set them together.
+ void setSatisfier(
+ @Nullable final NetworkAgentInfo satisfier,
+ @Nullable final NetworkRequest activeRequest) {
+ mSatisfier = satisfier;
+ mActiveRequest = activeRequest;
+ }
// The network currently satisfying this request, or null if none. Must only be touched
// on the handler thread. This only makes sense for network requests and not for listens,
// as defined by NetworkRequest#isRequest(). For listens, this is always null.
@Nullable
- NetworkAgentInfo mSatisfier;
+ private NetworkAgentInfo mSatisfier;
+ NetworkAgentInfo getSatisfier() {
+ return mSatisfier;
+ }
+
+ // The request in mRequests assigned to a network agent. This is null if none of the
+ // requests in mRequests can be satisfied. This member has the constraint of only being
+ // accessible on the handler thread.
+ @Nullable
+ private NetworkRequest mActiveRequest;
+ NetworkRequest getActiveRequest() {
+ return mActiveRequest;
+ }
+
final PendingIntent mPendingIntent;
boolean mPendingIntentSent;
private final IBinder mBinder;
@@ -5464,7 +5527,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
final Messenger messenger;
NetworkRequestInfo(NetworkRequest r, PendingIntent pi) {
- request = r;
mRequests = initializeRequests(r);
ensureAllNetworkRequestsHaveType(mRequests);
mPendingIntent = pi;
@@ -5472,20 +5534,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
mBinder = null;
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
- enforceRequestCountLimit();
+ mNetworkRequestCounter.incrementCountOrThrow(mUid);
}
NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder) {
super();
messenger = m;
- request = r;
mRequests = initializeRequests(r);
ensureAllNetworkRequestsHaveType(mRequests);
mBinder = binder;
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
mPendingIntent = null;
- enforceRequestCountLimit();
+ mNetworkRequestCounter.incrementCountOrThrow(mUid);
try {
mBinder.linkToDeath(this, 0);
@@ -5508,31 +5569,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
return Collections.unmodifiableList(tempRequests);
}
- private NetworkRequest getSatisfiedRequest() {
- if (mSatisfier == null) {
- return null;
- }
-
- for (NetworkRequest req : mRequests) {
- if (mSatisfier.isSatisfyingRequest(req.requestId)) {
- return req;
- }
- }
-
- return null;
- }
-
- private void enforceRequestCountLimit() {
- synchronized (mUidToNetworkRequestCount) {
- int networkRequests = mUidToNetworkRequestCount.get(mUid, 0) + 1;
- if (networkRequests >= MAX_NETWORK_REQUESTS_PER_UID) {
- throw new ServiceSpecificException(
- ConnectivityManager.Errors.TOO_MANY_REQUESTS);
- }
- mUidToNetworkRequestCount.put(mUid, networkRequests);
- }
- }
-
void unlinkDeathRecipient() {
if (mBinder != null) {
mBinder.unlinkToDeath(this, 0);
@@ -5579,6 +5615,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
private int[] getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) {
final SortedSet<Integer> thresholds = new TreeSet<>();
synchronized (nai) {
+ // mNetworkRequests may contain the same value multiple times in case of
+ // multilayer requests. It won't matter in this case because the thresholds
+ // will then be the same and be deduplicated as they enter the `thresholds` set.
+ // TODO : have mNetworkRequests be a Set<NetworkRequestInfo> or the like.
for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
for (final NetworkRequest req : nri.mRequests) {
if (req.networkCapabilities.hasSignalStrength()
@@ -5618,7 +5658,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (ns == null) {
return;
}
- MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(ns);
+ if (ns instanceof MatchAllNetworkSpecifier) {
+ throw new IllegalArgumentException("A MatchAllNetworkSpecifier is not permitted");
+ }
}
private void ensureValid(NetworkCapabilities nc) {
@@ -5642,31 +5684,43 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
- Messenger messenger, int timeoutMs, IBinder binder, int legacyType,
- @NonNull String callingPackageName, @Nullable String callingAttributionTag) {
+ int reqTypeInt, Messenger messenger, int timeoutMs, IBinder binder,
+ int legacyType, @NonNull String callingPackageName,
+ @Nullable String callingAttributionTag) {
if (legacyType != TYPE_NONE && !checkNetworkStackPermission()) {
if (checkUnsupportedStartingFrom(Build.VERSION_CODES.M, callingPackageName)) {
throw new SecurityException("Insufficient permissions to specify legacy type");
}
}
final int callingUid = mDeps.getCallingUid();
- final NetworkRequest.Type type = (networkCapabilities == null)
- ? NetworkRequest.Type.TRACK_DEFAULT
- : NetworkRequest.Type.REQUEST;
- // If the requested networkCapabilities is null, take them instead from
- // the default network request. This allows callers to keep track of
- // the system default network.
- if (type == NetworkRequest.Type.TRACK_DEFAULT) {
- networkCapabilities = createDefaultNetworkCapabilitiesForUid(callingUid);
- enforceAccessPermission();
- } else {
- networkCapabilities = new NetworkCapabilities(networkCapabilities);
- enforceNetworkRequestPermissions(networkCapabilities, callingPackageName,
- callingAttributionTag);
- // TODO: this is incorrect. We mark the request as metered or not depending on the state
- // of the app when the request is filed, but we never change the request if the app
- // changes network state. http://b/29964605
- enforceMeteredApnPolicy(networkCapabilities);
+ final NetworkRequest.Type reqType;
+ try {
+ reqType = NetworkRequest.Type.values()[reqTypeInt];
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new IllegalArgumentException("Unsupported request type " + reqTypeInt);
+ }
+ switch (reqType) {
+ case TRACK_DEFAULT:
+ // If the request type is TRACK_DEFAULT, the passed {@code networkCapabilities}
+ // is unused and will be replaced by the one from the default network request.
+ // This allows callers to keep track of the system default network.
+ networkCapabilities = createDefaultNetworkCapabilitiesForUid(callingUid);
+ enforceAccessPermission();
+ break;
+ case BACKGROUND_REQUEST:
+ enforceNetworkStackOrSettingsPermission();
+ // Fall-through since other checks are the same with normal requests.
+ case REQUEST:
+ networkCapabilities = new NetworkCapabilities(networkCapabilities);
+ enforceNetworkRequestPermissions(networkCapabilities, callingPackageName,
+ callingAttributionTag);
+ // TODO: this is incorrect. We mark the request as metered or not depending on
+ // the state of the app when the request is filed, but we never change the
+ // request if the app changes network state. http://b/29964605
+ enforceMeteredApnPolicy(networkCapabilities);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported request type " + reqType);
}
ensureRequestableCapabilities(networkCapabilities);
ensureSufficientPermissionsForRequest(networkCapabilities,
@@ -5685,7 +5739,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
ensureValid(networkCapabilities);
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
- nextNetworkRequestId(), type);
+ nextNetworkRequestId(), reqType);
NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder);
if (DBG) log("requestNetwork for " + nri);
@@ -5745,9 +5799,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Policy already enforced.
return;
}
- if (mPolicyManagerInternal.isUidRestrictedOnMeteredNetworks(uid)) {
- // If UID is restricted, don't allow them to bring up metered APNs.
- networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (mPolicyManager.isUidRestrictedOnMeteredNetworks(uid)) {
+ // If UID is restricted, don't allow them to bring up metered APNs.
+ networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -5940,13 +5999,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
@Override
- public void declareNetworkRequestUnfulfillable(NetworkRequest request) {
+ public void declareNetworkRequestUnfulfillable(@NonNull final NetworkRequest request) {
if (request.hasTransport(TRANSPORT_TEST)) {
enforceNetworkFactoryOrTestNetworksPermission();
} else {
enforceNetworkFactoryPermission();
}
- mHandler.post(() -> handleReleaseNetworkRequest(request, mDeps.getCallingUid(), true));
+ final NetworkRequestInfo nri = mNetworkRequests.get(request);
+ if (nri != null) {
+ // declareNetworkRequestUnfulfillable() paths don't apply to multilayer requests.
+ ensureNotMultilayerRequest(nri, "declareNetworkRequestUnfulfillable");
+ mHandler.post(() -> handleReleaseNetworkRequest(
+ nri.mRequests.get(0), mDeps.getCallingUid(), true));
+ }
}
// NOTE: Accessed on multiple threads, must be synchronized on itself.
@@ -6043,6 +6108,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
+ Objects.requireNonNull(networkInfo, "networkInfo must not be null");
+ Objects.requireNonNull(linkProperties, "linkProperties must not be null");
+ Objects.requireNonNull(networkCapabilities, "networkCapabilities must not be null");
+ Objects.requireNonNull(networkAgentConfig, "networkAgentConfig must not be null");
if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
enforceAnyPermissionOf(Manifest.permission.MANAGE_TEST_NETWORKS);
} else {
@@ -6078,7 +6147,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
final NetworkAgentInfo nai = new NetworkAgentInfo(na,
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
- this, mNetd, mDnsResolver, mNMS, providerId, uid);
+ this, mNetd, mDnsResolver, mNMS, providerId, uid, mQosCallbackTracker);
// Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
processCapabilitiesFromAgent(nai, nc);
@@ -6130,7 +6199,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
nai.networkAgentPortalData = lp.getCaptivePortalData();
}
- private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties newLp,
+ private void updateLinkProperties(NetworkAgentInfo networkAgent, @NonNull LinkProperties newLp,
@NonNull LinkProperties oldLp) {
int netId = networkAgent.network.getNetId();
@@ -6139,8 +6208,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// the LinkProperties for the network are accurate.
networkAgent.clatd.fixupLinkProperties(oldLp, newLp);
- updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities,
- networkAgent.networkInfo.getType());
+ updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities);
// update filtering rules, need to happen after the interface update so netd knows about the
// new interface (the interface name -> index map becomes initialized)
@@ -6279,7 +6347,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void updateInterfaces(final @Nullable LinkProperties newLp,
final @Nullable LinkProperties oldLp, final int netId,
- final @Nullable NetworkCapabilities caps, final int legacyType) {
+ final @NonNull NetworkCapabilities caps) {
final CompareResult<String> interfaceDiff = new CompareResult<>(
oldLp != null ? oldLp.getAllInterfaceNames() : null,
newLp != null ? newLp.getAllInterfaceNames() : null);
@@ -6290,7 +6358,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (DBG) log("Adding iface " + iface + " to network " + netId);
mNetd.networkAddInterface(netId, iface);
wakeupModifyInterface(iface, caps, true);
- bs.noteNetworkInterfaceType(iface, legacyType);
+ bs.noteNetworkInterfaceForTransports(iface, caps.getTransportTypes());
} catch (Exception e) {
loge("Exception adding interface: " + e);
}
@@ -6562,6 +6630,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
* maintained here that the NetworkAgent is not aware of (e.g., validated, captive portal,
* and foreground status).
*/
+ @NonNull
private NetworkCapabilities mixInCapabilities(NetworkAgentInfo nai, NetworkCapabilities nc) {
// Once a NetworkAgent is connected, complain if some immutable capabilities are removed.
// Don't complain for VPNs since they're not driven by requests and there is no risk of
@@ -6581,7 +6650,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
// Don't modify caller's NetworkCapabilities.
- NetworkCapabilities newNc = new NetworkCapabilities(nc);
+ final NetworkCapabilities newNc = new NetworkCapabilities(nc);
if (nai.lastValidated) {
newNc.addCapability(NET_CAPABILITY_VALIDATED);
} else {
@@ -6618,6 +6687,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
return newNc;
}
+ private void updateNetworkInfoForRoamingAndSuspended(NetworkAgentInfo nai,
+ NetworkCapabilities prevNc, NetworkCapabilities newNc) {
+ final boolean prevSuspended = !prevNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ final boolean suspended = !newNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ final boolean prevRoaming = !prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+ final boolean roaming = !newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+ if (prevSuspended != suspended) {
+ // TODO (b/73132094) : remove this call once the few users of onSuspended and
+ // onResumed have been removed.
+ notifyNetworkCallbacks(nai, suspended ? ConnectivityManager.CALLBACK_SUSPENDED
+ : ConnectivityManager.CALLBACK_RESUMED);
+ }
+ if (prevSuspended != suspended || prevRoaming != roaming) {
+ // updateNetworkInfo will mix in the suspended info from the capabilities and
+ // take appropriate action for the network having possibly changed state.
+ updateNetworkInfo(nai, nai.networkInfo);
+ }
+ }
+
/**
* Update the NetworkCapabilities for {@code nai} to {@code nc}. Specifically:
*
@@ -6649,46 +6737,29 @@ public class ConnectivityService extends IConnectivityManager.Stub
// on this network. We might have been called by rematchNetworkAndRequests when a
// network changed foreground state.
processListenRequests(nai);
- final boolean prevSuspended = !prevNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
- final boolean suspended = !newNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
- final boolean prevRoaming = !prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
- final boolean roaming = !newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
- if (prevSuspended != suspended || prevRoaming != roaming) {
- // TODO (b/73132094) : remove this call once the few users of onSuspended and
- // onResumed have been removed.
- notifyNetworkCallbacks(nai, suspended ? ConnectivityManager.CALLBACK_SUSPENDED
- : ConnectivityManager.CALLBACK_RESUMED);
- // updateNetworkInfo will mix in the suspended info from the capabilities and
- // take appropriate action for the network having possibly changed state.
- updateNetworkInfo(nai, nai.networkInfo);
- }
} else {
// If the requestable capabilities have changed or the score changed, we can't have been
// called by rematchNetworkAndRequests, so it's safe to start a rematch.
rematchAllNetworksAndRequests();
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
+ updateNetworkInfoForRoamingAndSuspended(nai, prevNc, newNc);
- // TODO : static analysis indicates that prevNc can't be null here (getAndSetNetworkCaps
- // never returns null), so mark the relevant members and functions in nai as @NonNull and
- // remove this test
- if (prevNc != null) {
- final boolean oldMetered = prevNc.isMetered();
- final boolean newMetered = newNc.isMetered();
- final boolean meteredChanged = oldMetered != newMetered;
+ final boolean oldMetered = prevNc.isMetered();
+ final boolean newMetered = newNc.isMetered();
+ final boolean meteredChanged = oldMetered != newMetered;
- if (meteredChanged) {
- maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground,
- mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges);
- }
+ if (meteredChanged) {
+ maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground,
+ mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges);
+ }
- final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) !=
- newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+ final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING)
+ != newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
- // Report changes that are interesting for network statistics tracking.
- if (meteredChanged || roamingChanged) {
- notifyIfacesChangedForNetworkStats();
- }
+ // Report changes that are interesting for network statistics tracking.
+ if (meteredChanged || roamingChanged) {
+ notifyIfacesChangedForNetworkStats();
}
// This network might have been underlying another network. Propagate its capabilities.
@@ -6872,6 +6943,39 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ private void sendUpdatedScoreToFactories(
+ @NonNull final NetworkReassignment.RequestReassignment event) {
+ // If a request of type REQUEST is now being satisfied by a new network.
+ if (null != event.mNewNetworkRequest && event.mNewNetworkRequest.isRequest()) {
+ sendUpdatedScoreToFactories(event.mNewNetworkRequest, event.mNewNetwork);
+ }
+
+ // If a previously satisfied request of type REQUEST is no longer being satisfied.
+ if (null != event.mOldNetworkRequest && event.mOldNetworkRequest.isRequest()
+ && event.mOldNetworkRequest != event.mNewNetworkRequest) {
+ sendUpdatedScoreToFactories(event.mOldNetworkRequest, null);
+ }
+
+ cancelMultilayerLowerPriorityNpiRequests(event.mNetworkRequestInfo);
+ }
+
+ /**
+ * Cancel with all NPIs the given NRI's multilayer requests that are a lower priority than
+ * its currently satisfied active request.
+ * @param nri the NRI to cancel lower priority requests for.
+ */
+ private void cancelMultilayerLowerPriorityNpiRequests(
+ @NonNull final NetworkRequestInfo nri) {
+ if (!nri.isMultilayerRequest() || null == nri.mActiveRequest) {
+ return;
+ }
+
+ final int indexOfNewRequest = nri.mRequests.indexOf(nri.mActiveRequest);
+ for (int i = indexOfNewRequest + 1; i < nri.mRequests.size(); i++) {
+ cancelNpiRequest(nri.mRequests.get(i));
+ }
+ }
+
private void sendUpdatedScoreToFactories(@NonNull NetworkRequest networkRequest,
@Nullable NetworkAgentInfo nai) {
final int score;
@@ -6892,21 +6996,35 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
/** Sends all current NetworkRequests to the specified factory. */
- private void sendAllRequestsToProvider(NetworkProviderInfo npi) {
+ private void sendAllRequestsToProvider(@NonNull final NetworkProviderInfo npi) {
ensureRunningOnConnectivityServiceThread();
- for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (nri.request.isListen()) continue;
- NetworkAgentInfo nai = nri.mSatisfier;
- final int score;
- final int serial;
- if (nai != null) {
- score = nai.getCurrentScore();
- serial = nai.factorySerialNumber;
- } else {
- score = 0;
- serial = NetworkProvider.ID_NONE;
+ for (final NetworkRequestInfo nri : getNrisFromGlobalRequests()) {
+ for (final NetworkRequest req : nri.mRequests) {
+ if (req.isListen() && nri.getActiveRequest() == req) {
+ break;
+ }
+ if (req.isListen()) {
+ continue;
+ }
+ // Only set the nai for the request it is satisfying.
+ final NetworkAgentInfo nai =
+ nri.getActiveRequest() == req ? nri.getSatisfier() : null;
+ final int score;
+ final int serial;
+ if (null != nai) {
+ score = nai.getCurrentScore();
+ serial = nai.factorySerialNumber;
+ } else {
+ score = 0;
+ serial = NetworkProvider.ID_NONE;
+ }
+ npi.requestNetwork(req, score, serial);
+ // For multilayer requests, don't send lower priority requests if a higher priority
+ // request is already satisfied.
+ if (null != nai) {
+ break;
+ }
}
- npi.requestNetwork(nri.request, score, serial);
}
}
@@ -6915,7 +7033,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (notificationType == ConnectivityManager.CALLBACK_AVAILABLE && !nri.mPendingIntentSent) {
Intent intent = new Intent();
intent.putExtra(ConnectivityManager.EXTRA_NETWORK, networkAgent.network);
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK_REQUEST, nri.request);
+ // If apps could file multi-layer requests with PendingIntents, they'd need to know
+ // which of the layer is satisfied alongside with some ID for the request. Hence, if
+ // such an API is ever implemented, there is no doubt the right request to send in
+ // EXTRA_NETWORK_REQUEST is mActiveRequest, and whatever ID would be added would need to
+ // be sent as a separate extra.
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK_REQUEST, nri.getActiveRequest());
nri.mPendingIntentSent = true;
sendIntent(nri.mPendingIntent, intent);
}
@@ -6945,8 +7068,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
releasePendingNetworkRequestWithDelay(pendingIntent);
}
- private void callCallbackForRequest(NetworkRequestInfo nri,
- NetworkAgentInfo networkAgent, int notificationType, int arg1) {
+ private void callCallbackForRequest(@NonNull final NetworkRequestInfo nri,
+ @NonNull final NetworkAgentInfo networkAgent, final int notificationType,
+ final int arg1) {
if (nri.messenger == null) {
// Default request has no msgr. Also prevents callbacks from being invoked for
// NetworkRequestInfos registered with ConnectivityDiagnostics requests. Those callbacks
@@ -6954,8 +7078,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
return;
}
Bundle bundle = new Bundle();
+ // In the case of multi-layer NRIs, the first request is not necessarily the one that
+ // is satisfied. This is vexing, but the ConnectivityManager code that receives this
+ // callback is only using the request as a token to identify the callback, so it doesn't
+ // matter too much at this point as long as the callback can be found.
+ // TODO b/177608132: make sure callbacks are indexed by NRIs and not NetworkRequest objects.
// TODO: check if defensive copies of data is needed.
- putParcelable(bundle, new NetworkRequest(nri.request));
+ final NetworkRequest nrForCallback = new NetworkRequest(nri.mRequests.get(0));
+ putParcelable(bundle, nrForCallback);
Message msg = Message.obtain();
if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL) {
putParcelable(bundle, networkAgent.network);
@@ -6967,8 +7097,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
networkAgent.networkCapabilities, nri.mPid, nri.mUid);
putParcelable(
bundle,
- maybeSanitizeLocationInfoForCaller(
- nc, nri.mUid, nri.request.getRequestorPackageName()));
+ createWithLocationInfoSanitizedIfNecessaryWhenParceled(
+ nc, nri.mUid, nrForCallback.getRequestorPackageName()));
putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
networkAgent.linkProperties, nri.mPid, nri.mUid));
// For this notification, arg1 contains the blocked status.
@@ -6986,8 +7116,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
networkAgent.networkCapabilities, nri.mPid, nri.mUid);
putParcelable(
bundle,
- maybeSanitizeLocationInfoForCaller(
- netCap, nri.mUid, nri.request.getRequestorPackageName()));
+ createWithLocationInfoSanitizedIfNecessaryWhenParceled(
+ netCap, nri.mUid, nrForCallback.getRequestorPackageName()));
break;
}
case ConnectivityManager.CALLBACK_IP_CHANGED: {
@@ -7006,12 +7136,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
try {
if (VDBG) {
String notification = ConnectivityManager.getCallbackName(notificationType);
- log("sending notification " + notification + " for " + nri.request);
+ log("sending notification " + notification + " for " + nrForCallback);
}
nri.messenger.send(msg);
} catch (RemoteException e) {
// may occur naturally in the race of binder death.
- loge("RemoteException caught trying to send a callback msg for " + nri.request);
+ loge("RemoteException caught trying to send a callback msg for " + nrForCallback);
}
}
@@ -7087,19 +7217,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
private void processNewlyLostListenRequests(@NonNull final NetworkAgentInfo nai) {
- for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- NetworkRequest nr = nri.request;
+ for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
+ if (nri.isMultilayerRequest()) {
+ continue;
+ }
+ final NetworkRequest nr = nri.mRequests.get(0);
if (!nr.isListen()) continue;
if (nai.isSatisfyingRequest(nr.requestId) && !nai.satisfies(nr)) {
- nai.removeRequest(nri.request.requestId);
+ nai.removeRequest(nr.requestId);
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_LOST, 0);
}
}
}
private void processNewlySatisfiedListenRequests(@NonNull final NetworkAgentInfo nai) {
- for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- NetworkRequest nr = nri.request;
+ for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
+ if (nri.isMultilayerRequest()) {
+ continue;
+ }
+ final NetworkRequest nr = nri.mRequests.get(0);
if (!nr.isListen()) continue;
if (nai.satisfies(nr) && !nai.isSatisfyingRequest(nr.requestId)) {
nai.addRequest(nr);
@@ -7111,19 +7247,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
// An accumulator class to gather the list of changes that result from a rematch.
private static class NetworkReassignment {
static class RequestReassignment {
- @NonNull public final NetworkRequestInfo mRequest;
+ @NonNull public final NetworkRequestInfo mNetworkRequestInfo;
+ @NonNull public final NetworkRequest mOldNetworkRequest;
+ @NonNull public final NetworkRequest mNewNetworkRequest;
@Nullable public final NetworkAgentInfo mOldNetwork;
@Nullable public final NetworkAgentInfo mNewNetwork;
- RequestReassignment(@NonNull final NetworkRequestInfo request,
+ RequestReassignment(@NonNull final NetworkRequestInfo networkRequestInfo,
+ @NonNull final NetworkRequest oldNetworkRequest,
+ @NonNull final NetworkRequest newNetworkRequest,
@Nullable final NetworkAgentInfo oldNetwork,
@Nullable final NetworkAgentInfo newNetwork) {
- mRequest = request;
+ mNetworkRequestInfo = networkRequestInfo;
+ mOldNetworkRequest = oldNetworkRequest;
+ mNewNetworkRequest = newNetworkRequest;
mOldNetwork = oldNetwork;
mNewNetwork = newNetwork;
}
public String toString() {
- return mRequest.mRequests.get(0).requestId + " : "
+ return mNetworkRequestInfo.mRequests.get(0).requestId + " : "
+ (null != mOldNetwork ? mOldNetwork.network.getNetId() : "null")
+ " → " + (null != mNewNetwork ? mNewNetwork.network.getNetId() : "null");
}
@@ -7141,7 +7283,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// sure this stays true, but without imposing this expensive check on all
// reassignments on all user devices.
for (final RequestReassignment existing : mReassignments) {
- if (existing.mRequest.equals(reassignment.mRequest)) {
+ if (existing.mNetworkRequestInfo.equals(reassignment.mNetworkRequestInfo)) {
throw new IllegalStateException("Trying to reassign ["
+ reassignment + "] but already have ["
+ existing + "]");
@@ -7156,7 +7298,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Nullable
private RequestReassignment getReassignment(@NonNull final NetworkRequestInfo nri) {
for (final RequestReassignment event : getRequestReassignments()) {
- if (nri == event.mRequest) return event;
+ if (nri == event.mNetworkRequestInfo) return event;
}
return null;
}
@@ -7183,6 +7325,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
private void updateSatisfiersForRematchRequest(@NonNull final NetworkRequestInfo nri,
+ @NonNull final NetworkRequest previousRequest,
+ @NonNull final NetworkRequest newRequest,
@Nullable final NetworkAgentInfo previousSatisfier,
@Nullable final NetworkAgentInfo newSatisfier,
final long now) {
@@ -7192,58 +7336,98 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (VDBG || DDBG) {
log(" accepting network in place of " + previousSatisfier.toShortString());
}
- previousSatisfier.removeRequest(nri.request.requestId);
- previousSatisfier.lingerRequest(nri.request.requestId, now, mLingerDelayMs);
+ previousSatisfier.removeRequest(previousRequest.requestId);
+ previousSatisfier.lingerRequest(previousRequest.requestId, now, mLingerDelayMs);
} else {
if (VDBG || DDBG) log(" accepting network in place of null");
}
- newSatisfier.unlingerRequest(nri.request.requestId);
- if (!newSatisfier.addRequest(nri.request)) {
+ newSatisfier.unlingerRequest(newRequest.requestId);
+ if (!newSatisfier.addRequest(newRequest)) {
Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has "
- + nri.request);
+ + newRequest);
}
} else {
if (DBG) {
log("Network " + previousSatisfier.toShortString() + " stopped satisfying"
- + " request " + nri.request.requestId);
+ + " request " + previousRequest.requestId);
}
- previousSatisfier.removeRequest(nri.request.requestId);
+ previousSatisfier.removeRequest(previousRequest.requestId);
}
- nri.mSatisfier = newSatisfier;
+ nri.setSatisfier(newSatisfier, newRequest);
}
+ /**
+ * This function is triggered when something can affect what network should satisfy what
+ * request, and it computes the network reassignment from the passed collection of requests to
+ * network match to the one that the system should now have. That data is encoded in an
+ * object that is a list of changes, each of them having an NRI, and old satisfier, and a new
+ * satisfier.
+ *
+ * After the reassignment is computed, it is applied to the state objects.
+ *
+ * @param networkRequests the nri objects to evaluate for possible network reassignment
+ * @return NetworkReassignment listing of proposed network assignment changes
+ */
@NonNull
- private NetworkReassignment computeNetworkReassignment() {
- ensureRunningOnConnectivityServiceThread();
+ private NetworkReassignment computeNetworkReassignment(
+ @NonNull final Collection<NetworkRequestInfo> networkRequests) {
final NetworkReassignment changes = new NetworkReassignment();
// Gather the list of all relevant agents and sort them by score.
final ArrayList<NetworkAgentInfo> nais = new ArrayList<>();
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
- if (!nai.everConnected) continue;
+ if (!nai.everConnected) {
+ continue;
+ }
nais.add(nai);
}
- for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (nri.request.isListen()) continue;
- final NetworkAgentInfo bestNetwork = mNetworkRanker.getBestNetwork(nri.request, nais);
+ for (final NetworkRequestInfo nri : networkRequests) {
+ // Non-multilayer listen requests can be ignored.
+ if (!nri.isMultilayerRequest() && nri.mRequests.get(0).isListen()) {
+ continue;
+ }
+ NetworkAgentInfo bestNetwork = null;
+ NetworkRequest bestRequest = null;
+ for (final NetworkRequest req : nri.mRequests) {
+ bestNetwork = mNetworkRanker.getBestNetwork(req, nais);
+ // Stop evaluating as the highest possible priority request is satisfied.
+ if (null != bestNetwork) {
+ bestRequest = req;
+ break;
+ }
+ }
if (bestNetwork != nri.mSatisfier) {
// bestNetwork may be null if no network can satisfy this request.
changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
- nri, nri.mSatisfier, bestNetwork));
+ nri, nri.mActiveRequest, bestRequest, nri.getSatisfier(), bestNetwork));
}
}
return changes;
}
+ private Set<NetworkRequestInfo> getNrisFromGlobalRequests() {
+ return new HashSet<>(mNetworkRequests.values());
+ }
+
/**
- * Attempt to rematch all Networks with NetworkRequests. This may result in Networks
+ * Attempt to rematch all Networks with all NetworkRequests. This may result in Networks
* being disconnected.
*/
private void rematchAllNetworksAndRequests() {
+ rematchNetworksAndRequests(getNrisFromGlobalRequests());
+ }
+
+ /**
+ * Attempt to rematch all Networks with given NetworkRequests. This may result in Networks
+ * being disconnected.
+ */
+ private void rematchNetworksAndRequests(
+ @NonNull final Set<NetworkRequestInfo> networkRequests) {
+ ensureRunningOnConnectivityServiceThread();
// TODO: This may be slow, and should be optimized.
final long now = SystemClock.elapsedRealtime();
- final NetworkReassignment changes = computeNetworkReassignment();
+ final NetworkReassignment changes = computeNetworkReassignment(networkRequests);
if (VDBG || DDBG) {
log(changes.debugString());
} else if (DBG) {
@@ -7268,8 +7452,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
// the linger status.
for (final NetworkReassignment.RequestReassignment event :
changes.getRequestReassignments()) {
- updateSatisfiersForRematchRequest(event.mRequest, event.mOldNetwork,
- event.mNewNetwork, now);
+ updateSatisfiersForRematchRequest(event.mNetworkRequestInfo,
+ event.mOldNetworkRequest, event.mNewNetworkRequest,
+ event.mOldNetwork, event.mNewNetwork,
+ now);
}
final NetworkAgentInfo oldDefaultNetwork = getDefaultNetwork();
@@ -7283,7 +7469,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (oldDefaultNetwork != null) {
mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
}
- updateDataActivityTracking(newDefaultNetwork, oldDefaultNetwork);
+ mNetworkActivityTracker.updateDataActivityTracking(
+ newDefaultNetwork, oldDefaultNetwork);
// Notify system services of the new default.
makeDefault(newDefaultNetwork);
@@ -7320,12 +7507,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
// trying to connect if they know they cannot match it.
// TODO - this could get expensive if there are a lot of outstanding requests for this
// network. Think of a way to reduce this. Push netid->request mapping to each factory?
- sendUpdatedScoreToFactories(event.mRequest.request, event.mNewNetwork);
+ sendUpdatedScoreToFactories(event);
if (null != event.mNewNetwork) {
- notifyNetworkAvailable(event.mNewNetwork, event.mRequest);
+ notifyNetworkAvailable(event.mNewNetwork, event.mNetworkRequestInfo);
} else {
- callCallbackForRequest(event.mRequest, event.mOldNetwork,
+ callCallbackForRequest(event.mNetworkRequestInfo, event.mOldNetwork,
ConnectivityManager.CALLBACK_LOST, 0);
}
}
@@ -7563,10 +7750,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) {
networkAgent.everConnected = true;
- if (networkAgent.linkProperties == null) {
- Log.wtf(TAG, networkAgent.toShortString() + " connected with null LinkProperties");
- }
-
// NetworkCapabilities need to be set before sending the private DNS config to
// NetworkMonitor, otherwise NetworkMonitor cannot determine if validation is required.
networkAgent.getAndSetNetworkCapabilities(networkAgent.networkCapabilities);
@@ -7818,10 +8001,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
activeIface = activeLinkProperties.getInterfaceName();
}
- final VpnInfo[] vpnInfos = getAllVpnInfo();
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos = getAllVpnInfo();
try {
- mStatsService.forceUpdateIfaces(
- getDefaultNetworks(), getAllNetworkState(), activeIface, vpnInfos);
+ mStatsService.forceUpdateIfaces(getDefaultNetworks(), getAllNetworkState(), activeIface,
+ underlyingNetworkInfos);
} catch (Exception ignored) {
}
}
@@ -7885,10 +8068,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
@Override
- public void startNattKeepaliveWithFd(Network network, FileDescriptor fd, int resourceId,
+ public void startNattKeepaliveWithFd(Network network, ParcelFileDescriptor pfd, int resourceId,
int intervalSeconds, ISocketKeepaliveCallback cb, String srcAddr,
String dstAddr) {
try {
+ final FileDescriptor fd = pfd.getFileDescriptor();
mKeepaliveTracker.startNattKeepalive(
getNetworkAgentInfoForNetwork(network), fd, resourceId,
intervalSeconds, cb,
@@ -7896,24 +8080,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
} finally {
// FileDescriptors coming from AIDL calls must be manually closed to prevent leaks.
// startNattKeepalive calls Os.dup(fd) before returning, so we can close immediately.
- if (fd != null && Binder.getCallingPid() != Process.myPid()) {
- IoUtils.closeQuietly(fd);
+ if (pfd != null && Binder.getCallingPid() != Process.myPid()) {
+ IoUtils.closeQuietly(pfd);
}
}
}
@Override
- public void startTcpKeepalive(Network network, FileDescriptor fd, int intervalSeconds,
+ public void startTcpKeepalive(Network network, ParcelFileDescriptor pfd, int intervalSeconds,
ISocketKeepaliveCallback cb) {
try {
enforceKeepalivePermission();
+ final FileDescriptor fd = pfd.getFileDescriptor();
mKeepaliveTracker.startTcpKeepalive(
getNetworkAgentInfoForNetwork(network), fd, intervalSeconds, cb);
} finally {
// FileDescriptors coming from AIDL calls must be manually closed to prevent leaks.
// startTcpKeepalive calls Os.dup(fd) before returning, so we can close immediately.
- if (fd != null && Binder.getCallingPid() != Process.myPid()) {
- IoUtils.closeQuietly(fd);
+ if (pfd != null && Binder.getCallingPid() != Process.myPid()) {
+ IoUtils.closeQuietly(pfd);
}
}
}
@@ -8079,6 +8264,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
return getVpnIfOwner(mDeps.getCallingUid());
}
+ // TODO: stop calling into Vpn.java and get this information from data in this class.
@GuardedBy("mVpns")
private Vpn getVpnIfOwner(int uid) {
final int user = UserHandle.getUserId(uid);
@@ -8087,7 +8273,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (vpn == null) {
return null;
} else {
- final VpnInfo info = vpn.getVpnInfo();
+ final UnderlyingNetworkInfo info = vpn.getUnderlyingNetworkInfo();
return (info == null || info.ownerUid != uid) ? null : vpn;
}
}
@@ -8364,7 +8550,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
- decrementNetworkRequestPerUidCount(nri);
+ mNetworkRequestCounter.decrementCount(nri.mUid);
return;
}
@@ -8430,7 +8616,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
- decrementNetworkRequestPerUidCount(nri);
+ mNetworkRequestCounter.decrementCount(nri.mUid);
iCb.unlinkToDeath(cbInfo, 0);
}
@@ -8639,4 +8825,194 @@ public class ConnectivityService extends IConnectivityManager.Stub
notifyDataStallSuspected(p, network.getNetId());
}
+
+ private final LegacyNetworkActivityTracker mNetworkActivityTracker;
+
+ /**
+ * Class used for updating network activity tracking with netd and notify network activity
+ * changes.
+ */
+ private static final class LegacyNetworkActivityTracker {
+ private final Context mContext;
+ private final INetworkManagementService mNMS;
+
+ LegacyNetworkActivityTracker(@NonNull Context context,
+ @NonNull INetworkManagementService nms) {
+ mContext = context;
+ mNMS = nms;
+ try {
+ mNMS.registerObserver(mDataActivityObserver);
+ } catch (RemoteException e) {
+ loge("Error registering observer :" + e);
+ }
+ }
+
+ // TODO: Migrate away the dependency with INetworkManagementEventObserver.
+ private final INetworkManagementEventObserver mDataActivityObserver =
+ new BaseNetworkObserver() {
+ @Override
+ public void interfaceClassDataActivityChanged(int transportType, boolean active,
+ long tsNanos, int uid) {
+ sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active,
+ tsNanos);
+ }
+ };
+
+ // This is deprecated and only to support legacy use cases.
+ private int transportTypeToLegacyType(int type) {
+ switch (type) {
+ case NetworkCapabilities.TRANSPORT_CELLULAR:
+ return ConnectivityManager.TYPE_MOBILE;
+ case NetworkCapabilities.TRANSPORT_WIFI:
+ return ConnectivityManager.TYPE_WIFI;
+ case NetworkCapabilities.TRANSPORT_BLUETOOTH:
+ return ConnectivityManager.TYPE_BLUETOOTH;
+ case NetworkCapabilities.TRANSPORT_ETHERNET:
+ return ConnectivityManager.TYPE_ETHERNET;
+ default:
+ loge("Unexpected transport in transportTypeToLegacyType: " + type);
+ }
+ return ConnectivityManager.TYPE_NONE;
+ }
+
+ public void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) {
+ final Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
+ intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
+ intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active);
+ intent.putExtra(ConnectivityManager.EXTRA_REALTIME_NS, tsNanos);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL,
+ RECEIVE_DATA_ACTIVITY_CHANGE,
+ null /* resultReceiver */,
+ null /* scheduler */,
+ 0 /* initialCode */,
+ null /* initialData */,
+ null /* initialExtra */);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ /**
+ * Setup data activity tracking for the given network.
+ *
+ * Every {@code setupDataActivityTracking} should be paired with a
+ * {@link #removeDataActivityTracking} for cleanup.
+ */
+ private void setupDataActivityTracking(NetworkAgentInfo networkAgent) {
+ final String iface = networkAgent.linkProperties.getInterfaceName();
+
+ final int timeout;
+ final int type;
+
+ if (networkAgent.networkCapabilities.hasTransport(
+ NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ timeout = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
+ 10);
+ type = NetworkCapabilities.TRANSPORT_CELLULAR;
+ } else if (networkAgent.networkCapabilities.hasTransport(
+ NetworkCapabilities.TRANSPORT_WIFI)) {
+ timeout = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
+ 15);
+ type = NetworkCapabilities.TRANSPORT_WIFI;
+ } else {
+ return; // do not track any other networks
+ }
+
+ if (timeout > 0 && iface != null) {
+ try {
+ // TODO: Access INetd directly instead of NMS
+ mNMS.addIdleTimer(iface, timeout, type);
+ } catch (Exception e) {
+ // You shall not crash!
+ loge("Exception in setupDataActivityTracking " + e);
+ }
+ }
+ }
+
+ /**
+ * Remove data activity tracking when network disconnects.
+ */
+ private void removeDataActivityTracking(NetworkAgentInfo networkAgent) {
+ final String iface = networkAgent.linkProperties.getInterfaceName();
+ final NetworkCapabilities caps = networkAgent.networkCapabilities;
+
+ if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
+ || caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) {
+ try {
+ // the call fails silently if no idle timer setup for this interface
+ // TODO: Access INetd directly instead of NMS
+ mNMS.removeIdleTimer(iface);
+ } catch (Exception e) {
+ // You shall not crash!
+ loge("Exception in removeDataActivityTracking " + e);
+ }
+ }
+ }
+
+ /**
+ * Update data activity tracking when network state is updated.
+ */
+ public void updateDataActivityTracking(NetworkAgentInfo newNetwork,
+ NetworkAgentInfo oldNetwork) {
+ if (newNetwork != null) {
+ setupDataActivityTracking(newNetwork);
+ }
+ if (oldNetwork != null) {
+ removeDataActivityTracking(oldNetwork);
+ }
+ }
+ }
+ /**
+ * Registers {@link QosSocketFilter} with {@link IQosCallback}.
+ *
+ * @param socketInfo the socket information
+ * @param callback the callback to register
+ */
+ @Override
+ public void registerQosSocketCallback(@NonNull final QosSocketInfo socketInfo,
+ @NonNull final IQosCallback callback) {
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(socketInfo.getNetwork());
+ if (nai == null || nai.networkCapabilities == null) {
+ try {
+ callback.onError(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
+ } catch (final RemoteException ex) {
+ loge("registerQosCallbackInternal: RemoteException", ex);
+ }
+ return;
+ }
+ registerQosCallbackInternal(new QosSocketFilter(socketInfo), callback, nai);
+ }
+
+ /**
+ * Register a {@link IQosCallback} with base {@link QosFilter}.
+ *
+ * @param filter the filter to register
+ * @param callback the callback to register
+ * @param nai the agent information related to the filter's network
+ */
+ @VisibleForTesting
+ public void registerQosCallbackInternal(@NonNull final QosFilter filter,
+ @NonNull final IQosCallback callback, @NonNull final NetworkAgentInfo nai) {
+ if (filter == null) throw new IllegalArgumentException("filter must be non-null");
+ if (callback == null) throw new IllegalArgumentException("callback must be non-null");
+
+ if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
+ enforceConnectivityRestrictedNetworksPermission();
+ }
+ mQosCallbackTracker.registerCallback(callback, filter, nai);
+ }
+
+ /**
+ * Unregisters the given callback.
+ *
+ * @param callback the callback to unregister
+ */
+ @Override
+ public void unregisterQosCallback(@NonNull final IQosCallback callback) {
+ mQosCallbackTracker.unregisterCallback(callback);
+ }
}
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index f2b63a642c29..88ce2208adcb 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -22,7 +22,6 @@ import android.gsi.AvbPublicKey;
import android.gsi.GsiProgress;
import android.gsi.IGsiService;
import android.gsi.IGsiServiceCallback;
-import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -30,7 +29,7 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.image.IDynamicSystemService;
import android.os.storage.StorageManager;
-import android.os.storage.StorageVolume;
+import android.os.storage.VolumeInfo;
import android.util.Slog;
import java.io.File;
@@ -88,16 +87,17 @@ public class DynamicSystemService extends IDynamicSystemService.Stub {
String path = SystemProperties.get("os.aot.path");
if (path.isEmpty()) {
final int userId = UserHandle.myUserId();
- final StorageVolume[] volumes =
- StorageManager.getVolumeList(userId, StorageManager.FLAG_FOR_WRITE);
- for (StorageVolume volume : volumes) {
- if (volume.isEmulated()) continue;
- if (!volume.isRemovable()) continue;
- if (!Environment.MEDIA_MOUNTED.equals(volume.getState())) continue;
- File sdCard = volume.getPathFile();
- if (sdCard.isDirectory()) {
- path = new File(sdCard, dsuSlot).getPath();
- break;
+ final StorageManager sm = mContext.getSystemService(StorageManager.class);
+ for (VolumeInfo volume : sm.getVolumes()) {
+ if (volume.getType() != volume.TYPE_PUBLIC) {
+ continue;
+ }
+ if (!volume.isMountedWritable()) {
+ continue;
+ }
+ File sd_internal = volume.getInternalPathForUser(userId);
+ if (sd_internal != null) {
+ path = new File(sd_internal, dsuSlot).getPath();
}
}
if (path.isEmpty()) {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 1ea4a89a761f..d30a6405e95d 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -405,6 +405,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
if (mLastPowerStateFromRadio != powerState) {
mLastPowerStateFromRadio = powerState;
try {
+ // TODO: The interface changes that comes from netd are handled by BSS itself.
+ // There are still events caused by setting or removing idle timer, so keep
+ // reporting from here until setting idler timer moved to CS.
getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos, uid);
} catch (RemoteException e) {
}
@@ -415,6 +418,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
if (mLastPowerStateFromWifi != powerState) {
mLastPowerStateFromWifi = powerState;
try {
+ // TODO: The interface changes that comes from netd are handled by BSS itself.
+ // There are still events caused by setting or removing idle timer, so keep
+ // reporting from here until setting idler timer moved to CS.
getBatteryStats().noteWifiRadioPowerState(powerState, tsNanos, uid);
} catch (RemoteException e) {
}
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index f6b72d6bfe2c..222c96f2496b 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -6,10 +6,10 @@ per-file VibratorService.java, DisplayThread.java = michaelwr@google.com
per-file VibratorService.java, DisplayThread.java = ogunwale@google.com
# Zram writeback
-per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com, srnvs@google.com
+per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com
# Userspace reboot
-per-file UserspaceRebootLogger.java = ioffe@google.com, tomcherry@google.com
+per-file UserspaceRebootLogger.java = ioffe@google.com, dvander@google.com
# Sensor Privacy
per-file SensorPrivacyService.java = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS
@@ -31,6 +31,7 @@ per-file IpSecService.java = file:/services/core/java/com/android/server/net/OWN
per-file MmsServiceBroker.java = file:/telephony/OWNERS
per-file NetIdManager.java = file:/services/core/java/com/android/server/net/OWNERS
per-file PackageWatchdog.java = file:/services/core/java/com/android/server/rollback/OWNERS
+per-file PinnerService.java = file:/apct-tests/perftests/OWNERS
per-file TelephonyRegistry.java = file:/telephony/OWNERS
per-file UiModeManagerService.java = file:/packages/SystemUI/OWNERS
per-file VcnManagementService.java = file:/services/core/java/com/android/server/vcn/OWNERS
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index c8d457d370ff..4e2519b47a47 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1537,6 +1537,9 @@ class StorageManagerService extends IStorageManager.Stub
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
} else if (vol.type == VolumeInfo.TYPE_STUB) {
+ if (vol.disk.isStubVisible()) {
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+ }
vol.mountUserId = mCurrentUserId;
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
} else {
@@ -1606,7 +1609,6 @@ class StorageManagerService extends IStorageManager.Stub
}
}
-
private void onVolumeStateChangedAsync(VolumeInfo vol, int oldState, int newState) {
synchronized (mLock) {
// Remember that we saw this volume so we're ready to accept user
@@ -3295,6 +3297,12 @@ class StorageManagerService extends IStorageManager.Stub
enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
if (isFsEncrypted) {
+ // When a user has secure lock screen, require secret to actually unlock.
+ // This check is mostly in place for emulation mode.
+ if (StorageManager.isFileEncryptedEmulatedOnly() &&
+ mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(secret)) {
+ throw new IllegalStateException("Secret required to unlock secure user " + userId);
+ }
try {
mVold.unlockUserKey(userId, serialNumber, encodeBytes(token),
encodeBytes(secret));
@@ -3427,6 +3435,27 @@ class StorageManagerService extends IStorageManager.Stub
}
}
+ /*
+ * Disable storage's app data isolation for testing.
+ */
+ @Override
+ public void disableAppDataIsolation(String pkgName, int pid, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) {
+ throw new SecurityException("no permission to enable app visibility");
+ }
+ final String[] sharedPackages =
+ mPmInternal.getSharedUserPackagesForPackage(pkgName, userId);
+ final int uid = mPmInternal.getPackageUid(pkgName, 0, userId);
+ final String[] packages =
+ sharedPackages.length != 0 ? sharedPackages : new String[]{pkgName};
+ try {
+ mVold.unmountAppStorageDirs(uid, pid, packages);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
/** Not thread safe */
class AppFuseMountScope extends AppFuseBridge.MountScope {
private boolean mMounted = false;
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 5f6e8df30f8d..81d2b831dc3c 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -52,7 +52,6 @@ import android.telephony.CallAttributes;
import android.telephony.CallQuality;
import android.telephony.CellIdentity;
import android.telephony.CellInfo;
-import android.telephony.CellLocation;
import android.telephony.CellSignalStrength;
import android.telephony.CellSignalStrengthCdma;
import android.telephony.CellSignalStrengthGsm;
@@ -64,6 +63,7 @@ import android.telephony.DisconnectCause;
import android.telephony.LocationAccessPolicy;
import android.telephony.PhoneCapability;
import android.telephony.PhoneStateListener;
+import android.telephony.PhysicalChannelConfig;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
import android.telephony.PreciseDisconnectCause;
@@ -78,6 +78,7 @@ import android.telephony.data.ApnSetting;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.LocalLog;
import android.util.Pair;
@@ -99,10 +100,13 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
/**
* Since phone process can be restarted, this class provides a centralized place
@@ -142,14 +146,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
int callerUid;
int callerPid;
- int events;
+ Set<Integer> eventList;
int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
int phoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
- boolean matchPhoneStateListenerEvent(int events) {
- return (callback != null) && ((events & this.events) != 0);
+ boolean matchPhoneStateListenerEvent(int event) {
+ return (callback != null) && (this.eventList.contains(event));
}
boolean matchOnSubscriptionsChangedListener() {
@@ -177,7 +181,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
+ onSubscriptionsChangedListenerCallback
+ " onOpportunisticSubscriptionsChangedListenererCallback="
+ onOpportunisticSubscriptionsChangedListenerCallback + " subId=" + subId
- + " phoneId=" + phoneId + " events=" + Integer.toHexString(events) + "}";
+ + " phoneId=" + phoneId + " events=" + eventList + "}";
}
}
@@ -306,6 +310,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private final LocalLog mListenLog = new LocalLog(200);
+ private List<PhysicalChannelConfig> mPhysicalChannelConfigs;
+
+ private boolean mIsDataEnabled = false;
+
+ private int mDataEnabledReason;
+
/**
* Per-phone map of precise data connection state. The key of the map is the pair of transport
* type and APN setting. This is the cache to prevent redundant callbacks to the listeners.
@@ -315,39 +325,62 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private List<Map<Pair<Integer, ApnSetting>, PreciseDataConnectionState>>
mPreciseDataConnectionStates;
- // Starting in Q, almost all cellular location requires FINE location enforcement.
- // Prior to Q, cellular was available with COARSE location enforcement. Bits in this
- // list will be checked for COARSE on apps targeting P or earlier and FINE on Q or later.
- static final int ENFORCE_LOCATION_PERMISSION_MASK =
- PhoneStateListener.LISTEN_CELL_LOCATION
- | PhoneStateListener.LISTEN_CELL_INFO
- | PhoneStateListener.LISTEN_REGISTRATION_FAILURE
- | PhoneStateListener.LISTEN_BARRING_INFO;
-
- static final int ENFORCE_PHONE_STATE_PERMISSION_MASK =
- PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
- | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
- | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST
- | PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED;
-
- static final int ENFORCE_PRECISE_PHONE_STATE_PERMISSION_MASK =
- PhoneStateListener.LISTEN_PRECISE_CALL_STATE
- | PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE
- | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES
- | PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED
- | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES
- | PhoneStateListener.LISTEN_REGISTRATION_FAILURE
- | PhoneStateListener.LISTEN_BARRING_INFO;
-
- static final int READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK =
- PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL
- | PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS;
-
- static final int READ_PRIVILEGED_PHONE_STATE_PERMISSION_MASK =
- PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT
- | PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED
- | PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED
- | PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE;
+ private static final Set<Integer> REQUIRE_PRECISE_PHONE_STATE_PERMISSION;
+ static {
+ REQUIRE_PRECISE_PHONE_STATE_PERMISSION = new HashSet<Integer>();
+ REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+ PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED);
+ REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+ PhoneStateListener.EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED);
+ REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+ PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED);
+ REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+ PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED);
+ REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+ PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED);
+ REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+ PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED);
+ REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(PhoneStateListener.EVENT_REGISTRATION_FAILURE);
+ REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(PhoneStateListener.EVENT_BARRING_INFO_CHANGED);
+ REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+ PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED);
+ REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+ PhoneStateListener.EVENT_DATA_ENABLED_CHANGED);
+ }
+
+ private boolean isLocationPermissionRequired(Set<Integer> events) {
+ return events.contains(PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)
+ || events.contains(PhoneStateListener.EVENT_CELL_INFO_CHANGED)
+ || events.contains(PhoneStateListener.EVENT_REGISTRATION_FAILURE)
+ || events.contains(PhoneStateListener.EVENT_BARRING_INFO_CHANGED);
+ }
+
+ private boolean isPhoneStatePermissionRequired(Set<Integer> events) {
+ return events.contains(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)
+ || events.contains(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)
+ || events.contains(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)
+ || events.contains(PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED);
+ }
+
+ private boolean isPrecisePhoneStatePermissionRequired(Set<Integer> events) {
+ for (Integer requireEvent : REQUIRE_PRECISE_PHONE_STATE_PERMISSION) {
+ if (events.contains(requireEvent)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isActiveEmergencySessionPermissionRequired(Set<Integer> events) {
+ return events.contains(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL)
+ || events.contains(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS);
+ }
+
+ private boolean isPrivilegedPhoneStatePermissionRequired(Set<Integer> events) {
+ return events.contains(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED)
+ || events.contains(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED)
+ || events.contains(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED);
+ }
private static final int MSG_USER_SWITCHED = 1;
private static final int MSG_UPDATE_DEFAULT_SUB = 2;
@@ -495,6 +528,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
cutListToSize(mImsReasonInfo, mNumPhones);
cutListToSize(mPreciseDataConnectionStates, mNumPhones);
cutListToSize(mBarringInfo, mNumPhones);
+ cutListToSize(mPhysicalChannelConfigs, mNumPhones);
return;
}
@@ -528,6 +562,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mPreciseDataConnectionStates.add(new ArrayMap<>());
mBarringInfo.add(i, new BarringInfo());
mTelephonyDisplayInfos[i] = null;
+ mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
}
}
@@ -548,8 +583,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public TelephonyRegistry(Context context, ConfigurationProvider configurationProvider) {
- CellLocation location = CellLocation.getEmpty();
-
mContext = context;
mConfigurationProvider = configurationProvider;
mBatteryStats = BatteryStatsService.getService();
@@ -588,6 +621,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mOutgoingSmsEmergencyNumber = new EmergencyNumber[numPhones];
mBarringInfo = new ArrayList<>();
mTelephonyDisplayInfos = new TelephonyDisplayInfo[numPhones];
+ mPhysicalChannelConfigs = new ArrayList<>();
for (int i = 0; i < numPhones; i++) {
mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
@@ -617,6 +651,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mPreciseDataConnectionStates.add(new ArrayMap<>());
mBarringInfo.add(i, new BarringInfo());
mTelephonyDisplayInfos[i] = null;
+ mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
}
mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -659,7 +694,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
r.callingFeatureId = callingFeatureId;
r.callerUid = Binder.getCallingUid();
r.callerPid = Binder.getCallingPid();
- r.events = 0;
+ r.eventList = new ArraySet<>();
if (DBG) {
log("listen oscl: Register r=" + r);
}
@@ -713,7 +748,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
r.callingFeatureId = callingFeatureId;
r.callerUid = Binder.getCallingUid();
r.callerPid = Binder.getCallingPid();
- r.events = 0;
+ r.eventList = new ArraySet<>();
if (DBG) {
log("listen ooscl: Register r=" + r);
}
@@ -786,323 +821,337 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- @Deprecated
- @Override
- public void listen(String callingPackage, IPhoneStateListener callback, int events,
- boolean notifyNow) {
- listenWithFeature(callingPackage, null, callback, events, notifyNow);
- }
-
@Override
- public void listenWithFeature(String callingPackage, String callingFeatureId,
- IPhoneStateListener callback, int events, boolean notifyNow) {
- listenForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, callingPackage,
- callingFeatureId, callback, events, notifyNow);
- }
-
- @Override
- public void listenForSubscriber(int subId, String callingPackage, String callingFeatureId,
- IPhoneStateListener callback, int events, boolean notifyNow) {
- listen(callingPackage, callingFeatureId, callback, events, notifyNow, subId);
+ public void listenWithEventList(int subId, String callingPackage, String callingFeatureId,
+ IPhoneStateListener callback, int[] events, boolean notifyNow) {
+ Set<Integer> eventList = Arrays.stream(events).boxed().collect(Collectors.toSet());
+ listen(callingPackage, callingFeatureId, callback, eventList, notifyNow, subId);
}
private void listen(String callingPackage, @Nullable String callingFeatureId,
- IPhoneStateListener callback, int events, boolean notifyNow, int subId) {
+ IPhoneStateListener callback, Set<Integer> events, boolean notifyNow, int subId) {
int callerUserId = UserHandle.getCallingUserId();
mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
String str = "listen: E pkg=" + pii(callingPackage) + " uid=" + Binder.getCallingUid()
- + " events=0x" + Integer.toHexString(events) + " notifyNow=" + notifyNow + " subId="
- + subId + " myUserId=" + UserHandle.myUserId() + " callerUserId=" + callerUserId;
+ + " events=" + events + " notifyNow=" + notifyNow
+ + " subId=" + subId + " myUserId=" + UserHandle.myUserId()
+ + " callerUserId=" + callerUserId;
mListenLog.log(str);
if (VDBG) {
log(str);
}
- if (events != PhoneStateListener.LISTEN_NONE) {
- // Checks permission and throws SecurityException for disallowed operations. For pre-M
- // apps whose runtime permission has been revoked, we return immediately to skip sending
- // events to the app without crashing it.
- if (!checkListenerPermission(events, subId, callingPackage, callingFeatureId,
- "listen")) {
- return;
+ if (events.isEmpty()) {
+ if (DBG) {
+ log("listen: Unregister");
}
+ events.clear();
+ remove(callback.asBinder());
+ return;
+ }
- int phoneId = getPhoneIdFromSubId(subId);
- synchronized (mRecords) {
- // register
- IBinder b = callback.asBinder();
- boolean doesLimitApply =
- Binder.getCallingUid() != Process.SYSTEM_UID
- && Binder.getCallingUid() != Process.PHONE_UID
- && Binder.getCallingUid() != Process.myUid();
- Record r = add(b, Binder.getCallingUid(), Binder.getCallingPid(), doesLimitApply);
+ // Checks permission and throws SecurityException for disallowed operations. For pre-M
+ // apps whose runtime permission has been revoked, we return immediately to skip sending
+ // events to the app without crashing it.
+ if (!checkListenerPermission(events, subId, callingPackage, callingFeatureId,
+ "listen")) {
+ return;
+ }
- if (r == null) {
- return;
- }
+ int phoneId = getPhoneIdFromSubId(subId);
+ synchronized (mRecords) {
+ // register
+ IBinder b = callback.asBinder();
+ boolean doesLimitApply =
+ Binder.getCallingUid() != Process.SYSTEM_UID
+ && Binder.getCallingUid() != Process.PHONE_UID
+ && Binder.getCallingUid() != Process.myUid();
+ Record r = add(b, Binder.getCallingUid(), Binder.getCallingPid(), doesLimitApply);
- r.context = mContext;
- r.callback = callback;
- r.callingPackage = callingPackage;
- r.callingFeatureId = callingFeatureId;
- r.callerUid = Binder.getCallingUid();
- r.callerPid = Binder.getCallingPid();
- // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
- // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
- if (!SubscriptionManager.isValidSubscriptionId(subId)) {
- r.subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
- } else {//APP specify subID
- r.subId = subId;
- }
- r.phoneId = phoneId;
- r.events = events;
- if (DBG) {
- log("listen: Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
- }
- if (notifyNow && validatePhoneId(phoneId)) {
- if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
- try {
- if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]);
- ServiceState rawSs = new ServiceState(mServiceState[phoneId]);
- if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
- r.callback.onServiceStateChanged(rawSs);
- } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
- r.callback.onServiceStateChanged(
- rawSs.createLocationInfoSanitizedCopy(false));
- } else {
- r.callback.onServiceStateChanged(
- rawSs.createLocationInfoSanitizedCopy(true));
- }
- } catch (RemoteException ex) {
- remove(r.binder);
+ if (r == null) {
+ return;
+ }
+
+ r.context = mContext;
+ r.callback = callback;
+ r.callingPackage = callingPackage;
+ r.callingFeatureId = callingFeatureId;
+ r.callerUid = Binder.getCallingUid();
+ r.callerPid = Binder.getCallingPid();
+ // Legacy applications pass SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+ // force all illegal subId to SubscriptionManager.DEFAULT_SUBSCRIPTION_ID
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ r.subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+ } else {//APP specify subID
+ r.subId = subId;
+ }
+ r.phoneId = phoneId;
+ r.eventList = events;
+ if (DBG) {
+ log("listen: Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
+ }
+ if (notifyNow && validatePhoneId(phoneId)) {
+ if (events.contains(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED)) {
+ try {
+ if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]);
+ ServiceState rawSs = new ServiceState(mServiceState[phoneId]);
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ r.callback.onServiceStateChanged(rawSs);
+ } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
+ r.callback.onServiceStateChanged(
+ rawSs.createLocationInfoSanitizedCopy(false));
+ } else {
+ r.callback.onServiceStateChanged(
+ rawSs.createLocationInfoSanitizedCopy(true));
}
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
- try {
- if (mSignalStrength[phoneId] != null) {
- int gsmSignalStrength = mSignalStrength[phoneId]
- .getGsmSignalStrength();
- r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
- : gsmSignalStrength));
- }
- } catch (RemoteException ex) {
- remove(r.binder);
+ }
+ if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED)) {
+ try {
+ if (mSignalStrength[phoneId] != null) {
+ int gsmSignalStrength = mSignalStrength[phoneId]
+ .getGsmSignalStrength();
+ r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
+ : gsmSignalStrength));
}
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
- try {
- r.callback.onMessageWaitingIndicatorChanged(
- mMessageWaiting[phoneId]);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(
+ PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)) {
+ try {
+ r.callback.onMessageWaitingIndicatorChanged(
+ mMessageWaiting[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
- try {
- r.callback.onCallForwardingIndicatorChanged(
- mCallForwarding[phoneId]);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(
+ PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)) {
+ try {
+ r.callback.onCallForwardingIndicatorChanged(
+ mCallForwarding[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
- try {
- if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]);
- if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
- && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
- // null will be translated to empty CellLocation object in client.
- r.callback.onCellLocationChanged(mCellIdentity[phoneId]);
- }
- } catch (RemoteException ex) {
- remove(r.binder);
+ }
+ if (validateEventAndUserLocked(
+ r, PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)) {
+ try {
+ if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]);
+ if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ // null will be translated to empty CellLocation object in client.
+ r.callback.onCellLocationChanged(mCellIdentity[phoneId]);
}
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
- try {
- r.callback.onCallStateChanged(mCallState[phoneId],
- getCallIncomingNumber(r, phoneId));
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(PhoneStateListener.EVENT_CALL_STATE_CHANGED)) {
+ try {
+ r.callback.onCallStateChanged(mCallState[phoneId],
+ getCallIncomingNumber(r, phoneId));
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
- try {
- r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+ }
+ if (events.contains(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED)) {
+ try {
+ r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
mDataConnectionNetworkType[phoneId]);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
- try {
- r.callback.onDataActivity(mDataActivity[phoneId]);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED)) {
+ try {
+ r.callback.onDataActivity(mDataActivity[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
- try {
- if (mSignalStrength[phoneId] != null) {
- r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
- }
- } catch (RemoteException ex) {
- remove(r.binder);
+ }
+ if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED)) {
+ try {
+ if (mSignalStrength[phoneId] != null) {
+ r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
}
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
- != 0) {
- updateReportSignalStrengthDecision(r.subId);
- try {
- if (mSignalStrength[phoneId] != null) {
- r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
- }
- } catch (RemoteException ex) {
- remove(r.binder);
+ }
+ if (events.contains(
+ PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
+ updateReportSignalStrengthDecision(r.subId);
+ try {
+ if (mSignalStrength[phoneId] != null) {
+ r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
}
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
- try {
- if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
- + mCellInfo.get(phoneId));
- if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
- && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
- r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
- }
- } catch (RemoteException ex) {
- remove(r.binder);
+ }
+ if (validateEventAndUserLocked(
+ r, PhoneStateListener.EVENT_CELL_INFO_CHANGED)) {
+ try {
+ if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
+ + mCellInfo.get(phoneId));
+ if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
}
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
- try {
- r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED)) {
+ try {
+ r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES) != 0) {
- try {
- r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId],
- mCallPreciseDisconnectCause[phoneId]);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED)) {
+ try {
+ r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId],
+ mCallPreciseDisconnectCause[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) != 0) {
- try {
- r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId));
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED)) {
+ try {
+ r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId));
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
- try {
- for (PreciseDataConnectionState pdcs
- : mPreciseDataConnectionStates.get(phoneId).values()) {
- r.callback.onPreciseDataConnectionStateChanged(pdcs);
- }
- } catch (RemoteException ex) {
- remove(r.binder);
+ }
+ if (events.contains(
+ PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)) {
+ try {
+ for (PreciseDataConnectionState pdcs
+ : mPreciseDataConnectionStates.get(phoneId).values()) {
+ r.callback.onPreciseDataConnectionStateChanged(pdcs);
}
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) != 0) {
- try {
- r.callback.onCarrierNetworkChange(mCarrierNetworkChangeState);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED)) {
+ try {
+ r.callback.onCarrierNetworkChange(mCarrierNetworkChangeState);
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) !=0) {
- try {
- r.callback.onVoiceActivationStateChanged(
- mVoiceActivationState[phoneId]);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED)) {
+ try {
+ r.callback.onVoiceActivationStateChanged(
+ mVoiceActivationState[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) !=0) {
- try {
- r.callback.onDataActivationStateChanged(mDataActivationState[phoneId]);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED)) {
+ try {
+ r.callback.onDataActivationStateChanged(mDataActivationState[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) {
- try {
- r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED)) {
+ try {
+ r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) != 0) {
- try {
- if (mTelephonyDisplayInfos[phoneId] != null) {
- r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[phoneId]);
- }
- } catch (RemoteException ex) {
- remove(r.binder);
+ }
+ if (events.contains(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED)) {
+ try {
+ if (mTelephonyDisplayInfos[phoneId] != null) {
+ r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[phoneId]);
}
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST) != 0) {
- try {
- r.callback.onEmergencyNumberListChanged(mEmergencyNumberList);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)) {
+ try {
+ r.callback.onEmergencyNumberListChanged(mEmergencyNumberList);
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE) != 0) {
- try {
- r.callback.onPhoneCapabilityChanged(mPhoneCapability);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED)) {
+ try {
+ r.callback.onPhoneCapabilityChanged(mPhoneCapability);
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener
- .LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE) != 0) {
- try {
- r.callback.onActiveDataSubIdChanged(mActiveDataSubId);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(
+ PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED)) {
+ try {
+ r.callback.onActiveDataSubIdChanged(mActiveDataSubId);
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED) != 0) {
- try {
- r.callback.onRadioPowerStateChanged(mRadioPowerState);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED)) {
+ try {
+ r.callback.onRadioPowerStateChanged(mRadioPowerState);
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) != 0) {
- try {
- r.callback.onSrvccStateChanged(mSrvccState[phoneId]);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED)) {
+ try {
+ r.callback.onSrvccStateChanged(mSrvccState[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED) != 0) {
- try {
- r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED)) {
+ try {
+ r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
- if ((events & PhoneStateListener.LISTEN_BARRING_INFO) != 0) {
- BarringInfo barringInfo = mBarringInfo.get(phoneId);
- BarringInfo biNoLocation = barringInfo != null
- ? barringInfo.createLocationInfoSanitizedCopy() : null;
- if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo);
- try {
- r.callback.onBarringInfoChanged(
- checkFineLocationAccess(r, Build.VERSION_CODES.BASE)
- ? barringInfo : biNoLocation);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
+ }
+ if (events.contains(PhoneStateListener.EVENT_BARRING_INFO_CHANGED)) {
+ BarringInfo barringInfo = mBarringInfo.get(phoneId);
+ BarringInfo biNoLocation = barringInfo != null
+ ? barringInfo.createLocationInfoSanitizedCopy() : null;
+ if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo);
+ try {
+ r.callback.onBarringInfoChanged(
+ checkFineLocationAccess(r, Build.VERSION_CODES.BASE)
+ ? barringInfo : biNoLocation);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
+ if (events.contains(
+ PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)) {
+ try {
+ r.callback.onPhysicalChannelConfigChanged(
+ mPhysicalChannelConfigs);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
+ if (events.contains(
+ PhoneStateListener.EVENT_DATA_ENABLED_CHANGED)) {
+ try {
+ r.callback.onDataEnabledChanged(mIsDataEnabled, mDataEnabledReason);
+ } catch (RemoteException ex) {
+ remove(r.binder);
}
}
}
- } else {
- if(DBG) log("listen: Unregister");
- remove(callback.asBinder());
}
}
@@ -1114,7 +1163,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
// If any of the system clients wants to always listen to signal strength,
// we need to set it on.
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)) {
+ PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
telephonyManager.createForSubscriptionId(subscriptionId)
.setAlwaysReportSignalStrength(true);
return;
@@ -1215,7 +1264,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
// strength is removed from registry records, we need to check if
// the signal strength decision needs to update on its slot.
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)) {
+ PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
updateReportSignalStrengthDecision(r.subId);
}
return;
@@ -1235,8 +1284,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
synchronized (mRecords) {
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) &&
- (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
+ if (r.matchPhoneStateListenerEvent(PhoneStateListener.EVENT_CALL_STATE_CHANGED)
+ && (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
try {
// Ensure the listener has read call log permission; if they do not return
// an empty phone number.
@@ -1270,9 +1319,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mCallState[phoneId] = state;
mCallIncomingNumber[phoneId] = incomingNumber;
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) &&
- (r.subId == subId) &&
- (r.subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
+ if (r.matchPhoneStateListenerEvent(PhoneStateListener.EVENT_CALL_STATE_CHANGED)
+ && (r.subId == subId)
+ && (r.subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
try {
String incomingNumberOrEmpty = getCallIncomingNumber(r, phoneId);
r.callback.onCallStateChanged(state, incomingNumberOrEmpty);
@@ -1312,8 +1361,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
log("notifyServiceStateForSubscriber: r=" + r + " subId=" + subId
+ " phoneId=" + phoneId + " state=" + state);
}
- if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SERVICE_STATE) &&
- idMatch(r.subId, subId, phoneId)) {
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.EVENT_SERVICE_STATE_CHANGED)
+ && idMatch(r.subId, subId, phoneId)) {
try {
ServiceState stateToSend;
@@ -1374,7 +1424,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
if ((activationType == SIM_ACTIVATION_TYPE_VOICE)
&& r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE)
+ PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
if (DBG) {
log("notifyVoiceActivationStateForPhoneId: callback.onVASC r=" + r
@@ -1385,7 +1435,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
if ((activationType == SIM_ACTIVATION_TYPE_DATA)
&& r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE)
+ PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
if (DBG) {
log("notifyDataActivationStateForPhoneId: callback.onDASC r=" + r
@@ -1424,9 +1474,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
log("notifySignalStrengthForPhoneId: r=" + r + " subId=" + subId
+ " phoneId=" + phoneId + " ss=" + signalStrength);
}
- if ((r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTHS)
+ if ((r.matchPhoneStateListenerEvent(
+ PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED)
|| r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH))
+ PhoneStateListener.
+ EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))
&& idMatch(r.subId, subId, phoneId)) {
try {
if (DBG) {
@@ -1439,8 +1491,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mRemoveList.add(r.binder);
}
}
- if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTH) &&
- idMatch(r.subId, subId, phoneId)) {
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED)
+ && idMatch(r.subId, subId, phoneId)) {
try {
int gsmSignalStrength = signalStrength.getGsmSignalStrength();
int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
@@ -1486,8 +1539,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) &&
- idMatch(r.subId, subId, phoneId)) {
+ PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED)
+ && idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onCarrierNetworkChange(active);
} catch (RemoteException ex) {
@@ -1517,9 +1570,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (validatePhoneId(phoneId)) {
mCellInfo.set(phoneId, cellInfo);
for (Record r : mRecords) {
- if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) &&
- idMatch(r.subId, subId, phoneId) &&
- (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ if (validateEventAndUserLocked(
+ r, PhoneStateListener.EVENT_CELL_INFO_CHANGED)
+ && idMatch(r.subId, subId, phoneId)
+ && (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
&& checkFineLocationAccess(r, Build.VERSION_CODES.Q))) {
try {
if (DBG_LOC) {
@@ -1551,8 +1605,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mMessageWaiting[phoneId] = mwi;
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) &&
- idMatch(r.subId, subId, phoneId)) {
+ PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)
+ && idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onMessageWaitingIndicatorChanged(mwi);
} catch (RemoteException ex) {
@@ -1578,8 +1632,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mUserMobileDataState[phoneId] = state;
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) &&
- idMatch(r.subId, subId, phoneId)) {
+ PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED)
+ && idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onUserMobileDataStateChanged(state);
} catch (RemoteException ex) {
@@ -1617,7 +1671,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mTelephonyDisplayInfos[phoneId] = telephonyDisplayInfo;
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)
+ PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED)
&& idMatchWithoutDefaultPhoneCheck(r.subId, subId)) {
try {
r.callback.onDisplayInfoChanged(telephonyDisplayInfo);
@@ -1649,8 +1703,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mCallForwarding[phoneId] = cfi;
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) &&
- idMatch(r.subId, subId, phoneId)) {
+ PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)
+ && idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onCallForwardingIndicatorChanged(cfi);
} catch (RemoteException ex) {
@@ -1677,8 +1731,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mDataActivity[phoneId] = state;
for (Record r : mRecords) {
// Notify by correct subId.
- if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_DATA_ACTIVITY) &&
- idMatch(r.subId, subId, phoneId)) {
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED)
+ && idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onDataActivity(state);
} catch (RemoteException ex) {
@@ -1725,7 +1780,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mLocalLog.log(str);
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_DATA_CONNECTION_STATE)
+ PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
if (DBG) {
@@ -1747,12 +1802,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
preciseState.getApnSetting());
PreciseDataConnectionState oldState = mPreciseDataConnectionStates.get(phoneId)
.remove(key);
- log("Jack: oldState=" + oldState);
- log("Jack: newState=" + preciseState);
if (!Objects.equals(oldState, preciseState)) {
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)
+ PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onPreciseDataConnectionStateChanged(preciseState);
@@ -1797,9 +1850,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (validatePhoneId(phoneId) && !Objects.equals(cellIdentity, mCellIdentity[phoneId])) {
mCellIdentity[phoneId] = cellIdentity;
for (Record r : mRecords) {
- if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
- idMatch(r.subId, subId, phoneId) &&
- (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+ if (validateEventAndUserLocked(
+ r, PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)
+ && idMatch(r.subId, subId, phoneId)
+ && (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
&& checkFineLocationAccess(r, Build.VERSION_CODES.Q))) {
try {
if (DBG_LOC) {
@@ -1850,7 +1904,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_PRECISE_CALL_STATE)
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]);
@@ -1859,7 +1914,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
if (notifyCallAttributes && r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED)
+ PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
@@ -1908,7 +1963,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mImsReasonInfo.set(phoneId, imsReasonInfo);
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES)
+ PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
if (DBG_LOC) {
@@ -1940,8 +1995,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mSrvccState[phoneId] = state;
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) &&
- idMatch(r.subId, subId, phoneId)) {
+ PhoneStateListener.EVENT_SRVCC_STATE_CHANGED)
+ && idMatch(r.subId, subId, phoneId)) {
try {
if (DBG_LOC) {
log("notifySrvccStateChanged: mSrvccState=" + state + " r=" + r);
@@ -1969,7 +2024,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
log("notifyOemHookRawEventForSubscriber: r=" + r + " subId=" + subId);
}
if ((r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT))
+ PhoneStateListener.EVENT_OEM_HOOK_RAW))
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onOemHookRawEvent(rawData);
@@ -1997,7 +2052,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE)) {
+ PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED)) {
try {
r.callback.onPhoneCapabilityChanged(capability);
} catch (RemoteException ex) {
@@ -2022,7 +2077,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
synchronized (mRecords) {
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE)) {
+ PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED)) {
try {
r.callback.onActiveDataSubIdChanged(activeDataSubId);
} catch (RemoteException ex) {
@@ -2049,7 +2104,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED)
+ PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onRadioPowerStateChanged(state);
@@ -2078,7 +2133,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST)
+ PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onEmergencyNumberListChanged(mEmergencyNumberList);
@@ -2110,7 +2165,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
for (Record r : mRecords) {
// Send to all listeners regardless of subscription
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL)) {
+ PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL)) {
try {
r.callback.onOutgoingEmergencyCall(emergencyNumber, subId);
} catch (RemoteException ex) {
@@ -2134,7 +2189,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
for (Record r : mRecords) {
// Send to all listeners regardless of subscription
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS)) {
+ PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS)) {
try {
r.callback.onOutgoingEmergencySms(emergencyNumber, subId);
} catch (RemoteException ex) {
@@ -2164,7 +2219,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED)
+ PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
@@ -2195,7 +2250,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (validatePhoneId(phoneId)) {
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_REGISTRATION_FAILURE)
+ PhoneStateListener.EVENT_REGISTRATION_FAILURE)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onRegistrationFailed(
@@ -2238,7 +2293,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo);
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_BARRING_INFO)
+ PhoneStateListener.EVENT_BARRING_INFO_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
if (DBG_LOC) {
@@ -2258,6 +2313,81 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
+ /**
+ * Send a notification to registrants that the configs of physical channel has changed for
+ * a particular subscription.
+ *
+ * @param subId the subId
+ * @param configs a list of {@link PhysicalChannelConfig}, the configs of physical channel.
+ */
+ public void notifyPhysicalChannelConfigForSubscriber(
+ int subId, List<PhysicalChannelConfig> configs) {
+ if (!checkNotifyPermission("notifyPhysicalChannelConfig()")) {
+ return;
+ }
+
+ if (VDBG) {
+ log("notifyPhysicalChannelConfig: subId=" + subId + " configs=" + configs);
+ }
+
+ synchronized (mRecords) {
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mPhysicalChannelConfigs.set(phoneId, configs.get(phoneId));
+ for (Record r : mRecords) {
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)
+ && idMatch(r.subId, subId, phoneId)) {
+ try {
+ if (DBG_LOC) {
+ log("notifyPhysicalChannelConfig: "
+ + "mPhysicalChannelConfigs="
+ + configs + " r=" + r);
+ }
+ r.callback.onPhysicalChannelConfigChanged(configs);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
+
+ /**
+ * Notify that the data enabled has changed.
+ *
+ * @param enabled True if data is enabled, otherwise disabled.
+ * @param reason Reason for data enabled/disabled. See {@code DATA_*} in
+ * {@link TelephonyManager}.
+ */
+ public void notifyDataEnabled(boolean enabled,
+ @TelephonyManager.DataEnabledReason int reason) {
+ if (!checkNotifyPermission("notifyDataEnabled()")) {
+ return;
+ }
+
+ if (VDBG) {
+ log("notifyDataEnabled: enabled=" + enabled + " reason=" + reason);
+ }
+
+ mIsDataEnabled = enabled;
+ mDataEnabledReason = reason;
+ synchronized (mRecords) {
+ for (Record r : mRecords) {
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.EVENT_DATA_ENABLED_CHANGED)) {
+ try {
+ r.callback.onDataEnabledChanged(enabled, reason);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
@@ -2310,6 +2440,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
pw.println("mEmergencyNumberList=" + mEmergencyNumberList);
pw.println("mDefaultPhoneId=" + mDefaultPhoneId);
pw.println("mDefaultSubId=" + mDefaultSubId);
+ pw.println("mPhysicalChannelConfigs=" + mPhysicalChannelConfigs);
+ pw.println("mIsDataEnabled=" + mIsDataEnabled);
+ pw.println("mDataEnabledReason=" + mDataEnabledReason);
pw.decreaseIndent();
@@ -2538,22 +2671,29 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
== PackageManager.PERMISSION_GRANTED;
}
- private boolean checkListenerPermission(int events, int subId, String callingPackage,
+ private boolean checkListenerPermission(Set<Integer> events, int subId, String callingPackage,
@Nullable String callingFeatureId, String message) {
LocationAccessPolicy.LocationPermissionQuery.Builder locationQueryBuilder =
new LocationAccessPolicy.LocationPermissionQuery.Builder()
- .setCallingPackage(callingPackage)
- .setMethod(message + " events: " + events)
- .setCallingPid(Binder.getCallingPid())
- .setCallingUid(Binder.getCallingUid());
+ .setCallingPackage(callingPackage)
+ .setMethod(message + " events: " + events)
+ .setCallingPid(Binder.getCallingPid())
+ .setCallingUid(Binder.getCallingUid());
+
+ boolean shouldCheckLocationPermissions = false;
- if ((events & ENFORCE_LOCATION_PERMISSION_MASK) != 0) {
+ if (isLocationPermissionRequired(events)) {
// Everything that requires fine location started in Q. So far...
locationQueryBuilder.setMinSdkVersionForFine(Build.VERSION_CODES.Q);
// If we're enforcing fine starting in Q, we also want to enforce coarse even for
// older SDK versions.
locationQueryBuilder.setMinSdkVersionForCoarse(0);
+ shouldCheckLocationPermissions = true;
+ }
+
+ boolean isPermissionCheckSuccessful = true;
+ if (shouldCheckLocationPermissions) {
LocationAccessPolicy.LocationPermissionResult result =
LocationAccessPolicy.checkLocationPermission(
mContext, locationQueryBuilder.build());
@@ -2562,18 +2702,18 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
throw new SecurityException("Unable to listen for events " + events + " due to "
+ "insufficient location permissions.");
case DENIED_SOFT:
- return false;
+ isPermissionCheckSuccessful = false;
}
}
- if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) {
+ if (isPhoneStatePermissionRequired(events)) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
mContext, subId, callingPackage, callingFeatureId, message)) {
- return false;
+ isPermissionCheckSuccessful = false;
}
}
- if ((events & ENFORCE_PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) {
+ if (isPrecisePhoneStatePermissionRequired(events)) {
// check if calling app has either permission READ_PRECISE_PHONE_STATE
// or with carrier privileges
try {
@@ -2584,47 +2724,46 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- if ((events & READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK) != 0) {
+ if (isActiveEmergencySessionPermissionRequired(events)) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null);
}
- if ((events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
+ if ((events.contains(PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH, null);
}
- if ((events & READ_PRIVILEGED_PHONE_STATE_PERMISSION_MASK) != 0) {
+ if (isPrivilegedPhoneStatePermissionRequired(events)) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
}
-
- return true;
+ return isPermissionCheckSuccessful;
}
private void handleRemoveListLocked() {
int size = mRemoveList.size();
if (VDBG) log("handleRemoveListLocked: mRemoveList.size()=" + size);
if (size > 0) {
- for (IBinder b: mRemoveList) {
+ for (IBinder b : mRemoveList) {
remove(b);
}
mRemoveList.clear();
}
}
- private boolean validateEventsAndUserLocked(Record r, int events) {
+ private boolean validateEventAndUserLocked(Record r, int event) {
int foregroundUser;
long callingIdentity = Binder.clearCallingIdentity();
boolean valid = false;
try {
foregroundUser = ActivityManager.getCurrentUser();
valid = UserHandle.getUserId(r.callerUid) == foregroundUser
- && r.matchPhoneStateListenerEvent(events);
+ && r.matchPhoneStateListenerEvent(event);
if (DBG | DBG_LOC) {
- log("validateEventsAndUserLocked: valid=" + valid
+ log("validateEventAndUserLocked: valid=" + valid
+ " r.callerUid=" + r.callerUid + " foregroundUser=" + foregroundUser
- + " r.events=" + r.events + " events=" + events);
+ + " r.eventList=" + r.eventList + " event=" + event);
}
} finally {
Binder.restoreCallingIdentity(callingIdentity);
@@ -2677,6 +2816,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
+ /**
+ * Note -- this method should only be used at the site of a permission check if you need to
+ * explicitly allow apps below a certain SDK level access regardless of location permissions.
+ * If you don't need app compat logic, use {@link #checkFineLocationAccess(Record)}.
+ */
private boolean checkFineLocationAccess(Record r, int minSdk) {
LocationAccessPolicy.LocationPermissionQuery query =
new LocationAccessPolicy.LocationPermissionQuery.Builder()
@@ -2695,6 +2839,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
});
}
+ /**
+ * Note -- this method should only be used at the site of a permission check if you need to
+ * explicitly allow apps below a certain SDK level access regardless of location permissions.
+ * If you don't need app compat logic, use {@link #checkCoarseLocationAccess(Record)}.
+ */
private boolean checkCoarseLocationAccess(Record r, int minSdk) {
LocationAccessPolicy.LocationPermissionQuery query =
new LocationAccessPolicy.LocationPermissionQuery.Builder()
@@ -2714,9 +2863,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
private void checkPossibleMissNotify(Record r, int phoneId) {
- int events = r.events;
+ Set<Integer> events = r.eventList;
+
+ if (events == null || events.isEmpty()) {
+ log("checkPossibleMissNotify: events = null.");
+ return;
+ }
- if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
+ if ((events.contains(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED))) {
try {
if (VDBG) log("checkPossibleMissNotify: onServiceStateChanged state=" +
mServiceState[phoneId]);
@@ -2735,8 +2889,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0
- || (events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
+ if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED)
+ || events.contains(
+ PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
try {
if (mSignalStrength[phoneId] != null) {
SignalStrength signalStrength = mSignalStrength[phoneId];
@@ -2751,7 +2906,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
+ if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED)) {
try {
if (mSignalStrength[phoneId] != null) {
int gsmSignalStrength = mSignalStrength[phoneId]
@@ -2768,7 +2923,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
+ if (validateEventAndUserLocked(r, PhoneStateListener.EVENT_CELL_INFO_CHANGED)) {
try {
if (DBG_LOC) {
log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = "
@@ -2783,7 +2938,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- if ((events & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) {
+ if (events.contains(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED)) {
try {
if (VDBG) {
log("checkPossibleMissNotify: onUserMobileDataStateChanged phoneId="
@@ -2795,7 +2950,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- if ((events & PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) != 0) {
+ if (events.contains(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED)) {
try {
if (VDBG) {
log("checkPossibleMissNotify: onDisplayInfoChanged phoneId="
@@ -2809,7 +2964,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
+ if (events.contains(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)) {
try {
if (VDBG) {
log("checkPossibleMissNotify: onMessageWaitingIndicatorChanged phoneId="
@@ -2822,7 +2977,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
+ if (events.contains(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)) {
try {
if (VDBG) {
log("checkPossibleMissNotify: onCallForwardingIndicatorChanged phoneId="
@@ -2835,7 +2990,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
+ if (validateEventAndUserLocked(r, PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)) {
try {
if (DBG_LOC) {
log("checkPossibleMissNotify: onCellLocationChanged mCellIdentity = "
@@ -2851,7 +3006,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
+ if (events.contains(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED)) {
try {
if (DBG) {
log("checkPossibleMissNotify: onDataConnectionStateChanged(mDataConnectionState"
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index e8687e57a07b..a08d066513c7 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -242,6 +242,7 @@ class TestNetworkService extends ITestNetworkManager.Stub {
nc.addTransportType(NetworkCapabilities.TRANSPORT_TEST);
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+ nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
nc.setNetworkSpecifier(new StringNetworkSpecifier(iface));
nc.setAdministratorUids(administratorUids);
if (!isMetered) {
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index c191a78aad0e..8562b0d9cb82 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -25,21 +25,28 @@ import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.Context;
import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
import android.net.vcn.IVcnManagementService;
+import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
+import android.net.vcn.VcnUnderlyingNetworkPolicy;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.UserHandle;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
+import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -154,6 +161,11 @@ public class VcnManagementService extends IVcnManagementService.Stub {
@NonNull private final PersistableBundleUtils.LockingReadWriteHelper mConfigDiskRwHelper;
+ @GuardedBy("mLock")
+ @NonNull
+ private final Map<IBinder, PolicyListenerBinderDeath> mRegisteredPolicyListeners =
+ new ArrayMap<>();
+
@VisibleForTesting(visibility = Visibility.PRIVATE)
VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) {
mContext = requireNonNull(context, "Missing context");
@@ -495,4 +507,84 @@ public class VcnManagementService extends IVcnManagementService.Stub {
return Collections.unmodifiableMap(mVcns);
}
}
+
+ /** Binder death recipient used to remove a registered policy listener. */
+ private class PolicyListenerBinderDeath implements Binder.DeathRecipient {
+ @NonNull private final IVcnUnderlyingNetworkPolicyListener mListener;
+
+ PolicyListenerBinderDeath(@NonNull IVcnUnderlyingNetworkPolicyListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void binderDied() {
+ Log.e(TAG, "app died without removing VcnUnderlyingNetworkPolicyListener");
+ removeVcnUnderlyingNetworkPolicyListener(mListener);
+ }
+ }
+
+ /** Adds the provided listener for receiving VcnUnderlyingNetworkPolicy updates. */
+ @GuardedBy("mLock")
+ @Override
+ public void addVcnUnderlyingNetworkPolicyListener(
+ @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
+ requireNonNull(listener, "listener was null");
+
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.NETWORK_FACTORY,
+ "Must have permission NETWORK_FACTORY to register a policy listener");
+
+ PolicyListenerBinderDeath listenerBinderDeath = new PolicyListenerBinderDeath(listener);
+
+ synchronized (mLock) {
+ mRegisteredPolicyListeners.put(listener.asBinder(), listenerBinderDeath);
+
+ try {
+ listener.asBinder().linkToDeath(listenerBinderDeath, 0 /* flags */);
+ } catch (RemoteException e) {
+ // Remote binder already died - cleanup registered Listener
+ listenerBinderDeath.binderDied();
+ }
+ }
+ }
+
+ /** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */
+ @GuardedBy("mLock")
+ @Override
+ public void removeVcnUnderlyingNetworkPolicyListener(
+ @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
+ requireNonNull(listener, "listener was null");
+
+ synchronized (mLock) {
+ PolicyListenerBinderDeath listenerBinderDeath =
+ mRegisteredPolicyListeners.remove(listener.asBinder());
+
+ if (listenerBinderDeath != null) {
+ listener.asBinder().unlinkToDeath(listenerBinderDeath, 0 /* flags */);
+ }
+ }
+ }
+
+ /**
+ * Gets the UnderlyingNetworkPolicy as determined by the provided NetworkCapabilities and
+ * LinkProperties.
+ */
+ @NonNull
+ @Override
+ public VcnUnderlyingNetworkPolicy getUnderlyingNetworkPolicy(
+ @NonNull NetworkCapabilities networkCapabilities,
+ @NonNull LinkProperties linkProperties) {
+ requireNonNull(networkCapabilities, "networkCapabilities was null");
+ requireNonNull(linkProperties, "linkProperties was null");
+
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.NETWORK_FACTORY,
+ "Must have permission NETWORK_FACTORY or be the SystemServer to get underlying"
+ + " Network policies");
+
+ // TODO(b/175914059): implement policy generation once VcnManagementService is able to
+ // determine policies
+
+ return new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, networkCapabilities);
+ }
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 630548df4b0b..ab24015a1174 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -704,7 +704,7 @@ public class Watchdog extends Thread {
WatchdogDiagnostics.diagnoseCheckers(blockedCheckers);
Slog.w(TAG, "*** GOODBYE!");
if (!Build.IS_USER && isCrashLoopFound()
- && !WatchdogProperties.is_fatal_ignore().orElse(false)) {
+ && !WatchdogProperties.should_ignore_fatal_count().orElse(false)) {
breakCrashLoop();
}
Process.killProcess(Process.myPid());
@@ -783,7 +783,7 @@ public class Watchdog extends Thread {
private boolean isCrashLoopFound() {
int fatalCount = WatchdogProperties.fatal_count().orElse(0);
long fatalWindowMs = TimeUnit.SECONDS.toMillis(
- WatchdogProperties.fatal_window_second().orElse(0));
+ WatchdogProperties.fatal_window_seconds().orElse(0));
if (fatalCount == 0 || fatalWindowMs == 0) {
if (fatalCount != fatalWindowMs) {
Slog.w(TAG, String.format("sysprops '%s' and '%s' should be set or unset together",
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 928ddab9dca7..686adbb7b793 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -190,6 +190,7 @@ import android.app.usage.UsageEvents.Event;
import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
+import android.compat.Compatibility;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
@@ -318,6 +319,7 @@ import com.android.internal.app.IAppOpsService;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.SystemUserHomeActivity;
import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.internal.content.PackageHelper;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
@@ -16944,6 +16946,8 @@ public class ActivityManagerService extends IActivityManager.Stub
if (disableHiddenApiChecks || disableTestApiChecks) {
enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS,
"disable hidden API checks");
+
+ enableTestApiAccess(ii.packageName);
}
// TODO(b/158750470): remove
@@ -17083,6 +17087,25 @@ public class ActivityManagerService extends IActivityManager.Stub
forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false, app.userId,
"finished inst");
+
+ disableTestApiAccess(app.info.packageName);
+ }
+
+ private void enableTestApiAccess(String packageName) {
+ if (mPlatformCompat != null) {
+ Compatibility.ChangeConfig config = new Compatibility.ChangeConfig(
+ Collections.singleton(166236554L /* VMRuntime.ALLOW_TEST_API_ACCESS */),
+ Collections.emptySet());
+ CompatibilityChangeConfig override = new CompatibilityChangeConfig(config);
+ mPlatformCompat.setOverridesForTest(override, packageName);
+ }
+ }
+
+ private void disableTestApiAccess(String packageName) {
+ if (mPlatformCompat != null) {
+ mPlatformCompat.clearOverrideForTest(166236554L /* VMRuntime.ALLOW_TEST_API_ACCESS */,
+ packageName);
+ }
}
public void finishInstrumentation(IApplicationThread target,
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 1ade8e7e9311..9986085224b1 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -21,11 +21,14 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.net.INetworkManagementEventObserver;
+import android.net.NetworkCapabilities;
import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
+import android.os.INetworkManagementService;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFormatException;
@@ -33,6 +36,7 @@ import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -52,6 +56,7 @@ import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.os.BatteryStatsImpl;
@@ -62,6 +67,7 @@ import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.ParseUtils;
import com.android.server.LocalServices;
+import com.android.server.net.BaseNetworkObserver;
import java.io.File;
import java.io.FileDescriptor;
@@ -108,6 +114,39 @@ public final class BatteryStatsService extends IBatteryStats.Stub
private CharBuffer mUtf16BufferStat = CharBuffer.allocate(MAX_LOW_POWER_STATS_SIZE);
private static final int MAX_LOW_POWER_STATS_SIZE = 4096;
+ @GuardedBy("mStats")
+ private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+ @GuardedBy("mStats")
+ private int mLastPowerStateFromWifi = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+ private final INetworkManagementEventObserver mActivityChangeObserver =
+ new BaseNetworkObserver() {
+ @Override
+ public void interfaceClassDataActivityChanged(int transportType, boolean active,
+ long tsNanos, int uid) {
+ final int powerState = active
+ ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
+ : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+ final long timestampNanos;
+ if (tsNanos <= 0) {
+ timestampNanos = SystemClock.elapsedRealtimeNanos();
+ } else {
+ timestampNanos = tsNanos;
+ }
+
+ switch (transportType) {
+ case NetworkCapabilities.TRANSPORT_CELLULAR:
+ noteMobileRadioPowerState(powerState, timestampNanos, uid);
+ break;
+ case NetworkCapabilities.TRANSPORT_WIFI:
+ noteWifiRadioPowerState(powerState, timestampNanos, uid);
+ break;
+ default:
+ Slog.d(TAG, "Received unexpected transport in "
+ + "interfaceClassDataActivityChanged unexpected type: "
+ + transportType);
+ }
+ }
+ };
/**
* Replaces the information in the given rpmStats with up-to-date information.
*/
@@ -203,6 +242,13 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
public void systemServicesReady() {
+ final INetworkManagementService nms = INetworkManagementService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+ try {
+ nms.registerObserver(mActivityChangeObserver);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Could not register INetworkManagement event observer " + e);
+ }
mStats.systemServicesReady(mContext);
}
@@ -680,8 +726,13 @@ public final class BatteryStatsService extends IBatteryStats.Stub
public void noteMobileRadioPowerState(int powerState, long timestampNs, int uid) {
enforceCallingPermission();
+
final boolean update;
synchronized (mStats) {
+ // Ignore if no power state change.
+ if (mLastPowerStateFromRadio == powerState) return;
+
+ mLastPowerStateFromRadio = powerState;
update = mStats.noteMobileRadioPowerStateLocked(powerState, timestampNs, uid);
}
@@ -863,6 +914,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
// There was a change in WiFi power state.
// Collect data now for the past activity.
synchronized (mStats) {
+ // Ignore if no power state change.
+ if (mLastPowerStateFromWifi == powerState) return;
+
+ mLastPowerStateFromWifi = powerState;
if (mStats.isOnBattery()) {
final String type = (powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH ||
powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM) ? "active"
@@ -1011,9 +1066,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
@Override
- public void noteNetworkInterfaceType(String iface, int networkType) {
+ public void noteNetworkInterfaceForTransports(final String iface, int[] transportTypes) {
enforceCallingPermission();
- mStats.noteNetworkInterfaceType(iface, networkType);
+ mStats.noteNetworkInterfaceForTransports(iface, transportTypes);
}
@Override
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 88b0c3be5464..b6e632d42d8e 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -110,7 +110,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.os.RuntimeInit;
import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
@@ -349,12 +348,23 @@ public final class ProcessList {
private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
/**
- * Enable memory tag checks in non-system apps. This flag will only have an effect on
- * hardware supporting the ARM Memory Tagging Extension (MTE).
+ * Enable asynchronous (ASYNC) memory tag checking in this process. This
+ * flag will only have an effect on hardware supporting the ARM Memory
+ * Tagging Extension (MTE).
*/
@ChangeId
@Disabled
- private static final long NATIVE_MEMORY_TAGGING = 135772972; // This is a bug id.
+ private static final long NATIVE_MEMTAG_ASYNC = 135772972; // This is a bug id.
+
+ /**
+ * Enable synchronous (SYNC) memory tag checking in this process. This flag
+ * will only have an effect on hardware supporting the ARM Memory Tagging
+ * Extension (MTE). If both NATIVE_MEMTAG_ASYNC and this option is selected,
+ * this option takes preference and MTE is enabled in SYNC mode.
+ */
+ @ChangeId
+ @Disabled
+ private static final long NATIVE_MEMTAG_SYNC = 177438394; // This is a bug id.
/**
* Enable sampled memory bug detection in the app.
@@ -1677,23 +1687,23 @@ public final class ProcessList {
return gidArray;
}
- private boolean shouldEnableMemoryTagging(ProcessRecord app) {
+ // Returns the memory tagging level to be enabled. If memory tagging isn't
+ // requested, returns zero.
+ private int getMemtagLevel(ProcessRecord app) {
// Ensure the hardware + kernel actually supports MTE.
if (!Zygote.nativeSupportsMemoryTagging()) {
- return false;
+ return 0;
}
- // Enable MTE for system apps if supported.
- if ((app.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- return true;
+ if (mPlatformCompat.isChangeEnabled(NATIVE_MEMTAG_SYNC, app.info)) {
+ return Zygote.MEMORY_TAG_LEVEL_SYNC;
}
- // Enable MTE if the compat feature is enabled.
- if (mPlatformCompat.isChangeEnabled(NATIVE_MEMORY_TAGGING, app.info)) {
- return true;
+ if (mPlatformCompat.isChangeEnabled(NATIVE_MEMTAG_ASYNC, app.info)) {
+ return Zygote.MEMORY_TAG_LEVEL_ASYNC;
}
- return false;
+ return 0;
}
private boolean shouldEnableTaggedPointers(ProcessRecord app) {
@@ -1717,8 +1727,9 @@ public final class ProcessList {
private int decideTaggingLevel(ProcessRecord app) {
// Check MTE support first, as it should take precedence over TBI.
- if (shouldEnableMemoryTagging(app)) {
- return Zygote.MEMORY_TAG_LEVEL_ASYNC;
+ int memtagLevel = getMemtagLevel(app);
+ if (memtagLevel != 0) {
+ return memtagLevel;
}
if (shouldEnableTaggedPointers(app)) {
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
new file mode 100644
index 000000000000..508bb01e50a8
--- /dev/null
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2021 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.apphibernation;
+
+import static android.content.Intent.ACTION_PACKAGE_ADDED;
+import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static android.content.Intent.ACTION_USER_ADDED;
+import static android.content.Intent.ACTION_USER_REMOVED;
+import static android.content.Intent.EXTRA_REPLACING;
+import static android.content.pm.PackageManager.MATCH_ALL;
+import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.apphibernation.IAppHibernationService;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.UserInfo;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ServiceManager;
+import android.os.ShellCallback;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.DeviceConfig;
+import android.util.ArrayMap;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.SystemService;
+
+import java.io.FileDescriptor;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * System service that manages app hibernation state, a state apps can enter that means they are
+ * not being actively used and can be optimized for storage. The actual policy for determining
+ * if an app should hibernate is managed by PermissionController code.
+ */
+public final class AppHibernationService extends SystemService {
+ private static final String TAG = "AppHibernationService";
+
+ /**
+ * Lock for accessing any in-memory hibernation state
+ */
+ private final Object mLock = new Object();
+ private final Context mContext;
+ private final IPackageManager mIPackageManager;
+ private final IActivityManager mIActivityManager;
+ private final UserManager mUserManager;
+ @GuardedBy("mLock")
+ private final SparseArray<Map<String, UserPackageState>> mUserStates = new SparseArray<>();
+
+ /**
+ * Initializes the system service.
+ * <p>
+ * Subclasses must define a single argument constructor that accepts the context
+ * and passes it to super.
+ * </p>
+ *
+ * @param context The system server context.
+ */
+ public AppHibernationService(@NonNull Context context) {
+ this(context, IPackageManager.Stub.asInterface(ServiceManager.getService("package")),
+ ActivityManager.getService(),
+ context.getSystemService(UserManager.class));
+ }
+
+ @VisibleForTesting
+ AppHibernationService(@NonNull Context context, IPackageManager packageManager,
+ IActivityManager activityManager, UserManager userManager) {
+ super(context);
+ mContext = context;
+ mIPackageManager = packageManager;
+ mIActivityManager = activityManager;
+ mUserManager = userManager;
+
+ final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(ACTION_USER_ADDED);
+ intentFilter.addAction(ACTION_USER_REMOVED);
+ userAllContext.registerReceiver(mBroadcastReceiver, intentFilter);
+
+ intentFilter = new IntentFilter();
+ intentFilter.addAction(ACTION_PACKAGE_ADDED);
+ intentFilter.addAction(ACTION_PACKAGE_REMOVED);
+ intentFilter.addDataScheme("package");
+ userAllContext.registerReceiver(mBroadcastReceiver, intentFilter);
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.APP_HIBERNATION_SERVICE, mServiceStub);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_BOOT_COMPLETED) {
+ synchronized (mLock) {
+ final List<UserInfo> users = mUserManager.getUsers();
+ // TODO: Pull from persistent disk storage. For now, just make from scratch.
+ for (UserInfo user : users) {
+ addUserPackageStatesL(user.id);
+ }
+ }
+ }
+ }
+
+ /**
+ * Whether a package is hibernating for a given user.
+ *
+ * @param packageName the package to check
+ * @param userId the user to check
+ * @return true if package is hibernating for the user
+ */
+ public boolean isHibernating(String packageName, int userId) {
+ userId = handleIncomingUser(userId, "isHibernating");
+ synchronized (mLock) {
+ final Map<String, UserPackageState> packageStates = mUserStates.get(userId);
+ if (packageStates == null) {
+ throw new IllegalArgumentException("No user associated with user id " + userId);
+ }
+ final UserPackageState pkgState = packageStates.get(packageName);
+ if (pkgState == null) {
+ throw new IllegalArgumentException(
+ String.format("Package %s is not installed for user %s",
+ packageName, userId));
+ }
+ return pkgState != null ? pkgState.hibernated : null;
+ }
+ }
+
+ /**
+ * Set whether the package is hibernating for the given user.
+ *
+ * @param packageName package to modify state
+ * @param userId user
+ * @param isHibernating new hibernation state
+ */
+ public void setHibernating(String packageName, int userId, boolean isHibernating) {
+ userId = handleIncomingUser(userId, "setHibernating");
+ synchronized (mLock) {
+ if (!mUserStates.contains(userId)) {
+ throw new IllegalArgumentException("No user associated with user id " + userId);
+ }
+ Map<String, UserPackageState> packageStates = mUserStates.get(userId);
+ UserPackageState pkgState = packageStates.get(packageName);
+ if (pkgState == null) {
+ throw new IllegalArgumentException(
+ String.format("Package %s is not installed for user %s",
+ packageName, userId));
+ }
+
+ if (pkgState.hibernated == isHibernating) {
+ return;
+ }
+
+
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ if (isHibernating) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage");
+ mIActivityManager.forceStopPackage(packageName, userId);
+ mIPackageManager.deleteApplicationCacheFilesAsUser(packageName, userId,
+ null /* observer */);
+ } else {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage");
+ mIPackageManager.setPackageStoppedState(packageName, false, userId);
+ }
+ pkgState.hibernated = isHibernating;
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Failed to hibernate due to manager not being available", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ Binder.restoreCallingIdentity(caller);
+ }
+
+ // TODO: Support package level hibernation when package is hibernating for all users
+ }
+ }
+
+ /**
+ * Populates {@link #mUserStates} with the users installed packages. The caller should hold
+ * {@link #mLock}.
+ *
+ * @param userId user id to add installed packages for
+ */
+ private void addUserPackageStatesL(int userId) {
+ Map<String, UserPackageState> packages = new ArrayMap<>();
+ List<PackageInfo> packageList;
+ try {
+ packageList = mIPackageManager.getInstalledPackages(MATCH_ALL, userId).getList();
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Package manager not available.", e);
+ }
+
+ for (PackageInfo pkg : packageList) {
+ packages.put(pkg.packageName, new UserPackageState());
+ }
+ mUserStates.put(userId, packages);
+ }
+
+ private void onUserAdded(int userId) {
+ synchronized (mLock) {
+ addUserPackageStatesL(userId);
+ }
+ }
+
+ private void onUserRemoved(int userId) {
+ synchronized (mLock) {
+ mUserStates.remove(userId);
+ }
+ }
+
+ private void onPackageAdded(@NonNull String packageName, int userId) {
+ synchronized (mLock) {
+ mUserStates.get(userId).put(packageName, new UserPackageState());
+ }
+ }
+
+ private void onPackageRemoved(@NonNull String packageName, int userId) {
+ synchronized (mLock) {
+ mUserStates.get(userId).remove(packageName);
+ }
+ }
+
+ /**
+ * Private helper method to get the real user id and enforce permission checks.
+ *
+ * @param userId user id to handle
+ * @param name name to use for exceptions
+ * @return real user id
+ */
+ private int handleIncomingUser(int userId, @NonNull String name) {
+ int callingUid = Binder.getCallingUid();
+ try {
+ return mIActivityManager.handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
+ false /* allowAll */, true /* requireFull */, name, null);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ private final AppHibernationServiceStub mServiceStub = new AppHibernationServiceStub(this);
+
+ static final class AppHibernationServiceStub extends IAppHibernationService.Stub {
+ final AppHibernationService mService;
+
+ AppHibernationServiceStub(AppHibernationService service) {
+ mService = service;
+ }
+
+ @Override
+ public boolean isHibernating(String packageName, int userId) {
+ return mService.isHibernating(packageName, userId);
+ }
+
+ @Override
+ public void setHibernating(String packageName, int userId, boolean isHibernating) {
+ mService.setHibernating(packageName, userId, isHibernating);
+ }
+
+ @Override
+ public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
+ @Nullable FileDescriptor err, @NonNull String[] args,
+ @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver) {
+ new AppHibernationShellCommand(mService).exec(this, in, out, err, args, callback,
+ resultReceiver);
+ }
+ }
+
+ // Broadcast receiver for user and package add/removal events
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (userId == UserHandle.USER_NULL) {
+ return;
+ }
+
+ final String action = intent.getAction();
+ if (ACTION_USER_ADDED.equals(action)) {
+ onUserAdded(userId);
+ }
+ if (ACTION_USER_REMOVED.equals(action)) {
+ onUserRemoved(userId);
+ }
+ if (ACTION_PACKAGE_ADDED.equals(action) || ACTION_PACKAGE_REMOVED.equals(action)) {
+ final String packageName = intent.getData().getSchemeSpecificPart();
+ if (intent.getBooleanExtra(EXTRA_REPLACING, false)) {
+ // Package removal/add is part of an update, so no need to modify package state.
+ return;
+ }
+
+ if (ACTION_PACKAGE_ADDED.equals(action)) {
+ onPackageAdded(packageName, userId);
+ } else if (ACTION_PACKAGE_REMOVED.equals(action)) {
+ onPackageRemoved(packageName, userId);
+ }
+ }
+ }
+ };
+
+ /**
+ * Whether app hibernation is enabled on this device.
+ *
+ * @return true if enabled, false otherwise
+ */
+ public static boolean isAppHibernationEnabled() {
+ return DeviceConfig.getBoolean(
+ NAMESPACE_APP_HIBERNATION,
+ AppHibernationConstants.KEY_APP_HIBERNATION_ENABLED,
+ false /* defaultValue */);
+ }
+
+ /**
+ * Data class that contains hibernation state info of a package for a user.
+ */
+ private static final class UserPackageState {
+ public boolean hibernated;
+ // TODO: Track whether hibernation is exempted by the user
+ }
+}
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java b/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java
new file mode 100644
index 000000000000..869885e28958
--- /dev/null
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2021 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.apphibernation;
+
+import android.os.ShellCommand;
+import android.os.UserHandle;
+import android.text.TextUtils;
+
+import java.io.PrintWriter;
+
+/**
+ * Shell command implementation for {@link AppHibernationService}.
+ */
+final class AppHibernationShellCommand extends ShellCommand {
+ private static final String USER_OPT = "--user";
+ private static final int SUCCESS = 0;
+ private static final int ERROR = -1;
+ private final AppHibernationService mService;
+
+ AppHibernationShellCommand(AppHibernationService service) {
+ mService = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ switch (cmd) {
+ case "set-state":
+ return runSetState();
+ case "get-state":
+ return runGetState();
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ }
+
+ private int runSetState() {
+ int userId = parseUserOption();
+
+ String pkg = getNextArgRequired();
+ if (pkg == null) {
+ getErrPrintWriter().println("Error: no package specified");
+ return ERROR;
+ }
+
+ String newStateRaw = getNextArgRequired();
+ if (newStateRaw == null) {
+ getErrPrintWriter().println("Error: No state to set specified");
+ return ERROR;
+ }
+ boolean newState = Boolean.parseBoolean(newStateRaw);
+
+ mService.setHibernating(pkg, userId, newState);
+ return SUCCESS;
+ }
+
+ private int runGetState() {
+ int userId = parseUserOption();
+
+ String pkg = getNextArgRequired();
+ if (pkg == null) {
+ getErrPrintWriter().println("Error: No package specified");
+ return ERROR;
+ }
+ boolean isHibernating = mService.isHibernating(pkg, userId);
+ final PrintWriter pw = getOutPrintWriter();
+ pw.println(isHibernating);
+ return SUCCESS;
+ }
+
+ private int parseUserOption() {
+ String option = getNextOption();
+ if (TextUtils.equals(option, USER_OPT)) {
+ return UserHandle.parseUserArg(getNextArgRequired());
+ }
+ return UserHandle.USER_CURRENT;
+ }
+
+ @Override
+ public void onHelp() {
+ final PrintWriter pw = getOutPrintWriter();
+ pw.println("App hibernation (app_hibernation) commands: ");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println("");
+ pw.println(" set-state [--user USER_ID] PACKAGE true|false");
+ pw.println(" Sets the hibernation state of the package to value specified");
+ pw.println("");
+ pw.println(" get-state [--user USER_ID] PACKAGE");
+ pw.println(" Gets the hibernation state of the package");
+ pw.println("");
+ }
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 024dca7e23c6..4c69704df0c9 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -32,6 +32,7 @@ import static com.android.server.audio.AudioEventLogger.Event.ALOGW;
import android.Manifest;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -166,6 +167,7 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
@@ -173,6 +175,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.BooleanSupplier;
import java.util.stream.Collectors;
/**
@@ -563,6 +566,117 @@ public class AudioService extends IAudioService.Stub
private boolean mDockAudioMediaEnabled = true;
+ /**
+ * RestorableParameters is a thread-safe class used to store a
+ * first-in first-out history of parameters for replay / restoration.
+ *
+ * The idealized implementation of restoration would have a list of setting methods and
+ * values to be called for restoration. Explicitly managing such setters and
+ * values would be tedious - a simpler method is to store the values and the
+ * method implicitly by lambda capture (the values must be immutable or synchronization
+ * needs to be taken).
+ *
+ * We provide queueRestoreWithRemovalIfTrue() to allow
+ * the caller to provide a BooleanSupplier lambda, which conveniently packages
+ * the setter and its parameters needed for restoration. If during restoration,
+ * the BooleanSupplier returns true, it is removed from the mMap.
+ *
+ * We provide a setParameters() method as an example helper method.
+ */
+ private static class RestorableParameters {
+ /**
+ * Sets a parameter and queues for restoration if successful.
+ *
+ * @param id a string handle associated with this parameter.
+ * @param parameter the actual parameter string.
+ * @return the result of AudioSystem.setParameters
+ */
+ public int setParameters(@NonNull String id, @NonNull String parameter) {
+ Objects.requireNonNull(id, "id must not be null");
+ Objects.requireNonNull(parameter, "parameter must not be null");
+ synchronized (mMap) {
+ final int status = AudioSystem.setParameters(parameter);
+ if (status == AudioSystem.AUDIO_STATUS_OK) { // Java uses recursive mutexes.
+ queueRestoreWithRemovalIfTrue(id, () -> { // remove me if set fails.
+ return AudioSystem.setParameters(parameter) != AudioSystem.AUDIO_STATUS_OK;
+ });
+ }
+ // Implementation detail: We do not mMap.remove(id); on failure.
+ return status;
+ }
+ }
+
+ /**
+ * Queues a restore method which is executed on restoreAll().
+ *
+ * If the supplier null, the id is removed from the restore map.
+ *
+ * Note: When the BooleanSupplier restore method is executed
+ * during restoreAll, if it returns true, it is removed from the
+ * restore map.
+ *
+ * @param id a unique tag associated with the restore method.
+ * @param supplier is a BooleanSupplier lambda.
+ */
+ public void queueRestoreWithRemovalIfTrue(
+ @NonNull String id, @Nullable BooleanSupplier supplier) {
+ Objects.requireNonNull(id, "id must not be null");
+ synchronized (mMap) {
+ if (supplier != null) {
+ mMap.put(id, supplier);
+ } else {
+ mMap.remove(id);
+ }
+ }
+ }
+
+ /**
+ * Restore all parameters
+ *
+ * During restoration after audioserver death, any BooleanSupplier that returns
+ * true will be removed from mMap.
+ */
+ public void restoreAll() {
+ synchronized (mMap) {
+ // Note: removing from values() also removes from the backing map.
+ // TODO: Consider catching exceptions?
+ mMap.values().removeIf(v -> {
+ return v.getAsBoolean();
+ });
+ }
+ }
+
+ /**
+ * mMap is a LinkedHashMap<Key, Value> of parameters restored by restore().
+ * The Key is a unique id tag for identification.
+ * The Value is a lambda expression which returns true if the entry is to
+ * be removed.
+ *
+ * 1) For memory limitation purposes, mMap keeps the latest MAX_ENTRIES
+ * accessed in the map.
+ * 2) Parameters are restored in order of queuing, first in first out,
+ * from earliest to latest.
+ */
+ @GuardedBy("mMap")
+ private Map</* @NonNull */ String, /* @NonNull */ BooleanSupplier> mMap =
+ new LinkedHashMap<>() {
+ // TODO: do we need this memory limitation?
+ private static final int MAX_ENTRIES = 1000; // limit our memory for now.
+ @Override
+ protected boolean removeEldestEntry(Map.Entry eldest) {
+ if (size() <= MAX_ENTRIES) return false;
+ Log.w(TAG, "Parameter map exceeds "
+ + MAX_ENTRIES + " removing " + eldest.getKey()); // don't silently remove.
+ return true;
+ }
+ };
+ }
+
+ // We currently have one instance for mRestorableParameters used for
+ // setAdditionalOutputDeviceDelay(). Other methods requiring restoration could share this
+ // or use their own instance.
+ private RestorableParameters mRestorableParameters = new RestorableParameters();
+
private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
// Used when safe volume warning message display is requested by setStreamVolume(). In this
@@ -1095,6 +1209,9 @@ public class AudioService extends IAudioService.Stub
RotationHelper.updateOrientation();
}
+ // Restore setParameters and other queued setters.
+ mRestorableParameters.restoreAll();
+
synchronized (mSettingsLock) {
final int forDock = mDockAudioMediaEnabled ?
AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE;
@@ -9303,6 +9420,95 @@ public class AudioService extends IAudioService.Stub
}
}
+ /**
+ * @hide
+ * Sets an additional audio output device delay in milliseconds.
+ *
+ * The additional output delay is a request to the output device to
+ * delay audio presentation (generally with respect to video presentation for better
+ * synchronization).
+ * It may not be supported by all output devices,
+ * and typically increases the audio latency by the amount of additional
+ * audio delay requested.
+ *
+ * If additional audio delay is supported by an audio output device,
+ * it is expected to be supported for all output streams (and configurations)
+ * opened on that device.
+ *
+ * @param deviceType
+ * @param address
+ * @param delayMillis delay in milliseconds desired. This should be in range of {@code 0}
+ * to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}.
+ * @return true if successful, false if the device does not support output device delay
+ * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}.
+ */
+ @Override
+ //@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public boolean setAdditionalOutputDeviceDelay(
+ @NonNull AudioDeviceAttributes device, @IntRange(from = 0) long delayMillis) {
+ Objects.requireNonNull(device, "device must not be null");
+ enforceModifyAudioRoutingPermission();
+ final String getterKey = "additional_output_device_delay="
+ + AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType())
+ + "," + device.getAddress(); // "getter" key as an id.
+ final String setterKey = getterKey + "," + delayMillis; // append the delay for setter
+ return mRestorableParameters.setParameters(getterKey, setterKey)
+ == AudioSystem.AUDIO_STATUS_OK;
+ }
+
+ /**
+ * @hide
+ * Returns the current additional audio output device delay in milliseconds.
+ *
+ * @param deviceType
+ * @param address
+ * @return the additional output device delay. This is a non-negative number.
+ * {@code 0} is returned if unsupported.
+ */
+ @Override
+ @IntRange(from = 0)
+ public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceAttributes device) {
+ Objects.requireNonNull(device, "device must not be null");
+ final String key = "additional_output_device_delay";
+ final String reply = AudioSystem.getParameters(
+ key + "=" + AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType())
+ + "," + device.getAddress());
+ long delayMillis;
+ try {
+ delayMillis = Long.parseLong(reply.substring(key.length() + 1));
+ } catch (NullPointerException e) {
+ delayMillis = 0;
+ }
+ return delayMillis;
+ }
+
+ /**
+ * @hide
+ * Returns the maximum additional audio output device delay in milliseconds.
+ *
+ * @param deviceType
+ * @param address
+ * @return the maximum output device delay in milliseconds that can be set.
+ * This is a non-negative number
+ * representing the additional audio delay supported for the device.
+ * {@code 0} is returned if unsupported.
+ */
+ @Override
+ @IntRange(from = 0)
+ public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceAttributes device) {
+ Objects.requireNonNull(device, "device must not be null");
+ final String key = "max_additional_output_device_delay";
+ final String reply = AudioSystem.getParameters(
+ key + "=" + AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType())
+ + "," + device.getAddress());
+ long delayMillis;
+ try {
+ delayMillis = Long.parseLong(reply.substring(key.length() + 1));
+ } catch (NullPointerException e) {
+ delayMillis = 0;
+ }
+ return delayMillis;
+ }
//======================
// misc
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index 9ba957ef27ae..e3757dfc6a59 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -23,8 +23,11 @@ import android.content.pm.ApplicationInfo;
import com.android.internal.compat.CompatibilityChangeInfo;
import com.android.server.compat.config.Change;
+import com.android.server.compat.overrides.ChangeOverrides;
+import com.android.server.compat.overrides.OverrideValue;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -253,6 +256,71 @@ public final class CompatChange extends CompatibilityChangeInfo {
return mDeferredOverrides != null && mDeferredOverrides.containsKey(packageName);
}
+ /**
+ * Checks whether a change has any package overrides.
+ * @return true if the change has at least one deferred override
+ */
+ boolean hasAnyPackageOverride() {
+ return mDeferredOverrides != null && !mDeferredOverrides.isEmpty();
+ }
+
+ /**
+ * Checks whether a change has any deferred overrides.
+ * @return true if the change has at least one deferred override
+ */
+ boolean hasAnyDeferredOverride() {
+ return mPackageOverrides != null && !mPackageOverrides.isEmpty();
+ }
+
+ void loadOverrides(ChangeOverrides changeOverrides) {
+ if (mDeferredOverrides == null) {
+ mDeferredOverrides = new HashMap<>();
+ }
+ mDeferredOverrides.clear();
+ for (OverrideValue override : changeOverrides.getDeferred().getOverrideValue()) {
+ mDeferredOverrides.put(override.getPackageName(), override.getEnabled());
+ }
+
+ if (mPackageOverrides == null) {
+ mPackageOverrides = new HashMap<>();
+ }
+ mPackageOverrides.clear();
+ for (OverrideValue override : changeOverrides.getValidated().getOverrideValue()) {
+ mPackageOverrides.put(override.getPackageName(), override.getEnabled());
+ }
+ }
+
+ ChangeOverrides saveOverrides() {
+ if (!hasAnyDeferredOverride() && !hasAnyPackageOverride()) {
+ return null;
+ }
+ ChangeOverrides changeOverrides = new ChangeOverrides();
+ changeOverrides.setChangeId(getId());
+ ChangeOverrides.Deferred deferredOverrides = new ChangeOverrides.Deferred();
+ List<OverrideValue> deferredList = deferredOverrides.getOverrideValue();
+ if (mDeferredOverrides != null) {
+ for (Map.Entry<String, Boolean> entry : mDeferredOverrides.entrySet()) {
+ OverrideValue override = new OverrideValue();
+ override.setPackageName(entry.getKey());
+ override.setEnabled(entry.getValue());
+ deferredList.add(override);
+ }
+ }
+ changeOverrides.setDeferred(deferredOverrides);
+ ChangeOverrides.Validated validatedOverrides = new ChangeOverrides.Validated();
+ List<OverrideValue> validatedList = validatedOverrides.getOverrideValue();
+ if (mPackageOverrides != null) {
+ for (Map.Entry<String, Boolean> entry : mPackageOverrides.entrySet()) {
+ OverrideValue override = new OverrideValue();
+ override.setPackageName(entry.getKey());
+ override.setEnabled(entry.getValue());
+ validatedList.add(override);
+ }
+ }
+ changeOverrides.setValidated(validatedOverrides);
+ return changeOverrides;
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder("ChangeId(")
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 9376e8dc16ea..6b77b9d4ce39 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -21,7 +21,6 @@ import android.compat.Compatibility.ChangeConfig;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.os.Environment;
-import android.os.RemoteException;
import android.text.TextUtils;
import android.util.LongArray;
import android.util.LongSparseArray;
@@ -35,7 +34,10 @@ import com.android.internal.compat.CompatibilityChangeInfo;
import com.android.internal.compat.IOverrideValidator;
import com.android.internal.compat.OverrideAllowedState;
import com.android.server.compat.config.Change;
-import com.android.server.compat.config.XmlParser;
+import com.android.server.compat.config.Config;
+import com.android.server.compat.overrides.ChangeOverrides;
+import com.android.server.compat.overrides.Overrides;
+import com.android.server.compat.overrides.XmlWriter;
import com.android.server.pm.ApexManager;
import org.xmlpull.v1.XmlPullParserException;
@@ -53,7 +55,7 @@ import java.util.Set;
import javax.xml.datatype.DatatypeConfigurationException;
/**
- * This class maintains state relating to platform compatibility changes.
+ * CompatConfig maintains state related to the platform compatibility changes.
*
* <p>It stores the default configuration for each change, and any per-package overrides that have
* been configured.
@@ -61,22 +63,47 @@ import javax.xml.datatype.DatatypeConfigurationException;
final class CompatConfig {
private static final String TAG = "CompatConfig";
+ private static final String APP_COMPAT_DATA_DIR = "/data/misc/appcompat";
+ private static final String OVERRIDES_FILE = "compat_framework_overrides.xml";
@GuardedBy("mChanges")
private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
- private OverrideValidatorImpl mOverrideValidator;
+ private final OverrideValidatorImpl mOverrideValidator;
+ private File mOverridesFile;
@VisibleForTesting
CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) {
mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this);
}
+ static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) {
+ CompatConfig config = new CompatConfig(androidBuildClassifier, context);
+ config.initConfigFromLib(Environment.buildPath(
+ Environment.getRootDirectory(), "etc", "compatconfig"));
+ config.initConfigFromLib(Environment.buildPath(
+ Environment.getRootDirectory(), "system_ext", "etc", "compatconfig"));
+
+ List<ApexManager.ActiveApexInfo> apexes = ApexManager.getInstance().getActiveApexInfos();
+ for (ApexManager.ActiveApexInfo apex : apexes) {
+ config.initConfigFromLib(Environment.buildPath(
+ apex.apexDirectory, "etc", "compatconfig"));
+ }
+ File overridesFile = new File(APP_COMPAT_DATA_DIR, OVERRIDES_FILE);
+ config.initOverrides(overridesFile);
+ config.invalidateCache();
+ return config;
+ }
+
/**
- * Add a change. This is intended to be used by code that reads change config from the
- * filesystem. This should be done at system startup time.
+ * Adds a change.
+ *
+ * <p>This is intended to be used by code that reads change config from the filesystem. This
+ * should be done at system startup time.
+ *
+ * <p>Any change with the same ID will be overwritten.
*
- * @param change The change to add. Any change with the same ID will be overwritten.
+ * @param change the change to add
*/
void addChange(CompatChange change) {
synchronized (mChanges) {
@@ -86,13 +113,15 @@ final class CompatConfig {
}
/**
- * Retrieves the set of disabled changes for a given app. Any change ID not in the returned
- * array is by default enabled for the app.
+ * Retrieves the set of disabled changes for a given app.
*
- * @param app The app in question
- * @return A sorted long array of change IDs. We use a primitive array to minimize memory
- * footprint: Every app process will store this array statically so we aim to reduce
- * overhead as much as possible.
+ * <p>Any change ID not in the returned array is by default enabled for the app.
+ *
+ * <p>We use a primitive array to minimize memory footprint: every app process will store this
+ * array statically so we aim to reduce overhead as much as possible.
+ *
+ * @param app the app in question
+ * @return a sorted long array of change IDs
*/
long[] getDisabledChanges(ApplicationInfo app) {
LongArray disabled = new LongArray();
@@ -110,10 +139,10 @@ final class CompatConfig {
}
/**
- * Look up a change ID by name.
+ * Looks up a change ID by name.
*
- * @param name Name of the change to look up
- * @return The change ID, or {@code -1} if no change with that name exists.
+ * @param name name of the change to look up
+ * @return the change ID, or {@code -1} if no change with that name exists
*/
long lookupChangeId(String name) {
synchronized (mChanges) {
@@ -127,10 +156,10 @@ final class CompatConfig {
}
/**
- * Find if a given change is enabled for a given application.
+ * Checks if a given change is enabled for a given application.
*
- * @param changeId The ID of the change in question
- * @param app App to check for
+ * @param changeId the ID of the change in question
+ * @param app app to check for
* @return {@code true} if the change is enabled for this app. Also returns {@code true} if the
* change ID is not known, as unknown changes are enabled by default.
*/
@@ -146,10 +175,10 @@ final class CompatConfig {
}
/**
- * Find if a given change will be enabled for a given package name, prior to installation.
+ * Checks if a given change will be enabled for a given package name after the installation.
*
- * @param changeId The ID of the change in question
- * @param packageName Package name to check for
+ * @param changeId the ID of the change in question
+ * @param packageName package name to check for
* @return {@code true} if the change would be enabled for this package name. Also returns
* {@code true} if the change ID is not known, as unknown changes are enabled by default.
*/
@@ -165,22 +194,33 @@ final class CompatConfig {
}
/**
- * Overrides the enabled state for a given change and app. This method is intended to be used
- * *only* for debugging purposes, ultimately invoked either by an adb command, or from some
- * developer settings UI.
+ * Overrides the enabled state for a given change and app.
*
- * <p>Note, package overrides are not persistent and will be lost on system or runtime restart.
+ * <p>This method is intended to be used *only* for debugging purposes, ultimately invoked
+ * either by an adb command, or from some developer settings UI.
*
- * @param changeId The ID of the change to be overridden. Note, this call will succeed even
- * if
- * this change is not known; it will only have any effect if any code in the
- * platform is gated on the ID given.
- * @param packageName The app package name to override the change for.
- * @param enabled If the change should be enabled or disabled.
- * @return {@code true} if the change existed before adding the override.
+ * <p>Note: package overrides are not persistent and will be lost on system or runtime restart.
+ *
+ * @param changeId the ID of the change to be overridden. Note, this call will succeed even
+ * if this change is not known; it will only have any effect if any code in
+ * the platform is gated on the ID given.
+ * @param packageName the app package name to override the change for
+ * @param enabled if the change should be enabled or disabled
+ * @return {@code true} if the change existed before adding the override
+ * @throws IllegalStateException if overriding is not allowed
*/
- boolean addOverride(long changeId, String packageName, boolean enabled)
- throws SecurityException {
+ boolean addOverride(long changeId, String packageName, boolean enabled) {
+ boolean alreadyKnown = addOverrideUnsafe(changeId, packageName, enabled);
+ saveOverrides();
+ invalidateCache();
+ return alreadyKnown;
+ }
+
+ /**
+ * Unsafe version of {@link #addOverride(long, String, boolean)}.
+ * It does not invalidate the cache nor save the overrides.
+ */
+ private boolean addOverrideUnsafe(long changeId, String packageName, boolean enabled) {
boolean alreadyKnown = true;
OverrideAllowedState allowedState =
mOverrideValidator.getOverrideAllowedState(changeId, packageName);
@@ -201,18 +241,13 @@ final class CompatConfig {
break;
default:
throw new IllegalStateException("Should only be able to override changes that "
- + "are allowed or can be deferred.");
+ + "are allowed or can be deferred.");
}
- invalidateCache();
}
return alreadyKnown;
}
- /**
- * Check whether the change is known to the compat config.
- *
- * @return {@code true} if the change is known.
- */
+ /** Checks whether the change is known to the compat config. */
boolean isKnownChangeId(long changeId) {
synchronized (mChanges) {
CompatChange c = mChanges.get(changeId);
@@ -221,16 +256,13 @@ final class CompatConfig {
}
/**
- * Returns the maximum sdk version for which this change can be opted in (or -1 if it is not
- * target sdk gated).
+ * Returns the maximum SDK version for which this change can be opted in (or -1 if it is not
+ * target SDK gated).
*/
int maxTargetSdkForChangeIdOptIn(long changeId) {
synchronized (mChanges) {
CompatChange c = mChanges.get(changeId);
- if (c == null) {
- return -1;
- }
- if (c.getEnableSinceTargetSdk() != -1) {
+ if (c != null && c.getEnableSinceTargetSdk() != -1) {
return c.getEnableSinceTargetSdk() - 1;
}
return -1;
@@ -243,10 +275,7 @@ final class CompatConfig {
boolean isLoggingOnly(long changeId) {
synchronized (mChanges) {
CompatChange c = mChanges.get(changeId);
- if (c == null) {
- return false;
- }
- return c.getLoggingOnly();
+ return c != null && c.getLoggingOnly();
}
}
@@ -256,24 +285,32 @@ final class CompatConfig {
boolean isDisabled(long changeId) {
synchronized (mChanges) {
CompatChange c = mChanges.get(changeId);
- if (c == null) {
- return false;
- }
- return c.getDisabled();
+ return c != null && c.getDisabled();
}
}
/**
- * Removes an override previously added via {@link #addOverride(long, String, boolean)}. This
- * restores the default behaviour for the given change and app, once any app processes have been
- * restarted.
+ * Removes an override previously added via {@link #addOverride(long, String, boolean)}.
+ *
+ * <p>This restores the default behaviour for the given change and app, once any app processes
+ * have been restarted.
*
- * @param changeId The ID of the change that was overridden.
- * @param packageName The app package name that was overridden.
+ * @param changeId the ID of the change that was overridden
+ * @param packageName the app package name that was overridden
* @return {@code true} if an override existed;
*/
- boolean removeOverride(long changeId, String packageName)
- throws SecurityException {
+ boolean removeOverride(long changeId, String packageName) {
+ boolean overrideExists = removeOverrideUnsafe(changeId, packageName);
+ saveOverrides();
+ invalidateCache();
+ return overrideExists;
+ }
+
+ /**
+ * Unsafe version of {@link #removeOverride(long, String)}.
+ * It does not invalidate the cache nor save the overrides.
+ */
+ private boolean removeOverrideUnsafe(long changeId, String packageName) {
boolean overrideExists = false;
synchronized (mChanges) {
CompatChange c = mChanges.get(changeId);
@@ -292,28 +329,27 @@ final class CompatConfig {
}
}
}
- invalidateCache();
return overrideExists;
}
/**
* Overrides the enabled state for a given change and app.
*
- * <p>Note, package overrides are not persistent and will be lost on system or runtime restart.
+ * <p>Note: package overrides are not persistent and will be lost on system or runtime restart.
*
- * @param overrides list of overrides to default changes config.
- * @param packageName app for which the overrides will be applied.
+ * @param overrides list of overrides to default changes config
+ * @param packageName app for which the overrides will be applied
*/
- void addOverrides(CompatibilityChangeConfig overrides, String packageName)
- throws RemoteException, SecurityException {
+ void addOverrides(CompatibilityChangeConfig overrides, String packageName) {
synchronized (mChanges) {
for (Long changeId : overrides.enabledChanges()) {
- addOverride(changeId, packageName, true);
+ addOverrideUnsafe(changeId, packageName, true);
}
for (Long changeId : overrides.disabledChanges()) {
- addOverride(changeId, packageName, false);
+ addOverrideUnsafe(changeId, packageName, false);
}
+ saveOverrides();
invalidateCache();
}
}
@@ -324,21 +360,21 @@ final class CompatConfig {
*
* <p>This restores the default behaviour for the given app.
*
- * @param packageName The package for which the overrides should be purged.
+ * @param packageName the package for which the overrides should be purged
*/
- void removePackageOverrides(String packageName) throws SecurityException {
+ void removePackageOverrides(String packageName) {
synchronized (mChanges) {
for (int i = 0; i < mChanges.size(); ++i) {
CompatChange change = mChanges.valueAt(i);
- removeOverride(change.getId(), packageName);
+ removeOverrideUnsafe(change.getId(), packageName);
}
+ saveOverrides();
invalidateCache();
}
}
private long[] getAllowedChangesSinceTargetSdkForPackage(String packageName,
- int targetSdkVersion)
- throws RemoteException {
+ int targetSdkVersion) {
LongArray allowed = new LongArray();
synchronized (mChanges) {
for (int i = 0; i < mChanges.size(); ++i) {
@@ -348,7 +384,7 @@ final class CompatConfig {
}
OverrideAllowedState allowedState =
mOverrideValidator.getOverrideAllowedState(change.getId(),
- packageName);
+ packageName);
if (allowedState.state == OverrideAllowedState.ALLOWED) {
allowed.add(change.getId());
}
@@ -361,30 +397,31 @@ final class CompatConfig {
* Enables all changes with enabledSinceTargetSdk == {@param targetSdkVersion} for
* {@param packageName}.
*
- * @return The number of changes that were toggled.
+ * @return the number of changes that were toggled
*/
- int enableTargetSdkChangesForPackage(String packageName, int targetSdkVersion)
- throws RemoteException {
+ int enableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) {
long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion);
for (long changeId : changes) {
- addOverride(changeId, packageName, true);
+ addOverrideUnsafe(changeId, packageName, true);
}
+ saveOverrides();
+ invalidateCache();
return changes.length;
}
-
/**
* Disables all changes with enabledSinceTargetSdk == {@param targetSdkVersion} for
* {@param packageName}.
*
- * @return The number of changes that were toggled.
+ * @return the number of changes that were toggled
*/
- int disableTargetSdkChangesForPackage(String packageName, int targetSdkVersion)
- throws RemoteException {
+ int disableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) {
long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion);
for (long changeId : changes) {
- addOverride(changeId, packageName, false);
+ addOverrideUnsafe(changeId, packageName, false);
}
+ saveOverrides();
+ invalidateCache();
return changes.length;
}
@@ -425,7 +462,7 @@ final class CompatConfig {
/**
* Dumps the current list of compatibility config information.
*
- * @param pw The {@link PrintWriter} instance to which the information will be dumped.
+ * @param pw {@link PrintWriter} instance to which the information will be dumped
*/
void dumpConfig(PrintWriter pw) {
synchronized (mChanges) {
@@ -441,13 +478,10 @@ final class CompatConfig {
}
/**
- * Get the config for a given app.
+ * Returns config for a given app.
*
- * @param applicationInfo the {@link ApplicationInfo} for which the info should be dumped.
- * @return A {@link CompatibilityChangeConfig} which contains the compat config info for the
- * given app.
+ * @param applicationInfo the {@link ApplicationInfo} for which the info should be dumped
*/
-
CompatibilityChangeConfig getAppConfig(ApplicationInfo applicationInfo) {
Set<Long> enabled = new HashSet<>();
Set<Long> disabled = new HashSet<>();
@@ -467,7 +501,7 @@ final class CompatConfig {
/**
* Dumps all the compatibility change information.
*
- * @return An array of {@link CompatibilityChangeInfo} with the current changes.
+ * @return an array of {@link CompatibilityChangeInfo} with the current changes
*/
CompatibilityChangeInfo[] dumpChanges() {
synchronized (mChanges) {
@@ -480,22 +514,6 @@ final class CompatConfig {
}
}
- static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) {
- CompatConfig config = new CompatConfig(androidBuildClassifier, context);
- config.initConfigFromLib(Environment.buildPath(
- Environment.getRootDirectory(), "etc", "compatconfig"));
- config.initConfigFromLib(Environment.buildPath(
- Environment.getRootDirectory(), "system_ext", "etc", "compatconfig"));
-
- List<ApexManager.ActiveApexInfo> apexes = ApexManager.getInstance().getActiveApexInfos();
- for (ApexManager.ActiveApexInfo apex : apexes) {
- config.initConfigFromLib(Environment.buildPath(
- apex.apexDirectory, "etc", "compatconfig"));
- }
- config.invalidateCache();
- return config;
- }
-
void initConfigFromLib(File libraryDir) {
if (!libraryDir.exists() || !libraryDir.isDirectory()) {
Slog.d(TAG, "No directory " + libraryDir + ", skipping");
@@ -510,7 +528,8 @@ final class CompatConfig {
private void readConfig(File configFile) {
try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) {
- for (Change change : XmlParser.read(in).getCompatChange()) {
+ Config config = com.android.server.compat.config.XmlParser.read(in);
+ for (Change change : config.getCompatChange()) {
Slog.d(TAG, "Adding: " + change.toString());
addChange(new CompatChange(change));
}
@@ -519,6 +538,65 @@ final class CompatConfig {
}
}
+ void initOverrides(File overridesFile) {
+ if (!overridesFile.exists()) {
+ mOverridesFile = overridesFile;
+ // There have not been any overrides added yet.
+ return;
+ }
+
+ try (InputStream in = new BufferedInputStream(new FileInputStream(overridesFile))) {
+ Overrides overrides = com.android.server.compat.overrides.XmlParser.read(in);
+ for (ChangeOverrides changeOverrides : overrides.getChangeOverrides()) {
+ long changeId = changeOverrides.getChangeId();
+ CompatChange compatChange = mChanges.get(changeId);
+ if (compatChange == null) {
+ Slog.w(TAG, "Change ID " + changeId + " not found. "
+ + "Skipping overrides for it.");
+ continue;
+ }
+ compatChange.loadOverrides(changeOverrides);
+ }
+ } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
+ Slog.w(TAG, "Error processing " + overridesFile + " " + e.toString());
+ return;
+ }
+ mOverridesFile = overridesFile;
+ }
+
+ /**
+ * Persist compat framework overrides to /data/misc/appcompat/compat_framework_overrides.xml
+ */
+ void saveOverrides() {
+ if (mOverridesFile == null) {
+ return;
+ }
+ synchronized (mChanges) {
+ // Create the file if it doesn't already exist
+ try {
+ mOverridesFile.createNewFile();
+ } catch (IOException e) {
+ Slog.e(TAG, "Could not create override config file: " + e.toString());
+ return;
+ }
+ try (PrintWriter out = new PrintWriter(mOverridesFile)) {
+ XmlWriter writer = new XmlWriter(out);
+ Overrides overrides = new Overrides();
+ List<ChangeOverrides> changeOverridesList = overrides.getChangeOverrides();
+ for (int idx = 0; idx < mChanges.size(); ++idx) {
+ CompatChange c = mChanges.valueAt(idx);
+ ChangeOverrides changeOverrides = c.saveOverrides();
+ if (changeOverrides != null) {
+ changeOverridesList.add(changeOverrides);
+ }
+ }
+ XmlWriter.write(writer, overrides);
+ } catch (IOException e) {
+ Slog.e(TAG, e.toString());
+ }
+ }
+ }
+
IOverrideValidator getOverrideValidator() {
return mOverrideValidator;
}
@@ -526,6 +604,7 @@ final class CompatConfig {
private void invalidateCache() {
ChangeIdStateCache.invalidate();
}
+
/**
* Rechecks all the existing overrides for a package.
*/
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 1ea468c341d2..6b2a1c950e38 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -63,45 +63,43 @@ public class PlatformCompat extends IPlatformCompat.Stub {
private final ChangeReporter mChangeReporter;
private final CompatConfig mCompatConfig;
- private static int sMinTargetSdk = Build.VERSION_CODES.Q;
-
public PlatformCompat(Context context) {
mContext = context;
- mChangeReporter = new ChangeReporter(
- ChangeReporter.SOURCE_SYSTEM_SERVER);
+ mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER);
mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext);
}
@VisibleForTesting
PlatformCompat(Context context, CompatConfig compatConfig) {
mContext = context;
- mChangeReporter = new ChangeReporter(
- ChangeReporter.SOURCE_SYSTEM_SERVER);
+ mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER);
mCompatConfig = compatConfig;
+
registerPackageReceiver(context);
}
@Override
public void reportChange(long changeId, ApplicationInfo appInfo) {
- checkCompatChangeLogPermission();
- reportChange(changeId, appInfo.uid,
- ChangeReporter.STATE_LOGGED);
+ reportChangeByUid(changeId, appInfo.uid);
}
@Override
- public void reportChangeByPackageName(long changeId, String packageName, int userId) {
- checkCompatChangeLogPermission();
+ public void reportChangeByPackageName(long changeId, String packageName,
+ @UserIdInt int userId) {
ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
- if (appInfo == null) {
- return;
+ if (appInfo != null) {
+ reportChangeByUid(changeId, appInfo.uid);
}
- reportChange(changeId, appInfo);
}
@Override
public void reportChangeByUid(long changeId, int uid) {
checkCompatChangeLogPermission();
- reportChange(changeId, uid, ChangeReporter.STATE_LOGGED);
+ reportChangeInternal(changeId, uid, ChangeReporter.STATE_LOGGED);
+ }
+
+ private void reportChangeInternal(long changeId, int uid, int state) {
+ mChangeReporter.reportChange(uid, changeId, state);
}
@Override
@@ -110,28 +108,6 @@ public class PlatformCompat extends IPlatformCompat.Stub {
return isChangeEnabledInternal(changeId, appInfo);
}
- /**
- * Internal version of the above method, without logging. Does not perform costly permission
- * check.
- * TODO(b/167551701): Remove this method and add 'loggability' as a changeid property.
- */
- public boolean isChangeEnabledInternalNoLogging(long changeId, ApplicationInfo appInfo) {
- return mCompatConfig.isChangeEnabled(changeId, appInfo);
- }
-
- /**
- * Internal version of {@link #isChangeEnabled(long, ApplicationInfo)}. Does not perform costly
- * permission check.
- */
- public boolean isChangeEnabledInternal(long changeId, ApplicationInfo appInfo) {
- boolean enabled = isChangeEnabledInternalNoLogging(changeId, appInfo);
- if (appInfo != null) {
- reportChange(changeId, appInfo.uid,
- enabled ? ChangeReporter.STATE_ENABLED : ChangeReporter.STATE_DISABLED);
- }
- return enabled;
- }
-
@Override
public boolean isChangeEnabledByPackageName(long changeId, String packageName,
@UserIdInt int userId) {
@@ -140,7 +116,7 @@ public class PlatformCompat extends IPlatformCompat.Stub {
if (appInfo == null) {
return mCompatConfig.willChangeBeEnabled(changeId, packageName);
}
- return isChangeEnabled(changeId, appInfo);
+ return isChangeEnabledInternal(changeId, appInfo);
}
@Override
@@ -152,81 +128,82 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
boolean enabled = true;
for (String packageName : packages) {
- enabled = enabled && isChangeEnabledByPackageName(changeId, packageName,
+ enabled &= isChangeEnabledByPackageName(changeId, packageName,
UserHandle.getUserId(uid));
}
return enabled;
}
/**
- * Register a listener for change state overrides. Only one listener per change is allowed.
+ * Internal version of the above method, without logging.
*
- * <p>{@code listener.onCompatChange(String)} method is guaranteed to be called with
- * packageName before the app is killed upon an override change. The state of a change is not
- * guaranteed to change when {@code listener.onCompatChange(String)} is called.
+ * <p>Does not perform costly permission check.
+ * TODO(b/167551701): Remove this method and add 'loggability' as a changeid property.
+ */
+ public boolean isChangeEnabledInternalNoLogging(long changeId, ApplicationInfo appInfo) {
+ return mCompatConfig.isChangeEnabled(changeId, appInfo);
+ }
+
+ /**
+ * Internal version of {@link #isChangeEnabled(long, ApplicationInfo)}.
*
- * @param changeId to get updates for
- * @param listener the listener that will be called upon a potential change for package.
- * @throws IllegalStateException if a listener was already registered for changeId
- * @returns {@code true} if a change with changeId was already known, or (@code false}
- * otherwise.
+ * <p>Does not perform costly permission check.
*/
- public boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
- return mCompatConfig.registerListener(changeId, listener);
+ public boolean isChangeEnabledInternal(long changeId, ApplicationInfo appInfo) {
+ boolean enabled = isChangeEnabledInternalNoLogging(changeId, appInfo);
+ if (appInfo != null) {
+ reportChangeInternal(changeId, appInfo.uid,
+ enabled ? ChangeReporter.STATE_ENABLED : ChangeReporter.STATE_DISABLED);
+ }
+ return enabled;
}
@Override
- public void setOverrides(CompatibilityChangeConfig overrides, String packageName)
- throws RemoteException, SecurityException {
+ public void setOverrides(CompatibilityChangeConfig overrides, String packageName) {
checkCompatChangeOverridePermission();
mCompatConfig.addOverrides(overrides, packageName);
killPackage(packageName);
}
@Override
- public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName)
- throws RemoteException, SecurityException {
+ public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) {
checkCompatChangeOverridePermission();
mCompatConfig.addOverrides(overrides, packageName);
}
@Override
- public int enableTargetSdkChanges(String packageName, int targetSdkVersion)
- throws RemoteException, SecurityException {
+ public int enableTargetSdkChanges(String packageName, int targetSdkVersion) {
checkCompatChangeOverridePermission();
- int numChanges = mCompatConfig.enableTargetSdkChangesForPackage(packageName,
- targetSdkVersion);
+ int numChanges =
+ mCompatConfig.enableTargetSdkChangesForPackage(packageName, targetSdkVersion);
killPackage(packageName);
return numChanges;
}
@Override
- public int disableTargetSdkChanges(String packageName, int targetSdkVersion)
- throws RemoteException, SecurityException {
+ public int disableTargetSdkChanges(String packageName, int targetSdkVersion) {
checkCompatChangeOverridePermission();
- int numChanges = mCompatConfig.disableTargetSdkChangesForPackage(packageName,
- targetSdkVersion);
+ int numChanges =
+ mCompatConfig.disableTargetSdkChangesForPackage(packageName, targetSdkVersion);
killPackage(packageName);
return numChanges;
}
@Override
- public void clearOverrides(String packageName) throws RemoteException, SecurityException {
+ public void clearOverrides(String packageName) {
checkCompatChangeOverridePermission();
mCompatConfig.removePackageOverrides(packageName);
killPackage(packageName);
}
@Override
- public void clearOverridesForTest(String packageName)
- throws RemoteException, SecurityException {
+ public void clearOverridesForTest(String packageName) {
checkCompatChangeOverridePermission();
mCompatConfig.removePackageOverrides(packageName);
}
@Override
- public boolean clearOverride(long changeId, String packageName)
- throws RemoteException, SecurityException {
+ public boolean clearOverride(long changeId, String packageName) {
checkCompatChangeOverridePermission();
boolean existed = mCompatConfig.removeOverride(changeId, packageName);
killPackage(packageName);
@@ -234,6 +211,12 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
+ public void clearOverrideForTest(long changeId, String packageName) {
+ checkCompatChangeOverridePermission();
+ mCompatConfig.removeOverride(changeId, packageName);
+ }
+
+ @Override
public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) {
checkCompatChangeReadAndLogPermission();
return mCompatConfig.getAppConfig(appInfo);
@@ -247,18 +230,13 @@ public class PlatformCompat extends IPlatformCompat.Stub {
@Override
public CompatibilityChangeInfo[] listUIChanges() {
- return Arrays.stream(listAllChanges()).filter(
- x -> isShownInUI(x)).toArray(CompatibilityChangeInfo[]::new);
+ return Arrays.stream(listAllChanges()).filter(this::isShownInUI).toArray(
+ CompatibilityChangeInfo[]::new);
}
- /**
- * Check whether the change is known to the compat config.
- *
- * @return {@code true} if the change is known.
- */
+ /** Checks whether the change is known to the compat config. */
public boolean isKnownChangeId(long changeId) {
return mCompatConfig.isKnownChangeId(changeId);
-
}
/**
@@ -286,7 +264,9 @@ public class PlatformCompat extends IPlatformCompat.Stub {
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) {
+ return;
+ }
checkCompatChangeReadAndLogPermission();
mCompatConfig.dumpConfig(pw);
}
@@ -298,7 +278,8 @@ public class PlatformCompat extends IPlatformCompat.Stub {
/**
* Clears information stored about events reported on behalf of an app.
- * To be called once upon app start or end. A second call would be a no-op.
+ *
+ * <p>To be called once upon app start or end. A second call would be a no-op.
*
* @param appInfo the app to reset
*/
@@ -311,13 +292,9 @@ public class PlatformCompat extends IPlatformCompat.Stub {
packageName, 0, userId, userId);
}
- private void reportChange(long changeId, int uid, int state) {
- mChangeReporter.reportChange(uid, changeId, state);
- }
-
private void killPackage(String packageName) {
int uid = LocalServices.getService(PackageManagerInternal.class).getPackageUid(packageName,
- 0, UserHandle.myUserId());
+ 0, UserHandle.myUserId());
if (uid < 0) {
Slog.w(TAG, "Didn't find package " + packageName + " on device.");
@@ -325,21 +302,18 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
Slog.d(TAG, "Killing package " + packageName + " (UID " + uid + ").");
- killUid(UserHandle.getAppId(uid),
- UserHandle.USER_ALL, "PlatformCompat overrides");
+ killUid(UserHandle.getAppId(uid));
}
- private void killUid(int appId, int userId, String reason) {
+ private void killUid(int appId) {
final long identity = Binder.clearCallingIdentity();
try {
IActivityManager am = ActivityManager.getService();
if (am != null) {
- try {
- am.killUid(appId, userId, reason);
- } catch (RemoteException e) {
- /* ignore - same process */
- }
+ am.killUid(appId, UserHandle.USER_ALL, "PlatformCompat overrides");
}
+ } catch (RemoteException e) {
+ /* ignore - same process */
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -350,13 +324,12 @@ public class PlatformCompat extends IPlatformCompat.Stub {
if (Binder.getCallingUid() == SYSTEM_UID) {
return;
}
- if (mContext.checkCallingOrSelfPermission(LOG_COMPAT_CHANGE)
- != PERMISSION_GRANTED) {
+ if (mContext.checkCallingOrSelfPermission(LOG_COMPAT_CHANGE) != PERMISSION_GRANTED) {
throw new SecurityException("Cannot log compat change usage");
}
}
- private void checkCompatChangeReadPermission() throws SecurityException {
+ private void checkCompatChangeReadPermission() {
// Don't check for permissions within the system process
if (Binder.getCallingUid() == SYSTEM_UID) {
return;
@@ -367,7 +340,7 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
}
- private void checkCompatChangeOverridePermission() throws SecurityException {
+ private void checkCompatChangeOverridePermission() {
// Don't check for permissions within the system process
if (Binder.getCallingUid() == SYSTEM_UID) {
return;
@@ -378,7 +351,7 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
}
- private void checkCompatChangeReadAndLogPermission() throws SecurityException {
+ private void checkCompatChangeReadAndLogPermission() {
checkCompatChangeReadPermission();
checkCompatChangeLogPermission();
}
@@ -391,16 +364,34 @@ public class PlatformCompat extends IPlatformCompat.Stub {
return false;
}
if (change.getEnableSinceTargetSdk() > 0) {
- if (change.getEnableSinceTargetSdk() < sMinTargetSdk) {
- return false;
- }
+ return change.getEnableSinceTargetSdk() >= Build.VERSION_CODES.Q;
}
return true;
}
/**
+ * Registers a listener for change state overrides.
+ *
+ * <p>Only one listener per change is allowed.
+ *
+ * <p>{@code listener.onCompatChange(String)} method is guaranteed to be called with
+ * packageName before the app is killed upon an override change. The state of a change is not
+ * guaranteed to change when {@code listener.onCompatChange(String)} is called.
+ *
+ * @param changeId to get updates for
+ * @param listener the listener that will be called upon a potential change for package
+ * @return {@code true} if a change with changeId was already known, or (@code false}
+ * otherwise
+ * @throws IllegalStateException if a listener was already registered for changeId
+ */
+ public boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
+ return mCompatConfig.registerListener(changeId, listener);
+ }
+
+ /**
* Registers a broadcast receiver that listens for package install, replace or remove.
- * @param context the context where the receiver should be registered.
+ *
+ * @param context the context where the receiver should be registered
*/
public void registerPackageReceiver(Context context) {
final BroadcastReceiver receiver = new BroadcastReceiver() {
@@ -429,8 +420,8 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
/**
- * Register the observer for
- * {@link android.provider.Settings.Global#FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT}
+ * Registers the observer for
+ * {@link android.provider.Settings.Global#FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT}.
*/
public void registerContentObserver() {
mCompatConfig.registerContentObserver();
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index 1024556c17eb..26244e62696b 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -368,6 +368,7 @@ final public class IpConnectivityMetrics extends SystemService {
@Override
public void logDefaultNetworkValidity(boolean valid) {
+ NetworkStack.checkNetworkStackPermission(getContext());
mDefaultNetworkMetrics.logDefaultNetworkValidity(SystemClock.elapsedRealtime(), valid);
}
@@ -375,6 +376,7 @@ final public class IpConnectivityMetrics extends SystemService {
public void logDefaultNetworkEvent(Network defaultNetwork, int score, boolean validated,
LinkProperties lp, NetworkCapabilities nc, Network previousDefaultNetwork,
int previousScore, LinkProperties previousLp, NetworkCapabilities previousNc) {
+ NetworkStack.checkNetworkStackPermission(getContext());
final long timeMs = SystemClock.elapsedRealtime();
mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs, defaultNetwork, score, validated,
lp, nc, previousDefaultNetwork, previousScore, previousLp, previousNc);
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index c1b1b6a2f26c..952193b77681 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -246,11 +246,6 @@ public class Nat464Xlat extends BaseNetworkObserver {
return;
}
- if (mNetwork.linkProperties == null) {
- Log.e(TAG, "startClat: Can't start clat with null LinkProperties");
- return;
- }
-
String baseIface = mNetwork.linkProperties.getInterfaceName();
if (baseIface == null) {
Log.e(TAG, "startClat: Can't start clat on null interface");
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index b0a73f105725..b2824846008c 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -36,13 +36,17 @@ import android.net.NetworkInfo;
import android.net.NetworkMonitorManager;
import android.net.NetworkRequest;
import android.net.NetworkState;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosFilterParcelable;
+import android.net.QosSession;
import android.net.TcpKeepalivePacketData;
-import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.telephony.data.EpsBearerQosSessionAttributes;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
@@ -53,7 +57,6 @@ import com.android.internal.util.WakeupMessage;
import com.android.server.ConnectivityService;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
@@ -136,12 +139,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
// This Network object should always be used if possible, so as to encourage reuse of the
// enclosed socket factory and connection pool. Avoid creating other Network objects.
// This Network object is always valid.
- public final Network network;
- public LinkProperties linkProperties;
+ @NonNull public final Network network;
+ @NonNull public LinkProperties linkProperties;
// This should only be modified by ConnectivityService, via setNetworkCapabilities().
// TODO: make this private with a getter.
- public NetworkCapabilities networkCapabilities;
- public final NetworkAgentConfig networkAgentConfig;
+ @NonNull public NetworkCapabilities networkCapabilities;
+ @NonNull public final NetworkAgentConfig networkAgentConfig;
// Underlying networks declared by the agent. Only set if supportsUnderlyingNetworks is true.
// The networks in this list might be declared by a VPN app using setUnderlyingNetworks and are
@@ -323,12 +326,20 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
private final ConnectivityService mConnService;
private final Context mContext;
private final Handler mHandler;
+ private final QosCallbackTracker mQosCallbackTracker;
public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info,
- LinkProperties lp, NetworkCapabilities nc, int score, Context context,
+ @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc, int score, Context context,
Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber,
- int creatorUid) {
+ int creatorUid, QosCallbackTracker qosCallbackTracker) {
+ Objects.requireNonNull(net);
+ Objects.requireNonNull(info);
+ Objects.requireNonNull(lp);
+ Objects.requireNonNull(nc);
+ Objects.requireNonNull(context);
+ Objects.requireNonNull(config);
+ Objects.requireNonNull(qosCallbackTracker);
networkAgent = na;
network = net;
networkInfo = info;
@@ -342,6 +353,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
networkAgentConfig = config;
this.factorySerialNumber = factorySerialNumber;
this.creatorUid = creatorUid;
+ mQosCallbackTracker = qosCallbackTracker;
}
private class AgentDeathMonitor implements IBinder.DeathRecipient {
@@ -527,6 +539,31 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
}
}
+ /**
+ * Notify the NetworkAgent that the qos filter should be registered against the given qos
+ * callback id.
+ */
+ public void onQosFilterCallbackRegistered(final int qosCallbackId,
+ final QosFilter qosFilter) {
+ try {
+ networkAgent.onQosFilterCallbackRegistered(qosCallbackId,
+ new QosFilterParcelable(qosFilter));
+ } catch (final RemoteException e) {
+ Log.e(TAG, "Error registering a qos callback id against a qos filter", e);
+ }
+ }
+
+ /**
+ * Notify the NetworkAgent that the given qos callback id should be unregistered.
+ */
+ public void onQosCallbackUnregistered(final int qosCallbackId) {
+ try {
+ networkAgent.onQosCallbackUnregistered(qosCallbackId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error unregistering a qos callback id", e);
+ }
+ }
+
// TODO: consider moving out of NetworkAgentInfo into its own class
private class NetworkAgentMessageHandler extends INetworkAgentRegistry.Stub {
private final Handler mHandler;
@@ -536,19 +573,22 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
}
@Override
- public void sendNetworkCapabilities(NetworkCapabilities nc) {
+ public void sendNetworkCapabilities(@NonNull NetworkCapabilities nc) {
+ Objects.requireNonNull(nc);
mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED,
new Pair<>(NetworkAgentInfo.this, nc)).sendToTarget();
}
@Override
- public void sendLinkProperties(LinkProperties lp) {
+ public void sendLinkProperties(@NonNull LinkProperties lp) {
+ Objects.requireNonNull(lp);
mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED,
new Pair<>(NetworkAgentInfo.this, lp)).sendToTarget();
}
@Override
- public void sendNetworkInfo(NetworkInfo info) {
+ public void sendNetworkInfo(@NonNull NetworkInfo info) {
+ Objects.requireNonNull(info);
mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_INFO_CHANGED,
new Pair<>(NetworkAgentInfo.this, info)).sendToTarget();
}
@@ -574,16 +614,25 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
@Override
public void sendUnderlyingNetworks(@Nullable List<Network> networks) {
- final Bundle args = new Bundle();
- if (networks instanceof ArrayList<?>) {
- args.putParcelableArrayList(NetworkAgent.UNDERLYING_NETWORKS_KEY,
- (ArrayList<Network>) networks);
- } else {
- args.putParcelableArrayList(NetworkAgent.UNDERLYING_NETWORKS_KEY,
- networks == null ? null : new ArrayList<>(networks));
- }
mHandler.obtainMessage(NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED,
- new Pair<>(NetworkAgentInfo.this, args)).sendToTarget();
+ new Pair<>(NetworkAgentInfo.this, networks)).sendToTarget();
+ }
+
+ @Override
+ public void sendEpsQosSessionAvailable(final int qosCallbackId, final QosSession session,
+ final EpsBearerQosSessionAttributes attributes) {
+ mQosCallbackTracker.sendEventQosSessionAvailable(qosCallbackId, session, attributes);
+ }
+
+ @Override
+ public void sendQosSessionLost(final int qosCallbackId, final QosSession session) {
+ mQosCallbackTracker.sendEventQosSessionLost(qosCallbackId, session);
+ }
+
+ @Override
+ public void sendQosCallbackError(final int qosCallbackId,
+ @QosCallbackException.ExceptionType final int exceptionType) {
+ mQosCallbackTracker.sendEventQosCallbackError(qosCallbackId, exceptionType);
}
}
@@ -603,7 +652,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
*
* @return the old capabilities of this network.
*/
- public synchronized NetworkCapabilities getAndSetNetworkCapabilities(
+ @NonNull public synchronized NetworkCapabilities getAndSetNetworkCapabilities(
@NonNull final NetworkCapabilities nc) {
final NetworkCapabilities oldNc = networkCapabilities;
networkCapabilities = nc;
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index a7be657ae7a3..5e6b9f39b40a 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -686,7 +686,7 @@ public class NetworkDiagnostics {
mHostname = hostname;
mMeasurement.description = "DNS TLS dst{" + mTarget.getHostAddress() + "} hostname{"
- + TextUtils.emptyIfNull(mHostname) + "}";
+ + (mHostname == null ? "" : mHostname) + "}";
}
private SSLSocket setupSSLSocket() throws IOException {
diff --git a/services/core/java/com/android/server/connectivity/PacProxyInstaller.java b/services/core/java/com/android/server/connectivity/PacProxyInstaller.java
index aadaf4d9584f..5dc8c1a00eaf 100644
--- a/services/core/java/com/android/server/connectivity/PacProxyInstaller.java
+++ b/services/core/java/com/android/server/connectivity/PacProxyInstaller.java
@@ -16,6 +16,7 @@
package com.android.server.connectivity;
+import android.annotation.NonNull;
import android.annotation.WorkerThread;
import android.app.AlarmManager;
import android.app.PendingIntent;
@@ -71,10 +72,6 @@ public class PacProxyInstaller {
private static final int DELAY_LONG = 4;
private static final long MAX_PAC_SIZE = 20 * 1000 * 1000;
- // Return values for #setCurrentProxyScriptUrl
- public static final boolean DONT_SEND_BROADCAST = false;
- public static final boolean DO_SEND_BROADCAST = true;
-
private String mCurrentPac;
@GuardedBy("mProxyLock")
private volatile Uri mPacUrl = Uri.EMPTY;
@@ -93,7 +90,7 @@ public class PacProxyInstaller {
private volatile boolean mHasSentBroadcast;
private volatile boolean mHasDownloaded;
- private Handler mConnectivityHandler;
+ private final Handler mConnectivityHandler;
private final int mProxyMessage;
/**
@@ -102,6 +99,13 @@ public class PacProxyInstaller {
private final Object mProxyLock = new Object();
/**
+ * Lock ensuring consistency between the values of mHasSentBroadcast, mHasDownloaded, the
+ * last URL and port, and the broadcast message being sent with the correct arguments.
+ * TODO : this should probably protect all instances of these variables
+ */
+ private final Object mBroadcastStateLock = new Object();
+
+ /**
* Runnable to download PAC script.
* The behavior relies on the assumption it always runs on mNetThread to guarantee that the
* latest data fetched from mPacUrl is stored in mProxyService.
@@ -146,7 +150,7 @@ public class PacProxyInstaller {
}
}
- public PacProxyInstaller(Context context, Handler handler, int proxyMessage) {
+ public PacProxyInstaller(@NonNull Context context, @NonNull Handler handler, int proxyMessage) {
mContext = context;
mLastPort = -1;
final HandlerThread netThread = new HandlerThread("android.pacproxyinstaller",
@@ -176,31 +180,27 @@ public class PacProxyInstaller {
* PacProxyInstaller will trigger a new broadcast when it is ready.
*
* @param proxy Proxy information that is about to be broadcast.
- * @return Returns whether the broadcast should be sent : either DO_ or DONT_SEND_BROADCAST
*/
- public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
- if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
- if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) {
- // Allow to send broadcast, nothing to do.
- return DO_SEND_BROADCAST;
- }
- mPacUrl = proxy.getPacFileUrl();
- mCurrentDelay = DELAY_1;
- mHasSentBroadcast = false;
- mHasDownloaded = false;
- getAlarmManager().cancel(mPacRefreshIntent);
- bind();
- return DONT_SEND_BROADCAST;
- } else {
- getAlarmManager().cancel(mPacRefreshIntent);
- synchronized (mProxyLock) {
- mPacUrl = Uri.EMPTY;
- mCurrentPac = null;
- if (mProxyService != null) {
- unbind();
+ public void setCurrentProxyScriptUrl(@NonNull ProxyInfo proxy) {
+ synchronized (mBroadcastStateLock) {
+ if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
+ if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) return;
+ mPacUrl = proxy.getPacFileUrl();
+ mCurrentDelay = DELAY_1;
+ mHasSentBroadcast = false;
+ mHasDownloaded = false;
+ getAlarmManager().cancel(mPacRefreshIntent);
+ bind();
+ } else {
+ getAlarmManager().cancel(mPacRefreshIntent);
+ synchronized (mProxyLock) {
+ mPacUrl = Uri.EMPTY;
+ mCurrentPac = null;
+ if (mProxyService != null) {
+ unbind();
+ }
}
}
- return DO_SEND_BROADCAST;
}
}
@@ -275,6 +275,7 @@ public class PacProxyInstaller {
getAlarmManager().set(AlarmManager.ELAPSED_REALTIME, timeTillTrigger, mPacRefreshIntent);
}
+ @GuardedBy("mProxyLock")
private void setCurrentProxyScript(String script) {
if (mProxyService == null) {
Log.e(TAG, "setCurrentProxyScript: no proxy service");
@@ -347,6 +348,9 @@ public class PacProxyInstaller {
public void setProxyPort(int port) {
if (mLastPort != -1) {
// Always need to send if port changed
+ // TODO: Here lacks synchronization because this write cannot
+ // guarantee that it's visible from sendProxyIfNeeded() when
+ // it's called by a Runnable which is post by mNetThread.
mHasSentBroadcast = false;
}
mLastPort = port;
@@ -386,13 +390,15 @@ public class PacProxyInstaller {
mConnectivityHandler.sendMessage(mConnectivityHandler.obtainMessage(mProxyMessage, proxy));
}
- private synchronized void sendProxyIfNeeded() {
- if (!mHasDownloaded || (mLastPort == -1)) {
- return;
- }
- if (!mHasSentBroadcast) {
- sendPacBroadcast(ProxyInfo.buildPacProxy(mPacUrl, mLastPort));
- mHasSentBroadcast = true;
+ private void sendProxyIfNeeded() {
+ synchronized (mBroadcastStateLock) {
+ if (!mHasDownloaded || (mLastPort == -1)) {
+ return;
+ }
+ if (!mHasSentBroadcast) {
+ sendPacBroadcast(ProxyInfo.buildPacProxy(mPacUrl, mLastPort));
+ mHasSentBroadcast = true;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index d83ff837d9be..b618d2b99a63 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -226,9 +226,9 @@ public class ProxyTracker {
final ProxyInfo defaultProxy = getDefaultProxy();
final ProxyInfo proxyInfo = null != defaultProxy ?
defaultProxy : ProxyInfo.buildDirectProxy("", 0, Collections.emptyList());
+ mPacProxyInstaller.setCurrentProxyScriptUrl(proxyInfo);
- if (mPacProxyInstaller.setCurrentProxyScriptUrl(proxyInfo)
- == PacProxyInstaller.DONT_SEND_BROADCAST) {
+ if (!shouldSendBroadcast(proxyInfo)) {
return;
}
if (DBG) Log.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
@@ -244,6 +244,13 @@ public class ProxyTracker {
}
}
+ private boolean shouldSendBroadcast(ProxyInfo proxy) {
+ if (Uri.EMPTY.equals(proxy.getPacFileUrl())) return false;
+ if (proxy.getPacFileUrl().equals(proxy.getPacFileUrl())
+ && (proxy.getPort() > 0)) return true;
+ return true;
+ }
+
/**
* Sets the global proxy in memory. Also writes the values to the global settings of the device.
*
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
new file mode 100644
index 000000000000..816bf2be0d69
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import static android.net.QosCallbackException.EX_TYPE_FILTER_NONE;
+
+import android.annotation.NonNull;
+import android.net.IQosCallback;
+import android.net.Network;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosSession;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.util.Slog;
+
+import java.util.Objects;
+
+/**
+ * Wraps callback related information and sends messages between network agent and the application.
+ * <p/>
+ * This is a satellite class of {@link com.android.server.ConnectivityService} and not meant
+ * to be used in other contexts.
+ *
+ * @hide
+ */
+class QosCallbackAgentConnection implements IBinder.DeathRecipient {
+ private static final String TAG = QosCallbackAgentConnection.class.getSimpleName();
+ private static final boolean DBG = false;
+
+ private final int mAgentCallbackId;
+ @NonNull private final QosCallbackTracker mQosCallbackTracker;
+ @NonNull private final IQosCallback mCallback;
+ @NonNull private final IBinder mBinder;
+ @NonNull private final QosFilter mFilter;
+ @NonNull private final NetworkAgentInfo mNetworkAgentInfo;
+
+ private final int mUid;
+
+ /**
+ * Gets the uid
+ * @return uid
+ */
+ int getUid() {
+ return mUid;
+ }
+
+ /**
+ * Gets the binder
+ * @return binder
+ */
+ @NonNull
+ IBinder getBinder() {
+ return mBinder;
+ }
+
+ /**
+ * Gets the callback id
+ *
+ * @return callback id
+ */
+ int getAgentCallbackId() {
+ return mAgentCallbackId;
+ }
+
+ /**
+ * Gets the network tied to the callback of this connection
+ *
+ * @return network
+ */
+ @NonNull
+ Network getNetwork() {
+ return mFilter.getNetwork();
+ }
+
+ QosCallbackAgentConnection(@NonNull final QosCallbackTracker qosCallbackTracker,
+ final int agentCallbackId,
+ @NonNull final IQosCallback callback,
+ @NonNull final QosFilter filter,
+ final int uid,
+ @NonNull final NetworkAgentInfo networkAgentInfo) {
+ Objects.requireNonNull(qosCallbackTracker, "qosCallbackTracker must be non-null");
+ Objects.requireNonNull(callback, "callback must be non-null");
+ Objects.requireNonNull(filter, "filter must be non-null");
+ Objects.requireNonNull(networkAgentInfo, "networkAgentInfo must be non-null");
+
+ mQosCallbackTracker = qosCallbackTracker;
+ mAgentCallbackId = agentCallbackId;
+ mCallback = callback;
+ mFilter = filter;
+ mUid = uid;
+ mBinder = mCallback.asBinder();
+ mNetworkAgentInfo = networkAgentInfo;
+ }
+
+ @Override
+ public void binderDied() {
+ logw("binderDied: binder died with callback id: " + mAgentCallbackId);
+ mQosCallbackTracker.unregisterCallback(mCallback);
+ }
+
+ void unlinkToDeathRecipient() {
+ mBinder.unlinkToDeath(this, 0);
+ }
+
+ // Returns false if the NetworkAgent was never notified.
+ boolean sendCmdRegisterCallback() {
+ final int exceptionType = mFilter.validate();
+ if (exceptionType != EX_TYPE_FILTER_NONE) {
+ try {
+ if (DBG) log("sendCmdRegisterCallback: filter validation failed");
+ mCallback.onError(exceptionType);
+ } catch (final RemoteException e) {
+ loge("sendCmdRegisterCallback:", e);
+ }
+ return false;
+ }
+
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (final RemoteException e) {
+ loge("failed linking to death recipient", e);
+ return false;
+ }
+ mNetworkAgentInfo.onQosFilterCallbackRegistered(mAgentCallbackId, mFilter);
+ return true;
+ }
+
+ void sendCmdUnregisterCallback() {
+ if (DBG) log("sendCmdUnregisterCallback: unregistering");
+ mNetworkAgentInfo.onQosCallbackUnregistered(mAgentCallbackId);
+ }
+
+ void sendEventQosSessionAvailable(final QosSession session,
+ final EpsBearerQosSessionAttributes attributes) {
+ try {
+ if (DBG) log("sendEventQosSessionAvailable: sending...");
+ mCallback.onQosEpsBearerSessionAvailable(session, attributes);
+ } catch (final RemoteException e) {
+ loge("sendEventQosSessionAvailable: remote exception", e);
+ }
+ }
+
+ void sendEventQosSessionLost(@NonNull final QosSession session) {
+ try {
+ if (DBG) log("sendEventQosSessionLost: sending...");
+ mCallback.onQosSessionLost(session);
+ } catch (final RemoteException e) {
+ loge("sendEventQosSessionLost: remote exception", e);
+ }
+ }
+
+ void sendEventQosCallbackError(@QosCallbackException.ExceptionType final int exceptionType) {
+ try {
+ if (DBG) log("sendEventQosCallbackError: sending...");
+ mCallback.onError(exceptionType);
+ } catch (final RemoteException e) {
+ loge("sendEventQosCallbackError: remote exception", e);
+ }
+ }
+
+ private static void log(@NonNull final String msg) {
+ Slog.d(TAG, msg);
+ }
+
+ private static void logw(@NonNull final String msg) {
+ Slog.w(TAG, msg);
+ }
+
+ private static void loge(@NonNull final String msg, final Throwable t) {
+ Slog.e(TAG, msg, t);
+ }
+
+ private static void logwtf(@NonNull final String msg) {
+ Slog.wtf(TAG, msg);
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
new file mode 100644
index 000000000000..87b4c162a2cc
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.IQosCallback;
+import android.net.Network;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosSession;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.util.Slog;
+
+import com.android.internal.util.CollectionUtils;
+import com.android.server.ConnectivityService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tracks qos callbacks and handles the communication between the network agent and application.
+ * <p/>
+ * Any method prefixed by handle must be called from the
+ * {@link com.android.server.ConnectivityService} handler thread.
+ *
+ * @hide
+ */
+public class QosCallbackTracker {
+ private static final String TAG = QosCallbackTracker.class.getSimpleName();
+ private static final boolean DBG = true;
+
+ @NonNull
+ private final Handler mConnectivityServiceHandler;
+
+ @NonNull
+ private final ConnectivityService.PerUidCounter mNetworkRequestCounter;
+
+ /**
+ * Each agent gets a unique callback id that is used to proxy messages back to the original
+ * callback.
+ * <p/>
+ * Note: The fact that this is initialized to 0 is to ensure that the thread running
+ * {@link #handleRegisterCallback(IQosCallback, QosFilter, int, NetworkAgentInfo)} sees the
+ * initialized value. This would not necessarily be the case if the value was initialized to
+ * the non-default value.
+ * <p/>
+ * Note: The term previous does not apply to the first callback id that is assigned.
+ */
+ private int mPreviousAgentCallbackId = 0;
+
+ @NonNull
+ private final List<QosCallbackAgentConnection> mConnections = new ArrayList<>();
+
+ /**
+ *
+ * @param connectivityServiceHandler must be the same handler used with
+ * {@link com.android.server.ConnectivityService}
+ * @param networkRequestCounter keeps track of the number of open requests under a given
+ * uid
+ */
+ public QosCallbackTracker(@NonNull final Handler connectivityServiceHandler,
+ final ConnectivityService.PerUidCounter networkRequestCounter) {
+ mConnectivityServiceHandler = connectivityServiceHandler;
+ mNetworkRequestCounter = networkRequestCounter;
+ }
+
+ /**
+ * Registers the callback with the tracker
+ *
+ * @param callback the callback to register
+ * @param filter the filter being registered alongside the callback
+ */
+ public void registerCallback(@NonNull final IQosCallback callback,
+ @NonNull final QosFilter filter, @NonNull final NetworkAgentInfo networkAgentInfo) {
+ final int uid = Binder.getCallingUid();
+
+ // Enforce that the number of requests under this uid has exceeded the allowed number
+ mNetworkRequestCounter.incrementCountOrThrow(uid);
+
+ mConnectivityServiceHandler.post(
+ () -> handleRegisterCallback(callback, filter, uid, networkAgentInfo));
+ }
+
+ private void handleRegisterCallback(@NonNull final IQosCallback callback,
+ @NonNull final QosFilter filter, final int uid,
+ @NonNull final NetworkAgentInfo networkAgentInfo) {
+ final QosCallbackAgentConnection ac =
+ handleRegisterCallbackInternal(callback, filter, uid, networkAgentInfo);
+ if (ac != null) {
+ if (DBG) log("handleRegisterCallback: added callback " + ac.getAgentCallbackId());
+ mConnections.add(ac);
+ } else {
+ mNetworkRequestCounter.decrementCount(uid);
+ }
+ }
+
+ private QosCallbackAgentConnection handleRegisterCallbackInternal(
+ @NonNull final IQosCallback callback,
+ @NonNull final QosFilter filter, final int uid,
+ @NonNull final NetworkAgentInfo networkAgentInfo) {
+ final IBinder binder = callback.asBinder();
+ if (CollectionUtils.any(mConnections, c -> c.getBinder().equals(binder))) {
+ // A duplicate registration would have only made this far due to a programming error.
+ logwtf("handleRegisterCallback: Callbacks can only be register once.");
+ return null;
+ }
+
+ mPreviousAgentCallbackId = mPreviousAgentCallbackId + 1;
+ final int newCallbackId = mPreviousAgentCallbackId;
+
+ final QosCallbackAgentConnection ac =
+ new QosCallbackAgentConnection(this, newCallbackId, callback,
+ filter, uid, networkAgentInfo);
+
+ final int exceptionType = filter.validate();
+ if (exceptionType != QosCallbackException.EX_TYPE_FILTER_NONE) {
+ ac.sendEventQosCallbackError(exceptionType);
+ return null;
+ }
+
+ // Only add to the callback maps if the NetworkAgent successfully registered it
+ if (!ac.sendCmdRegisterCallback()) {
+ // There was an issue when registering the agent
+ if (DBG) log("handleRegisterCallback: error sending register callback");
+ mNetworkRequestCounter.decrementCount(uid);
+ return null;
+ }
+ return ac;
+ }
+
+ /**
+ * Unregisters callback
+ * @param callback callback to unregister
+ */
+ public void unregisterCallback(@NonNull final IQosCallback callback) {
+ mConnectivityServiceHandler.post(() -> handleUnregisterCallback(callback.asBinder(), true));
+ }
+
+ private void handleUnregisterCallback(@NonNull final IBinder binder,
+ final boolean sendToNetworkAgent) {
+ final QosCallbackAgentConnection agentConnection =
+ CollectionUtils.find(mConnections, c -> c.getBinder().equals(binder));
+ if (agentConnection == null) {
+ logw("handleUnregisterCallback: agentConnection is null");
+ return;
+ }
+
+ if (DBG) {
+ log("handleUnregisterCallback: unregister "
+ + agentConnection.getAgentCallbackId());
+ }
+
+ mNetworkRequestCounter.decrementCount(agentConnection.getUid());
+ mConnections.remove(agentConnection);
+
+ if (sendToNetworkAgent) {
+ agentConnection.sendCmdUnregisterCallback();
+ }
+ agentConnection.unlinkToDeathRecipient();
+ }
+
+ /**
+ * Called when the NetworkAgent sends the qos session available event
+ *
+ * @param qosCallbackId the callback id that the qos session is now available to
+ * @param session the qos session that is now available
+ * @param attributes the qos attributes that are now available on the qos session
+ */
+ public void sendEventQosSessionAvailable(final int qosCallbackId,
+ final QosSession session,
+ final EpsBearerQosSessionAttributes attributes) {
+ runOnAgentConnection(qosCallbackId, "sendEventQosSessionAvailable: ",
+ ac -> ac.sendEventQosSessionAvailable(session, attributes));
+ }
+
+ /**
+ * Called when the NetworkAgent sends the qos session lost event
+ *
+ * @param qosCallbackId the callback id that lost the qos session
+ * @param session the corresponding qos session
+ */
+ public void sendEventQosSessionLost(final int qosCallbackId,
+ final QosSession session) {
+ runOnAgentConnection(qosCallbackId, "sendEventQosSessionLost: ",
+ ac -> ac.sendEventQosSessionLost(session));
+ }
+
+ /**
+ * Called when the NetworkAgent sends the qos session on error event
+ *
+ * @param qosCallbackId the callback id that should receive the exception
+ * @param exceptionType the type of exception that caused the callback to error
+ */
+ public void sendEventQosCallbackError(final int qosCallbackId,
+ @QosCallbackException.ExceptionType final int exceptionType) {
+ runOnAgentConnection(qosCallbackId, "sendEventQosCallbackError: ",
+ ac -> {
+ ac.sendEventQosCallbackError(exceptionType);
+ handleUnregisterCallback(ac.getBinder(), false);
+ });
+ }
+
+ /**
+ * Unregisters all callbacks associated to this network agent
+ *
+ * Note: Must be called on the connectivity service handler thread
+ *
+ * @param network the network that was released
+ */
+ public void handleNetworkReleased(@Nullable final Network network) {
+ final List<QosCallbackAgentConnection> connections =
+ CollectionUtils.filter(mConnections, ac -> ac.getNetwork().equals(network));
+
+ for (final QosCallbackAgentConnection agentConnection : connections) {
+ agentConnection.sendEventQosCallbackError(
+ QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
+
+ // Call unregister workflow w\o sending anything to agent since it is disconnected.
+ handleUnregisterCallback(agentConnection.getBinder(), false);
+ }
+ }
+
+ private interface AgentConnectionAction {
+ void execute(@NonNull QosCallbackAgentConnection agentConnection);
+ }
+
+ @Nullable
+ private void runOnAgentConnection(final int qosCallbackId,
+ @NonNull final String logPrefix,
+ @NonNull final AgentConnectionAction action) {
+ mConnectivityServiceHandler.post(() -> {
+ final QosCallbackAgentConnection ac =
+ CollectionUtils.find(mConnections,
+ c -> c.getAgentCallbackId() == qosCallbackId);
+ if (ac == null) {
+ loge(logPrefix + ": " + qosCallbackId + " missing callback id");
+ return;
+ }
+
+ action.execute(ac);
+ });
+ }
+
+ private static void log(final String msg) {
+ Slog.d(TAG, msg);
+ }
+
+ private static void logw(final String msg) {
+ Slog.w(TAG, msg);
+ }
+
+ private static void loge(final String msg) {
+ Slog.e(TAG, msg);
+ }
+
+ private static void logwtf(final String msg) {
+ Slog.wtf(TAG, msg);
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index b250f164a264..80944773c2c4 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -70,6 +70,7 @@ import android.net.NetworkRequest;
import android.net.RouteInfo;
import android.net.UidRange;
import android.net.UidRangeParcel;
+import android.net.UnderlyingNetworkInfo;
import android.net.VpnManager;
import android.net.VpnService;
import android.net.ipsec.ike.ChildSessionCallback;
@@ -109,7 +110,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
@@ -439,6 +439,11 @@ public class Vpn {
mEnableTeardown = enableTeardown;
}
+ @VisibleForTesting
+ public boolean getEnableTeardown() {
+ return mEnableTeardown;
+ }
+
/**
* Update current state, dispatching event to listeners.
*/
@@ -1229,7 +1234,8 @@ public class Vpn {
private boolean canHaveRestrictedProfile(int userId) {
final long token = Binder.clearCallingIdentity();
try {
- return UserManager.get(mContext).canHaveRestrictedProfile(userId);
+ final Context userContext = mContext.createContextAsUser(UserHandle.of(userId), 0);
+ return userContext.getSystemService(UserManager.class).canHaveRestrictedProfile();
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1810,18 +1816,15 @@ public class Vpn {
}
/**
- * This method should only be called by ConnectivityService because it doesn't
- * have enough data to fill VpnInfo.primaryUnderlyingIface field.
+ * This method should not be called if underlying interfaces field is needed, because it doesn't
+ * have enough data to fill VpnInfo.underlyingIfaces field.
*/
- public synchronized VpnInfo getVpnInfo() {
+ public synchronized UnderlyingNetworkInfo getUnderlyingNetworkInfo() {
if (!isRunningLocked()) {
return null;
}
- VpnInfo info = new VpnInfo();
- info.ownerUid = mOwnerUID;
- info.vpnIface = mInterface;
- return info;
+ return new UnderlyingNetworkInfo(mOwnerUID, mInterface, new ArrayList<>());
}
public synchronized boolean appliesToUid(int uid) {
@@ -2145,6 +2148,11 @@ public class Vpn {
// Start a new LegacyVpnRunner and we are done!
mVpnRunner = new LegacyVpnRunner(config, racoon, mtpd, profile);
+ startLegacyVpnRunner();
+ }
+
+ @VisibleForTesting
+ protected void startLegacyVpnRunner() {
mVpnRunner.start();
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index ab289ea6f081..f876e1ad4b88 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -901,7 +901,6 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
@ServiceThreadOnly
void setArcStatus(boolean enabled) {
- // TODO(shubang): add tests
assertRunOnServiceThread();
HdmiLogger.debug("Set Arc Status[old:%b new:%b]", mArcEstablished, enabled);
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 8e50bb4885d8..5d1c4e6715f1 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -621,7 +621,14 @@ public class HdmiControlService extends SystemService {
mWakeUpMessageReceived = false;
if (isTvDeviceEnabled()) {
- mCecController.setOption(OptionKey.WAKEUP, tv().getAutoWakeup());
+ boolean autoWakeupEnabled =
+ readBooleanSetting(Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, true);
+ boolean autoDeviceOffEnabled =
+ readBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, true);
+
+ mCecController.setOption(OptionKey.WAKEUP, autoWakeupEnabled);
+ tv().setAutoWakeup(autoWakeupEnabled);
+ tv().setAutoDeviceOff(autoDeviceOffEnabled);
}
int reason = -1;
switch (initiatedBy) {
diff --git a/services/core/java/com/android/server/location/contexthub/OWNERS b/services/core/java/com/android/server/location/contexthub/OWNERS
index d4393d6a83d2..90c233030ed1 100644
--- a/services/core/java/com/android/server/location/contexthub/OWNERS
+++ b/services/core/java/com/android/server/location/contexthub/OWNERS
@@ -1,2 +1,3 @@
arthuri@google.com
bduddie@google.com
+stange@google.com
diff --git a/services/core/java/com/android/server/location/timezone/OWNERS b/services/core/java/com/android/server/location/timezone/OWNERS
deleted file mode 100644
index 28aff188dbd8..000000000000
--- a/services/core/java/com/android/server/location/timezone/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 847766
-nfuller@google.com
-include /core/java/android/app/timedetector/OWNERS
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index d003b89e8877..c005af4e9696 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -89,6 +89,7 @@ import android.os.storage.StorageManager;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.provider.Settings.SettingNotFoundException;
+import android.security.Authorization;
import android.security.KeyStore;
import android.security.keystore.AndroidKeyStoreProvider;
import android.security.keystore.KeyProperties;
@@ -1272,6 +1273,7 @@ public class LockSettingsService extends ILockSettings.Stub {
private void unlockKeystore(byte[] password, int userHandle) {
if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
+ new Authorization().onLockScreenEvent(false, userHandle, password);
// TODO(b/120484642): Update keystore to accept byte[] passwords
String passwordString = password == null ? null : new String(password);
final KeyStore ks = KeyStore.getInstance();
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 81d07cc11527..c4225eda7d24 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -88,6 +88,7 @@ class LockSettingsStorage {
private static final String CHILD_PROFILE_LOCK_FILE = "gatekeeper.profile.key";
private static final String REBOOT_ESCROW_FILE = "reboot.escrow.key";
+ private static final String REBOOT_ESCROW_SERVER_BLOB = "reboot.escrow.server.blob.key";
private static final String SYNTHETIC_PASSWORD_DIRECTORY = "spblob/";
@@ -317,6 +318,22 @@ class LockSettingsStorage {
deleteFile(getRebootEscrowFile(userId));
}
+ public void writeRebootEscrowServerBlob(byte[] serverBlob) {
+ writeFile(getRebootEscrowServerBlob(), serverBlob);
+ }
+
+ public byte[] readRebootEscrowServerBlob() {
+ return readFile(getRebootEscrowServerBlob());
+ }
+
+ public boolean hasRebootEscrowServerBlob() {
+ return hasFile(getRebootEscrowServerBlob());
+ }
+
+ public void removeRebootEscrowServerBlob() {
+ deleteFile(getRebootEscrowServerBlob());
+ }
+
public boolean hasPassword(int userId) {
return hasFile(getLockPasswordFilename(userId));
}
@@ -445,6 +462,12 @@ class LockSettingsStorage {
return getLockCredentialFilePathForUser(userId, REBOOT_ESCROW_FILE);
}
+ @VisibleForTesting
+ String getRebootEscrowServerBlob() {
+ // There is a single copy of server blob for all users.
+ return getLockCredentialFilePathForUser(UserHandle.USER_SYSTEM, REBOOT_ESCROW_SERVER_BLOB);
+ }
+
private String getLockCredentialFilePathForUser(int userId, String basename) {
String dataSystemDirectory = Environment.getDataDirectory().getAbsolutePath() +
SYSTEM_DIRECTORY;
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 289290bab4dc..06962d414009 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -124,26 +124,28 @@ class RebootEscrowManager {
static class Injector {
protected Context mContext;
private final RebootEscrowKeyStoreManager mKeyStoreManager;
- private final RebootEscrowProviderInterface mRebootEscrowProvider;
+ private final LockSettingsStorage mStorage;
+ private RebootEscrowProviderInterface mRebootEscrowProvider;
- Injector(Context context) {
+ Injector(Context context, LockSettingsStorage storage) {
mContext = context;
+ mStorage = storage;
mKeyStoreManager = new RebootEscrowKeyStoreManager();
+ }
- RebootEscrowProviderInterface rebootEscrowProvider = null;
- // TODO(xunchang) add implementation for server based ror.
+ private RebootEscrowProviderInterface createRebootEscrowProvider() {
+ RebootEscrowProviderInterface rebootEscrowProvider;
if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
"server_based_ror_enabled", false)) {
- Slog.e(TAG, "Server based ror isn't implemented yet.");
+ rebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(mContext, mStorage);
} else {
rebootEscrowProvider = new RebootEscrowProviderHalImpl();
}
- if (rebootEscrowProvider != null && rebootEscrowProvider.hasRebootEscrowSupport()) {
- mRebootEscrowProvider = rebootEscrowProvider;
- } else {
- mRebootEscrowProvider = null;
+ if (rebootEscrowProvider.hasRebootEscrowSupport()) {
+ return rebootEscrowProvider;
}
+ return null;
}
public Context getContext() {
@@ -159,6 +161,12 @@ class RebootEscrowManager {
}
public RebootEscrowProviderInterface getRebootEscrowProvider() {
+ // Initialize for the provider lazily. Because the device_config and service
+ // implementation apps may change when system server is running.
+ if (mRebootEscrowProvider == null) {
+ mRebootEscrowProvider = createRebootEscrowProvider();
+ }
+
return mRebootEscrowProvider;
}
@@ -177,7 +185,7 @@ class RebootEscrowManager {
}
RebootEscrowManager(Context context, Callbacks callbacks, LockSettingsStorage storage) {
- this(new Injector(context), callbacks, storage);
+ this(new Injector(context, storage), callbacks, storage);
}
@VisibleForTesting
@@ -224,6 +232,10 @@ class RebootEscrowManager {
for (UserInfo user : rebootEscrowUsers) {
allUsersUnlocked &= restoreRebootEscrowForUser(user.id, escrowKey, kk);
}
+
+ // Clear the old key in keystore. A new key will be generated by new RoR requests.
+ mKeyStoreManager.clearKeyStoreEncryptionKey();
+
onEscrowRestoreComplete(allUsersUnlocked);
}
@@ -273,9 +285,6 @@ class RebootEscrowManager {
} catch (IOException e) {
Slog.w(TAG, "Could not load reboot escrow data for user " + userId, e);
return false;
- } finally {
- // Clear the old key in keystore. A new key will be generated by new RoR requests.
- mKeyStoreManager.clearKeyStoreEncryptionKey();
}
}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
new file mode 100644
index 000000000000..ba1a680ba7fb
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2021 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.locksettings;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.RemoteException;
+import android.provider.DeviceConfig;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.locksettings.ResumeOnRebootServiceProvider.ResumeOnRebootServiceConnection;
+
+import java.io.IOException;
+import java.util.concurrent.TimeoutException;
+
+import javax.crypto.SecretKey;
+
+/**
+ * An implementation of the {@link RebootEscrowProviderInterface} by communicating with server to
+ * encrypt & decrypt the blob.
+ */
+class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterface {
+ private static final String TAG = "RebootEscrowProvider";
+
+ // Timeout for service binding
+ private static final long DEFAULT_SERVICE_TIMEOUT_IN_SECONDS = 10;
+
+ /**
+ * Use the default lifetime of 10 minutes. The lifetime covers the following activities:
+ * Server wrap secret -> device reboot -> server unwrap blob.
+ */
+ private static final long DEFAULT_SERVER_BLOB_LIFETIME_IN_MILLIS = 600_1000;
+
+ private final LockSettingsStorage mStorage;
+
+ private final Injector mInjector;
+
+ static class Injector {
+ private ResumeOnRebootServiceConnection mServiceConnection = null;
+
+ Injector(Context context) {
+ mServiceConnection = new ResumeOnRebootServiceProvider(context).getServiceConnection();
+ if (mServiceConnection == null) {
+ Slog.e(TAG, "Failed to resolve resume on reboot server service.");
+ }
+ }
+
+ Injector(ResumeOnRebootServiceConnection serviceConnection) {
+ mServiceConnection = serviceConnection;
+ }
+
+ @Nullable
+ private ResumeOnRebootServiceConnection getServiceConnection() {
+ return mServiceConnection;
+ }
+
+ long getServiceTimeoutInSeconds() {
+ return DeviceConfig.getLong(DeviceConfig.NAMESPACE_OTA,
+ "server_based_service_timeout_in_seconds",
+ DEFAULT_SERVICE_TIMEOUT_IN_SECONDS);
+ }
+
+ long getServerBlobLifetimeInMillis() {
+ return DeviceConfig.getLong(DeviceConfig.NAMESPACE_OTA,
+ "server_based_server_blob_lifetime_in_millis",
+ DEFAULT_SERVER_BLOB_LIFETIME_IN_MILLIS);
+ }
+ }
+
+ RebootEscrowProviderServerBasedImpl(Context context, LockSettingsStorage storage) {
+ this(storage, new Injector(context));
+ }
+
+ @VisibleForTesting
+ RebootEscrowProviderServerBasedImpl(LockSettingsStorage storage, Injector injector) {
+ mStorage = storage;
+ mInjector = injector;
+ }
+
+ @Override
+ public boolean hasRebootEscrowSupport() {
+ return mInjector.getServiceConnection() != null;
+ }
+
+ private byte[] unwrapServerBlob(byte[] serverBlob, SecretKey decryptionKey) throws
+ TimeoutException, RemoteException, IOException {
+ ResumeOnRebootServiceConnection serviceConnection = mInjector.getServiceConnection();
+ if (serviceConnection == null) {
+ Slog.w(TAG, "Had reboot escrow data for users, but resume on reboot server"
+ + " service is unavailable");
+ return null;
+ }
+
+ // Decrypt with k_k from the key store first.
+ byte[] decryptedBlob = AesEncryptionUtil.decrypt(decryptionKey, serverBlob);
+ if (decryptedBlob == null) {
+ Slog.w(TAG, "Decrypted server blob should not be null");
+ return null;
+ }
+
+ // Ask the server connection service to decrypt the inner layer, to get the reboot
+ // escrow key (k_s).
+ serviceConnection.bindToService(mInjector.getServiceTimeoutInSeconds());
+ byte[] escrowKeyBytes = serviceConnection.unwrap(decryptedBlob,
+ mInjector.getServiceTimeoutInSeconds());
+ serviceConnection.unbindService();
+
+ return escrowKeyBytes;
+ }
+
+ @Override
+ public RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) {
+ byte[] serverBlob = mStorage.readRebootEscrowServerBlob();
+ // Delete the server blob in storage.
+ mStorage.removeRebootEscrowServerBlob();
+ if (serverBlob == null) {
+ Slog.w(TAG, "Failed to read reboot escrow server blob from storage");
+ return null;
+ }
+
+ try {
+ byte[] escrowKeyBytes = unwrapServerBlob(serverBlob, decryptionKey);
+ if (escrowKeyBytes == null) {
+ Slog.w(TAG, "Decrypted reboot escrow key bytes should not be null");
+ return null;
+ } else if (escrowKeyBytes.length != 32) {
+ Slog.e(TAG, "Decrypted reboot escrow key has incorrect size "
+ + escrowKeyBytes.length);
+ return null;
+ }
+
+ return RebootEscrowKey.fromKeyBytes(escrowKeyBytes);
+ } catch (TimeoutException | RemoteException | IOException e) {
+ Slog.w(TAG, "Failed to decrypt the server blob ", e);
+ return null;
+ }
+ }
+
+ @Override
+ public void clearRebootEscrowKey() {
+ mStorage.removeRebootEscrowServerBlob();
+ }
+
+ private byte[] wrapEscrowKey(byte[] escrowKeyBytes, SecretKey encryptionKey) throws
+ TimeoutException, RemoteException, IOException {
+ ResumeOnRebootServiceConnection serviceConnection = mInjector.getServiceConnection();
+ if (serviceConnection == null) {
+ Slog.w(TAG, "Failed to encrypt the reboot escrow key: resume on reboot server"
+ + " service is unavailable");
+ return null;
+ }
+
+ serviceConnection.bindToService(mInjector.getServiceTimeoutInSeconds());
+ // Ask the server connection service to encrypt the reboot escrow key.
+ byte[] serverEncryptedBlob = serviceConnection.wrapBlob(escrowKeyBytes,
+ mInjector.getServerBlobLifetimeInMillis(), mInjector.getServiceTimeoutInSeconds());
+ serviceConnection.unbindService();
+
+ if (serverEncryptedBlob == null) {
+ Slog.w(TAG, "Server encrypted reboot escrow key cannot be null");
+ return null;
+ }
+
+ // Additionally wrap the server blob with a local key.
+ return AesEncryptionUtil.encrypt(encryptionKey, serverEncryptedBlob);
+ }
+
+ @Override
+ public boolean storeRebootEscrowKey(RebootEscrowKey escrowKey, SecretKey encryptionKey) {
+ mStorage.removeRebootEscrowServerBlob();
+ try {
+ byte[] wrappedBlob = wrapEscrowKey(escrowKey.getKeyBytes(), encryptionKey);
+ if (wrappedBlob == null) {
+ Slog.w(TAG, "Failed to encrypt the reboot escrow key");
+ return false;
+ }
+ mStorage.writeRebootEscrowServerBlob(wrappedBlob);
+
+ Slog.i(TAG, "Reboot escrow key encrypted and stored.");
+ return true;
+ } catch (TimeoutException | RemoteException | IOException e) {
+ Slog.w(TAG, "Failed to encrypt the reboot escrow key ", e);
+ }
+
+ return false;
+ }
+}
diff --git a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
new file mode 100644
index 000000000000..8399f54764e0
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2021 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.locksettings;
+
+import android.Manifest;
+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.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelableException;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.DeviceConfig;
+import android.service.resumeonreboot.IResumeOnRebootService;
+import android.service.resumeonreboot.ResumeOnRebootService;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/** @hide */
+public class ResumeOnRebootServiceProvider {
+
+ private static final String PROVIDER_PACKAGE = DeviceConfig.getString(
+ DeviceConfig.NAMESPACE_OTA, "resume_on_reboot_service_package", "");
+ private static final String PROVIDER_REQUIRED_PERMISSION =
+ Manifest.permission.BIND_RESUME_ON_REBOOT_SERVICE;
+ private static final String TAG = "ResumeOnRebootServiceProvider";
+
+ private final Context mContext;
+ private final PackageManager mPackageManager;
+
+ public ResumeOnRebootServiceProvider(Context context) {
+ this(context, context.getPackageManager());
+ }
+
+ @VisibleForTesting
+ public ResumeOnRebootServiceProvider(Context context, PackageManager packageManager) {
+ this.mContext = context;
+ this.mPackageManager = packageManager;
+ }
+
+ @Nullable
+ private ServiceInfo resolveService() {
+ Intent intent = new Intent();
+ intent.setAction(ResumeOnRebootService.SERVICE_INTERFACE);
+ if (PROVIDER_PACKAGE != null && !PROVIDER_PACKAGE.equals("")) {
+ intent.setPackage(PROVIDER_PACKAGE);
+ }
+
+ List<ResolveInfo> resolvedIntents =
+ mPackageManager.queryIntentServices(intent, PackageManager.MATCH_SYSTEM_ONLY);
+ for (ResolveInfo resolvedInfo : resolvedIntents) {
+ if (resolvedInfo.serviceInfo != null
+ && PROVIDER_REQUIRED_PERMISSION.equals(resolvedInfo.serviceInfo.permission)) {
+ return resolvedInfo.serviceInfo;
+ }
+ }
+ return null;
+ }
+
+ /** Creates a new {@link ResumeOnRebootServiceConnection} */
+ @Nullable
+ public ResumeOnRebootServiceConnection getServiceConnection() {
+ ServiceInfo serviceInfo = resolveService();
+ if (serviceInfo == null) {
+ return null;
+ }
+ return new ResumeOnRebootServiceConnection(mContext, serviceInfo.getComponentName());
+ }
+
+ /**
+ * Connection class used for contacting the registered {@link IResumeOnRebootService}
+ */
+ public static class ResumeOnRebootServiceConnection {
+
+ private static final String TAG = "ResumeOnRebootServiceConnection";
+ private final Context mContext;
+ private final ComponentName mComponentName;
+ private IResumeOnRebootService mBinder;
+
+ private ResumeOnRebootServiceConnection(Context context,
+ @NonNull ComponentName componentName) {
+ mContext = context;
+ mComponentName = componentName;
+ }
+
+ /** Unbind from the service */
+ public void unbindService() {
+ mContext.unbindService(new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mBinder = null;
+
+ }
+ });
+ }
+
+ /** Bind to the service */
+ public void bindToService(long timeOut) throws TimeoutException {
+ if (mBinder == null || !mBinder.asBinder().isBinderAlive()) {
+ CountDownLatch connectionLatch = new CountDownLatch(1);
+ Intent intent = new Intent();
+ intent.setComponent(mComponentName);
+ final boolean success = mContext.bindServiceAsUser(intent, new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mBinder = IResumeOnRebootService.Stub.asInterface(service);
+ connectionLatch.countDown();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ }
+ },
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+ BackgroundThread.getHandler(), UserHandle.SYSTEM);
+
+ if (!success) {
+ Slog.e(TAG, "Binding: " + mComponentName + " u" + UserHandle.SYSTEM
+ + " failed.");
+ return;
+ }
+ waitForLatch(connectionLatch, "serviceConnection", timeOut);
+ }
+ }
+
+ /** Wrap opaque blob */
+ public byte[] wrapBlob(byte[] unwrappedBlob, long lifeTimeInMillis,
+ long timeOutInMillis)
+ throws RemoteException, TimeoutException, IOException {
+ if (mBinder == null || !mBinder.asBinder().isBinderAlive()) {
+ throw new RemoteException("Service not bound");
+ }
+ CountDownLatch binderLatch = new CountDownLatch(1);
+ ResumeOnRebootServiceCallback
+ resultCallback =
+ new ResumeOnRebootServiceCallback(
+ binderLatch);
+ mBinder.wrapSecret(unwrappedBlob, lifeTimeInMillis, new RemoteCallback(resultCallback));
+ waitForLatch(binderLatch, "wrapSecret", timeOutInMillis);
+ if (resultCallback.getResult().containsKey(ResumeOnRebootService.EXCEPTION_KEY)) {
+ throwTypedException(resultCallback.getResult().getParcelable(
+ ResumeOnRebootService.EXCEPTION_KEY));
+ }
+ return resultCallback.mResult.getByteArray(ResumeOnRebootService.WRAPPED_BLOB_KEY);
+ }
+
+ /** Unwrap wrapped blob */
+ public byte[] unwrap(byte[] wrappedBlob, long timeOut)
+ throws RemoteException, TimeoutException, IOException {
+ if (mBinder == null || !mBinder.asBinder().isBinderAlive()) {
+ throw new RemoteException("Service not bound");
+ }
+ CountDownLatch binderLatch = new CountDownLatch(1);
+ ResumeOnRebootServiceCallback
+ resultCallback =
+ new ResumeOnRebootServiceCallback(
+ binderLatch);
+ mBinder.unwrap(wrappedBlob, new RemoteCallback(resultCallback));
+ waitForLatch(binderLatch, "unWrapSecret", timeOut);
+ if (resultCallback.getResult().containsKey(ResumeOnRebootService.EXCEPTION_KEY)) {
+ throwTypedException(resultCallback.getResult().getParcelable(
+ ResumeOnRebootService.EXCEPTION_KEY));
+ }
+ return resultCallback.getResult().getByteArray(
+ ResumeOnRebootService.UNWRAPPED_BLOB_KEY);
+ }
+
+ private void throwTypedException(
+ ParcelableException exception)
+ throws IOException {
+ if (exception.getCause() instanceof IOException) {
+ exception.maybeRethrow(IOException.class);
+ } else if (exception.getCause() instanceof IllegalStateException) {
+ exception.maybeRethrow(IllegalStateException.class);
+ } else {
+ // This should not happen. Wrap the cause in IllegalStateException so that it
+ // doesn't disrupt the exception handling
+ throw new IllegalStateException(exception.getCause());
+ }
+ }
+
+ private void waitForLatch(CountDownLatch latch, String reason, long timeOut)
+ throws TimeoutException {
+ try {
+ if (!latch.await(timeOut, TimeUnit.SECONDS)) {
+ throw new TimeoutException("Latch wait for " + reason + " elapsed");
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException("Latch wait for " + reason + " interrupted");
+ }
+ }
+ }
+
+ private static class ResumeOnRebootServiceCallback implements
+ RemoteCallback.OnResultListener {
+
+ private final CountDownLatch mResultLatch;
+ private Bundle mResult;
+
+ private ResumeOnRebootServiceCallback(CountDownLatch resultLatch) {
+ this.mResultLatch = resultLatch;
+ }
+
+ @Override
+ public void onResult(@Nullable Bundle result) {
+ this.mResult = result;
+ mResultLatch.countDown();
+ }
+
+ private Bundle getResult() {
+ return mResult;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index f882c57e49ba..edc9d7c64146 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -77,7 +77,7 @@ abstract class MediaRoute2Provider {
@NonNull
public List<RoutingSessionInfo> getSessionInfos() {
synchronized (mLock) {
- return mSessionInfos;
+ return new ArrayList<>(mSessionInfos);
}
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index 85af346aa88a..ab38dca2387d 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -108,8 +108,8 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
mLastDiscoveryPreference = discoveryPreference;
if (mConnectionReady) {
mActiveConnection.updateDiscoveryPreference(discoveryPreference);
- updateBinding();
}
+ updateBinding();
}
@Override
@@ -205,9 +205,11 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
}
private boolean shouldBind() {
- //TODO: Binding could be delayed until it's necessary.
if (mRunning) {
- return true;
+ // Bind when there is a discovery preference or an active route session.
+ return (mLastDiscoveryPreference != null
+ && !mLastDiscoveryPreference.getPreferredFeatures().isEmpty())
+ || !getSessionInfos().isEmpty();
}
return false;
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 1114fe0d9bf8..31edf43679e9 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -16,6 +16,7 @@
package com.android.server.media;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
import static android.media.MediaRouter2Utils.getOriginalId;
import static android.media.MediaRouter2Utils.getProviderId;
@@ -73,10 +74,12 @@ class MediaRouter2ServiceImpl {
// TODO: (In Android S or later) if we add callback methods for generic failures
// in MediaRouter2, remove this constant and replace the usages with the real request IDs.
private static final long DUMMY_REQUEST_ID = -1;
+ private static final int PACKAGE_IMPORTANCE_FOR_DISCOVERY = IMPORTANCE_FOREGROUND;
private final Context mContext;
private final Object mLock = new Object();
final AtomicInteger mNextRouterOrManagerId = new AtomicInteger(1);
+ final ActivityManager mActivityManager;
@GuardedBy("mLock")
private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
@@ -87,8 +90,21 @@ class MediaRouter2ServiceImpl {
@GuardedBy("mLock")
private int mCurrentUserId = -1;
+ private final ActivityManager.OnUidImportanceListener mOnUidImportanceListener =
+ (uid, importance) -> {
+ synchronized (mLock) {
+ final int count = mUserRecords.size();
+ for (int i = 0; i < count; i++) {
+ mUserRecords.valueAt(i).mHandler.maybeUpdateDiscoveryPreferenceForUid(uid);
+ }
+ }
+ };
+
MediaRouter2ServiceImpl(Context context) {
mContext = context;
+ mActivityManager = mContext.getSystemService(ActivityManager.class);
+ mActivityManager.addOnUidImportanceListener(mOnUidImportanceListener,
+ PACKAGE_IMPORTANCE_FOR_DISCOVERY);
}
////////////////////////////////////////////////////////////////
@@ -388,6 +404,30 @@ class MediaRouter2ServiceImpl {
}
}
+ public void startScan(IMediaRouter2Manager manager) {
+ Objects.requireNonNull(manager, "manager must not be null");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ startScanLocked(manager);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ public void stopScan(IMediaRouter2Manager manager) {
+ Objects.requireNonNull(manager, "manager must not be null");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ stopScanLocked(manager);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
MediaRoute2Info route, int volume) {
Objects.requireNonNull(manager, "manager must not be null");
@@ -839,6 +879,24 @@ class MediaRouter2ServiceImpl {
disposeUserIfNeededLocked(userRecord); // since manager removed from user
}
+ private void startScanLocked(@NonNull IMediaRouter2Manager manager) {
+ final IBinder binder = manager.asBinder();
+ ManagerRecord managerRecord = mAllManagerRecords.get(binder);
+ if (managerRecord == null) {
+ return;
+ }
+ managerRecord.startScan();
+ }
+
+ private void stopScanLocked(@NonNull IMediaRouter2Manager manager) {
+ final IBinder binder = manager.asBinder();
+ ManagerRecord managerRecord = mAllManagerRecords.get(binder);
+ if (managerRecord == null) {
+ return;
+ }
+ managerRecord.stopScan();
+ }
+
private void setRouteVolumeWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager,
@NonNull MediaRoute2Info route, int volume) {
@@ -1122,6 +1180,7 @@ class MediaRouter2ServiceImpl {
public final String mPackageName;
public final int mManagerId;
public SessionCreationRequest mLastSessionCreationRequest;
+ public boolean mIsScanning;
ManagerRecord(UserRecord userRecord, IMediaRouter2Manager manager,
int uid, int pid, String packageName) {
@@ -1146,6 +1205,24 @@ class MediaRouter2ServiceImpl {
pw.println(prefix + this);
}
+ public void startScan() {
+ if (mIsScanning) {
+ return;
+ }
+ mIsScanning = true;
+ mUserRecord.mHandler.sendMessage(PooledLambda.obtainMessage(
+ UserHandler::updateDiscoveryPreferenceOnHandler, mUserRecord.mHandler));
+ }
+
+ public void stopScan() {
+ if (!mIsScanning) {
+ return;
+ }
+ mIsScanning = false;
+ mUserRecord.mHandler.sendMessage(PooledLambda.obtainMessage(
+ UserHandler::updateDiscoveryPreferenceOnHandler, mUserRecord.mHandler));
+ }
+
@Override
public String toString() {
return "Manager " + mPackageName + " (pid " + mPid + ")";
@@ -1262,6 +1339,24 @@ class MediaRouter2ServiceImpl {
return null;
}
+ public void maybeUpdateDiscoveryPreferenceForUid(int uid) {
+ MediaRouter2ServiceImpl service = mServiceRef.get();
+ if (service == null) {
+ return;
+ }
+ boolean isUidRelevant;
+ synchronized (service.mLock) {
+ isUidRelevant = mUserRecord.mRouterRecords.stream().anyMatch(
+ router -> router.mUid == uid)
+ | mUserRecord.mManagerRecords.stream().anyMatch(
+ manager -> manager.mUid == uid);
+ }
+ if (isUidRelevant) {
+ sendMessage(PooledLambda.obtainMessage(
+ UserHandler::updateDiscoveryPreferenceOnHandler, this));
+ }
+ }
+
private void onProviderStateChangedOnHandler(@NonNull MediaRoute2Provider provider) {
int providerInfoIndex = getLastProviderInfoIndex(provider.getUniqueId());
MediaRoute2ProviderInfo currentInfo = provider.getProviderInfo();
@@ -1767,6 +1862,16 @@ class MediaRouter2ServiceImpl {
return managers;
}
+ private List<RouterRecord> getRouterRecords() {
+ MediaRouter2ServiceImpl service = mServiceRef.get();
+ if (service == null) {
+ return Collections.emptyList();
+ }
+ synchronized (service.mLock) {
+ return new ArrayList<>(mUserRecord.mRouterRecords);
+ }
+ }
+
private List<ManagerRecord> getManagerRecords() {
MediaRouter2ServiceImpl service = mServiceRef.get();
if (service == null) {
@@ -2001,13 +2106,28 @@ class MediaRouter2ServiceImpl {
return;
}
List<RouteDiscoveryPreference> discoveryPreferences = new ArrayList<>();
- synchronized (service.mLock) {
- for (RouterRecord routerRecord : mUserRecord.mRouterRecords) {
+ List<RouterRecord> routerRecords = getRouterRecords();
+ List<ManagerRecord> managerRecords = getManagerRecords();
+ boolean isAnyManagerScanning =
+ managerRecords.stream().anyMatch(manager -> manager.mIsScanning
+ && service.mActivityManager.getPackageImportance(manager.mPackageName)
+ <= PACKAGE_IMPORTANCE_FOR_DISCOVERY);
+
+ for (RouterRecord routerRecord : routerRecords) {
+ if (isAnyManagerScanning
+ || service.mActivityManager.getPackageImportance(routerRecord.mPackageName)
+ <= PACKAGE_IMPORTANCE_FOR_DISCOVERY) {
discoveryPreferences.add(routerRecord.mDiscoveryPreference);
}
- mUserRecord.mCompositeDiscoveryPreference =
- new RouteDiscoveryPreference.Builder(discoveryPreferences)
- .build();
+ }
+
+ synchronized (service.mLock) {
+ RouteDiscoveryPreference newPreference =
+ new RouteDiscoveryPreference.Builder(discoveryPreferences).build();
+ if (newPreference.equals(mUserRecord.mCompositeDiscoveryPreference)) {
+ return;
+ }
+ mUserRecord.mCompositeDiscoveryPreference = newPreference;
}
for (MediaRoute2Provider provider : mRouteProviders) {
provider.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference);
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 0e52a67c8d39..b6d6cc48d0cd 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -544,6 +544,18 @@ public final class MediaRouterService extends IMediaRouterService.Stub
// Binder call
@Override
+ public void startScan(IMediaRouter2Manager manager) {
+ mService2.startScan(manager);
+ }
+
+ // Binder call
+ @Override
+ public void stopScan(IMediaRouter2Manager manager) {
+ mService2.stopScan(manager);
+ }
+
+ // Binder call
+ @Override
public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
MediaRoute2Info route, int volume) {
mService2.setRouteVolumeWithManager(manager, requestId, route, volume);
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index ea1d8da74185..ea2788c0c3d8 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -34,7 +34,6 @@ import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkInfo.State;
import android.os.Handler;
-import android.security.Credentials;
import android.security.KeyStore;
import android.text.TextUtils;
import android.util.Log;
@@ -70,6 +69,7 @@ public class LockdownVpnTracker {
@NonNull private final Handler mHandler;
@NonNull private final Vpn mVpn;
@NonNull private final VpnProfile mProfile;
+ @NonNull private final KeyStore mKeyStore;
@NonNull private final Object mStateLock = new Object();
@@ -81,13 +81,10 @@ public class LockdownVpnTracker {
private int mErrorCount;
- public static boolean isEnabled() {
- return KeyStore.getInstance().contains(Credentials.LOCKDOWN_VPN);
- }
-
public LockdownVpnTracker(@NonNull Context context,
@NonNull ConnectivityService connService,
@NonNull Handler handler,
+ @NonNull KeyStore keyStore,
@NonNull Vpn vpn,
@NonNull VpnProfile profile) {
mContext = Objects.requireNonNull(context);
@@ -95,6 +92,7 @@ public class LockdownVpnTracker {
mHandler = Objects.requireNonNull(handler);
mVpn = Objects.requireNonNull(vpn);
mProfile = Objects.requireNonNull(profile);
+ mKeyStore = Objects.requireNonNull(keyStore);
mNotificationManager = mContext.getSystemService(NotificationManager.class);
final Intent configIntent = new Intent(ACTION_VPN_SETTINGS);
@@ -157,7 +155,7 @@ public class LockdownVpnTracker {
try {
// Use the privileged method because Lockdown VPN is initiated by the system, so
// no additional permission checks are necessary.
- mVpn.startLegacyVpnPrivileged(mProfile, KeyStore.getInstance(), egressProp);
+ mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, egressProp);
} catch (IllegalStateException e) {
mAcceptedEgressIface = null;
Log.e(TAG, "Failed to start VPN", e);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index 141fa6a17873..f92f3dcd77ef 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
@@ -39,11 +39,6 @@ public abstract class NetworkPolicyManagerInternal {
public abstract void resetUserState(int userId);
/**
- * @return true if the given uid is restricted from doing networking on metered networks.
- */
- public abstract boolean isUidRestrictedOnMeteredNetworks(int uid);
-
- /**
* Figure out if networking is blocked for a given set of conditions.
*
* This is used by ConnectivityService via passing stale copies of conditions, so it must not
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 1c41dc073ac8..01d4faf5c594 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -5361,7 +5361,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
public boolean isUidNetworkingBlocked(int uid, boolean isNetworkMetered) {
final long startTime = mStatLogger.getTime();
- enforceAnyPermissionOf(OBSERVE_NETWORK_POLICY, PERMISSION_MAINLINE_NETWORK_STACK);
+ mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
final int uidRules;
final boolean isBackgroundRestricted;
synchronized (mUidRulesFirstLock) {
@@ -5376,6 +5376,23 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
return ret;
}
+ @Override
+ public boolean isUidRestrictedOnMeteredNetworks(int uid) {
+ mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
+ final int uidRules;
+ final boolean isBackgroundRestricted;
+ synchronized (mUidRulesFirstLock) {
+ uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
+ isBackgroundRestricted = mRestrictBackground;
+ }
+ //TODO(b/177490332): The logic here might not be correct because it doesn't consider
+ // RULE_REJECT_METERED condition. And it could be replaced by
+ // isUidNetworkingBlockedInternal().
+ return isBackgroundRestricted
+ && !hasRule(uidRules, RULE_ALLOW_METERED)
+ && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED);
+ }
+
private static boolean isSystem(int uid) {
return uid < Process.FIRST_APPLICATION_UID;
}
@@ -5444,22 +5461,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- /**
- * @return true if the given uid is restricted from doing networking on metered networks.
- */
- @Override
- public boolean isUidRestrictedOnMeteredNetworks(int uid) {
- final int uidRules;
- final boolean isBackgroundRestricted;
- synchronized (mUidRulesFirstLock) {
- uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
- isBackgroundRestricted = mRestrictBackground;
- }
- return isBackgroundRestricted
- && !hasRule(uidRules, RULE_ALLOW_METERED)
- && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED);
- }
-
@Override
public void onTempPowerSaveWhitelistChange(int appId, boolean added) {
synchronized (mUidRulesFirstLock) {
diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java
index e9868fde3059..d042b882fee1 100644
--- a/services/core/java/com/android/server/net/NetworkStatsFactory.java
+++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java
@@ -27,6 +27,7 @@ import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
import android.annotation.Nullable;
import android.net.INetd;
import android.net.NetworkStats;
+import android.net.UnderlyingNetworkInfo;
import android.net.util.NetdService;
import android.os.RemoteException;
import android.os.StrictMode;
@@ -34,7 +35,6 @@ import android.os.SystemClock;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.VpnInfo;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ProcFileReader;
@@ -81,7 +81,7 @@ public class NetworkStatsFactory {
private final Object mPersistentDataLock = new Object();
/** Set containing info about active VPNs and their underlying networks. */
- private volatile VpnInfo[] mVpnInfos = new VpnInfo[0];
+ private volatile UnderlyingNetworkInfo[] mUnderlyingNetworkInfos = new UnderlyingNetworkInfo[0];
// A persistent snapshot of cumulative stats since device start
@GuardedBy("mPersistentDataLock")
@@ -116,8 +116,8 @@ public class NetworkStatsFactory {
*
* @param vpnArray The snapshot of the currently-running VPNs.
*/
- public void updateVpnInfos(VpnInfo[] vpnArray) {
- mVpnInfos = vpnArray.clone();
+ public void updateUnderlyingNetworkInfos(UnderlyingNetworkInfo[] vpnArray) {
+ mUnderlyingNetworkInfos = vpnArray.clone();
}
/**
@@ -319,7 +319,7 @@ public class NetworkStatsFactory {
// code that will acquire other locks within the system server. See b/134244752.
synchronized (mPersistentDataLock) {
// Take a reference. If this gets swapped out, we still have the old reference.
- final VpnInfo[] vpnArray = mVpnInfos;
+ final UnderlyingNetworkInfo[] vpnArray = mUnderlyingNetworkInfos;
// Take a defensive copy. mPersistSnapshot is mutated in some cases below
final NetworkStats prev = mPersistSnapshot.clone();
@@ -369,8 +369,8 @@ public class NetworkStatsFactory {
}
@GuardedBy("mPersistentDataLock")
- private NetworkStats adjustForTunAnd464Xlat(
- NetworkStats uidDetailStats, NetworkStats previousStats, VpnInfo[] vpnArray) {
+ private NetworkStats adjustForTunAnd464Xlat(NetworkStats uidDetailStats,
+ NetworkStats previousStats, UnderlyingNetworkInfo[] vpnArray) {
// Calculate delta from last snapshot
final NetworkStats delta = uidDetailStats.subtract(previousStats);
@@ -381,8 +381,9 @@ public class NetworkStatsFactory {
delta.apply464xlatAdjustments(mStackedIfaces);
// Migrate data usage over a VPN to the TUN network.
- for (VpnInfo info : vpnArray) {
- delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces);
+ for (UnderlyingNetworkInfo info : vpnArray) {
+ delta.migrateTun(info.ownerUid, info.iface,
+ info.underlyingIfaces.toArray(new String[0]));
// Filter out debug entries as that may lead to over counting.
delta.filterDebugEntries();
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 81a6641de8a4..0ab35a911025 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -104,6 +104,7 @@ import android.net.NetworkStats.NonMonotonicObserver;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TrafficStats;
+import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
import android.net.netstats.provider.INetworkStatsProvider;
import android.net.netstats.provider.INetworkStatsProviderCallback;
@@ -143,7 +144,6 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.VpnInfo;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FileRotator;
@@ -973,7 +973,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
Network[] defaultNetworks,
NetworkState[] networkStates,
String activeIface,
- VpnInfo[] vpnInfos) {
+ UnderlyingNetworkInfo[] underlyingNetworkInfos) {
checkNetworkStackPermission(mContext);
final long token = Binder.clearCallingIdentity();
@@ -986,7 +986,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// Update the VPN underlying interfaces only after the poll is made and tun data has been
// migrated. Otherwise the migration would use the new interfaces instead of the ones that
// were current when the polled data was transferred.
- mStatsFactory.updateVpnInfos(vpnInfos);
+ mStatsFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
}
@Override
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 0f8c9c789a3f..fc5654144b3f 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -24,11 +24,15 @@ import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_REASON;
+import static android.content.om.OverlayManagerTransaction.Request.TYPE_SET_DISABLED;
+import static android.content.om.OverlayManagerTransaction.Request.TYPE_SET_ENABLED;
import static android.content.pm.PackageManager.SIGNATURE_MATCH;
import static android.os.Trace.TRACE_TAG_RRO;
import static android.os.Trace.traceBegin;
import static android.os.Trace.traceEnd;
+import static com.android.server.om.OverlayManagerServiceImpl.OperationFailedException;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -39,6 +43,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
+import android.content.om.OverlayManagerTransaction;
import android.content.om.OverlayableInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
@@ -48,6 +53,7 @@ import android.content.res.ApkAssets;
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -64,7 +70,6 @@ import android.util.SparseArray;
import com.android.internal.content.om.OverlayConfig;
import com.android.server.FgThread;
-import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
@@ -82,12 +87,15 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Consumer;
/**
* Service to manage asset overlays.
@@ -236,7 +244,14 @@ public final class OverlayManagerService extends SystemService {
private final OverlayActorEnforcer mActorEnforcer;
- private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false);
+ private final Consumer<PackageAndUser> mPropagateOverlayChange = (pair) -> {
+ persistSettings();
+ FgThread.getHandler().post(() -> {
+ List<String> affectedTargets = updatePackageManager(pair.packageName, pair.userId);
+ updateActivityManager(affectedTargets, pair.userId);
+ broadcastActionOverlayChanged(pair.packageName, pair.userId);
+ });
+ };
public OverlayManagerService(@NonNull final Context context) {
super(context);
@@ -249,17 +264,19 @@ public final class OverlayManagerService extends SystemService {
IdmapManager im = new IdmapManager(IdmapDaemon.getInstance(), mPackageManager);
mSettings = new OverlayManagerSettings();
mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
- OverlayConfig.getSystemInstance(), getDefaultOverlayPackages(),
- new OverlayChangeListener());
+ OverlayConfig.getSystemInstance(), getDefaultOverlayPackages());
mActorEnforcer = new OverlayActorEnforcer(mPackageManager);
+ HandlerThread packageReceiverThread = new HandlerThread(TAG);
+ packageReceiverThread.start();
+
final IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(ACTION_PACKAGE_ADDED);
packageFilter.addAction(ACTION_PACKAGE_CHANGED);
packageFilter.addAction(ACTION_PACKAGE_REMOVED);
packageFilter.addDataScheme("package");
getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
- packageFilter, null, null);
+ packageFilter, null, packageReceiverThread.getThreadHandler());
final IntentFilter userFilter = new IntentFilter();
userFilter.addAction(ACTION_USER_ADDED);
@@ -292,11 +309,11 @@ public final class OverlayManagerService extends SystemService {
for (int i = 0; i < userCount; i++) {
final UserInfo userInfo = users.get(i);
if (!userInfo.supportsSwitchTo() && userInfo.id != UserHandle.USER_SYSTEM) {
- // Initialize any users that can't be switched to, as there state would
+ // Initialize any users that can't be switched to, as their state would
// never be setup in onSwitchUser(). We will switch to the system user right
// after this, and its state will be setup there.
final List<String> targets = mImpl.updateOverlaysForUser(users.get(i).id);
- updateOverlayPaths(users.get(i).id, targets);
+ updatePackageManager(targets, users.get(i).id);
}
}
}
@@ -310,9 +327,10 @@ public final class OverlayManagerService extends SystemService {
// any asset changes to the rest of the system
synchronized (mLock) {
final List<String> targets = mImpl.updateOverlaysForUser(newUserId);
- updateAssets(newUserId, targets);
+ final List<String> affectedTargets = updatePackageManager(targets, newUserId);
+ updateActivityManager(affectedTargets, newUserId);
}
- schedulePersistSettings();
+ persistSettings();
} finally {
traceEnd(TRACE_TAG_RRO);
}
@@ -396,10 +414,17 @@ public final class OverlayManagerService extends SystemService {
false);
if (pi != null && !pi.applicationInfo.isInstantApp()) {
mPackageManager.cachePackageInfo(packageName, userId, pi);
- if (pi.isOverlayPackage()) {
- mImpl.onOverlayPackageAdded(packageName, userId);
- } else {
- mImpl.onTargetPackageAdded(packageName, userId);
+
+ try {
+ if (pi.isOverlayPackage()) {
+ mImpl.onOverlayPackageAdded(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ } else {
+ mImpl.onTargetPackageAdded(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ }
+ } catch (OperationFailedException e) {
+ Slog.e(TAG, "onPackageAdded internal error", e);
}
}
}
@@ -419,10 +444,17 @@ public final class OverlayManagerService extends SystemService {
false);
if (pi != null && pi.applicationInfo.isInstantApp()) {
mPackageManager.cachePackageInfo(packageName, userId, pi);
- if (pi.isOverlayPackage()) {
- mImpl.onOverlayPackageChanged(packageName, userId);
- } else {
- mImpl.onTargetPackageChanged(packageName, userId);
+
+ try {
+ if (pi.isOverlayPackage()) {
+ mImpl.onOverlayPackageChanged(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ } else {
+ mImpl.onTargetPackageChanged(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ }
+ } catch (OperationFailedException e) {
+ Slog.e(TAG, "onPackageChanged internal error", e);
}
}
}
@@ -441,7 +473,12 @@ public final class OverlayManagerService extends SystemService {
mPackageManager.forgetPackageInfo(packageName, userId);
final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
if (oi != null) {
- mImpl.onOverlayPackageReplacing(packageName, userId);
+ try {
+ mImpl.onOverlayPackageReplacing(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ } catch (OperationFailedException e) {
+ Slog.e(TAG, "onPackageReplacing internal error", e);
+ }
}
}
}
@@ -460,10 +497,16 @@ public final class OverlayManagerService extends SystemService {
false);
if (pi != null && !pi.applicationInfo.isInstantApp()) {
mPackageManager.cachePackageInfo(packageName, userId, pi);
- if (pi.isOverlayPackage()) {
- mImpl.onOverlayPackageReplaced(packageName, userId);
- } else {
- mImpl.onTargetPackageReplaced(packageName, userId);
+ try {
+ if (pi.isOverlayPackage()) {
+ mImpl.onOverlayPackageReplaced(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ } else {
+ mImpl.onTargetPackageReplaced(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ }
+ } catch (OperationFailedException e) {
+ Slog.e(TAG, "onPackageReplaced internal error", e);
}
}
}
@@ -481,10 +524,17 @@ public final class OverlayManagerService extends SystemService {
synchronized (mLock) {
mPackageManager.forgetPackageInfo(packageName, userId);
final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
- if (oi != null) {
- mImpl.onOverlayPackageRemoved(packageName, userId);
- } else {
- mImpl.onTargetPackageRemoved(packageName, userId);
+
+ try {
+ if (oi != null) {
+ mImpl.onOverlayPackageRemoved(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ } else {
+ mImpl.onTargetPackageRemoved(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ }
+ } catch (OperationFailedException e) {
+ Slog.e(TAG, "onPackageRemoved internal error", e);
}
}
}
@@ -507,7 +557,7 @@ public final class OverlayManagerService extends SystemService {
synchronized (mLock) {
targets = mImpl.updateOverlaysForUser(userId);
}
- updateOverlayPaths(userId, targets);
+ updatePackageManager(targets, userId);
} finally {
traceEnd(TRACE_TAG_RRO);
}
@@ -602,7 +652,13 @@ public final class OverlayManagerService extends SystemService {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- return mImpl.setEnabled(packageName, enable, realUserId);
+ try {
+ mImpl.setEnabled(packageName, enable, realUserId)
+ .ifPresent(mPropagateOverlayChange);
+ return true;
+ } catch (OperationFailedException e) {
+ return false;
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -627,8 +683,14 @@ public final class OverlayManagerService extends SystemService {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- return mImpl.setEnabledExclusive(packageName, false /* withinCategory */,
- realUserId);
+ try {
+ mImpl.setEnabledExclusive(packageName,
+ false /* withinCategory */, realUserId)
+ .ifPresent(mPropagateOverlayChange);
+ return true;
+ } catch (OperationFailedException e) {
+ return false;
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -654,8 +716,14 @@ public final class OverlayManagerService extends SystemService {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- return mImpl.setEnabledExclusive(packageName, true /* withinCategory */,
- realUserId);
+ try {
+ mImpl.setEnabledExclusive(packageName,
+ true /* withinCategory */, realUserId)
+ .ifPresent(mPropagateOverlayChange);
+ return true;
+ } catch (OperationFailedException e) {
+ return false;
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -681,7 +749,13 @@ public final class OverlayManagerService extends SystemService {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- return mImpl.setPriority(packageName, parentPackageName, realUserId);
+ try {
+ mImpl.setPriority(packageName, parentPackageName, realUserId)
+ .ifPresent(mPropagateOverlayChange);
+ return true;
+ } catch (OperationFailedException e) {
+ return false;
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -705,7 +779,13 @@ public final class OverlayManagerService extends SystemService {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- return mImpl.setHighestPriority(packageName, realUserId);
+ try {
+ mImpl.setHighestPriority(packageName, realUserId)
+ .ifPresent(mPropagateOverlayChange);
+ return true;
+ } catch (OperationFailedException e) {
+ return false;
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -729,7 +809,13 @@ public final class OverlayManagerService extends SystemService {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- return mImpl.setLowestPriority(packageName, realUserId);
+ try {
+ mImpl.setLowestPriority(packageName, realUserId)
+ .ifPresent(mPropagateOverlayChange);
+ return true;
+ } catch (OperationFailedException e) {
+ return false;
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -778,6 +864,129 @@ public final class OverlayManagerService extends SystemService {
}
@Override
+ public void commit(@NonNull final OverlayManagerTransaction transaction)
+ throws RemoteException {
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#commit " + transaction);
+ try {
+ executeAllRequests(transaction);
+ } catch (Exception e) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ restoreSettings();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ Slog.d(TAG, "commit failed: " + e.getMessage(), e);
+ throw new SecurityException("commit failed"
+ + (DEBUG ? ": " + e.getMessage() : ""));
+ }
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
+ }
+ }
+
+ private Optional<PackageAndUser> executeRequest(
+ @NonNull final OverlayManagerTransaction.Request request) throws Exception {
+ final int realUserId = handleIncomingUser(request.userId, request.typeToString());
+ enforceActor(request.packageName, request.typeToString(), realUserId);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ switch (request.type) {
+ case TYPE_SET_ENABLED:
+ Optional<PackageAndUser> opt1 =
+ mImpl.setEnabled(request.packageName, true, request.userId);
+ Optional<PackageAndUser> opt2 =
+ mImpl.setHighestPriority(request.packageName, request.userId);
+ // Both setEnabled and setHighestPriority affected the same
+ // target package and user: if both return non-empty
+ // Optionals, they are identical
+ return opt1.isPresent() ? opt1 : opt2;
+ case TYPE_SET_DISABLED:
+ return mImpl.setEnabled(request.packageName, false, request.userId);
+ default:
+ throw new IllegalArgumentException("unsupported request: " + request);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ private void executeAllRequests(@NonNull final OverlayManagerTransaction transaction)
+ throws Exception {
+ if (DEBUG) {
+ Slog.d(TAG, "commit " + transaction);
+ }
+ if (transaction == null) {
+ throw new IllegalArgumentException("null transaction");
+ }
+
+ // map: userId -> set<package-name>: target packages of overlays in
+ // this transaction
+ SparseArray<Set<String>> transactionTargets = new SparseArray<>();
+
+ // map: userId -> set<package-name>: packages that need to reload
+ // their resources due to changes to the overlays in this
+ // transaction
+ SparseArray<List<String>> affectedPackagesToUpdate = new SparseArray<>();
+
+ synchronized (mLock) {
+
+ // execute the requests (as calling user)
+ for (final OverlayManagerTransaction.Request request : transaction) {
+ executeRequest(request).ifPresent(target -> {
+ Set<String> userTargets = transactionTargets.get(target.userId);
+ if (userTargets == null) {
+ userTargets = new ArraySet<String>();
+ transactionTargets.put(target.userId, userTargets);
+ }
+ userTargets.add(target.packageName);
+ });
+ }
+
+ // past the point of no return: the entire transaction has been
+ // processed successfully, we can no longer fail: continue as
+ // system_server
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ persistSettings();
+
+ // inform the package manager about the new paths
+ for (int index = 0; index < transactionTargets.size(); index++) {
+ final int userId = transactionTargets.keyAt(index);
+ final List<String> affectedTargets =
+ updatePackageManager(transactionTargets.valueAt(index), userId);
+ affectedPackagesToUpdate.put(userId, affectedTargets);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ } // synchronized (mLock)
+
+ FgThread.getHandler().post(() -> {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ // schedule apps to refresh
+ for (int index = 0; index < affectedPackagesToUpdate.size(); index++) {
+ final int userId = affectedPackagesToUpdate.keyAt(index);
+ updateActivityManager(affectedPackagesToUpdate.valueAt(index), userId);
+ }
+
+ // broadcast the ACTION_OVERLAY_CHANGED intents
+ for (int index = 0; index < transactionTargets.size(); index++) {
+ final int userId = transactionTargets.keyAt(index);
+ for (String pkg: transactionTargets.valueAt(index)) {
+ broadcastActionOverlayChanged(pkg, userId);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ });
+ }
+
+ @Override
public void onShellCommand(@NonNull final FileDescriptor in,
@NonNull final FileDescriptor out, @NonNull final FileDescriptor err,
@NonNull final String[] args, @NonNull final ShellCallback callback,
@@ -898,162 +1107,7 @@ public final class OverlayManagerService extends SystemService {
}
};
- private final class OverlayChangeListener
- implements OverlayManagerServiceImpl.OverlayChangeListener {
- @Override
- public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
- schedulePersistSettings();
- FgThread.getHandler().post(() -> {
- updateAssets(userId, targetPackageName);
-
- final Intent intent = new Intent(ACTION_OVERLAY_CHANGED,
- Uri.fromParts("package", targetPackageName, null));
- intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-
- if (DEBUG) {
- Slog.d(TAG, "send broadcast " + intent);
- }
-
- try {
- ActivityManager.getService().broadcastIntentWithFeature(null, null, intent,
- null, null, 0, null, null, null, android.app.AppOpsManager.OP_NONE,
- null, false, false, userId);
- } catch (RemoteException e) {
- // Intentionally left empty.
- }
- });
- }
- }
-
- /**
- * Updates the target packages' set of enabled overlays in PackageManager.
- */
- private ArrayList<String> updateOverlayPaths(int userId, List<String> targetPackageNames) {
- try {
- traceBegin(TRACE_TAG_RRO, "OMS#updateOverlayPaths " + targetPackageNames);
- if (DEBUG) {
- Slog.d(TAG, "Updating overlay assets");
- }
- final PackageManagerInternal pm =
- LocalServices.getService(PackageManagerInternal.class);
- final boolean updateFrameworkRes = targetPackageNames.contains("android");
- if (updateFrameworkRes) {
- targetPackageNames = pm.getTargetPackageNames(userId);
- }
-
- final Map<String, List<String>> pendingChanges =
- new ArrayMap<>(targetPackageNames.size());
- synchronized (mLock) {
- final List<String> frameworkOverlays =
- mImpl.getEnabledOverlayPackageNames("android", userId);
- final int n = targetPackageNames.size();
- for (int i = 0; i < n; i++) {
- final String targetPackageName = targetPackageNames.get(i);
- List<String> list = new ArrayList<>();
- if (!"android".equals(targetPackageName)) {
- list.addAll(frameworkOverlays);
- }
- list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
- pendingChanges.put(targetPackageName, list);
- }
- }
-
- final HashSet<String> updatedPackages = new HashSet<>();
- final int n = targetPackageNames.size();
- for (int i = 0; i < n; i++) {
- final String targetPackageName = targetPackageNames.get(i);
- if (DEBUG) {
- Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
- + TextUtils.join(",", pendingChanges.get(targetPackageName))
- + "] userId=" + userId);
- }
-
- if (!pm.setEnabledOverlayPackages(
- userId, targetPackageName, pendingChanges.get(targetPackageName),
- updatedPackages)) {
- Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
- targetPackageName, userId));
- }
- }
- return new ArrayList<>(updatedPackages);
- } finally {
- traceEnd(TRACE_TAG_RRO);
- }
- }
-
- private void updateAssets(final int userId, final String targetPackageName) {
- updateAssets(userId, Collections.singletonList(targetPackageName));
- }
-
- private void updateAssets(final int userId, List<String> targetPackageNames) {
- final IActivityManager am = ActivityManager.getService();
- try {
- final ArrayList<String> updatedPaths = updateOverlayPaths(userId, targetPackageNames);
- am.scheduleApplicationInfoChanged(updatedPaths, userId);
- } catch (RemoteException e) {
- // Intentionally left empty.
- }
- }
-
- private void schedulePersistSettings() {
- if (mPersistSettingsScheduled.getAndSet(true)) {
- return;
- }
- IoThread.getHandler().post(() -> {
- mPersistSettingsScheduled.set(false);
- if (DEBUG) {
- Slog.d(TAG, "Writing overlay settings");
- }
- synchronized (mLock) {
- FileOutputStream stream = null;
- try {
- stream = mSettingsFile.startWrite();
- mSettings.persist(stream);
- mSettingsFile.finishWrite(stream);
- } catch (IOException | XmlPullParserException e) {
- mSettingsFile.failWrite(stream);
- Slog.e(TAG, "failed to persist overlay state", e);
- }
- }
- });
- }
-
- private void restoreSettings() {
- try {
- traceBegin(TRACE_TAG_RRO, "OMS#restoreSettings");
- synchronized (mLock) {
- if (!mSettingsFile.getBaseFile().exists()) {
- return;
- }
- try (FileInputStream stream = mSettingsFile.openRead()) {
- mSettings.restore(stream);
-
- // We might have data for dying users if the device was
- // restarted before we received USER_REMOVED. Remove data for
- // users that will not exist after the system is ready.
-
- final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
- final int[] liveUserIds = new int[liveUsers.size()];
- for (int i = 0; i < liveUsers.size(); i++) {
- liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
- }
- Arrays.sort(liveUserIds);
-
- for (int userId : mSettings.getUsers()) {
- if (Arrays.binarySearch(liveUserIds, userId) < 0) {
- mSettings.removeUser(userId);
- }
- }
- } catch (IOException | XmlPullParserException e) {
- Slog.e(TAG, "failed to restore overlay state", e);
- }
- }
- } finally {
- traceEnd(TRACE_TAG_RRO);
- }
- }
-
- private static final class PackageManagerHelperImpl implements PackageManagerHelper {
+ private static final class PackageManagerHelperImpl implements PackageManagerHelper {
private final Context mContext;
private final IPackageManager mPackageManager;
@@ -1263,4 +1317,144 @@ public final class OverlayManagerService extends SystemService {
}
}
}
+
+ // Helper methods to update other parts of the system or read/write
+ // settings: these methods should never call into each other!
+
+ private void broadcastActionOverlayChanged(@NonNull final String targetPackageName,
+ final int userId) {
+ final Intent intent = new Intent(ACTION_OVERLAY_CHANGED,
+ Uri.fromParts("package", targetPackageName, null));
+ intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ try {
+ ActivityManager.getService().broadcastIntent(null, intent, null, null, 0, null, null,
+ null, android.app.AppOpsManager.OP_NONE, null, false, false, userId);
+ } catch (RemoteException e) {
+ // Intentionally left empty.
+ }
+ }
+
+ /**
+ * Tell the activity manager to tell a set of packages to reload their
+ * resources.
+ */
+ private void updateActivityManager(List<String> targetPackageNames, final int userId) {
+ final IActivityManager am = ActivityManager.getService();
+ try {
+ am.scheduleApplicationInfoChanged(targetPackageNames, userId);
+ } catch (RemoteException e) {
+ // Intentionally left empty.
+ }
+ }
+
+ private ArrayList<String> updatePackageManager(String targetPackageNames, final int userId) {
+ return updatePackageManager(Collections.singletonList(targetPackageNames), userId);
+ }
+
+ /**
+ * Updates the target packages' set of enabled overlays in PackageManager.
+ * @return the package names of affected targets (a superset of
+ * targetPackageNames: the target themserlves and shared libraries)
+ */
+ private ArrayList<String> updatePackageManager(@NonNull Collection<String> targetPackageNames,
+ final int userId) {
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#updatePackageManager " + targetPackageNames);
+ if (DEBUG) {
+ Slog.d(TAG, "Update package manager about changed overlays");
+ }
+ final PackageManagerInternal pm =
+ LocalServices.getService(PackageManagerInternal.class);
+ final boolean updateFrameworkRes = targetPackageNames.contains("android");
+ if (updateFrameworkRes) {
+ targetPackageNames = pm.getTargetPackageNames(userId);
+ }
+
+ final Map<String, List<String>> pendingChanges =
+ new ArrayMap<>(targetPackageNames.size());
+ synchronized (mLock) {
+ final List<String> frameworkOverlays =
+ mImpl.getEnabledOverlayPackageNames("android", userId);
+ for (final String targetPackageName : targetPackageNames) {
+ List<String> list = new ArrayList<>();
+ if (!"android".equals(targetPackageName)) {
+ list.addAll(frameworkOverlays);
+ }
+ list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
+ pendingChanges.put(targetPackageName, list);
+ }
+ }
+
+ final HashSet<String> updatedPackages = new HashSet<>();
+ for (final String targetPackageName : targetPackageNames) {
+ if (DEBUG) {
+ Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
+ + TextUtils.join(",", pendingChanges.get(targetPackageName))
+ + "] userId=" + userId);
+ }
+
+ if (!pm.setEnabledOverlayPackages(
+ userId, targetPackageName, pendingChanges.get(targetPackageName),
+ updatedPackages)) {
+ Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
+ targetPackageName, userId));
+ }
+ }
+ return new ArrayList<>(updatedPackages);
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
+ }
+ }
+
+ private void persistSettings() {
+ if (DEBUG) {
+ Slog.d(TAG, "Writing overlay settings");
+ }
+ synchronized (mLock) {
+ FileOutputStream stream = null;
+ try {
+ stream = mSettingsFile.startWrite();
+ mSettings.persist(stream);
+ mSettingsFile.finishWrite(stream);
+ } catch (IOException | XmlPullParserException e) {
+ mSettingsFile.failWrite(stream);
+ Slog.e(TAG, "failed to persist overlay state", e);
+ }
+ }
+ }
+
+ private void restoreSettings() {
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#restoreSettings");
+ synchronized (mLock) {
+ if (!mSettingsFile.getBaseFile().exists()) {
+ return;
+ }
+ try (FileInputStream stream = mSettingsFile.openRead()) {
+ mSettings.restore(stream);
+
+ // We might have data for dying users if the device was
+ // restarted before we received USER_REMOVED. Remove data for
+ // users that will not exist after the system is ready.
+
+ final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
+ final int[] liveUserIds = new int[liveUsers.size()];
+ for (int i = 0; i < liveUsers.size(); i++) {
+ liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
+ }
+ Arrays.sort(liveUserIds);
+
+ for (int userId : mSettings.getUsers()) {
+ if (Arrays.binarySearch(liveUserIds, userId) < 0) {
+ mSettings.removeUser(userId);
+ }
+ }
+ } catch (IOException | XmlPullParserException e) {
+ Slog.e(TAG, "failed to restore overlay state", e);
+ }
+ }
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 05a4a38feef1..e60411bb78c5 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -45,6 +45,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
/**
@@ -71,7 +72,6 @@ final class OverlayManagerServiceImpl {
private final OverlayManagerSettings mSettings;
private final OverlayConfig mOverlayConfig;
private final String[] mDefaultOverlays;
- private final OverlayChangeListener mListener;
/**
* Helper method to merge the overlay manager's (as read from overlays.xml)
@@ -114,14 +114,12 @@ final class OverlayManagerServiceImpl {
@NonNull final IdmapManager idmapManager,
@NonNull final OverlayManagerSettings settings,
@NonNull final OverlayConfig overlayConfig,
- @NonNull final String[] defaultOverlays,
- @NonNull final OverlayChangeListener listener) {
+ @NonNull final String[] defaultOverlays) {
mPackageManager = packageManager;
mIdmapManager = idmapManager;
mSettings = settings;
mOverlayConfig = overlayConfig;
mDefaultOverlays = defaultOverlays;
- mListener = listener;
}
/**
@@ -259,52 +257,58 @@ final class OverlayManagerServiceImpl {
mSettings.removeUser(userId);
}
- void onTargetPackageAdded(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onTargetPackageAdded(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onTargetPackageAdded packageName=" + packageName + " userId=" + userId);
}
- updateAndRefreshOverlaysForTarget(packageName, userId, 0);
+ return updateAndRefreshOverlaysForTarget(packageName, userId, 0);
}
- void onTargetPackageChanged(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onTargetPackageChanged(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onTargetPackageChanged packageName=" + packageName + " userId=" + userId);
}
- updateAndRefreshOverlaysForTarget(packageName, userId, 0);
+ return updateAndRefreshOverlaysForTarget(packageName, userId, 0);
}
- void onTargetPackageReplacing(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onTargetPackageReplacing(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onTargetPackageReplacing packageName=" + packageName + " userId="
+ userId);
}
- updateAndRefreshOverlaysForTarget(packageName, userId, 0);
+ return updateAndRefreshOverlaysForTarget(packageName, userId, 0);
}
- void onTargetPackageReplaced(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onTargetPackageReplaced(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onTargetPackageReplaced packageName=" + packageName + " userId=" + userId);
}
- updateAndRefreshOverlaysForTarget(packageName, userId, 0);
+ return updateAndRefreshOverlaysForTarget(packageName, userId, 0);
}
- void onTargetPackageRemoved(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onTargetPackageRemoved(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onTargetPackageRemoved packageName=" + packageName + " userId=" + userId);
}
- updateAndRefreshOverlaysForTarget(packageName, userId, 0);
+ return updateAndRefreshOverlaysForTarget(packageName, userId, 0);
}
/**
* Update the state of any overlays for this target.
*/
- private void updateAndRefreshOverlaysForTarget(@NonNull final String targetPackageName,
- final int userId, final int flags) {
+ private Optional<PackageAndUser> updateAndRefreshOverlaysForTarget(
+ @NonNull final String targetPackageName, final int userId, final int flags)
+ throws OperationFailedException {
final List<OverlayInfo> targetOverlays = mSettings.getOverlaysForTarget(targetPackageName,
userId);
@@ -364,11 +368,13 @@ final class OverlayManagerServiceImpl {
}
if (modified) {
- mListener.onOverlaysChanged(targetPackageName, userId);
+ return Optional.of(new PackageAndUser(targetPackageName, userId));
}
+ return Optional.empty();
}
- void onOverlayPackageAdded(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onOverlayPackageAdded(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onOverlayPackageAdded packageName=" + packageName + " userId=" + userId);
}
@@ -376,8 +382,7 @@ final class OverlayManagerServiceImpl {
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null) {
Slog.w(TAG, "overlay package " + packageName + " was added, but couldn't be found");
- onOverlayPackageRemoved(packageName, userId);
- return;
+ return onOverlayPackageRemoved(packageName, userId);
}
mSettings.init(packageName, userId, overlayPackage.overlayTarget,
@@ -389,15 +394,17 @@ final class OverlayManagerServiceImpl {
overlayPackage.overlayCategory);
try {
if (updateState(overlayPackage.overlayTarget, packageName, userId, 0)) {
- mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
+ return Optional.of(new PackageAndUser(overlayPackage.overlayTarget, userId));
}
+ return Optional.empty();
} catch (OverlayManagerSettings.BadKeyException e) {
- Slog.e(TAG, "failed to update settings", e);
mSettings.remove(packageName, userId);
+ throw new OperationFailedException("failed to update settings", e);
}
}
- void onOverlayPackageChanged(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onOverlayPackageChanged(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onOverlayPackageChanged packageName=" + packageName + " userId=" + userId);
}
@@ -405,14 +412,16 @@ final class OverlayManagerServiceImpl {
try {
final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
if (updateState(oi.targetPackageName, packageName, userId, 0)) {
- mListener.onOverlaysChanged(oi.targetPackageName, userId);
+ return Optional.of(new PackageAndUser(oi.targetPackageName, userId));
}
+ return Optional.empty();
} catch (OverlayManagerSettings.BadKeyException e) {
- Slog.e(TAG, "failed to update settings", e);
+ throw new OperationFailedException("failed to update settings", e);
}
}
- void onOverlayPackageReplacing(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onOverlayPackageReplacing(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onOverlayPackageReplacing packageName=" + packageName + " userId="
+ userId);
@@ -423,14 +432,16 @@ final class OverlayManagerServiceImpl {
if (updateState(oi.targetPackageName, packageName, userId,
FLAG_OVERLAY_IS_BEING_REPLACED)) {
removeIdmapIfPossible(oi);
- mListener.onOverlaysChanged(oi.targetPackageName, userId);
+ return Optional.of(new PackageAndUser(oi.targetPackageName, userId));
}
+ return Optional.empty();
} catch (OverlayManagerSettings.BadKeyException e) {
- Slog.e(TAG, "failed to update settings", e);
+ throw new OperationFailedException("failed to update settings", e);
}
}
- void onOverlayPackageReplaced(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onOverlayPackageReplaced(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onOverlayPackageReplaced packageName=" + packageName + " userId="
+ userId);
@@ -439,16 +450,12 @@ final class OverlayManagerServiceImpl {
final PackageInfo pkg = mPackageManager.getPackageInfo(packageName, userId);
if (pkg == null) {
Slog.w(TAG, "overlay package " + packageName + " was replaced, but couldn't be found");
- onOverlayPackageRemoved(packageName, userId);
- return;
+ return onOverlayPackageRemoved(packageName, userId);
}
try {
final OverlayInfo oldOi = mSettings.getOverlayInfo(packageName, userId);
if (mustReinitializeOverlay(pkg, oldOi)) {
- if (oldOi != null && !oldOi.targetPackageName.equals(pkg.overlayTarget)) {
- mListener.onOverlaysChanged(pkg.overlayTarget, userId);
- }
mSettings.init(packageName, userId, pkg.overlayTarget, pkg.targetOverlayableName,
pkg.applicationInfo.getBaseCodePath(),
isPackageConfiguredMutable(pkg.packageName),
@@ -457,22 +464,25 @@ final class OverlayManagerServiceImpl {
}
if (updateState(pkg.overlayTarget, packageName, userId, 0)) {
- mListener.onOverlaysChanged(pkg.overlayTarget, userId);
+ return Optional.of(new PackageAndUser(pkg.overlayTarget, userId));
}
+ return Optional.empty();
} catch (OverlayManagerSettings.BadKeyException e) {
- Slog.e(TAG, "failed to update settings", e);
+ throw new OperationFailedException("failed to update settings", e);
}
}
- void onOverlayPackageRemoved(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onOverlayPackageRemoved(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
try {
final OverlayInfo overlayInfo = mSettings.getOverlayInfo(packageName, userId);
if (mSettings.remove(packageName, userId)) {
removeIdmapIfPossible(overlayInfo);
- mListener.onOverlaysChanged(overlayInfo.targetPackageName, userId);
+ return Optional.of(new PackageAndUser(overlayInfo.targetPackageName, userId));
}
+ return Optional.empty();
} catch (OverlayManagerSettings.BadKeyException e) {
- Slog.e(TAG, "failed to remove overlay", e);
+ throw new OperationFailedException("failed to remove overlay", e);
}
}
@@ -493,8 +503,8 @@ final class OverlayManagerServiceImpl {
return mSettings.getOverlaysForUser(userId);
}
- boolean setEnabled(@NonNull final String packageName, final boolean enable,
- final int userId) {
+ Optional<PackageAndUser> setEnabled(@NonNull final String packageName, final boolean enable,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, String.format("setEnabled packageName=%s enable=%s userId=%d",
packageName, enable, userId));
@@ -502,30 +512,33 @@ final class OverlayManagerServiceImpl {
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null) {
- return false;
+ throw new OperationFailedException(
+ String.format("failed to find overlay package %s for user %d",
+ packageName, userId));
}
try {
final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
if (!oi.isMutable) {
// Ignore immutable overlays.
- return false;
+ throw new OperationFailedException(
+ "cannot enable immutable overlay packages in runtime");
}
boolean modified = mSettings.setEnabled(packageName, userId, enable);
modified |= updateState(oi.targetPackageName, oi.packageName, userId, 0);
if (modified) {
- mListener.onOverlaysChanged(oi.targetPackageName, userId);
+ return Optional.of(new PackageAndUser(oi.targetPackageName, userId));
}
- return true;
+ return Optional.empty();
} catch (OverlayManagerSettings.BadKeyException e) {
- return false;
+ throw new OperationFailedException("failed to update settings", e);
}
}
- boolean setEnabledExclusive(@NonNull final String packageName, boolean withinCategory,
- final int userId) {
+ Optional<PackageAndUser> setEnabledExclusive(@NonNull final String packageName,
+ boolean withinCategory, final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, String.format("setEnabledExclusive packageName=%s"
+ " withinCategory=%s userId=%d", packageName, withinCategory, userId));
@@ -533,7 +546,8 @@ final class OverlayManagerServiceImpl {
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null) {
- return false;
+ throw new OperationFailedException(String.format(
+ "failed to find overlay package %s for user %d", packageName, userId));
}
try {
@@ -576,11 +590,11 @@ final class OverlayManagerServiceImpl {
modified |= updateState(targetPackageName, packageName, userId, 0);
if (modified) {
- mListener.onOverlaysChanged(targetPackageName, userId);
+ return Optional.of(new PackageAndUser(targetPackageName, userId));
}
- return true;
+ return Optional.empty();
} catch (OverlayManagerSettings.BadKeyException e) {
- return false;
+ throw new OperationFailedException("failed to update settings", e);
}
}
@@ -596,66 +610,75 @@ final class OverlayManagerServiceImpl {
return mOverlayConfig.isEnabled(packageName);
}
- boolean setPriority(@NonNull final String packageName,
- @NonNull final String newParentPackageName, final int userId) {
+ Optional<PackageAndUser> setPriority(@NonNull final String packageName,
+ @NonNull final String newParentPackageName, final int userId)
+ throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "setPriority packageName=" + packageName + " newParentPackageName="
+ newParentPackageName + " userId=" + userId);
}
if (!isPackageConfiguredMutable(packageName)) {
- return false;
+ throw new OperationFailedException(String.format(
+ "overlay package %s user %d is not updatable", packageName, userId));
}
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null) {
- return false;
+ throw new OperationFailedException(String.format(
+ "failed to find overlay package %s for user %d", packageName, userId));
}
if (mSettings.setPriority(packageName, newParentPackageName, userId)) {
- mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
+ return Optional.of(new PackageAndUser(overlayPackage.overlayTarget, userId));
}
- return true;
+ return Optional.empty();
}
- boolean setHighestPriority(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> setHighestPriority(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "setHighestPriority packageName=" + packageName + " userId=" + userId);
}
if (!isPackageConfiguredMutable(packageName)) {
- return false;
+ throw new OperationFailedException(String.format(
+ "overlay package %s user %d is not updatable", packageName, userId));
}
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null) {
- return false;
+ throw new OperationFailedException(String.format(
+ "failed to find overlay package %s for user %d", packageName, userId));
}
if (mSettings.setHighestPriority(packageName, userId)) {
- mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
+ return Optional.of(new PackageAndUser(overlayPackage.overlayTarget, userId));
}
- return true;
+ return Optional.empty();
}
- boolean setLowestPriority(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> setLowestPriority(@NonNull final String packageName, final int userId)
+ throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "setLowestPriority packageName=" + packageName + " userId=" + userId);
}
if (!isPackageConfiguredMutable(packageName)) {
- return false;
+ throw new OperationFailedException(String.format(
+ "overlay package %s user %d is not updatable", packageName, userId));
}
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null) {
- return false;
+ throw new OperationFailedException(String.format(
+ "failed to find overlay package %s for user %d", packageName, userId));
}
if (mSettings.setLowestPriority(packageName, userId)) {
- mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
+ return Optional.of(new PackageAndUser(overlayPackage.overlayTarget, userId));
}
- return true;
+ return Optional.empty();
}
void dump(@NonNull final PrintWriter pw, @NonNull DumpState dumpState) {
@@ -797,12 +820,13 @@ final class OverlayManagerServiceImpl {
mIdmapManager.removeIdmap(oi, oi.userId);
}
- interface OverlayChangeListener {
+ static final class OperationFailedException extends Exception {
+ OperationFailedException(@NonNull final String message) {
+ super(message);
+ }
- /**
- * An event triggered by changes made to overlay state or settings as well as changes that
- * add or remove target packages of overlays.
- **/
- void onOverlaysChanged(@NonNull String targetPackage, int userId);
+ OperationFailedException(@NonNull final String message, @NonNull Throwable cause) {
+ super(message, cause);
+ }
}
}
diff --git a/services/core/java/com/android/server/om/PackageAndUser.java b/services/core/java/com/android/server/om/PackageAndUser.java
new file mode 100644
index 000000000000..5c38ba7ce97b
--- /dev/null
+++ b/services/core/java/com/android/server/om/PackageAndUser.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.om;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+
+final class PackageAndUser {
+ public final @NonNull String packageName;
+ public final @UserIdInt int userId;
+
+ PackageAndUser(@NonNull String packageName, @UserIdInt int userId) {
+ this.packageName = packageName;
+ this.userId = userId;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof PackageAndUser)) {
+ return false;
+ }
+ PackageAndUser other = (PackageAndUser) obj;
+ return packageName.equals(other.packageName) && userId == other.userId;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + packageName.hashCode();
+ result = prime * result + userId;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("PackageAndUser{packageName=%s, userId=%d}", packageName, userId);
+ }
+}
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index dd507a3b1f81..4ff75fa06077 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -21,6 +21,7 @@ import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.BugreportParams;
@@ -31,6 +32,7 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserManager;
+import android.telephony.TelephonyManager;
import android.util.ArraySet;
import android.util.Slog;
@@ -53,11 +55,13 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
private final Object mLock = new Object();
private final Context mContext;
private final AppOpsManager mAppOps;
+ private final TelephonyManager mTelephonyManager;
private final ArraySet<String> mBugreportWhitelistedPackages;
BugreportManagerServiceImpl(Context context) {
mContext = context;
- mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ mAppOps = context.getSystemService(AppOpsManager.class);
+ mTelephonyManager = context.getSystemService(TelephonyManager.class);
mBugreportWhitelistedPackages =
SystemConfig.getInstance().getBugreportWhitelistedPackages();
}
@@ -67,11 +71,14 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
public void startBugreport(int callingUidUnused, String callingPackage,
FileDescriptor bugreportFd, FileDescriptor screenshotFd,
int bugreportMode, IDumpstateListener listener, boolean isScreenshotRequested) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "startBugreport");
Objects.requireNonNull(callingPackage);
Objects.requireNonNull(bugreportFd);
Objects.requireNonNull(listener);
validateBugreportMode(bugreportMode);
+
+ int callingUid = Binder.getCallingUid();
+ enforcePermission(callingPackage, callingUid, bugreportMode
+ == BugreportParams.BUGREPORT_MODE_TELEPHONY /* checkCarrierPrivileges */);
final long identity = Binder.clearCallingIdentity();
try {
ensureIsPrimaryUser();
@@ -79,13 +86,6 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
Binder.restoreCallingIdentity(identity);
}
- int callingUid = Binder.getCallingUid();
- mAppOps.checkPackage(callingUid, callingPackage);
-
- if (!mBugreportWhitelistedPackages.contains(callingPackage)) {
- throw new SecurityException(
- callingPackage + " is not whitelisted to use Bugreport API");
- }
synchronized (mLock) {
startBugreportLocked(callingUid, callingPackage, bugreportFd, screenshotFd,
bugreportMode, listener, isScreenshotRequested);
@@ -93,10 +93,11 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
}
@Override
- @RequiresPermission(android.Manifest.permission.DUMP)
- public void cancelBugreport() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
- "cancelBugreport");
+ @RequiresPermission(android.Manifest.permission.DUMP) // or carrier privileges
+ public void cancelBugreport(int callingUidUnused, String callingPackage) {
+ int callingUid = Binder.getCallingUid();
+ enforcePermission(callingPackage, callingUid, true /* checkCarrierPrivileges */);
+
synchronized (mLock) {
IDumpstate ds = getDumpstateBinderServiceLocked();
if (ds == null) {
@@ -104,7 +105,11 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
return;
}
try {
- ds.cancelBugreport();
+ // Note: this may throw SecurityException back out to the caller if they aren't
+ // allowed to cancel the report, in which case we should NOT be setting ctl.stop,
+ // since that would unintentionally kill some other app's bugreport, which we
+ // specifically disallow.
+ ds.cancelBugreport(callingUid, callingPackage);
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException in cancelBugreport", e);
}
@@ -127,6 +132,34 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
}
}
+ private void enforcePermission(
+ String callingPackage, int callingUid, boolean checkCarrierPrivileges) {
+ mAppOps.checkPackage(callingUid, callingPackage);
+
+ // To gain access through the DUMP permission, the OEM has to allow this package explicitly
+ // via sysconfig and privileged permissions.
+ if (mBugreportWhitelistedPackages.contains(callingPackage)
+ && mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ == PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+ // For carrier privileges, this can include user-installed apps. This is essentially a
+ // function of the current active SIM(s) in the device to let carrier apps through.
+ if (checkCarrierPrivileges
+ && mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(callingPackage)
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ return;
+ }
+
+ String message =
+ callingPackage
+ + " does not hold the DUMP permission or is not bugreport-whitelisted "
+ + (checkCarrierPrivileges ? "and does not have carrier privileges " : "")
+ + "to request a bugreport";
+ Slog.w(TAG, message);
+ throw new SecurityException(message);
+ }
+
/**
* Validates that the current user is the primary user.
*
@@ -182,7 +215,7 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
// lifecycle correctly. If we don't subsequent callers will get
// BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS error.
// Note that listener will be notified by the death recipient below.
- cancelBugreport();
+ cancelBugreport(callingUid, callingPackage);
}
}
@@ -303,6 +336,13 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
@Override
public void binderDied() {
+ try {
+ // Allow a small amount of time for any error or finished callbacks to be made.
+ // This ensures that the listener does not receive an erroneous runtime error
+ // callback.
+ Thread.sleep(1000);
+ } catch (InterruptedException ignored) {
+ }
synchronized (mLock) {
if (!mDone) {
// If we have not gotten a "done" callback this must be a crash.
diff --git a/services/core/java/com/android/server/pm/ModuleInfoProvider.java b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
index 06706cd06e11..0ffc1ed9e90c 100644
--- a/services/core/java/com/android/server/pm/ModuleInfoProvider.java
+++ b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
@@ -184,7 +184,7 @@ public class ModuleInfoProvider {
List<PackageInfo> allPackages;
try {
allPackages = mPackageManager.getInstalledPackages(
- flags | PackageManager.MATCH_APEX, UserHandle.USER_SYSTEM).getList();
+ flags | PackageManager.MATCH_APEX, UserHandle.getCallingUserId()).getList();
} catch (RemoteException e) {
Slog.w(TAG, "Unable to retrieve all package names", e);
return Collections.emptyList();
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index 5c01e43af5a9..fd2d8e1b834b 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.content.Context;
import android.content.IntentSender;
import android.content.pm.PackageManager;
+import android.hardware.boot.V1_0.IBootControl;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Binder;
@@ -73,6 +74,8 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb";
@VisibleForTesting
static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb";
+ @VisibleForTesting
+ static final String AB_UPDATE = "ro.build.ab_update";
private static final Object sRequestLock = new Object();
@@ -177,6 +180,25 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
return socket;
}
+ /**
+ * Throws remote exception if there's an error getting the boot control HAL.
+ * Returns null if the boot control HAL's version is older than V1_2.
+ */
+ public android.hardware.boot.V1_2.IBootControl getBootControl() throws RemoteException {
+ IBootControl bootControlV10 = IBootControl.getService(true);
+ if (bootControlV10 == null) {
+ throw new RemoteException("Failed to get boot control HAL V1_0.");
+ }
+
+ android.hardware.boot.V1_2.IBootControl bootControlV12 =
+ android.hardware.boot.V1_2.IBootControl.castFrom(bootControlV10);
+ if (bootControlV12 == null) {
+ Slog.w(TAG, "Device doesn't implement boot control HAL V1_2.");
+ return null;
+ }
+ return bootControlV12;
+ }
+
public void threadSleep(long millis) throws InterruptedException {
Thread.sleep(millis);
}
@@ -476,6 +498,56 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
return needClear ? ROR_REQUESTED_NEED_CLEAR : ROR_REQUESTED_SKIP_CLEAR;
}
+ private boolean isAbDevice() {
+ return "true".equalsIgnoreCase(mInjector.systemPropertiesGet(AB_UPDATE));
+ }
+
+ private boolean verifySlotForNextBoot(boolean slotSwitch) {
+ if (!isAbDevice()) {
+ Slog.w(TAG, "Device isn't a/b, skipping slot verification.");
+ return true;
+ }
+
+ android.hardware.boot.V1_2.IBootControl bootControl;
+ try {
+ bootControl = mInjector.getBootControl();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to get the boot control HAL " + e);
+ return false;
+ }
+
+ // TODO(xunchang) enforce boot control V1_2 HAL on devices using multi client RoR
+ if (bootControl == null) {
+ Slog.w(TAG, "Cannot get the boot control HAL, skipping slot verification.");
+ return true;
+ }
+
+ int current_slot;
+ int next_active_slot;
+ try {
+ current_slot = bootControl.getCurrentSlot();
+ if (current_slot != 0 && current_slot != 1) {
+ throw new IllegalStateException("Current boot slot should be 0 or 1, got "
+ + current_slot);
+ }
+ next_active_slot = bootControl.getActiveBootSlot();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to query the active slots", e);
+ return false;
+ }
+
+ int expected_active_slot = current_slot;
+ if (slotSwitch) {
+ expected_active_slot = current_slot == 0 ? 1 : 0;
+ }
+ if (next_active_slot != expected_active_slot) {
+ Slog.w(TAG, "The next active boot slot doesn't match the expected value, "
+ + "expected " + expected_active_slot + ", got " + next_active_slot);
+ return false;
+ }
+ return true;
+ }
+
private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) {
if (packageName == null) {
Slog.w(TAG, "Missing packageName when rebooting with lskf.");
@@ -485,7 +557,10 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
return false;
}
- // TODO(xunchang) check the slot to boot into, and fail the reboot upon slot mismatch.
+ if (!verifySlotForNextBoot(slotSwitch)) {
+ return false;
+ }
+
// TODO(xunchang) write the vbmeta digest along with the escrowKey before reboot.
if (!mInjector.getLockSettingsService().armRebootEscrow()) {
Slog.w(TAG, "Failure to escrow key for reboot");
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
index f20d80d57476..ae71c1a1e444 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
@@ -76,7 +76,7 @@ public class RecoverySystemShellCommand extends ShellCommand {
private int rebootAndApply() throws RemoteException {
String packageName = getNextArgRequired();
String rebootReason = getNextArgRequired();
- boolean success = mService.rebootWithLskf(packageName, rebootReason, true);
+ boolean success = mService.rebootWithLskf(packageName, rebootReason, false);
PrintWriter pw = getOutPrintWriter();
// Keep the old message for cts test.
pw.printf("%s Reboot and apply status: %s\n", packageName,
diff --git a/services/core/java/com/android/server/security/OWNERS b/services/core/java/com/android/server/security/OWNERS
new file mode 100644
index 000000000000..91b240bcb189
--- /dev/null
+++ b/services/core/java/com/android/server/security/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 36824
+
+per-file FileIntegrityService.java = victorhsieh@google.com
+per-file VerityUtils.java = victorhsieh@google.com
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index 0d059ae389e9..8345424712dd 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -361,7 +361,11 @@ public final class StorageSessionController {
}
}
+ private static boolean isSupportedVolume(VolumeInfo vol) {
+ return isEmulatedOrPublic(vol) || vol.type == VolumeInfo.TYPE_STUB;
+ }
+
private boolean shouldHandle(@Nullable VolumeInfo vol) {
- return mIsFuseEnabled && !mIsResetting && (vol == null || isEmulatedOrPublic(vol));
+ return mIsFuseEnabled && !mIsResetting && (vol == null || isSupportedVolume(vol));
}
}
diff --git a/services/core/java/com/android/server/textservices/OWNERS b/services/core/java/com/android/server/textservices/OWNERS
new file mode 100644
index 000000000000..9fa9b296706d
--- /dev/null
+++ b/services/core/java/com/android/server/textservices/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 816455
+
+include /services/core/java/com/android/server/inputmethod/OWNERS
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 25cd6416d9c8..75277d1c338d 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -53,6 +53,7 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.security.Authorization;
import android.security.KeyStore;
import android.service.trust.TrustAgentService;
import android.text.TextUtils;
@@ -185,6 +186,8 @@ public class TrustManagerService extends SystemService {
private boolean mTrustAgentsCanRun = false;
private int mCurrentUser = UserHandle.USER_SYSTEM;
+ private Authorization mAuthorizationService;
+
public TrustManagerService(Context context) {
super(context);
mContext = context;
@@ -194,6 +197,7 @@ public class TrustManagerService extends SystemService {
mStrongAuthTracker = new StrongAuthTracker(context);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mSettingsObserver = new SettingsObserver(mHandler);
+ mAuthorizationService = new Authorization();
}
@Override
@@ -696,11 +700,13 @@ public class TrustManagerService extends SystemService {
if (changed) {
dispatchDeviceLocked(userId, locked);
+ mAuthorizationService.onLockScreenEvent(locked, userId, null);
KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
// Also update the user's profiles who have unified challenge, since they
// share the same unlocked state (see {@link #isDeviceLocked(int)})
for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) {
if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(profileHandle)) {
+ mAuthorizationService.onLockScreenEvent(locked, profileHandle, null);
KeyStore.getInstance().onUserLockedStateChanged(profileHandle, locked);
}
}
@@ -1252,6 +1258,7 @@ public class TrustManagerService extends SystemService {
mDeviceLockedForUser.put(userId, locked);
}
+ mAuthorizationService.onLockScreenEvent(locked, userId, null);
KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
if (locked) {
diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java
index 42f12eb23d39..07725038255e 100644
--- a/services/core/java/com/android/server/tv/TvInputHal.java
+++ b/services/core/java/com/android/server/tv/TvInputHal.java
@@ -51,7 +51,8 @@ final class TvInputHal implements Handler.Callback {
public interface Callback {
void onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs);
void onDeviceUnavailable(int deviceId);
- void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs);
+ void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs,
+ int cableConnectionStatus);
void onFirstFrameCaptured(int deviceId, int streamId);
}
@@ -142,8 +143,9 @@ final class TvInputHal implements Handler.Callback {
mHandler.obtainMessage(EVENT_DEVICE_UNAVAILABLE, deviceId, 0).sendToTarget();
}
- private void streamConfigsChangedFromNative(int deviceId) {
- mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, 0).sendToTarget();
+ private void streamConfigsChangedFromNative(int deviceId, int cableConnectionStatus) {
+ mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId,
+ cableConnectionStatus).sendToTarget();
}
private void firstFrameCapturedFromNative(int deviceId, int streamId) {
@@ -184,6 +186,7 @@ final class TvInputHal implements Handler.Callback {
case EVENT_STREAM_CONFIGURATION_CHANGED: {
TvStreamConfig[] configs;
int deviceId = msg.arg1;
+ int cableConnectionStatus = msg.arg2;
synchronized (mLock) {
if (DEBUG) {
Slog.d(TAG, "EVENT_STREAM_CONFIGURATION_CHANGED: deviceId = " + deviceId);
@@ -191,7 +194,7 @@ final class TvInputHal implements Handler.Callback {
retrieveStreamConfigsLocked(deviceId);
configs = mStreamConfigs.get(deviceId);
}
- mCallback.onStreamConfigurationChanged(deviceId, configs);
+ mCallback.onStreamConfigurationChanged(deviceId, configs, cableConnectionStatus);
break;
}
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 2314afc787c3..3dfb99e5c0fc 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -156,6 +156,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
synchronized (mLock) {
Connection connection = new Connection(info);
connection.updateConfigsLocked(configs);
+ connection.updateCableConnectionStatusLocked(info.getCableConnectionStatus());
mConnections.put(info.getDeviceId(), connection);
buildHardwareListLocked();
mHandler.obtainMessage(
@@ -202,7 +203,8 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
@Override
- public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs) {
+ public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs,
+ int cableConnectionStatus) {
synchronized (mLock) {
Connection connection = mConnections.get(deviceId);
if (connection == null) {
@@ -211,12 +213,22 @@ class TvInputHardwareManager implements TvInputHal.Callback {
return;
}
int previousConfigsLength = connection.getConfigsLengthLocked();
+ int previousCableConnectionStatus = connection.getInputStateLocked();
connection.updateConfigsLocked(configs);
String inputId = mHardwareInputIdMap.get(deviceId);
- if (inputId != null
- && (previousConfigsLength == 0) != (connection.getConfigsLengthLocked() == 0)) {
- mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
- connection.getInputStateLocked(), 0, inputId).sendToTarget();
+ if (inputId != null) {
+ if (connection.updateCableConnectionStatusLocked(cableConnectionStatus)) {
+ if (previousCableConnectionStatus != connection.getInputStateLocked()) {
+ mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
+ connection.getInputStateLocked(), 0, inputId).sendToTarget();
+ }
+ } else {
+ if ((previousConfigsLength == 0)
+ != (connection.getConfigsLengthLocked() == 0)) {
+ mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
+ connection.getInputStateLocked(), 0, inputId).sendToTarget();
+ }
+ }
}
ITvInputHardwareCallback callback = connection.getCallbackLocked();
if (callback != null) {
@@ -624,7 +636,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
private class Connection implements IBinder.DeathRecipient {
- private final TvInputHardwareInfo mHardwareInfo;
+ private TvInputHardwareInfo mHardwareInfo;
private TvInputInfo mInfo;
private TvInputHardwareImpl mHardware = null;
private ITvInputHardwareCallback mCallback;
@@ -633,6 +645,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
private Integer mResolvedUserId = null;
private Runnable mOnFirstFrameCaptured;
private ResourceClientProfile mResourceClientProfile = null;
+ private boolean mIsCableConnectionStatusUpdated = false;
public Connection(TvInputHardwareInfo hardwareInfo) {
mHardwareInfo = hardwareInfo;
@@ -735,6 +748,17 @@ class TvInputHardwareManager implements TvInputHal.Callback {
+ " }";
}
+ public boolean updateCableConnectionStatusLocked(int cableConnectionStatus) {
+ // Update connection status only if it's not default value
+ if (cableConnectionStatus != TvInputHardwareInfo.CABLE_CONNECTION_STATUS_UNKNOWN
+ || mIsCableConnectionStatusUpdated) {
+ mIsCableConnectionStatusUpdated = true;
+ mHardwareInfo = mHardwareInfo.toBuilder()
+ .cableConnectionStatus(cableConnectionStatus).build();
+ }
+ return mIsCableConnectionStatusUpdated;
+ }
+
private int getConfigsLengthLocked() {
return mConfigs == null ? 0 : mConfigs.length;
}
@@ -742,7 +766,9 @@ class TvInputHardwareManager implements TvInputHal.Callback {
private int getInputStateLocked() {
int configsLength = getConfigsLengthLocked();
if (configsLength > 0) {
- return INPUT_STATE_CONNECTED;
+ if (!mIsCableConnectionStatusUpdated) {
+ return INPUT_STATE_CONNECTED;
+ }
}
switch (mHardwareInfo.getCableConnectionStatus()) {
case TvInputHardwareInfo.CABLE_CONNECTION_STATUS_CONNECTED:
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 6cd02581ee67..d858ae41cee8 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -20,6 +20,7 @@ import static android.media.AudioManager.DEVICE_NONE;
import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED;
import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED_STANDBY;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
@@ -1728,6 +1729,46 @@ public final class TvInputManagerService extends SystemService {
}
@Override
+ public void pauseRecording(IBinder sessionToken, @NonNull Bundle params, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "pauseRecording");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ getSessionLocked(sessionToken, callingUid, resolvedUserId)
+ .pauseRecording(params);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slog.e(TAG, "error in pauseRecording", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void resumeRecording(IBinder sessionToken, @NonNull Bundle params, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "resumeRecording");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ getSessionLocked(sessionToken, callingUid, resolvedUserId)
+ .resumeRecording(params);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slog.e(TAG, "error in resumeRecording", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public List<TvInputHardwareInfo> getHardwareList() throws RemoteException {
if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
!= PackageManager.PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index e1feb5aab869..6427ae2dc13c 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -24,6 +24,9 @@ import android.net.NetworkCapabilities;
import android.os.Handler;
import android.os.ParcelUuid;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+
import java.util.Objects;
/**
@@ -72,7 +75,8 @@ public class UnderlyingNetworkTracker extends Handler {
@NonNull public final LinkProperties linkProperties;
public final boolean blocked;
- private UnderlyingNetworkRecord(
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ UnderlyingNetworkRecord(
@NonNull Network network,
@NonNull NetworkCapabilities networkCapabilities,
@NonNull LinkProperties linkProperties,
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 7024e67a8204..703bfab6d868 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -24,7 +24,6 @@ import static com.android.server.VcnManagementService.VDBG;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.net.ConnectivityManager;
import android.net.InetAddresses;
import android.net.IpPrefix;
import android.net.IpSecManager;
@@ -36,8 +35,6 @@ import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
import android.net.RouteInfo;
import android.net.annotations.PolicyDirection;
import android.net.ipsec.ike.ChildSessionCallback;
@@ -54,7 +51,6 @@ import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.Message;
import android.os.ParcelUuid;
-import android.telephony.TelephonyManager;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -123,10 +119,12 @@ public class VcnGatewayConnection extends StateMachine {
private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST =
"Underlying Network lost";
private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel";
- private static final int TOKEN_ANY = Integer.MIN_VALUE;
+ private static final int TOKEN_ALL = Integer.MIN_VALUE;
private static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30;
- private static final int TEARDOWN_TIMEOUT_SECONDS = 5;
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final int TEARDOWN_TIMEOUT_SECONDS = 5;
private interface EventInfo {}
@@ -139,7 +137,7 @@ public class VcnGatewayConnection extends StateMachine {
*
* <p>In the Connected state, this MAY indicate a mobility even occurred.
*
- * @param arg1 The "any" token; this event is always applicable.
+ * @param arg1 The "all" token; this event is always applicable.
* @param obj @NonNull An EventUnderlyingNetworkChangedInfo instance with relevant data.
*/
private static final int EVENT_UNDERLYING_NETWORK_CHANGED = 1;
@@ -175,7 +173,7 @@ public class VcnGatewayConnection extends StateMachine {
* <p>Upon receipt of this signal, the state machine will transition from the Retry-timeout
* state to the Connecting state.
*
- * @param arg1 The "any" token; no sessions are active in the RetryTimeoutState.
+ * @param arg1 The "all" token; no sessions are active in the RetryTimeoutState.
*/
private static final int EVENT_RETRY_TIMEOUT_EXPIRED = 2;
@@ -318,7 +316,7 @@ public class VcnGatewayConnection extends StateMachine {
* <p>Upon receipt of this signal, the state machine MUST tear down all active sessions, cancel
* any pending work items, and move to the Disconnected state.
*
- * @param arg1 The "any" token; this signal is always honored.
+ * @param arg1 The "all" token; this signal is always honored.
* @param obj @NonNull An EventDisconnectRequestedInfo instance with relevant data.
*/
private static final int EVENT_DISCONNECT_REQUESTED = 7;
@@ -360,11 +358,25 @@ public class VcnGatewayConnection extends StateMachine {
*/
private static final int EVENT_TEARDOWN_TIMEOUT_EXPIRED = 8;
- @NonNull private final DisconnectedState mDisconnectedState = new DisconnectedState();
- @NonNull private final DisconnectingState mDisconnectingState = new DisconnectingState();
- @NonNull private final ConnectingState mConnectingState = new ConnectingState();
- @NonNull private final ConnectedState mConnectedState = new ConnectedState();
- @NonNull private final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState();
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ @NonNull
+ final DisconnectedState mDisconnectedState = new DisconnectedState();
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ @NonNull
+ final DisconnectingState mDisconnectingState = new DisconnectingState();
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ @NonNull
+ final ConnectingState mConnectingState = new ConnectingState();
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ @NonNull
+ final ConnectedState mConnectedState = new ConnectedState();
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ @NonNull
+ final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState();
@NonNull private final VcnContext mVcnContext;
@NonNull private final ParcelUuid mSubscriptionGroup;
@@ -403,13 +415,6 @@ public class VcnGatewayConnection extends StateMachine {
private int mCurrentToken = -1;
/**
- * The next usable token.
- *
- * <p>A new token MUST be used for all new IKE sessions.
- */
- private int mNextToken = 0;
-
- /**
* The number of unsuccessful attempts since the last successful connection.
*
* <p>This number MUST be incremented each time the RetryTimeout state is entered, and cleared
@@ -430,7 +435,7 @@ public class VcnGatewayConnection extends StateMachine {
* <p>Set in Connecting or Migrating States, always @NonNull in Connecting, Connected, and
* Migrating states, null otherwise.
*/
- private IkeSession mIkeSession;
+ private VcnIkeSession mIkeSession;
/**
* The last known child configuration.
@@ -455,7 +460,8 @@ public class VcnGatewayConnection extends StateMachine {
this(vcnContext, subscriptionGroup, connectionConfig, new Dependencies());
}
- private VcnGatewayConnection(
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ VcnGatewayConnection(
@NonNull VcnContext vcnContext,
@NonNull ParcelUuid subscriptionGroup,
@NonNull VcnGatewayConnectionConfig connectionConfig,
@@ -504,23 +510,25 @@ public class VcnGatewayConnection extends StateMachine {
* <p>Once torn down, this VcnTunnel CANNOT be started again.
*/
public void teardownAsynchronously() {
- mUnderlyingNetworkTracker.teardown();
-
- // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down.
- if (mTunnelIface != null) {
- mTunnelIface.close();
- }
-
sendMessage(
EVENT_DISCONNECT_REQUESTED,
- TOKEN_ANY,
+ TOKEN_ALL,
new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN));
- quit();
// TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this
// is also called asynchronously when a NetworkAgent becomes unwanted
}
+ @Override
+ protected void onQuitting() {
+ // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down.
+ if (mTunnelIface != null) {
+ mTunnelIface.close();
+ }
+
+ mUnderlyingNetworkTracker.teardown();
+ }
+
private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback {
@Override
public void onSelectedUnderlyingNetworkChanged(
@@ -530,26 +538,24 @@ public class VcnGatewayConnection extends StateMachine {
if (underlying == null) {
sendMessageDelayed(
EVENT_DISCONNECT_REQUESTED,
- TOKEN_ANY,
+ TOKEN_ALL,
new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST),
TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS));
- return;
- }
+ } else if (getHandler() != null) {
+ // Cancel any existing disconnect due to loss of underlying network
+ // getHandler() can return null if the state machine has already quit. Since this is
+ // called from other classes, this condition must be verified.
- // Cancel any existing disconnect due to loss of underlying network
- // getHandler() can return null if the state machine has already quit. Since this is
- // called
- // from other classes, this condition must be verified.
- if (getHandler() != null) {
getHandler()
.removeEqualMessages(
EVENT_DISCONNECT_REQUESTED,
new EventDisconnectRequestedInfo(
DISCONNECT_REASON_UNDERLYING_NETWORK_LOST));
}
+
sendMessage(
EVENT_UNDERLYING_NETWORK_CHANGED,
- TOKEN_ANY,
+ TOKEN_ALL,
new EventUnderlyingNetworkChangedInfo(underlying));
}
}
@@ -594,10 +600,112 @@ public class VcnGatewayConnection extends StateMachine {
}
private abstract class BaseState extends State {
+ @Override
+ public void enter() {
+ try {
+ enterState();
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Uncaught exception", e);
+ sendMessage(
+ EVENT_DISCONNECT_REQUESTED,
+ TOKEN_ALL,
+ new EventDisconnectRequestedInfo(
+ DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
+ }
+ }
+
protected void enterState() throws Exception {}
+ /**
+ * Top-level processMessage with safeguards to prevent crashing the System Server on non-eng
+ * builds.
+ */
+ @Override
+ public boolean processMessage(Message msg) {
+ try {
+ processStateMsg(msg);
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Uncaught exception", e);
+ sendMessage(
+ EVENT_DISCONNECT_REQUESTED,
+ TOKEN_ALL,
+ new EventDisconnectRequestedInfo(
+ DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
+ }
+
+ return HANDLED;
+ }
+
protected abstract void processStateMsg(Message msg) throws Exception;
+
+ @Override
+ public void exit() {
+ try {
+ exitState();
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Uncaught exception", e);
+ sendMessage(
+ EVENT_DISCONNECT_REQUESTED,
+ TOKEN_ALL,
+ new EventDisconnectRequestedInfo(
+ DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
+ }
+ }
+
+ protected void exitState() throws Exception {}
+
+ protected void logUnhandledMessage(Message msg) {
+ // Log as unexpected all known messages, and log all else as unknown.
+ switch (msg.what) {
+ case EVENT_UNDERLYING_NETWORK_CHANGED: // Fallthrough
+ case EVENT_RETRY_TIMEOUT_EXPIRED: // Fallthrough
+ case EVENT_SESSION_LOST: // Fallthrough
+ case EVENT_SESSION_CLOSED: // Fallthrough
+ case EVENT_TRANSFORM_CREATED: // Fallthrough
+ case EVENT_SETUP_COMPLETED: // Fallthrough
+ case EVENT_DISCONNECT_REQUESTED: // Fallthrough
+ case EVENT_TEARDOWN_TIMEOUT_EXPIRED:
+ logUnexpectedEvent(msg.what);
+ break;
+ default:
+ logWtfUnknownEvent(msg.what);
+ break;
+ }
+ }
+
+ protected void teardownNetwork() {
+ if (mNetworkAgent != null) {
+ mNetworkAgent.unregister();
+ mNetworkAgent = null;
+ }
+ }
+
+ protected void handleDisconnectRequested(String msg) {
+ Slog.v(TAG, "Tearing down. Cause: " + msg);
+ mIsRunning = false;
+
+ teardownNetwork();
+
+ if (mIkeSession == null) {
+ // Already disconnected, go straight to DisconnectedState
+ transitionTo(mDisconnectedState);
+ } else {
+ // Still need to wait for full closure
+ transitionTo(mDisconnectingState);
+ }
+ }
+
+ protected void logUnexpectedEvent(int what) {
+ Slog.d(TAG, String.format(
+ "Unexpected event code %d in state %s", what, this.getClass().getSimpleName()));
+ }
+
+ protected void logWtfUnknownEvent(int what) {
+ Slog.wtf(TAG, String.format(
+ "Unknown event code %d in state %s", what, this.getClass().getSimpleName()));
+ }
}
+
/**
* State representing the a disconnected VCN tunnel.
*
@@ -605,10 +713,62 @@ public class VcnGatewayConnection extends StateMachine {
*/
private class DisconnectedState extends BaseState {
@Override
- protected void processStateMsg(Message msg) {}
+ protected void enterState() {
+ if (!mIsRunning) {
+ quitNow(); // Ignore all queued events; cleanup is complete.
+ }
+
+ if (mIkeSession != null || mNetworkAgent != null) {
+ Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState");
+ }
+ }
+
+ @Override
+ protected void processStateMsg(Message msg) {
+ switch (msg.what) {
+ case EVENT_UNDERLYING_NETWORK_CHANGED:
+ // First network found; start tunnel
+ mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
+
+ if (mUnderlying != null) {
+ transitionTo(mConnectingState);
+ }
+ break;
+ case EVENT_DISCONNECT_REQUESTED:
+ mIsRunning = false;
+
+ quitNow();
+ break;
+ default:
+ logUnhandledMessage(msg);
+ break;
+ }
+ }
}
- private abstract class ActiveBaseState extends BaseState {}
+ private abstract class ActiveBaseState extends BaseState {
+ /**
+ * Handles all incoming messages, discarding messages for previous networks.
+ *
+ * <p>States that handle mobility events may need to override this method to receive
+ * messages for all underlying networks.
+ */
+ @Override
+ public boolean processMessage(Message msg) {
+ final int token = msg.arg1;
+ // Only process if a valid token is presented.
+ if (isValidToken(token)) {
+ return super.processMessage(msg);
+ }
+
+ Slog.v(TAG, "Message called with obsolete token: " + token + "; what: " + msg.what);
+ return HANDLED;
+ }
+
+ protected boolean isValidToken(int token) {
+ return (token == TOKEN_ALL || token == mCurrentToken);
+ }
+ }
/**
* Transitive state representing a VCN that is tearing down an IKE session.
@@ -617,8 +777,91 @@ public class VcnGatewayConnection extends StateMachine {
* does not complete teardown in a timely fashion, it will be killed (forcibly closed).
*/
private class DisconnectingState extends ActiveBaseState {
+ /**
+ * Whether to skip the RetryTimeoutState and go straight to the ConnectingState.
+ *
+ * <p>This is used when an underlying network change triggered a restart on a new network.
+ *
+ * <p>Reset (to false) upon exit of the DisconnectingState.
+ */
+ private boolean mSkipRetryTimeout = false;
+
+ // TODO(b/178441390): Remove this in favor of resetting retry timers on UND_NET change.
+ public void setSkipRetryTimeout(boolean shouldSkip) {
+ mSkipRetryTimeout = shouldSkip;
+ }
+
@Override
- protected void processStateMsg(Message msg) {}
+ protected void enterState() throws Exception {
+ if (mIkeSession == null) {
+ Slog.wtf(TAG, "IKE session was already closed when entering Disconnecting state.");
+ sendMessage(EVENT_SESSION_CLOSED, mCurrentToken);
+ return;
+ }
+
+ // If underlying network has already been lost, save some time and just kill the session
+ if (mUnderlying == null) {
+ // Will trigger a EVENT_SESSION_CLOSED as IkeSession shuts down.
+ mIkeSession.kill();
+ return;
+ }
+
+ mIkeSession.close();
+ sendMessageDelayed(
+ EVENT_TEARDOWN_TIMEOUT_EXPIRED,
+ mCurrentToken,
+ TimeUnit.SECONDS.toMillis(TEARDOWN_TIMEOUT_SECONDS));
+ }
+
+ @Override
+ protected void processStateMsg(Message msg) {
+ switch (msg.what) {
+ case EVENT_UNDERLYING_NETWORK_CHANGED: // Fallthrough
+ mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
+
+ // If we received a new underlying network, continue.
+ if (mUnderlying != null) {
+ break;
+ }
+
+ // Fallthrough; no network exists to send IKE close session requests.
+ case EVENT_TEARDOWN_TIMEOUT_EXPIRED:
+ // Grace period ended. Kill session, triggering EVENT_SESSION_CLOSED
+ mIkeSession.kill();
+
+ break;
+ case EVENT_DISCONNECT_REQUESTED:
+ teardownNetwork();
+
+ String reason = ((EventDisconnectRequestedInfo) msg.obj).reason;
+ if (reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) {
+ // Will trigger EVENT_SESSION_CLOSED immediately.
+ mIkeSession.kill();
+ break;
+ }
+
+ // Otherwise we are already in the process of shutting down.
+ break;
+ case EVENT_SESSION_CLOSED:
+ mIkeSession = null;
+
+ if (mIsRunning && mUnderlying != null) {
+ transitionTo(mSkipRetryTimeout ? mConnectingState : mRetryTimeoutState);
+ } else {
+ teardownNetwork();
+ transitionTo(mDisconnectedState);
+ }
+ break;
+ default:
+ logUnhandledMessage(msg);
+ break;
+ }
+ }
+
+ @Override
+ protected void exitState() throws Exception {
+ mSkipRetryTimeout = false;
+ }
}
/**
@@ -629,7 +872,69 @@ public class VcnGatewayConnection extends StateMachine {
*/
private class ConnectingState extends ActiveBaseState {
@Override
- protected void processStateMsg(Message msg) {}
+ protected void enterState() {
+ if (mIkeSession != null) {
+ Slog.wtf(TAG, "ConnectingState entered with active session");
+
+ // Attempt to recover.
+ mIkeSession.kill();
+ mIkeSession = null;
+ }
+
+ mIkeSession = buildIkeSession();
+ }
+
+ @Override
+ protected void processStateMsg(Message msg) {
+ switch (msg.what) {
+ case EVENT_UNDERLYING_NETWORK_CHANGED:
+ final UnderlyingNetworkRecord oldUnderlying = mUnderlying;
+ mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
+
+ if (oldUnderlying == null) {
+ // This should never happen, but if it does, there's likely a nasty bug.
+ Slog.wtf(TAG, "Old underlying network was null in connected state. Bug?");
+ }
+
+ // If new underlying is null, all underlying networks have been lost; disconnect
+ if (mUnderlying == null) {
+ transitionTo(mDisconnectingState);
+ break;
+ }
+
+ if (oldUnderlying != null
+ && mUnderlying.network.equals(oldUnderlying.network)) {
+ break; // Only network properties have changed; continue connecting.
+ }
+ // Else, retry on the new network.
+
+ // Immediately come back to the ConnectingState (skip RetryTimeout, since this
+ // isn't a failure)
+ mDisconnectingState.setSkipRetryTimeout(true);
+
+ // fallthrough - disconnect, and retry on new network.
+ case EVENT_SESSION_LOST:
+ transitionTo(mDisconnectingState);
+ break;
+ case EVENT_SESSION_CLOSED:
+ deferMessage(msg);
+
+ transitionTo(mDisconnectingState);
+ break;
+ case EVENT_SETUP_COMPLETED: // fallthrough
+ case EVENT_TRANSFORM_CREATED:
+ // Child setup complete; move to ConnectedState for NetworkAgent registration
+ deferMessage(msg);
+ transitionTo(mConnectedState);
+ break;
+ case EVENT_DISCONNECT_REQUESTED:
+ handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
+ break;
+ default:
+ logUnhandledMessage(msg);
+ break;
+ }
+ }
}
private abstract class ConnectedStateBase extends ActiveBaseState {}
@@ -655,20 +960,6 @@ public class VcnGatewayConnection extends StateMachine {
protected void processStateMsg(Message msg) {}
}
- // TODO: Remove this when migrating to new NetworkAgent API
- private static NetworkInfo buildNetworkInfo(boolean isConnected) {
- NetworkInfo info =
- new NetworkInfo(
- ConnectivityManager.TYPE_MOBILE,
- TelephonyManager.NETWORK_TYPE_UNKNOWN,
- "MOBILE",
- "VCN");
- info.setDetailedState(
- isConnected ? DetailedState.CONNECTED : DetailedState.DISCONNECTED, null, null);
-
- return info;
- }
-
@VisibleForTesting(visibility = Visibility.PRIVATE)
static NetworkCapabilities buildNetworkCapabilities(
@NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) {
@@ -779,7 +1070,64 @@ public class VcnGatewayConnection extends StateMachine {
}
}
- /** External dependencies used by VcnGatewayConnection, for injection in tests. */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ UnderlyingNetworkTrackerCallback getUnderlyingNetworkTrackerCallback() {
+ return mUnderlyingNetworkTrackerCallback;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ UnderlyingNetworkRecord getUnderlyingNetwork() {
+ return mUnderlying;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ void setUnderlyingNetwork(@Nullable UnderlyingNetworkRecord record) {
+ mUnderlying = record;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ boolean isRunning() {
+ return mIsRunning;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ void setIsRunning(boolean isRunning) {
+ mIsRunning = isRunning;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ VcnIkeSession getIkeSession() {
+ return mIkeSession;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ void setIkeSession(@Nullable VcnIkeSession session) {
+ mIkeSession = session;
+ }
+
+ private IkeSessionParams buildIkeParams() {
+ // TODO: Implement this once IkeSessionParams is persisted
+ return null;
+ }
+
+ private ChildSessionParams buildChildParams() {
+ // TODO: Implement this once IkeSessionParams is persisted
+ return null;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ VcnIkeSession buildIkeSession() {
+ final int token = ++mCurrentToken;
+
+ return mDeps.newIkeSession(
+ mVcnContext,
+ buildIkeParams(),
+ buildChildParams(),
+ new IkeSessionCallbackImpl(token),
+ new ChildSessionCallbackImpl(token));
+ }
+
+ /** External dependencies used by VcnGatewayConnection, for injection in tests */
@VisibleForTesting(visibility = Visibility.PRIVATE)
public static class Dependencies {
/** Builds a new UnderlyingNetworkTracker. */
@@ -791,19 +1139,67 @@ public class VcnGatewayConnection extends StateMachine {
}
/** Builds a new IkeSession. */
- public IkeSession newIkeSession(
+ public VcnIkeSession newIkeSession(
VcnContext vcnContext,
IkeSessionParams ikeSessionParams,
ChildSessionParams childSessionParams,
IkeSessionCallback ikeSessionCallback,
ChildSessionCallback childSessionCallback) {
- return new IkeSession(
- vcnContext.getContext(),
+ return new VcnIkeSession(
+ vcnContext,
ikeSessionParams,
childSessionParams,
- new HandlerExecutor(new Handler(vcnContext.getLooper())),
ikeSessionCallback,
childSessionCallback);
}
}
+
+ /** Proxy implementation of IKE session, used for testing. */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static class VcnIkeSession {
+ private final IkeSession mImpl;
+
+ public VcnIkeSession(
+ VcnContext vcnContext,
+ IkeSessionParams ikeSessionParams,
+ ChildSessionParams childSessionParams,
+ IkeSessionCallback ikeSessionCallback,
+ ChildSessionCallback childSessionCallback) {
+ mImpl =
+ new IkeSession(
+ vcnContext.getContext(),
+ ikeSessionParams,
+ childSessionParams,
+ new HandlerExecutor(new Handler(vcnContext.getLooper())),
+ ikeSessionCallback,
+ childSessionCallback);
+ }
+
+ /** Creates a new IKE Child session. */
+ public void openChildSession(
+ @NonNull ChildSessionParams childSessionParams,
+ @NonNull ChildSessionCallback childSessionCallback) {
+ mImpl.openChildSession(childSessionParams, childSessionCallback);
+ }
+
+ /** Closes an IKE session as identified by the ChildSessionCallback. */
+ public void closeChildSession(@NonNull ChildSessionCallback childSessionCallback) {
+ mImpl.closeChildSession(childSessionCallback);
+ }
+
+ /** Gracefully closes this IKE Session, waiting for remote acknowledgement. */
+ public void close() {
+ mImpl.close();
+ }
+
+ /** Forcibly kills this IKE Session, without waiting for a closure confirmation. */
+ public void kill() {
+ mImpl.kill();
+ }
+
+ /** Sets the underlying network used by the IkeSession. */
+ public void setNetwork(@NonNull Network network) {
+ mImpl.setNetwork(network);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0542ef9b09a4..783037f6f171 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3306,9 +3306,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
final ActivityStack stack = r.getRootTask();
- final Task task = stack.getDisplayArea().createStack(stack.getWindowingMode(),
- stack.getActivityType(), !ON_TOP, ainfo, intent,
- false /* createdByOrganizer */);
+ final Task task = new ActivityStack(this, stack.getDisplayArea().getNextStackId(),
+ stack.getActivityType(), ainfo, intent, false /* createdByOrganizer */);
if (!mRecentTasks.addToBottom(task)) {
// The app has too many tasks already and we can't add any more
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 4e1a23416330..a5311f33eb36 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -261,7 +261,7 @@ public:
void onDeviceAvailable(const TvInputDeviceInfo& info);
void onDeviceUnavailable(int deviceId);
- void onStreamConfigurationsChanged(int deviceId);
+ void onStreamConfigurationsChanged(int deviceId, int cableConnectionStatus);
void onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded);
private:
@@ -519,7 +519,7 @@ void JTvInputHal::onDeviceUnavailable(int deviceId) {
deviceId);
}
-void JTvInputHal::onStreamConfigurationsChanged(int deviceId) {
+void JTvInputHal::onStreamConfigurationsChanged(int deviceId, int cableConnectionStatus) {
{
Mutex::Autolock autoLock(&mLock);
KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
@@ -529,10 +529,8 @@ void JTvInputHal::onStreamConfigurationsChanged(int deviceId) {
connections.clear();
}
JNIEnv* env = AndroidRuntime::getJNIEnv();
- env->CallVoidMethod(
- mThiz,
- gTvInputHalClassInfo.streamConfigsChanged,
- deviceId);
+ env->CallVoidMethod(mThiz, gTvInputHalClassInfo.streamConfigsChanged, deviceId,
+ cableConnectionStatus);
}
void JTvInputHal::onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded) {
@@ -572,7 +570,8 @@ void JTvInputHal::NotifyHandler::handleMessage(const Message& message) {
mHal->onDeviceUnavailable(mEvent.deviceInfo.deviceId);
} break;
case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED: {
- mHal->onStreamConfigurationsChanged(mEvent.deviceInfo.deviceId);
+ int cableConnectionStatus = static_cast<int>(mEvent.deviceInfo.cableConnectionStatus);
+ mHal->onStreamConfigurationsChanged(mEvent.deviceInfo.deviceId, cableConnectionStatus);
} break;
default:
ALOGE("Unrecognizable event");
@@ -688,9 +687,8 @@ int register_android_server_tv_TvInputHal(JNIEnv* env) {
"deviceAvailableFromNative", "(Landroid/media/tv/TvInputHardwareInfo;)V");
GET_METHOD_ID(
gTvInputHalClassInfo.deviceUnavailable, clazz, "deviceUnavailableFromNative", "(I)V");
- GET_METHOD_ID(
- gTvInputHalClassInfo.streamConfigsChanged, clazz,
- "streamConfigsChangedFromNative", "(I)V");
+ GET_METHOD_ID(gTvInputHalClassInfo.streamConfigsChanged, clazz,
+ "streamConfigsChangedFromNative", "(II)V");
GET_METHOD_ID(
gTvInputHalClassInfo.firstFrameCaptured, clazz,
"firstFrameCapturedFromNative", "(II)V");
diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp
index b7d6424450f3..3690afc1bc41 100644
--- a/services/core/xsd/Android.bp
+++ b/services/core/xsd/Android.bp
@@ -8,11 +8,19 @@ xsd_config {
xsd_config {
name: "platform-compat-config",
- srcs: ["platform-compat-config.xsd"],
- api_dir: "platform-compat-schema",
+ srcs: ["platform-compat/config/platform-compat-config.xsd"],
+ api_dir: "platform-compat/config/schema",
package_name: "com.android.server.compat.config",
}
+xsd_config {
+ name: "platform-compat-overrides",
+ srcs: ["platform-compat/overrides/platform-compat-overrides.xsd"],
+ api_dir: "platform-compat/overrides/schema",
+ package_name: "com.android.server.compat.overrides",
+ gen_writer: true,
+}
+
xsd_config {
name: "display-device-config",
diff --git a/services/core/xsd/platform-compat-schema/removed.txt b/services/core/xsd/platform-compat-schema/removed.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/services/core/xsd/platform-compat-schema/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/services/core/xsd/platform-compat-schema/OWNERS b/services/core/xsd/platform-compat/OWNERS
index f8c3520e9fa8..f8c3520e9fa8 100644
--- a/services/core/xsd/platform-compat-schema/OWNERS
+++ b/services/core/xsd/platform-compat/OWNERS
diff --git a/services/core/xsd/platform-compat-config.xsd b/services/core/xsd/platform-compat/config/platform-compat-config.xsd
index a62e2c385766..a62e2c385766 100644
--- a/services/core/xsd/platform-compat-config.xsd
+++ b/services/core/xsd/platform-compat/config/platform-compat-config.xsd
diff --git a/services/core/xsd/platform-compat-schema/current.txt b/services/core/xsd/platform-compat/config/schema/current.txt
index fb8bbefd8374..fb8bbefd8374 100644
--- a/services/core/xsd/platform-compat-schema/current.txt
+++ b/services/core/xsd/platform-compat/config/schema/current.txt
diff --git a/services/core/xsd/platform-compat-schema/last_current.txt b/services/core/xsd/platform-compat/config/schema/last_current.txt
index e69de29bb2d1..e69de29bb2d1 100644
--- a/services/core/xsd/platform-compat-schema/last_current.txt
+++ b/services/core/xsd/platform-compat/config/schema/last_current.txt
diff --git a/services/core/xsd/platform-compat-schema/last_removed.txt b/services/core/xsd/platform-compat/config/schema/last_removed.txt
index e69de29bb2d1..e69de29bb2d1 100644
--- a/services/core/xsd/platform-compat-schema/last_removed.txt
+++ b/services/core/xsd/platform-compat/config/schema/last_removed.txt
diff --git a/apex/permission/framework/api/removed.txt b/services/core/xsd/platform-compat/config/schema/removed.txt
index d802177e249b..d802177e249b 100644
--- a/apex/permission/framework/api/removed.txt
+++ b/services/core/xsd/platform-compat/config/schema/removed.txt
diff --git a/services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd b/services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd
new file mode 100644
index 000000000000..e27e1b8ca89d
--- /dev/null
+++ b/services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- This defines the format of the XML file used to store compat config overrides in
+ ~ /data/misc/appcompat/compat_framework_overrides.xml
+-->
+<xs:schema version="2.0" elementFormDefault="qualified"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+
+ <xs:complexType name="override-value">
+ <xs:attribute type="xs:string" name="packageName" use="required" />
+ <xs:attribute type="xs:boolean" name="enabled" use="required" />
+ </xs:complexType>
+
+ <xs:complexType name="change-overrides">
+ <xs:attribute type="xs:long" name="changeId" use="required"/>
+ <xs:element name="validated">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="override-value" type="override-value" maxOccurs="unbounded" minOccurs="0" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="deferred">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="override-value" type="override-value" maxOccurs="unbounded" minOccurs="0" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:complexType>
+
+ <xs:element name="overrides">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="change-overrides" type="change-overrides" maxOccurs="unbounded" minOccurs="0" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+</xs:schema>
diff --git a/services/core/xsd/platform-compat/overrides/schema/current.txt b/services/core/xsd/platform-compat/overrides/schema/current.txt
new file mode 100644
index 000000000000..08b82072747b
--- /dev/null
+++ b/services/core/xsd/platform-compat/overrides/schema/current.txt
@@ -0,0 +1,51 @@
+// Signature format: 2.0
+package com.android.server.compat.overrides {
+
+ public class ChangeOverrides {
+ ctor public ChangeOverrides();
+ method public long getChangeId();
+ method public com.android.server.compat.overrides.ChangeOverrides.Deferred getDeferred();
+ method public com.android.server.compat.overrides.ChangeOverrides.Validated getValidated();
+ method public void setChangeId(long);
+ method public void setDeferred(com.android.server.compat.overrides.ChangeOverrides.Deferred);
+ method public void setValidated(com.android.server.compat.overrides.ChangeOverrides.Validated);
+ }
+
+ public static class ChangeOverrides.Deferred {
+ ctor public ChangeOverrides.Deferred();
+ method public java.util.List<com.android.server.compat.overrides.OverrideValue> getOverrideValue();
+ }
+
+ public static class ChangeOverrides.Validated {
+ ctor public ChangeOverrides.Validated();
+ method public java.util.List<com.android.server.compat.overrides.OverrideValue> getOverrideValue();
+ }
+
+ public class OverrideValue {
+ ctor public OverrideValue();
+ method public boolean getEnabled();
+ method public String getPackageName();
+ method public void setEnabled(boolean);
+ method public void setPackageName(String);
+ }
+
+ public class Overrides {
+ ctor public Overrides();
+ method public java.util.List<com.android.server.compat.overrides.ChangeOverrides> getChangeOverrides();
+ }
+
+ public class XmlParser {
+ ctor public XmlParser();
+ method public static com.android.server.compat.overrides.Overrides read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+ public class XmlWriter implements java.io.Closeable {
+ ctor public XmlWriter(java.io.PrintWriter);
+ method public void close();
+ method public static void write(com.android.server.compat.overrides.XmlWriter, com.android.server.compat.overrides.Overrides) throws java.io.IOException;
+ }
+
+}
+
diff --git a/services/core/xsd/platform-compat/overrides/schema/last_current.txt b/services/core/xsd/platform-compat/overrides/schema/last_current.txt
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/services/core/xsd/platform-compat/overrides/schema/last_current.txt
diff --git a/services/core/xsd/platform-compat/overrides/schema/last_removed.txt b/services/core/xsd/platform-compat/overrides/schema/last_removed.txt
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/services/core/xsd/platform-compat/overrides/schema/last_removed.txt
diff --git a/apex/permission/service/api/removed.txt b/services/core/xsd/platform-compat/overrides/schema/removed.txt
index d802177e249b..d802177e249b 100644
--- a/apex/permission/service/api/removed.txt
+++ b/services/core/xsd/platform-compat/overrides/schema/removed.txt
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 516c64217177..6089a52ae0bb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -97,6 +97,7 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.ILockSettings;
import com.android.server.am.ActivityManagerService;
import com.android.server.appbinding.AppBindingService;
+import com.android.server.apphibernation.AppHibernationService;
import com.android.server.attention.AttentionManagerService;
import com.android.server.audio.AudioService;
import com.android.server.biometrics.AuthService;
@@ -220,6 +221,8 @@ public final class SystemServer {
"com.android.server.appwidget.AppWidgetService";
private static final String VOICE_RECOGNITION_MANAGER_SERVICE_CLASS =
"com.android.server.voiceinteraction.VoiceInteractionManagerService";
+ private static final String APP_HIBERNATION_SERVICE_CLASS =
+ "com.android.server.apphibernation.AppHibernationService";
private static final String PRINT_MANAGER_SERVICE_CLASS =
"com.android.server.print.PrintManagerService";
private static final String COMPANION_DEVICE_MANAGER_SERVICE_CLASS =
@@ -457,7 +460,7 @@ public final class SystemServer {
}
try {
- Thread.sleep(checkInterval);
+ Thread.sleep(checkInterval * 1000);
} catch (InterruptedException ex) {
continue;
}
@@ -1863,6 +1866,12 @@ public final class SystemServer {
mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS);
t.traceEnd();
+ if (AppHibernationService.isAppHibernationEnabled()) {
+ t.traceBegin("StartAppHibernationService");
+ mSystemServiceManager.startService(APP_HIBERNATION_SERVICE_CLASS);
+ t.traceEnd();
+ }
+
if (GestureLauncherService.isGestureLauncherEnabled(context.getResources())) {
t.traceBegin("StartGestureLauncher");
mSystemServiceManager.startService(GestureLauncherService.class);
diff --git a/services/searchui/OWNERS b/services/searchui/OWNERS
new file mode 100644
index 000000000000..92835c2b0626
--- /dev/null
+++ b/services/searchui/OWNERS
@@ -0,0 +1,2 @@
+hyunyoungs@google.com
+sfufa@google.com
diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
new file mode 100644
index 000000000000..d0370b6c25e9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2021 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.apphibernation;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.AdditionalAnswers.returnsArgAt;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.mockito.internal.verification.VerificationModeFactory.times;
+
+import android.app.IActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.UserInfo;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.os.UserManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.SystemService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link com.android.server.apphibernation.AppHibernationService}
+ */
+@SmallTest
+public final class AppHibernationServiceTest {
+ private static final String PACKAGE_SCHEME = "package";
+ private static final String PACKAGE_NAME_1 = "package1";
+ private static final String PACKAGE_NAME_2 = "package2";
+ private static final int USER_ID_1 = 1;
+ private static final int USER_ID_2 = 2;
+
+ private AppHibernationService mAppHibernationService;
+ private BroadcastReceiver mBroadcastReceiver;
+ @Mock
+ private Context mContext;
+ @Mock
+ private IPackageManager mIPackageManager;
+ @Mock
+ private IActivityManager mIActivityManager;
+ @Mock
+ private UserManager mUserManager;
+ @Captor
+ private ArgumentCaptor<BroadcastReceiver> mReceiverCaptor;
+
+ @Before
+ public void setUp() throws RemoteException {
+ MockitoAnnotations.initMocks(this);
+ doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt());
+
+ mAppHibernationService = new AppHibernationService(mContext, mIPackageManager,
+ mIActivityManager, mUserManager);
+
+ verify(mContext, times(2)).registerReceiver(mReceiverCaptor.capture(), any());
+ mBroadcastReceiver = mReceiverCaptor.getValue();
+
+ List<UserInfo> userList = new ArrayList<>();
+ userList.add(new UserInfo(USER_ID_1, "user 1", 0 /* flags */));
+ doReturn(userList).when(mUserManager).getUsers();
+
+ List<PackageInfo> userPackages = new ArrayList<>();
+ userPackages.add(makePackageInfo(PACKAGE_NAME_1));
+
+ doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager)
+ .getInstalledPackages(anyInt(), eq(USER_ID_1));
+
+ doAnswer(returnsArgAt(2)).when(mIActivityManager).handleIncomingUser(anyInt(), anyInt(),
+ anyInt(), anyBoolean(), anyBoolean(), any(), any());
+
+ mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+ }
+
+ @Test
+ public void testSetHibernating_packageIsHibernating() {
+ // WHEN we hibernate a package for a user
+ mAppHibernationService.setHibernating(PACKAGE_NAME_1, USER_ID_1, true);
+
+ // THEN the package is marked hibernating for the user
+ assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_1, USER_ID_1));
+ }
+
+ @Test
+ public void testSetHibernating_newPackageAdded_packageIsHibernating() {
+ // WHEN a new package is added and it is hibernated
+ Intent intent = new Intent(Intent.ACTION_PACKAGE_ADDED,
+ Uri.fromParts(PACKAGE_SCHEME, PACKAGE_NAME_2, null /* fragment */));
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_1);
+ mBroadcastReceiver.onReceive(mContext, intent);
+
+ mAppHibernationService.setHibernating(PACKAGE_NAME_2, USER_ID_1, true);
+
+ // THEN the new package is hibernated
+ assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_2, USER_ID_1));
+ }
+
+ @Test
+ public void testSetHibernating_newUserAdded_packageIsHibernating() throws RemoteException {
+ // WHEN a new user is added and a package from the user is hibernated
+ List<PackageInfo> userPackages = new ArrayList<>();
+ userPackages.add(makePackageInfo(PACKAGE_NAME_1));
+ doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager)
+ .getInstalledPackages(anyInt(), eq(USER_ID_2));
+ Intent intent = new Intent(Intent.ACTION_USER_ADDED);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_2);
+ mBroadcastReceiver.onReceive(mContext, intent);
+
+ mAppHibernationService.setHibernating(PACKAGE_NAME_1, USER_ID_2, true);
+
+ // THEN the new user's package is hibernated
+ assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_1, USER_ID_2));
+ }
+
+ @Test
+ public void testIsHibernating_packageReplaced_stillReturnsHibernating() {
+ // GIVEN a package is currently hibernated
+ mAppHibernationService.setHibernating(PACKAGE_NAME_1, USER_ID_1, true);
+
+ // WHEN the package is removed but marked as replacing
+ Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED,
+ Uri.fromParts(PACKAGE_SCHEME, PACKAGE_NAME_2, null /* fragment */));
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_1);
+ intent.putExtra(Intent.EXTRA_REPLACING, true);
+ mBroadcastReceiver.onReceive(mContext, intent);
+
+ // THEN the package is still hibernating
+ assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_1, USER_ID_1));
+ }
+
+ private static PackageInfo makePackageInfo(String packageName) {
+ PackageInfo pkg = new PackageInfo();
+ pkg.packageName = packageName;
+ return pkg;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index ac8dc341999a..a53ff9bc7fdc 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -44,6 +44,8 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import java.util.UUID;
@RunWith(AndroidJUnit4.class)
@@ -69,6 +71,10 @@ public class CompatConfigTest {
os.close();
}
+ private String readFile(File file) throws IOException {
+ return new String(Files.readAllBytes(Paths.get(file.toURI())));
+ }
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -499,4 +505,86 @@ public class CompatConfigTest {
assertThat(compatConfig.isChangeEnabled(1236L,
ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue();
}
+
+ @Test
+ public void testSaveOverrides() throws Exception {
+ File overridesFile = new File(createTempDir(), "overrides.xml");
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1L)
+ .addEnableSinceSdkChangeWithId(2, 2L)
+ .build();
+ compatConfig.forceNonDebuggableFinalForTest(true);
+ compatConfig.initOverrides(overridesFile);
+ when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName("foo.bar")
+ .debuggable()
+ .build());
+ when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt()))
+ .thenThrow(new NameNotFoundException());
+
+ compatConfig.addOverride(1L, "foo.bar", true);
+ compatConfig.addOverride(2L, "bar.baz", false);
+
+ assertThat(readFile(overridesFile)).isEqualTo("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ + "<overrides>\n"
+ + " <change-overrides changeId=\"1\">\n"
+ + " <validated>\n"
+ + " <override-value packageName=\"foo.bar\" enabled=\"true\">\n"
+ + " </override-value>\n"
+ + " </validated>\n"
+ + " <deferred>\n"
+ + " </deferred>\n"
+ + " </change-overrides>\n"
+ + " <change-overrides changeId=\"2\">\n"
+ + " <validated>\n"
+ + " </validated>\n"
+ + " <deferred>\n"
+ + " <override-value packageName=\"bar.baz\" enabled=\"false\">\n"
+ + " </override-value>\n"
+ + " </deferred>\n"
+ + " </change-overrides>\n"
+ + "</overrides>\n");
+ }
+
+ @Test
+ public void testLoadOverrides() throws Exception {
+ File tempDir = createTempDir();
+ File overridesFile = new File(tempDir, "overrides.xml");
+ // Change 1 is enabled for foo.bar (validated)
+ // Change 2 is disabled for bar.baz (deferred)
+ String xmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ + "<overrides>"
+ + "<change-overrides changeId=\"1\">"
+ + "<deferred/>"
+ + "<validated>"
+ + "<override-value packageName=\"foo.bar\" enabled=\"true\"/>"
+ + "</validated>"
+ + "</change-overrides>"
+ + "<change-overrides changeId=\"2\">"
+ + "<deferred>"
+ + "<override-value packageName=\"bar.baz\" enabled=\"false\"/>"
+ + "</deferred>"
+ + "<validated/>"
+ + "</change-overrides>"
+ + "</overrides>";
+ writeToFile(tempDir, "overrides.xml", xmlData);
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1L)
+ .addEnableSinceSdkChangeWithId(2, 2L)
+ .build();
+ compatConfig.forceNonDebuggableFinalForTest(true);
+ compatConfig.initOverrides(overridesFile);
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("foo.bar")
+ .debuggable()
+ .build();
+ when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
+ .thenReturn(applicationInfo);
+ when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt()))
+ .thenThrow(new NameNotFoundException());
+
+ assertThat(compatConfig.isChangeEnabled(1L, applicationInfo)).isTrue();
+ assertThat(compatConfig.willChangeBeEnabled(2L, "bar.baz")).isFalse();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 6786f6014f2d..5d06da78fe80 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -30,6 +30,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.PasswordMetrics.computeForPassword;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
+import static android.net.InetAddresses.parseNumericAddress;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
@@ -65,6 +66,8 @@ import static org.mockito.Mockito.when;
import static org.mockito.hamcrest.MockitoHamcrest.argThat;
import static org.testng.Assert.assertThrows;
+import static java.util.Collections.emptyList;
+
import android.Manifest.permission;
import android.app.Activity;
import android.app.AppOpsManager;
@@ -118,6 +121,8 @@ import org.mockito.internal.util.collections.Sets;
import org.mockito.stubbing.Answer;
import java.io.File;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -2246,6 +2251,48 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertThat(actualAccounts).containsExactlyElementsIn(expectedAccounts);
}
+ public void testGetProxyParameters() throws Exception {
+ assertThat(dpm.getProxyParameters(inetAddrProxy("192.0.2.1", 1234), emptyList()))
+ .isEqualTo(new Pair<>("192.0.2.1:1234", ""));
+ assertThat(dpm.getProxyParameters(inetAddrProxy("192.0.2.1", 1234),
+ listOf("one.example.com ", " two.example.com ")))
+ .isEqualTo(new Pair<>("192.0.2.1:1234", "one.example.com,two.example.com"));
+ assertThat(dpm.getProxyParameters(hostnameProxy("proxy.example.com", 1234), emptyList()))
+ .isEqualTo(new Pair<>("proxy.example.com:1234", ""));
+ assertThat(dpm.getProxyParameters(hostnameProxy("proxy.example.com", 1234),
+ listOf("excluded.example.com")))
+ .isEqualTo(new Pair<>("proxy.example.com:1234", "excluded.example.com"));
+
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ inetAddrProxy("192.0.2.1", 0), emptyList()));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("", 1234), emptyList()));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("", 0), emptyList()));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("invalid! hostname", 1234), emptyList()));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("proxy.example.com", 1234), listOf("invalid exclusion")));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("proxy.example.com", -1), emptyList()));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("proxy.example.com", 0xFFFF + 1), emptyList()));
+ }
+
+ private static Proxy inetAddrProxy(String inetAddr, int port) {
+ return new Proxy(
+ Proxy.Type.HTTP, new InetSocketAddress(parseNumericAddress(inetAddr), port));
+ }
+
+ private static Proxy hostnameProxy(String hostname, int port) {
+ return new Proxy(
+ Proxy.Type.HTTP, InetSocketAddress.createUnresolved(hostname, port));
+ }
+
+ private static List<String> listOf(String... args) {
+ return Arrays.asList(args);
+ }
+
public void testSetKeyguardDisabledFeaturesWithDO() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -5156,7 +5203,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Attempt to set to empty list (which means no listener is allowlisted)
mContext.binder.callingUid = adminUid;
assertFalse(dpms.setPermittedCrossProfileNotificationListeners(
- admin1, Collections.emptyList()));
+ admin1, emptyList()));
assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1));
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
@@ -5248,7 +5295,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Setting an empty allowlist - only system listeners allowed
mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
assertTrue(dpms.setPermittedCrossProfileNotificationListeners(
- admin1, Collections.emptyList()));
+ admin1, emptyList()));
assertEquals(0, dpms.getPermittedCrossProfileNotificationListeners(admin1).size());
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
@@ -5312,7 +5359,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// all allowed in primary profile
mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
assertTrue(dpms.setPermittedCrossProfileNotificationListeners(
- admin1, Collections.emptyList()));
+ admin1, emptyList()));
assertEquals(0, dpms.getPermittedCrossProfileNotificationListeners(admin1).size());
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index dd98c4b09b78..09dd3e3e50db 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -538,6 +538,15 @@ public class HdmiCecLocalDeviceAudioSystemTest {
}
@Test
+ public void setArcStatus() {
+ mHdmiCecLocalDeviceAudioSystem.setArcStatus(true);
+ assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isTrue();
+
+ mHdmiCecLocalDeviceAudioSystem.setArcStatus(false);
+ assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse();
+ }
+
+ @Test
@Ignore("b/151150320")
public void handleSystemAudioModeRequest_fromNonTV_tVNotSupport() {
HdmiCecMessage message =
diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/OWNERS b/services/tests/servicestests/src/com/android/server/location/timezone/OWNERS
deleted file mode 100644
index 28aff188dbd8..000000000000
--- a/services/tests/servicestests/src/com/android/server/location/timezone/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 847766
-nfuller@google.com
-include /core/java/android/app/timedetector/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
index 1581d9ac1811..691d174f55f8 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
@@ -82,6 +82,11 @@ public class LockSettingsStorageTestable extends LockSettingsStorage {
}
@Override
+ String getRebootEscrowServerBlob() {
+ return makeDirs(mStorageDir, super.getRebootEscrowServerBlob()).getAbsolutePath();
+ }
+
+ @Override
protected File getSyntheticPasswordDirectoryForUser(int userId) {
return makeDirs(mStorageDir, super.getSyntheticPasswordDirectoryForUser(
userId).getAbsolutePath());
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index f74e45b6e59b..a4ba4c86a8fd 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -26,6 +26,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
@@ -52,6 +53,7 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.widget.RebootEscrowListener;
+import com.android.server.locksettings.ResumeOnRebootServiceProvider.ResumeOnRebootServiceConnection;
import org.junit.Before;
import org.junit.Test;
@@ -92,6 +94,7 @@ public class RebootEscrowManagerTests {
private UserManager mUserManager;
private RebootEscrowManager.Callbacks mCallbacks;
private IRebootEscrow mRebootEscrow;
+ private ResumeOnRebootServiceConnection mServiceConnection;
private RebootEscrowKeyStoreManager mKeyStoreManager;
LockSettingsStorageTestable mStorage;
@@ -108,6 +111,7 @@ public class RebootEscrowManagerTests {
static class MockInjector extends RebootEscrowManager.Injector {
private final IRebootEscrow mRebootEscrow;
+ private final ResumeOnRebootServiceConnection mServiceConnection;
private final RebootEscrowProviderInterface mRebootEscrowProvider;
private final UserManager mUserManager;
private final MockableRebootEscrowInjected mInjected;
@@ -116,10 +120,11 @@ public class RebootEscrowManagerTests {
MockInjector(Context context, UserManager userManager,
IRebootEscrow rebootEscrow,
RebootEscrowKeyStoreManager keyStoreManager,
+ LockSettingsStorageTestable storage,
MockableRebootEscrowInjected injected) {
- super(context);
+ super(context, storage);
mRebootEscrow = rebootEscrow;
-
+ mServiceConnection = null;
RebootEscrowProviderHalImpl.Injector halInjector =
new RebootEscrowProviderHalImpl.Injector() {
@Override
@@ -133,6 +138,22 @@ public class RebootEscrowManagerTests {
mInjected = injected;
}
+ MockInjector(Context context, UserManager userManager,
+ ResumeOnRebootServiceConnection serviceConnection,
+ RebootEscrowKeyStoreManager keyStoreManager,
+ LockSettingsStorageTestable storage,
+ MockableRebootEscrowInjected injected) {
+ super(context, storage);
+ mServiceConnection = serviceConnection;
+ mRebootEscrow = null;
+ RebootEscrowProviderServerBasedImpl.Injector injector =
+ new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection);
+ mRebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(storage, injector);
+ mUserManager = userManager;
+ mKeyStoreManager = keyStoreManager;
+ mInjected = injected;
+ }
+
@Override
public UserManager getUserManager() {
return mUserManager;
@@ -165,6 +186,7 @@ public class RebootEscrowManagerTests {
mUserManager = mock(UserManager.class);
mCallbacks = mock(RebootEscrowManager.Callbacks.class);
mRebootEscrow = mock(IRebootEscrow.class);
+ mServiceConnection = mock(ResumeOnRebootServiceConnection.class);
mKeyStoreManager = mock(RebootEscrowKeyStoreManager.class);
mAesKey = new SecretKeySpec(TEST_AES_KEY, "AES");
@@ -186,7 +208,12 @@ public class RebootEscrowManagerTests {
when(mCallbacks.isUserSecure(SECURE_SECONDARY_USER_ID)).thenReturn(true);
mInjected = mock(MockableRebootEscrowInjected.class);
mService = new RebootEscrowManager(new MockInjector(mContext, mUserManager, mRebootEscrow,
- mKeyStoreManager, mInjected), mCallbacks, mStorage);
+ mKeyStoreManager, mStorage, mInjected), mCallbacks, mStorage);
+ }
+
+ private void setServerBasedRebootEscrowProvider() throws Exception {
+ mService = new RebootEscrowManager(new MockInjector(mContext, mUserManager,
+ mServiceConnection, mKeyStoreManager, mStorage, mInjected), mCallbacks, mStorage);
}
@Test
@@ -202,6 +229,19 @@ public class RebootEscrowManagerTests {
}
@Test
+ public void prepareRebootEscrowServerBased_Success() throws Exception {
+ setServerBasedRebootEscrowProvider();
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+ assertFalse(mStorage.hasRebootEscrowServerBlob());
+ }
+
+ @Test
public void prepareRebootEscrow_ClearCredentials_Success() throws Exception {
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
mService.setRebootEscrowListener(mockListener);
@@ -246,6 +286,28 @@ public class RebootEscrowManagerTests {
}
@Test
+ public void armServiceServerBased_Success() throws Exception {
+ setServerBasedRebootEscrowProvider();
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertTrue(mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+
+ assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
+ assertFalse(mStorage.hasRebootEscrow(NONSECURE_SECONDARY_USER_ID));
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+ }
+
+ @Test
public void armService_HalFailure_NonFatal() throws Exception {
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
mService.setRebootEscrowListener(mockListener);
@@ -346,6 +408,40 @@ public class RebootEscrowManagerTests {
}
@Test
+ public void loadRebootEscrowDataIfAvailable_ServerBased_Success() throws Exception {
+ setServerBasedRebootEscrowProvider();
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertTrue(mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture());
+
+ when(mServiceConnection.unwrap(any(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ mService.loadRebootEscrowDataIfAvailable();
+ verify(mServiceConnection).unwrap(any(), anyLong());
+ assertTrue(metricsSuccessCaptor.getValue());
+ verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
+ }
+
+ @Test
public void loadRebootEscrowDataIfAvailable_TooManyBootsInBetween_NoMetrics() throws Exception {
when(mInjected.getBootCount()).thenReturn(0);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java
new file mode 100644
index 000000000000..bc1e025dd99f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2021 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.locksettings;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.stubbing.Answer;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class RebootEscrowProviderServerBasedImplTests {
+ private SecretKey mKeyStoreEncryptionKey;
+ private RebootEscrowKey mRebootEscrowKey;
+ private ResumeOnRebootServiceProvider.ResumeOnRebootServiceConnection mServiceConnection;
+ private LockSettingsStorageTestable mStorage;
+ private RebootEscrowProviderServerBasedImpl mRebootEscrowProvider;
+ private Answer<byte[]> mFakeEncryption;
+
+ private static final byte[] TEST_AES_KEY = new byte[] {
+ 0x48, 0x19, 0x12, 0x54, 0x13, 0x13, 0x52, 0x31,
+ 0x44, 0x74, 0x61, 0x54, 0x29, 0x74, 0x37, 0x61,
+ 0x70, 0x70, 0x75, 0x25, 0x27, 0x31, 0x49, 0x09,
+ 0x26, 0x52, 0x72, 0x63, 0x63, 0x61, 0x78, 0x23,
+ };
+
+ @Before
+ public void setUp() throws Exception {
+ mKeyStoreEncryptionKey = new SecretKeySpec(TEST_AES_KEY, "AES");
+ mRebootEscrowKey = RebootEscrowKey.generate();
+ mServiceConnection = mock(
+ ResumeOnRebootServiceProvider.ResumeOnRebootServiceConnection.class);
+
+ Context context = new ContextWrapper(InstrumentationRegistry.getContext());
+ mStorage = new LockSettingsStorageTestable(context,
+ new File(InstrumentationRegistry.getContext().getFilesDir(), "locksettings"));
+ mRebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(mStorage,
+ new RebootEscrowProviderServerBasedImpl.Injector(mServiceConnection));
+
+ mFakeEncryption = invocation -> {
+ byte[] secret = invocation.getArgument(0);
+ for (int i = 0; i < secret.length; i++) {
+ secret[i] = (byte) (secret[i] ^ 0xf);
+ }
+ return secret;
+ };
+ }
+
+ @Test
+ public void getAndClearRebootEscrowKey_loopback_success() throws Exception {
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong())).thenAnswer(mFakeEncryption);
+ when(mServiceConnection.unwrap(any(), anyLong())).thenAnswer(mFakeEncryption);
+
+ assertTrue(mRebootEscrowProvider.hasRebootEscrowSupport());
+ mRebootEscrowProvider.storeRebootEscrowKey(mRebootEscrowKey, mKeyStoreEncryptionKey);
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+
+ RebootEscrowKey ks = mRebootEscrowProvider.getAndClearRebootEscrowKey(
+ mKeyStoreEncryptionKey);
+ assertThat(ks.getKeyBytes(), is(mRebootEscrowKey.getKeyBytes()));
+ assertFalse(mStorage.hasRebootEscrowServerBlob());
+ }
+
+ @Test
+ public void getAndClearRebootEscrowKey_WrongDecryptionMethod_failure() throws Exception {
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong())).thenAnswer(mFakeEncryption);
+ when(mServiceConnection.unwrap(any(), anyLong())).thenAnswer(
+ invocation -> {
+ byte[] secret = invocation.getArgument(0);
+ for (int i = 0; i < secret.length; i++) {
+ secret[i] = (byte) (secret[i] ^ 0xe);
+ }
+ return secret;
+ }
+ );
+
+ assertTrue(mRebootEscrowProvider.hasRebootEscrowSupport());
+ mRebootEscrowProvider.storeRebootEscrowKey(mRebootEscrowKey, mKeyStoreEncryptionKey);
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // Expect to get wrong key bytes
+ RebootEscrowKey ks = mRebootEscrowProvider.getAndClearRebootEscrowKey(
+ mKeyStoreEncryptionKey);
+ assertNotEquals(ks.getKeyBytes(), mRebootEscrowKey.getKeyBytes());
+ assertFalse(mStorage.hasRebootEscrowServerBlob());
+ }
+
+ @Test
+ public void getAndClearRebootEscrowKey_ServiceConnectionException_failure() throws Exception {
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong())).thenAnswer(mFakeEncryption);
+ doThrow(IOException.class).when(mServiceConnection).unwrap(any(), anyLong());
+
+ assertTrue(mRebootEscrowProvider.hasRebootEscrowSupport());
+ mRebootEscrowProvider.storeRebootEscrowKey(mRebootEscrowKey, mKeyStoreEncryptionKey);
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // Expect to get null key bytes when the server service fails to unwrap the blob.
+ RebootEscrowKey ks = mRebootEscrowProvider.getAndClearRebootEscrowKey(
+ mKeyStoreEncryptionKey);
+ assertNull(ks);
+ assertFalse(mStorage.hasRebootEscrowServerBlob());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/ResumeOnRebootServiceProviderTests.java b/services/tests/servicestests/src/com/android/server/locksettings/ResumeOnRebootServiceProviderTests.java
new file mode 100644
index 000000000000..b9af82b64c02
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/ResumeOnRebootServiceProviderTests.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 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.locksettings;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.service.resumeonreboot.ResumeOnRebootService;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+
+@SmallTest
+@RunWith(JUnit4.class)
+public class ResumeOnRebootServiceProviderTests {
+
+ @Mock
+ Context mMockContext;
+ @Mock
+ PackageManager mMockPackageManager;
+ @Mock
+ ResolveInfo mMockResolvedInfo;
+ @Mock
+ ServiceInfo mMockServiceInfo;
+ @Mock
+ ComponentName mMockComponentName;
+ @Captor
+ ArgumentCaptor<Intent> mIntentArgumentCaptor;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mMockContext.getUserId()).thenReturn(0);
+ when(mMockResolvedInfo.serviceInfo).thenReturn(mMockServiceInfo);
+ when(mMockServiceInfo.getComponentName()).thenReturn(mMockComponentName);
+ }
+
+ @Test
+ public void noServiceFound() throws Exception {
+ when(mMockPackageManager.queryIntentServices(any(),
+ eq(PackageManager.MATCH_SYSTEM_ONLY))).thenReturn(
+ null);
+ assertThat(new ResumeOnRebootServiceProvider(mMockContext,
+ mMockPackageManager).getServiceConnection()).isNull();
+ }
+
+ @Test
+ public void serviceNotGuardedWithPermission() throws Exception {
+ ArrayList<ResolveInfo> resultList = new ArrayList<>();
+ when(mMockServiceInfo.permission).thenReturn("");
+ resultList.add(mMockResolvedInfo);
+ when(mMockPackageManager.queryIntentServices(any(), any())).thenReturn(
+ resultList);
+ assertThat(new ResumeOnRebootServiceProvider(mMockContext,
+ mMockPackageManager).getServiceConnection()).isNull();
+ }
+
+ @Test
+ public void serviceResolved() throws Exception {
+ ArrayList<ResolveInfo> resultList = new ArrayList<>();
+ resultList.add(mMockResolvedInfo);
+ when(mMockServiceInfo.permission).thenReturn(
+ Manifest.permission.BIND_RESUME_ON_REBOOT_SERVICE);
+ when(mMockPackageManager.queryIntentServices(any(),
+ eq(PackageManager.MATCH_SYSTEM_ONLY))).thenReturn(
+ resultList);
+
+ assertThat(new ResumeOnRebootServiceProvider(mMockContext,
+ mMockPackageManager).getServiceConnection()).isNotNull();
+
+ verify(mMockPackageManager).queryIntentServices(mIntentArgumentCaptor.capture(),
+ eq(PackageManager.MATCH_SYSTEM_ONLY));
+ assertThat(mIntentArgumentCaptor.getValue().getAction()).isEqualTo(
+ ResumeOnRebootService.SERVICE_INTERFACE);
+ }
+}
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 4db7ce2e6ef5..df19aeb13707 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -2051,6 +2051,7 @@ public class NetworkPolicyManagerServiceTest {
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_IFACE);
final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
+ networkCapabilities.setSSID(TEST_SSID);
return new NetworkState(info, prop, networkCapabilities, null, null, TEST_SSID);
}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
index 391611b72dab..5468fba59c10 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
@@ -78,7 +78,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
}
@Test
- public void testImmutableEnabledChange() {
+ public void testImmutableEnabledChange() throws Exception {
final OverlayManagerServiceImpl impl = getImpl();
installNewPackage(target(TARGET), USER);
installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -106,7 +106,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
}
@Test
- public void testMutableEnabledChangeHasNoEffect() {
+ public void testMutableEnabledChangeHasNoEffect() throws Exception {
final OverlayManagerServiceImpl impl = getImpl();
installNewPackage(target(TARGET), USER);
installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -134,7 +134,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
}
@Test
- public void testMutableEnabledToImmutableEnabled() {
+ public void testMutableEnabledToImmutableEnabled() throws Exception {
final OverlayManagerServiceImpl impl = getImpl();
installNewPackage(target(TARGET), USER);
installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -178,7 +178,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
}
@Test
- public void testMutablePriorityChange() {
+ public void testMutablePriorityChange() throws Exception {
final OverlayManagerServiceImpl impl = getImpl();
installNewPackage(target(TARGET), USER);
installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -218,7 +218,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
}
@Test
- public void testImmutablePriorityChange() {
+ public void testImmutablePriorityChange() throws Exception {
final OverlayManagerServiceImpl impl = getImpl();
installNewPackage(target(TARGET), USER);
installNewPackage(overlay(OVERLAY, TARGET), USER);
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
index 4f882ce13dd4..33dbcc0855be 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
@@ -22,11 +22,14 @@ import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
import static android.os.OverlayablePolicy.CONFIG_SIGNATURE;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.testng.Assert.assertThrows;
import android.content.om.OverlayInfo;
+import android.util.Pair;
import androidx.test.runner.AndroidJUnit4;
@@ -35,6 +38,7 @@ import org.junit.runner.RunWith;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
@RunWith(AndroidJUnit4.class)
public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTestsBase {
@@ -55,7 +59,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
private static final String CERT_CONFIG_NOK = "config_certificate_nok";
@Test
- public void testGetOverlayInfo() {
+ public void testGetOverlayInfo() throws Exception {
installNewPackage(overlay(OVERLAY, TARGET), USER);
final OverlayManagerServiceImpl impl = getImpl();
@@ -67,7 +71,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
}
@Test
- public void testGetOverlayInfosForTarget() {
+ public void testGetOverlayInfosForTarget() throws Exception {
installNewPackage(overlay(OVERLAY, TARGET), USER);
installNewPackage(overlay(OVERLAY2, TARGET), USER);
installNewPackage(overlay(OVERLAY3, TARGET), USER2);
@@ -92,7 +96,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
}
@Test
- public void testGetOverlayInfosForUser() {
+ public void testGetOverlayInfosForUser() throws Exception {
installNewPackage(target(TARGET), USER);
installNewPackage(overlay(OVERLAY, TARGET), USER);
installNewPackage(overlay(OVERLAY2, TARGET), USER);
@@ -119,7 +123,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
}
@Test
- public void testPriority() {
+ public void testPriority() throws Exception {
installNewPackage(overlay(OVERLAY, TARGET), USER);
installNewPackage(overlay(OVERLAY2, TARGET), USER);
installNewPackage(overlay(OVERLAY3, TARGET), USER);
@@ -131,18 +135,21 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
assertOverlayInfoForTarget(TARGET, USER, o1, o2, o3);
- assertTrue(impl.setLowestPriority(OVERLAY3, USER));
+ assertEquals(impl.setLowestPriority(OVERLAY3, USER),
+ Optional.of(new PackageAndUser(TARGET, USER)));
assertOverlayInfoForTarget(TARGET, USER, o3, o1, o2);
- assertTrue(impl.setHighestPriority(OVERLAY3, USER));
+ assertEquals(impl.setHighestPriority(OVERLAY3, USER),
+ Optional.of(new PackageAndUser(TARGET, USER)));
assertOverlayInfoForTarget(TARGET, USER, o1, o2, o3);
- assertTrue(impl.setPriority(OVERLAY, OVERLAY2, USER));
+ assertEquals(impl.setPriority(OVERLAY, OVERLAY2, USER),
+ Optional.of(new PackageAndUser(TARGET, USER)));
assertOverlayInfoForTarget(TARGET, USER, o2, o1, o3);
}
@Test
- public void testOverlayInfoStateTransitions() {
+ public void testOverlayInfoStateTransitions() throws Exception {
final OverlayManagerServiceImpl impl = getImpl();
assertNull(impl.getOverlayInfo(OVERLAY, USER));
@@ -153,7 +160,8 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
installNewPackage(target, USER);
assertState(STATE_DISABLED, OVERLAY, USER);
- impl.setEnabled(OVERLAY, true, USER);
+ assertEquals(impl.setEnabled(OVERLAY, true, USER),
+ Optional.of(new PackageAndUser(TARGET, USER)));
assertState(STATE_ENABLED, OVERLAY, USER);
// target upgrades do not change the state of the overlay
@@ -168,50 +176,40 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
}
@Test
- public void testOnOverlayPackageUpgraded() {
- final FakeListener listener = getListener();
+ public void testOnOverlayPackageUpgraded() throws Exception {
final FakeDeviceState.PackageBuilder target = target(TARGET);
final FakeDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET);
installNewPackage(target, USER);
installNewPackage(overlay, USER);
- listener.count = 0;
upgradePackage(overlay, USER);
- assertEquals(2, listener.count);
// upgrade to a version where the overlay has changed its target
- // expect once for the old target package, once for the new target package
- listener.count = 0;
final FakeDeviceState.PackageBuilder overlay2 = overlay(OVERLAY, "some.other.target");
- upgradePackage(overlay2, USER);
- assertEquals(3, listener.count);
-
- listener.count = 0;
- upgradePackage(overlay2, USER);
- assertEquals(2, listener.count);
+ final Pair<Optional<PackageAndUser>, Optional<PackageAndUser>> pair =
+ upgradePackage(overlay2, USER);
+ assertEquals(pair.first, Optional.of(new PackageAndUser(TARGET, USER)));
+ assertEquals(pair.second, Optional.of(new PackageAndUser("some.other.target", USER)));
}
@Test
- public void testListener() {
+ public void testSetEnabledAtVariousConditions() throws Exception {
final OverlayManagerServiceImpl impl = getImpl();
- final FakeListener listener = getListener();
- installNewPackage(overlay(OVERLAY, TARGET), USER);
- assertEquals(1, listener.count);
- listener.count = 0;
+ assertThrows(OverlayManagerServiceImpl.OperationFailedException.class,
+ () -> impl.setEnabled(OVERLAY, true, USER));
+ // request succeeded, and there was a change that needs to be
+ // propagated to the rest of the system
installNewPackage(target(TARGET), USER);
- assertEquals(1, listener.count);
- listener.count = 0;
-
- impl.setEnabled(OVERLAY, true, USER);
- assertEquals(1, listener.count);
- listener.count = 0;
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
+ assertEquals(impl.setEnabled(OVERLAY, true, USER),
+ Optional.of(new PackageAndUser(TARGET, USER)));
- impl.setEnabled(OVERLAY, true, USER);
- assertEquals(0, listener.count);
+ // request succeeded, but nothing changed
+ assertFalse(impl.setEnabled(OVERLAY, true, USER).isPresent());
}
@Test
- public void testConfigSignaturePolicyOk() {
+ public void testConfigSignaturePolicyOk() throws Exception {
setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
reinitializeImpl();
@@ -229,7 +227,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
}
@Test
- public void testConfigSignaturePolicyCertNok() {
+ public void testConfigSignaturePolicyCertNok() throws Exception {
setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
reinitializeImpl();
@@ -247,7 +245,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
}
@Test
- public void testConfigSignaturePolicyNoConfig() {
+ public void testConfigSignaturePolicyNoConfig() throws Exception {
addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
installNewPackage(target(TARGET), USER);
installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
@@ -262,7 +260,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
}
@Test
- public void testConfigSignaturePolicyNoRefPkg() {
+ public void testConfigSignaturePolicyNoRefPkg() throws Exception {
installNewPackage(target(TARGET), USER);
installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
@@ -276,7 +274,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
}
@Test
- public void testConfigSignaturePolicyRefPkgNotSystem() {
+ public void testConfigSignaturePolicyRefPkgNotSystem() throws Exception {
setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
reinitializeImpl();
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
index 006dda0f80e3..2c477c897b30 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
@@ -16,6 +16,8 @@
package com.android.server.om;
+import static com.android.server.om.OverlayManagerServiceImpl.OperationFailedException;
+
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
@@ -30,6 +32,7 @@ import android.content.pm.PackageInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Pair;
import androidx.annotation.Nullable;
@@ -43,13 +46,13 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.stream.Collectors;
/** Base class for creating {@link OverlayManagerServiceImplTests} tests. */
class OverlayManagerServiceImplTestsBase {
private OverlayManagerServiceImpl mImpl;
private FakeDeviceState mState;
- private FakeListener mListener;
private FakePackageManagerHelper mPackageManager;
private FakeIdmapDaemon mIdmapDaemon;
private OverlayConfig mOverlayConfig;
@@ -58,7 +61,6 @@ class OverlayManagerServiceImplTestsBase {
@Before
public void setUp() {
mState = new FakeDeviceState();
- mListener = new FakeListener();
mPackageManager = new FakePackageManagerHelper(mState);
mIdmapDaemon = new FakeIdmapDaemon(mState);
mOverlayConfig = mock(OverlayConfig.class);
@@ -73,18 +75,13 @@ class OverlayManagerServiceImplTestsBase {
new IdmapManager(mIdmapDaemon, mPackageManager),
new OverlayManagerSettings(),
mOverlayConfig,
- new String[0],
- mListener);
+ new String[0]);
}
OverlayManagerServiceImpl getImpl() {
return mImpl;
}
- FakeListener getListener() {
- return mListener;
- }
-
FakeIdmapDaemon getIdmapd() {
return mIdmapDaemon;
}
@@ -155,7 +152,8 @@ class OverlayManagerServiceImplTestsBase {
*
* @throws IllegalStateException if the package is currently installed
*/
- void installNewPackage(FakeDeviceState.PackageBuilder pkg, int userId) {
+ void installNewPackage(FakeDeviceState.PackageBuilder pkg, int userId)
+ throws OperationFailedException {
if (mState.select(pkg.packageName, userId) != null) {
throw new IllegalStateException("package " + pkg.packageName + " already installed");
}
@@ -176,23 +174,30 @@ class OverlayManagerServiceImplTestsBase {
* {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast with the
* {@link android.content.Intent#EXTRA_REPLACING} extra.
*
+ * @return the two Optional<PackageAndUser> objects from starting and finishing the upgrade
+ *
* @throws IllegalStateException if the package is not currently installed
*/
- void upgradePackage(FakeDeviceState.PackageBuilder pkg, int userId) {
+ Pair<Optional<PackageAndUser>, Optional<PackageAndUser>> upgradePackage(
+ FakeDeviceState.PackageBuilder pkg, int userId) throws OperationFailedException {
final FakeDeviceState.Package replacedPackage = mState.select(pkg.packageName, userId);
if (replacedPackage == null) {
throw new IllegalStateException("package " + pkg.packageName + " not installed");
}
+ Optional<PackageAndUser> opt1 = Optional.empty();
if (replacedPackage.targetPackageName != null) {
- mImpl.onOverlayPackageReplacing(pkg.packageName, userId);
+ opt1 = mImpl.onOverlayPackageReplacing(pkg.packageName, userId);
}
mState.add(pkg, userId);
+ Optional<PackageAndUser> opt2;
if (pkg.targetPackage == null) {
- mImpl.onTargetPackageReplaced(pkg.packageName, userId);
+ opt2 = mImpl.onTargetPackageReplaced(pkg.packageName, userId);
} else {
- mImpl.onOverlayPackageReplaced(pkg.packageName, userId);
+ opt2 = mImpl.onOverlayPackageReplaced(pkg.packageName, userId);
}
+
+ return Pair.create(opt1, opt2);
}
/**
@@ -203,7 +208,7 @@ class OverlayManagerServiceImplTestsBase {
*
* @throws IllegalStateException if the package is not currently installed
*/
- void uninstallPackage(String packageName, int userId) {
+ void uninstallPackage(String packageName, int userId) throws OperationFailedException {
final FakeDeviceState.Package pkg = mState.select(packageName, userId);
if (pkg == null) {
throw new IllegalStateException("package " + packageName+ " not installed");
@@ -485,12 +490,4 @@ class OverlayManagerServiceImplTestsBase {
}
}
}
-
- static class FakeListener implements OverlayManagerServiceImpl.OverlayChangeListener {
- public int count;
-
- public void onOverlaysChanged(@NonNull String targetPackage, int userId) {
- count++;
- }
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
index b07b8fa059d1..9b8a2a82c6df 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.IntentSender;
import android.content.pm.PackageManager;
+import android.hardware.boot.V1_2.IBootControl;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.IRecoverySystemProgressListener;
@@ -68,12 +69,13 @@ public class RecoverySystemServiceTest {
private IThermalService mIThermalService;
private FileWriter mUncryptUpdateFileWriter;
private LockSettingsInternal mLockSettingsInternal;
+ private IBootControl mIBootControl;
private static final String FAKE_OTA_PACKAGE_NAME = "fake.ota.package";
private static final String FAKE_OTHER_PACKAGE_NAME = "fake.other.package";
@Before
- public void setup() {
+ public void setup() throws Exception {
mContext = mock(Context.class);
mSystemProperties = new RecoverySystemServiceTestable.FakeSystemProperties();
mUncryptSocket = mock(RecoverySystemService.UncryptSocket.class);
@@ -88,8 +90,13 @@ public class RecoverySystemServiceTest {
PowerManager powerManager = new PowerManager(mock(Context.class), mIPowerManager,
mIThermalService, new Handler(looper));
+ mIBootControl = mock(IBootControl.class);
+ when(mIBootControl.getCurrentSlot()).thenReturn(0);
+ when(mIBootControl.getActiveBootSlot()).thenReturn(1);
+
mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties,
- powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal);
+ powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal,
+ mIBootControl);
}
@Test
@@ -332,6 +339,15 @@ public class RecoverySystemServiceTest {
verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
}
+
+ @Test
+ public void rebootWithLskf_slotMismatch_Failure() throws Exception {
+ assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true));
+ mRecoverySystemService.onPreparedForReboot(true);
+ assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", false),
+ is(false));
+ }
+
@Test
public void rebootWithLskf_withoutPrepare_Failure() throws Exception {
assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, null, true),
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
index 131e4f321a6c..0727e5adb9ca 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
@@ -17,6 +17,7 @@
package com.android.server.recoverysystem;
import android.content.Context;
+import android.hardware.boot.V1_2.IBootControl;
import android.os.PowerManager;
import com.android.internal.widget.LockSettingsInternal;
@@ -30,16 +31,19 @@ public class RecoverySystemServiceTestable extends RecoverySystemService {
private final FileWriter mUncryptPackageFileWriter;
private final UncryptSocket mUncryptSocket;
private final LockSettingsInternal mLockSettingsInternal;
+ private final IBootControl mIBootControl;
MockInjector(Context context, FakeSystemProperties systemProperties,
PowerManager powerManager, FileWriter uncryptPackageFileWriter,
- UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal) {
+ UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal,
+ IBootControl bootControl) {
super(context);
mSystemProperties = systemProperties;
mPowerManager = powerManager;
mUncryptPackageFileWriter = uncryptPackageFileWriter;
mUncryptSocket = uncryptSocket;
mLockSettingsInternal = lockSettingsInternal;
+ mIBootControl = bootControl;
}
@Override
@@ -85,13 +89,19 @@ public class RecoverySystemServiceTestable extends RecoverySystemService {
public LockSettingsInternal getLockSettingsService() {
return mLockSettingsInternal;
}
+
+ @Override
+ public IBootControl getBootControl() {
+ return mIBootControl;
+ }
}
RecoverySystemServiceTestable(Context context, FakeSystemProperties systemProperties,
PowerManager powerManager, FileWriter uncryptPackageFileWriter,
- UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal) {
+ UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal,
+ IBootControl bootControl) {
super(new MockInjector(context, systemProperties, powerManager, uncryptPackageFileWriter,
- uncryptSocket, lockSettingsInternal));
+ uncryptSocket, lockSettingsInternal, bootControl));
}
public static class FakeSystemProperties {
@@ -102,6 +112,8 @@ public class RecoverySystemServiceTestable extends RecoverySystemService {
|| RecoverySystemService.INIT_SERVICE_SETUP_BCB.equals(key)
|| RecoverySystemService.INIT_SERVICE_CLEAR_BCB.equals(key)) {
return null;
+ } else if (RecoverySystemService.AB_UPDATE.equals(key)) {
+ return "true";
} else {
throw new IllegalArgumentException("unexpected test key: " + key);
}
diff --git a/services/tests/servicestests/src/com/android/server/textservices/OWNERS b/services/tests/servicestests/src/com/android/server/textservices/OWNERS
new file mode 100644
index 000000000000..0471e29a25cd
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/textservices/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 816455
+
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/services/tests/shortcutmanagerutils/OWNERS b/services/tests/shortcutmanagerutils/OWNERS
new file mode 100644
index 000000000000..d825dfd7cf00
--- /dev/null
+++ b/services/tests/shortcutmanagerutils/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 724a9e477b95..e55720c6dc7e 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -109,6 +109,20 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public abstract class Connection extends Conferenceable {
+ /**@hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "STATE_", value = {
+ STATE_INITIALIZING,
+ STATE_NEW,
+ STATE_RINGING,
+ STATE_DIALING,
+ STATE_ACTIVE,
+ STATE_HOLDING,
+ STATE_DISCONNECTED,
+ STATE_PULLING_CALL
+ })
+ public @interface ConnectionState {}
+
/**
* The connection is initializing. This is generally the first state for a {@code Connection}
* returned by a {@link ConnectionService}.
diff --git a/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java b/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java
new file mode 100644
index 000000000000..c7e7cd5ec64e
--- /dev/null
+++ b/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.net.Uri;
+import android.util.Log;
+import android.util.Pair;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Utility methods for parsing parts of {@link android.telephony.ims.SipMessage}s.
+ * See RFC 3261 for more information.
+ * @hide
+ */
+// Note: This is lightweight in order to avoid a full SIP stack import in frameworks/base.
+public class SipMessageParsingUtils {
+ private static final String TAG = "SipMessageParsingUtils";
+ // "Method" in request-line
+ // Request-Line = Method SP Request-URI SP SIP-Version CRLF
+ private static final String[] SIP_REQUEST_METHODS = new String[] {"INVITE", "ACK", "OPTIONS",
+ "BYE", "CANCEL", "REGISTER", "PRACK", "SUBSCRIBE", "NOTIFY", "PUBLISH", "INFO", "REFER",
+ "MESSAGE", "UPDATE"};
+
+ // SIP Version 2.0 (corresponding to RCS 3261), set in "SIP-Version" of Status-Line and
+ // Request-Line
+ //
+ // Request-Line = Method SP Request-URI SP SIP-Version CRLF
+ // Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF
+ private static final String SIP_VERSION_2 = "SIP/2.0";
+
+ // headers are formatted Key:Value
+ private static final String HEADER_KEY_VALUE_SEPARATOR = ":";
+ // Multiple of the same header can be concatenated and put into one header Key:Value pair, for
+ // example "v: XX1;branch=YY1,XX2;branch=YY2". This needs to be treated as two "v:" headers.
+ private static final String SUBHEADER_VALUE_SEPARATOR = ",";
+
+ // SIP header parameters have the format ";paramName=paramValue"
+ private static final String PARAM_SEPARATOR = ";";
+ // parameters are formatted paramName=ParamValue
+ private static final String PARAM_KEY_VALUE_SEPARATOR = "=";
+
+ // The via branch parameter definition
+ private static final String BRANCH_PARAM_KEY = "branch";
+
+ // via header key
+ private static final String VIA_SIP_HEADER_KEY = "via";
+ // compact form of the via header key
+ private static final String VIA_SIP_HEADER_KEY_COMPACT = "v";
+
+ /**
+ * @return true if the SIP message start line is considered a request (based on known request
+ * methods).
+ */
+ public static boolean isSipRequest(String startLine) {
+ String[] splitLine = splitStartLineAndVerify(startLine);
+ if (splitLine == null) return false;
+ return verifySipRequest(splitLine);
+ }
+
+ /**
+ * Return the via branch parameter, which is used to identify the transaction ID (request and
+ * response pair) in a SIP transaction.
+ * @param headerString The string containing the headers of the SIP message.
+ */
+ public static String getTransactionId(String headerString) {
+ // search for Via: or v: parameter, we only care about the first one.
+ List<Pair<String, String>> headers = parseHeaders(headerString, true,
+ VIA_SIP_HEADER_KEY, VIA_SIP_HEADER_KEY_COMPACT);
+ for (Pair<String, String> header : headers) {
+ // Headers can also be concatenated together using a "," between each header value.
+ // format becomes v: XX1;branch=YY1,XX2;branch=YY2. Need to extract only the first ID's
+ // branch param YY1.
+ String[] subHeaders = header.second.split(SUBHEADER_VALUE_SEPARATOR);
+ for (String subHeader : subHeaders) {
+ // Search for ;branch=z9hG4bKXXXXXX and return parameter value
+ String[] params = subHeader.split(PARAM_SEPARATOR);
+ if (params.length < 2) {
+ // This param doesn't include a branch param, move to next param.
+ Log.w(TAG, "getTransactionId: via detected without branch param:"
+ + subHeader);
+ continue;
+ }
+ // by spec, each param can only appear once in a header.
+ for (String param : params) {
+ String[] pair = param.split(PARAM_KEY_VALUE_SEPARATOR);
+ if (pair.length < 2) {
+ // ignore info before the first parameter
+ continue;
+ }
+ if (pair.length > 2) {
+ Log.w(TAG,
+ "getTransactionId: unexpected parameter" + Arrays.toString(pair));
+ }
+ // Trim whitespace in parameter
+ pair[0] = pair[0].trim();
+ pair[1] = pair[1].trim();
+ if (BRANCH_PARAM_KEY.equalsIgnoreCase(pair[0])) {
+ // There can be multiple "Via" headers in the SIP message, however we want
+ // to return the first once found, as this corresponds with the transaction
+ // that is relevant here.
+ return pair[1];
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private static String[] splitStartLineAndVerify(String startLine) {
+ String[] splitLine = startLine.split(" ");
+ if (isStartLineMalformed(splitLine)) return null;
+ return splitLine;
+ }
+
+ private static boolean isStartLineMalformed(String[] startLine) {
+ if (startLine == null || startLine.length == 0) {
+ return true;
+ }
+ // start lines contain three segments separated by spaces (SP):
+ // Request-Line = Method SP Request-URI SP SIP-Version CRLF
+ // Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF
+ return (startLine.length != 3);
+ }
+
+ private static boolean verifySipRequest(String[] request) {
+ // Request-Line = Method SP Request-URI SP SIP-Version CRLF
+ boolean verified = request[2].contains(SIP_VERSION_2);
+ verified &= (Uri.parse(request[1]).getScheme() != null);
+ verified &= Arrays.stream(SIP_REQUEST_METHODS).anyMatch(s -> request[0].contains(s));
+ return verified;
+ }
+
+ private static boolean verifySipResponse(String[] response) {
+ // Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF
+ boolean verified = response[0].contains(SIP_VERSION_2);
+ int statusCode = Integer.parseInt(response[1]);
+ verified &= (statusCode >= 100 && statusCode < 700);
+ return verified;
+ }
+
+ /**
+ * Parse a String representation of the Header portion of the SIP Message and re-structure it
+ * into a List of key->value pairs representing each header in the order that they appeared in
+ * the message.
+ *
+ * @param headerString The raw string containing all headers
+ * @param stopAtFirstMatch Return early when the first match is found from matching header keys.
+ * @param matchingHeaderKeys An optional list of Strings containing header keys that should be
+ * returned if they exist. If none exist, all keys will be returned.
+ * (This is internally an equalsIgnoreMatch comparison).
+ * @return the matched header keys and values.
+ */
+ private static List<Pair<String, String>> parseHeaders(String headerString,
+ boolean stopAtFirstMatch, String... matchingHeaderKeys) {
+ // Ensure there is no leading whitespace
+ headerString = removeLeadingWhitespace(headerString);
+
+ List<Pair<String, String>> result = new ArrayList<>();
+ // Split the string line-by-line.
+ String[] headerLines = headerString.split("\\r?\\n");
+ if (headerLines.length == 0) {
+ return Collections.emptyList();
+ }
+
+ String headerKey = null;
+ StringBuilder headerValueSegment = new StringBuilder();
+ // loop through each line, either parsing a "key: value" pair or appending values that span
+ // multiple lines.
+ for (String line : headerLines) {
+ // This line is a continuation of the last line if it starts with whitespace or tab
+ if (line.startsWith("\t") || line.startsWith(" ")) {
+ headerValueSegment.append(removeLeadingWhitespace(line));
+ continue;
+ }
+ // This line is the start of a new key, If headerKey/value is already populated from a
+ // previous key/value pair, add it to list of parsed header pairs.
+ if (headerKey != null) {
+ final String key = headerKey;
+ if (matchingHeaderKeys == null || matchingHeaderKeys.length == 0
+ || Arrays.stream(matchingHeaderKeys).anyMatch(
+ (s) -> s.equalsIgnoreCase(key))) {
+ result.add(new Pair<>(key, headerValueSegment.toString()));
+ if (stopAtFirstMatch) {
+ return result;
+ }
+ }
+ headerKey = null;
+ headerValueSegment = new StringBuilder();
+ }
+
+ // Format is "Key:Value", ignore any ":" after the first.
+ String[] pair = line.split(HEADER_KEY_VALUE_SEPARATOR, 2);
+ if (pair.length < 2) {
+ // malformed line, skip
+ Log.w(TAG, "parseHeaders - received malformed line: " + line);
+ continue;
+ }
+
+ headerKey = pair[0].trim();
+ for (int i = 1; i < pair.length; i++) {
+ headerValueSegment.append(removeLeadingWhitespace(pair[i]));
+ }
+ }
+ // Pick up the last pending header being parsed, if it exists.
+ if (headerKey != null) {
+ final String key = headerKey;
+ if (matchingHeaderKeys == null || matchingHeaderKeys.length == 0
+ || Arrays.stream(matchingHeaderKeys).anyMatch(
+ (s) -> s.equalsIgnoreCase(key))) {
+ result.add(new Pair<>(key, headerValueSegment.toString()));
+ }
+ }
+
+ return result;
+ }
+
+ private static String removeLeadingWhitespace(String line) {
+ return line.replaceFirst("^\\s*", "");
+ }
+}
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index d01297147fdb..f6d18fcd9ab3 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -18,10 +18,7 @@ package android.telephony;
import android.annotation.IntDef;
import android.annotation.SystemApi;
-import android.hardware.radio.V1_1.GeranBands;
import android.hardware.radio.V1_5.AccessNetwork;
-import android.hardware.radio.V1_5.EutranBands;
-import android.hardware.radio.V1_5.UtranBands;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -117,52 +114,120 @@ public final class AccessNetworkConstants {
* http://www.etsi.org/deliver/etsi_ts/145000_145099/145005/14.00.00_60/ts_145005v140000p.pdf
*/
public static final class GeranBand {
- public static final int BAND_T380 = GeranBands.BAND_T380;
- public static final int BAND_T410 = GeranBands.BAND_T410;
- public static final int BAND_450 = GeranBands.BAND_450;
- public static final int BAND_480 = GeranBands.BAND_480;
- public static final int BAND_710 = GeranBands.BAND_710;
- public static final int BAND_750 = GeranBands.BAND_750;
- public static final int BAND_T810 = GeranBands.BAND_T810;
- public static final int BAND_850 = GeranBands.BAND_850;
- public static final int BAND_P900 = GeranBands.BAND_P900;
- public static final int BAND_E900 = GeranBands.BAND_E900;
- public static final int BAND_R900 = GeranBands.BAND_R900;
- public static final int BAND_DCS1800 = GeranBands.BAND_DCS1800;
- public static final int BAND_PCS1900 = GeranBands.BAND_PCS1900;
- public static final int BAND_ER900 = GeranBands.BAND_ER900;
+ public static final int BAND_T380 = android.hardware.radio.V1_1.GeranBands.BAND_T380;
+ public static final int BAND_T410 = android.hardware.radio.V1_1.GeranBands.BAND_T410;
+ public static final int BAND_450 = android.hardware.radio.V1_1.GeranBands.BAND_450;
+ public static final int BAND_480 = android.hardware.radio.V1_1.GeranBands.BAND_480;
+ public static final int BAND_710 = android.hardware.radio.V1_1.GeranBands.BAND_710;
+ public static final int BAND_750 = android.hardware.radio.V1_1.GeranBands.BAND_750;
+ public static final int BAND_T810 = android.hardware.radio.V1_1.GeranBands.BAND_T810;
+ public static final int BAND_850 = android.hardware.radio.V1_1.GeranBands.BAND_850;
+ public static final int BAND_P900 = android.hardware.radio.V1_1.GeranBands.BAND_P900;
+ public static final int BAND_E900 = android.hardware.radio.V1_1.GeranBands.BAND_E900;
+ public static final int BAND_R900 = android.hardware.radio.V1_1.GeranBands.BAND_R900;
+ public static final int BAND_DCS1800 = android.hardware.radio.V1_1.GeranBands.BAND_DCS1800;
+ public static final int BAND_PCS1900 = android.hardware.radio.V1_1.GeranBands.BAND_PCS1900;
+ public static final int BAND_ER900 = android.hardware.radio.V1_1.GeranBands.BAND_ER900;
+
+ /**
+ * GeranBand
+ *
+ * @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"BAND_"},
+ value = {BAND_T380,
+ BAND_T410,
+ BAND_450,
+ BAND_480,
+ BAND_710,
+ BAND_750,
+ BAND_T810,
+ BAND_850,
+ BAND_P900,
+ BAND_E900,
+ BAND_R900,
+ BAND_DCS1800,
+ BAND_PCS1900,
+ BAND_ER900})
+
+ public @interface GeranBands {}
/** @hide */
private GeranBand() {}
}
/**
+ * 3GPP TS 45.005 Table 2-1 Dynamically mapped ARFCN.
+ * 3GPP TS 45.005 Table 2-2 Fixed designation of ARFCN.
+ * @hide
+ */
+ enum GeranBandArfcnFrequency {
+
+ // Dynamically mapped ARFCN
+// GERAN_ARFCN_FREQUENCY_BAND_T380(GeranBand.BAND_T380, 380.2, 0),
+// GERAN_ARFCN_FREQUENCY_BAND_T410(GeranBand.BAND_T410, 410.2, 0),
+// GERAN_ARFCN_FREQUENCY_BAND_710(GeranBand.BAND_710, 698, 0),
+// GERAN_ARFCN_FREQUENCY_BAND_750(GeranBand.BAND_750, 747, 438, 30),
+// GERAN_ARFCN_FREQUENCY_BAND_T810(GeranBand.BAND_T810, 806, 350),
+ // Fixed designation of ARFCN
+ GERAN_ARFCN_FREQUENCY_BAND_450(GeranBand.BAND_450, 450600, 259, 259, 293, 10),
+ GERAN_ARFCN_FREQUENCY_BAND_480(GeranBand.BAND_480, 479000, 306, 306, 340, 10),
+ GERAN_ARFCN_FREQUENCY_BAND_850(GeranBand.BAND_850, 824200, 128, 128, 251, 45),
+ GERAN_ARFCN_FREQUENCY_BAND_DCS1800(GeranBand.BAND_DCS1800, 1710200, 512, 512, 885, 95),
+ GERAN_ARFCN_FREQUENCY_BAND_PCS1900(GeranBand.BAND_PCS1900, 1850200, 512, 512, 810, 80),
+ GERAN_ARFCN_FREQUENCY_BAND_E900_1(GeranBand.BAND_E900, 890000, 0, 0, 124, 45),
+ GERAN_ARFCN_FREQUENCY_BAND_E900_2(GeranBand.BAND_E900, 890000, 1024, 975, 1023, 45),
+ GERAN_ARFCN_FREQUENCY_BAND_R900_1(GeranBand.BAND_R900, 890000, 0, 0, 124, 45),
+ GERAN_ARFCN_FREQUENCY_BAND_R900_2(GeranBand.BAND_R900, 890000, 1024, 955, 1023, 45),
+ GERAN_ARFCN_FREQUENCY_BAND_P900(GeranBand.BAND_P900, 890000, 0, 1, 124, 45),
+ GERAN_ARFCN_FREQUENCY_BAND_ER900_1(GeranBand.BAND_ER900, 890000, 0, 0, 124, 45),
+ GERAN_ARFCN_FREQUENCY_BAND_ER900_2(GeranBand.BAND_ER900, 890000, 1024, 940, 1023, 1024);
+
+ GeranBandArfcnFrequency(int band, int uplinkFrequencyFirstKhz, int arfcnOffset,
+ int arfcnRangeFirst, int arfcnRangeLast, int downlinkOffset) {
+ this.band = band;
+ this.uplinkFrequencyFirst = uplinkFrequencyFirstKhz;
+ this.arfcnOffset = arfcnOffset;
+ this.arfcnRangeFirst = arfcnRangeFirst;
+ this.arfcnRangeLast = arfcnRangeLast;
+ this.downlinkOffset = downlinkOffset;
+ }
+
+ int band;
+ int uplinkFrequencyFirst;
+ int arfcnOffset;
+ int arfcnRangeFirst;
+ int arfcnRangeLast;
+ int downlinkOffset;
+ }
+
+ /**
* Frequency bands for UTRAN.
* http://www.etsi.org/deliver/etsi_ts/125100_125199/125104/13.03.00_60/ts_125104v130p.pdf
*/
public static final class UtranBand {
- public static final int BAND_1 = UtranBands.BAND_1;
- public static final int BAND_2 = UtranBands.BAND_2;
- public static final int BAND_3 = UtranBands.BAND_3;
- public static final int BAND_4 = UtranBands.BAND_4;
- public static final int BAND_5 = UtranBands.BAND_5;
- public static final int BAND_6 = UtranBands.BAND_6;
- public static final int BAND_7 = UtranBands.BAND_7;
- public static final int BAND_8 = UtranBands.BAND_8;
- public static final int BAND_9 = UtranBands.BAND_9;
- public static final int BAND_10 = UtranBands.BAND_10;
- public static final int BAND_11 = UtranBands.BAND_11;
- public static final int BAND_12 = UtranBands.BAND_12;
- public static final int BAND_13 = UtranBands.BAND_13;
- public static final int BAND_14 = UtranBands.BAND_14;
+ public static final int BAND_1 = android.hardware.radio.V1_5.UtranBands.BAND_1;
+ public static final int BAND_2 = android.hardware.radio.V1_5.UtranBands.BAND_2;
+ public static final int BAND_3 = android.hardware.radio.V1_5.UtranBands.BAND_3;
+ public static final int BAND_4 = android.hardware.radio.V1_5.UtranBands.BAND_4;
+ public static final int BAND_5 = android.hardware.radio.V1_5.UtranBands.BAND_5;
+ public static final int BAND_6 = android.hardware.radio.V1_5.UtranBands.BAND_6;
+ public static final int BAND_7 = android.hardware.radio.V1_5.UtranBands.BAND_7;
+ public static final int BAND_8 = android.hardware.radio.V1_5.UtranBands.BAND_8;
+ public static final int BAND_9 = android.hardware.radio.V1_5.UtranBands.BAND_9;
+ public static final int BAND_10 = android.hardware.radio.V1_5.UtranBands.BAND_10;
+ public static final int BAND_11 = android.hardware.radio.V1_5.UtranBands.BAND_11;
+ public static final int BAND_12 = android.hardware.radio.V1_5.UtranBands.BAND_12;
+ public static final int BAND_13 = android.hardware.radio.V1_5.UtranBands.BAND_13;
+ public static final int BAND_14 = android.hardware.radio.V1_5.UtranBands.BAND_14;
// band 15, 16, 17, 18 are reserved
- public static final int BAND_19 = UtranBands.BAND_19;
- public static final int BAND_20 = UtranBands.BAND_20;
- public static final int BAND_21 = UtranBands.BAND_21;
- public static final int BAND_22 = UtranBands.BAND_22;
+ public static final int BAND_19 = android.hardware.radio.V1_5.UtranBands.BAND_19;
+ public static final int BAND_20 = android.hardware.radio.V1_5.UtranBands.BAND_20;
+ public static final int BAND_21 = android.hardware.radio.V1_5.UtranBands.BAND_21;
+ public static final int BAND_22 = android.hardware.radio.V1_5.UtranBands.BAND_22;
// band 23, 24 are reserved
- public static final int BAND_25 = UtranBands.BAND_25;
- public static final int BAND_26 = UtranBands.BAND_26;
+ public static final int BAND_25 = android.hardware.radio.V1_5.UtranBands.BAND_25;
+ public static final int BAND_26 = android.hardware.radio.V1_5.UtranBands.BAND_26;
// Frequency bands for TD-SCDMA. Defined in 3GPP TS 25.102, Table 5.2.
@@ -171,115 +236,423 @@ public final class AccessNetworkConstants {
* 1900 - 1920 MHz: Uplink and downlink transmission
* 2010 - 2025 MHz: Uplink and downlink transmission
*/
- public static final int BAND_A = UtranBands.BAND_A;
+ public static final int BAND_A = android.hardware.radio.V1_5.UtranBands.BAND_A;
/**
* Band B
* 1850 - 1910 MHz: Uplink and downlink transmission
* 1930 - 1990 MHz: Uplink and downlink transmission
*/
- public static final int BAND_B = UtranBands.BAND_B;
+ public static final int BAND_B = android.hardware.radio.V1_5.UtranBands.BAND_B;
/**
* Band C
* 1910 - 1930 MHz: Uplink and downlink transmission
*/
- public static final int BAND_C = UtranBands.BAND_C;
+ public static final int BAND_C = android.hardware.radio.V1_5.UtranBands.BAND_C;
/**
* Band D
* 2570 - 2620 MHz: Uplink and downlink transmission
*/
- public static final int BAND_D = UtranBands.BAND_D;
+ public static final int BAND_D = android.hardware.radio.V1_5.UtranBands.BAND_D;
/**
* Band E
* 2300—2400 MHz: Uplink and downlink transmission
*/
- public static final int BAND_E = UtranBands.BAND_E;
+ public static final int BAND_E = android.hardware.radio.V1_5.UtranBands.BAND_E;
/**
* Band F
* 1880 - 1920 MHz: Uplink and downlink transmission
*/
- public static final int BAND_F = UtranBands.BAND_F;
+ public static final int BAND_F = android.hardware.radio.V1_5.UtranBands.BAND_F;
+
+ /**
+ * UtranBand
+ *
+ * @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"BAND_"},
+ value = {BAND_1,
+ BAND_2,
+ BAND_3,
+ BAND_4,
+ BAND_5,
+ BAND_6,
+ BAND_7,
+ BAND_8,
+ BAND_9,
+ BAND_10,
+ BAND_11,
+ BAND_12,
+ BAND_13,
+ BAND_14,
+ BAND_19,
+ BAND_20,
+ BAND_21,
+ BAND_22,
+ BAND_25,
+ BAND_26,
+ BAND_A,
+ BAND_B,
+ BAND_C,
+ BAND_D,
+ BAND_E,
+ BAND_F})
+
+ public @interface UtranBands {}
/** @hide */
private UtranBand() {}
}
/**
+ * 3GPP TS 25.101, Table 5.1 UARFCN definition (general)
+ * 3GPP TS 25.102, Table 5.2 UTRA Absolute Radio Frequency Channel Number 1.28 Mcps TDD Option.
+ *
+ * @hide
+ */
+ enum UtranBandArfcnFrequency {
+
+ UTRAN_ARFCN_FREQUENCY_BAND_1(UtranBand.BAND_1, 0, 10562, 10838, 0, 9612, 9888),
+ UTRAN_ARFCN_FREQUENCY_BAND_2(UtranBand.BAND_2, 0, 9662, 9938, 0, 9262, 9538),
+ UTRAN_ARFCN_FREQUENCY_BAND_3(UtranBand.BAND_3, 1575000, 1162, 1513, 1525000, 937, 1288),
+ UTRAN_ARFCN_FREQUENCY_BAND_4(UtranBand.BAND_4, 1805000, 1537, 1738, 1450000, 1312, 1513),
+ UTRAN_ARFCN_FREQUENCY_BAND_5(UtranBand.BAND_5, 0, 4357, 4458, 0, 4132, 4233),
+ UTRAN_ARFCN_FREQUENCY_BAND_6(UtranBand.BAND_6, 0, 4387, 4413, 0, 4162, 4188),
+ UTRAN_ARFCN_FREQUENCY_BAND_7(UtranBand.BAND_7, 2175000, 2237, 2563, 2100000, 2012, 2338),
+ UTRAN_ARFCN_FREQUENCY_BAND_8(UtranBand.BAND_8, 340000, 2937, 3088, 340000, 2712, 2863),
+ UTRAN_ARFCN_FREQUENCY_BAND_9(UtranBand.BAND_9, 0, 9327, 9837, 0, 8762, 8912),
+ UTRAN_ARFCN_FREQUENCY_BAND_10(UtranBand.BAND_10, 1490000, 3112, 3388, 1135000, 2887, 3163),
+ UTRAN_ARFCN_FREQUENCY_BAND_11(UtranBand.BAND_11, 736000, 3712, 3787, 733000, 3487, 3562),
+ UTRAN_ARFCN_FREQUENCY_BAND_12(UtranBand.BAND_12, -37000, 3842, 3903, -22000, 3617, 3678),
+ UTRAN_ARFCN_FREQUENCY_BAND_13(UtranBand.BAND_13, -55000, 4017, 4043, 21000, 3792, 3818),
+ UTRAN_ARFCN_FREQUENCY_BAND_14(UtranBand.BAND_14, -63000, 4117, 4143, 12000, 3892, 3918),
+ UTRAN_ARFCN_FREQUENCY_BAND_19(UtranBand.BAND_19, 735000, 712, 763, 770000, 312, 363),
+ UTRAN_ARFCN_FREQUENCY_BAND_20(UtranBand.BAND_20, -109000, 4512, 4638, -23000, 4287, 4413),
+ UTRAN_ARFCN_FREQUENCY_BAND_21(UtranBand.BAND_21, 1326000, 862, 912, 1358000, 462, 512),
+ UTRAN_ARFCN_FREQUENCY_BAND_22(UtranBand.BAND_22, 2580000, 4662, 5038, 2525000, 4437, 4813),
+ UTRAN_ARFCN_FREQUENCY_BAND_25(UtranBand.BAND_25, 910000, 5112, 5413, 875000, 4887, 5188),
+ UTRAN_ARFCN_FREQUENCY_BAND_A(UtranBand.BAND_A, 0, 10054, 10121, 0, 9504, 9596),
+ UTRAN_ARFCN_FREQUENCY_BAND_B(UtranBand.BAND_B, 0, 9654, 9946, 0, 9254, 9546),
+ UTRAN_ARFCN_FREQUENCY_BAND_C(UtranBand.BAND_C, 0, 0, 0, 0, 9554, 9646),
+ UTRAN_ARFCN_FREQUENCY_BAND_D(UtranBand.BAND_D, 0, 0, 0, 0, 12854, 13096),
+ UTRAN_ARFCN_FREQUENCY_BAND_E(UtranBand.BAND_E, 0, 0, 0, 0, 11504, 11996),
+ UTRAN_ARFCN_FREQUENCY_BAND_F(UtranBand.BAND_F, 0, 0, 0, 0, 9404, 9596);
+
+ UtranBandArfcnFrequency(int band, int downlinkOffsetKhz, int downlinkRangeFirst,
+ int downlinkRangeLast, int uplinkOffsetKhz, int uplinkRangeFirst,
+ int uplinkRangeLast) {
+ this.band = band;
+ this.downlinkOffset = downlinkOffsetKhz;
+ this.downlinkRangeFirst = downlinkRangeFirst;
+ this.downlinkRangeLast = downlinkRangeLast;
+ this.uplinkOffset = uplinkOffsetKhz;
+ this.uplinkRangeFirst = uplinkRangeFirst;
+ this.uplinkRangeLast = uplinkRangeLast;
+ }
+
+ int band;
+ int downlinkOffset;
+ int downlinkRangeFirst;
+ int downlinkRangeLast;
+ int uplinkOffset;
+ int uplinkRangeFirst;
+ int uplinkRangeLast;
+ }
+
+ /**
* Frequency bands for EUTRAN.
* 3GPP TS 36.101, Version 16.4.0, Table 5.5: Operating bands
* https://www.etsi.org/deliver/etsi_ts/136100_136199/136101/15.09.00_60/ts_136101v150900p.pdf
*/
public static final class EutranBand {
- public static final int BAND_1 = EutranBands.BAND_1;
- public static final int BAND_2 = EutranBands.BAND_2;
- public static final int BAND_3 = EutranBands.BAND_3;
- public static final int BAND_4 = EutranBands.BAND_4;
- public static final int BAND_5 = EutranBands.BAND_5;
- public static final int BAND_6 = EutranBands.BAND_6;
- public static final int BAND_7 = EutranBands.BAND_7;
- public static final int BAND_8 = EutranBands.BAND_8;
- public static final int BAND_9 = EutranBands.BAND_9;
- public static final int BAND_10 = EutranBands.BAND_10;
- public static final int BAND_11 = EutranBands.BAND_11;
- public static final int BAND_12 = EutranBands.BAND_12;
- public static final int BAND_13 = EutranBands.BAND_13;
- public static final int BAND_14 = EutranBands.BAND_14;
- public static final int BAND_17 = EutranBands.BAND_17;
- public static final int BAND_18 = EutranBands.BAND_18;
- public static final int BAND_19 = EutranBands.BAND_19;
- public static final int BAND_20 = EutranBands.BAND_20;
- public static final int BAND_21 = EutranBands.BAND_21;
- public static final int BAND_22 = EutranBands.BAND_22;
- public static final int BAND_23 = EutranBands.BAND_23;
- public static final int BAND_24 = EutranBands.BAND_24;
- public static final int BAND_25 = EutranBands.BAND_25;
- public static final int BAND_26 = EutranBands.BAND_26;
- public static final int BAND_27 = EutranBands.BAND_27;
- public static final int BAND_28 = EutranBands.BAND_28;
- public static final int BAND_30 = EutranBands.BAND_30;
- public static final int BAND_31 = EutranBands.BAND_31;
- public static final int BAND_33 = EutranBands.BAND_33;
- public static final int BAND_34 = EutranBands.BAND_34;
- public static final int BAND_35 = EutranBands.BAND_35;
- public static final int BAND_36 = EutranBands.BAND_36;
- public static final int BAND_37 = EutranBands.BAND_37;
- public static final int BAND_38 = EutranBands.BAND_38;
- public static final int BAND_39 = EutranBands.BAND_39;
- public static final int BAND_40 = EutranBands.BAND_40;
- public static final int BAND_41 = EutranBands.BAND_41;
- public static final int BAND_42 = EutranBands.BAND_42;
- public static final int BAND_43 = EutranBands.BAND_43;
- public static final int BAND_44 = EutranBands.BAND_44;
- public static final int BAND_45 = EutranBands.BAND_45;
- public static final int BAND_46 = EutranBands.BAND_46;
- public static final int BAND_47 = EutranBands.BAND_47;
- public static final int BAND_48 = EutranBands.BAND_48;
- public static final int BAND_49 = EutranBands.BAND_49;
- public static final int BAND_50 = EutranBands.BAND_50;
- public static final int BAND_51 = EutranBands.BAND_51;
- public static final int BAND_52 = EutranBands.BAND_52;
- public static final int BAND_53 = EutranBands.BAND_53;
- public static final int BAND_65 = EutranBands.BAND_65;
- public static final int BAND_66 = EutranBands.BAND_66;
- public static final int BAND_68 = EutranBands.BAND_68;
- public static final int BAND_70 = EutranBands.BAND_70;
- public static final int BAND_71 = EutranBands.BAND_71;
- public static final int BAND_72 = EutranBands.BAND_72;
- public static final int BAND_73 = EutranBands.BAND_73;
- public static final int BAND_74 = EutranBands.BAND_74;
- public static final int BAND_85 = EutranBands.BAND_85;
- public static final int BAND_87 = EutranBands.BAND_87;
- public static final int BAND_88 = EutranBands.BAND_88;
+ public static final int BAND_1 = android.hardware.radio.V1_5.EutranBands.BAND_1;
+ public static final int BAND_2 = android.hardware.radio.V1_5.EutranBands.BAND_2;
+ public static final int BAND_3 = android.hardware.radio.V1_5.EutranBands.BAND_3;
+ public static final int BAND_4 = android.hardware.radio.V1_5.EutranBands.BAND_4;
+ public static final int BAND_5 = android.hardware.radio.V1_5.EutranBands.BAND_5;
+ public static final int BAND_6 = android.hardware.radio.V1_5.EutranBands.BAND_6;
+ public static final int BAND_7 = android.hardware.radio.V1_5.EutranBands.BAND_7;
+ public static final int BAND_8 = android.hardware.radio.V1_5.EutranBands.BAND_8;
+ public static final int BAND_9 = android.hardware.radio.V1_5.EutranBands.BAND_9;
+ public static final int BAND_10 = android.hardware.radio.V1_5.EutranBands.BAND_10;
+ public static final int BAND_11 = android.hardware.radio.V1_5.EutranBands.BAND_11;
+ public static final int BAND_12 = android.hardware.radio.V1_5.EutranBands.BAND_12;
+ public static final int BAND_13 = android.hardware.radio.V1_5.EutranBands.BAND_13;
+ public static final int BAND_14 = android.hardware.radio.V1_5.EutranBands.BAND_14;
+ public static final int BAND_17 = android.hardware.radio.V1_5.EutranBands.BAND_17;
+ public static final int BAND_18 = android.hardware.radio.V1_5.EutranBands.BAND_18;
+ public static final int BAND_19 = android.hardware.radio.V1_5.EutranBands.BAND_19;
+ public static final int BAND_20 = android.hardware.radio.V1_5.EutranBands.BAND_20;
+ public static final int BAND_21 = android.hardware.radio.V1_5.EutranBands.BAND_21;
+ public static final int BAND_22 = android.hardware.radio.V1_5.EutranBands.BAND_22;
+ public static final int BAND_23 = android.hardware.radio.V1_5.EutranBands.BAND_23;
+ public static final int BAND_24 = android.hardware.radio.V1_5.EutranBands.BAND_24;
+ public static final int BAND_25 = android.hardware.radio.V1_5.EutranBands.BAND_25;
+ public static final int BAND_26 = android.hardware.radio.V1_5.EutranBands.BAND_26;
+ public static final int BAND_27 = android.hardware.radio.V1_5.EutranBands.BAND_27;
+ public static final int BAND_28 = android.hardware.radio.V1_5.EutranBands.BAND_28;
+ public static final int BAND_30 = android.hardware.radio.V1_5.EutranBands.BAND_30;
+ public static final int BAND_31 = android.hardware.radio.V1_5.EutranBands.BAND_31;
+ public static final int BAND_33 = android.hardware.radio.V1_5.EutranBands.BAND_33;
+ public static final int BAND_34 = android.hardware.radio.V1_5.EutranBands.BAND_34;
+ public static final int BAND_35 = android.hardware.radio.V1_5.EutranBands.BAND_35;
+ public static final int BAND_36 = android.hardware.radio.V1_5.EutranBands.BAND_36;
+ public static final int BAND_37 = android.hardware.radio.V1_5.EutranBands.BAND_37;
+ public static final int BAND_38 = android.hardware.radio.V1_5.EutranBands.BAND_38;
+ public static final int BAND_39 = android.hardware.radio.V1_5.EutranBands.BAND_39;
+ public static final int BAND_40 = android.hardware.radio.V1_5.EutranBands.BAND_40;
+ public static final int BAND_41 = android.hardware.radio.V1_5.EutranBands.BAND_41;
+ public static final int BAND_42 = android.hardware.radio.V1_5.EutranBands.BAND_42;
+ public static final int BAND_43 = android.hardware.radio.V1_5.EutranBands.BAND_43;
+ public static final int BAND_44 = android.hardware.radio.V1_5.EutranBands.BAND_44;
+ public static final int BAND_45 = android.hardware.radio.V1_5.EutranBands.BAND_45;
+ public static final int BAND_46 = android.hardware.radio.V1_5.EutranBands.BAND_46;
+ public static final int BAND_47 = android.hardware.radio.V1_5.EutranBands.BAND_47;
+ public static final int BAND_48 = android.hardware.radio.V1_5.EutranBands.BAND_48;
+ public static final int BAND_49 = android.hardware.radio.V1_5.EutranBands.BAND_49;
+ public static final int BAND_50 = android.hardware.radio.V1_5.EutranBands.BAND_50;
+ public static final int BAND_51 = android.hardware.radio.V1_5.EutranBands.BAND_51;
+ public static final int BAND_52 = android.hardware.radio.V1_5.EutranBands.BAND_52;
+ public static final int BAND_53 = android.hardware.radio.V1_5.EutranBands.BAND_53;
+ public static final int BAND_65 = android.hardware.radio.V1_5.EutranBands.BAND_65;
+ public static final int BAND_66 = android.hardware.radio.V1_5.EutranBands.BAND_66;
+ public static final int BAND_68 = android.hardware.radio.V1_5.EutranBands.BAND_68;
+ public static final int BAND_70 = android.hardware.radio.V1_5.EutranBands.BAND_70;
+ public static final int BAND_71 = android.hardware.radio.V1_5.EutranBands.BAND_71;
+ public static final int BAND_72 = android.hardware.radio.V1_5.EutranBands.BAND_72;
+ public static final int BAND_73 = android.hardware.radio.V1_5.EutranBands.BAND_73;
+ public static final int BAND_74 = android.hardware.radio.V1_5.EutranBands.BAND_74;
+ public static final int BAND_85 = android.hardware.radio.V1_5.EutranBands.BAND_85;
+ public static final int BAND_87 = android.hardware.radio.V1_5.EutranBands.BAND_87;
+ public static final int BAND_88 = android.hardware.radio.V1_5.EutranBands.BAND_88;
+
+ /**
+ * EutranBands
+ *
+ * @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"BAND_"},
+ value = {BAND_1,
+ BAND_2,
+ BAND_3,
+ BAND_4,
+ BAND_5,
+ BAND_6,
+ BAND_7,
+ BAND_8,
+ BAND_9,
+ BAND_10,
+ BAND_11,
+ BAND_12,
+ BAND_13,
+ BAND_14,
+ BAND_17,
+ BAND_18,
+ BAND_19,
+ BAND_20,
+ BAND_21,
+ BAND_22,
+ BAND_23,
+ BAND_24,
+ BAND_25,
+ BAND_26,
+ BAND_27,
+ BAND_28,
+ BAND_30,
+ BAND_31,
+ BAND_33,
+ BAND_34,
+ BAND_35,
+ BAND_36,
+ BAND_37,
+ BAND_38,
+ BAND_39,
+ BAND_40,
+ BAND_41,
+ BAND_42,
+ BAND_43,
+ BAND_44,
+ BAND_45,
+ BAND_46,
+ BAND_47,
+ BAND_48,
+ BAND_49,
+ BAND_50,
+ BAND_51,
+ BAND_52,
+ BAND_53,
+ BAND_65,
+ BAND_66,
+ BAND_68,
+ BAND_70,
+ BAND_71,
+ BAND_72,
+ BAND_73,
+ BAND_74,
+ BAND_85,
+ BAND_87,
+ BAND_88})
+
+ public @interface EutranBands {}
/** @hide */
private EutranBand() {};
}
/**
+ * 3GPP TS 36.101 Table 5.7.3-1 E-UTRA channel numbers.
+ *
+ * @hide
+ */
+ enum EutranBandArfcnFrequency {
+
+ EUTRAN_ARFCN_FREQUENCY_BAND_1(
+ EutranBand.BAND_1, 2110000, 0, 599, 1920000, 18800, 18599),
+ EUTRAN_ARFCN_FREQUENCY_BAND_2(
+ EutranBand.BAND_2, 1930000, 600, 1199, 1850000, 18600, 19199),
+ EUTRAN_ARFCN_FREQUENCY_BAND_3(
+ EutranBand.BAND_3, 1805000, 1200, 1949, 1710000, 19200, 19949),
+ EUTRAN_ARFCN_FREQUENCY_BAND_4(
+ EutranBand.BAND_4, 2110000, 1950, 2399, 1710000, 19950, 20399),
+ EUTRAN_ARFCN_FREQUENCY_BAND_5(
+ EutranBand.BAND_5, 869000, 2400, 2649, 824000, 20400, 20649),
+ EUTRAN_ARFCN_FREQUENCY_BAND_6(
+ EutranBand.BAND_6, 875000, 2650, 2749, 830000, 20650, 20749),
+ EUTRAN_ARFCN_FREQUENCY_BAND_7(
+ EutranBand.BAND_7, 2620000, 2750, 3449, 2500000, 20750, 21449),
+ EUTRAN_ARFCN_FREQUENCY_BAND_8(
+ EutranBand.BAND_8, 925000, 3450, 3799, 880000, 21450, 21799),
+ EUTRAN_ARFCN_FREQUENCY_BAND_9(
+ EutranBand.BAND_9, 1844900, 3800, 4149, 1749900, 21800, 22149),
+ EUTRAN_ARFCN_FREQUENCY_BAND_10(
+ EutranBand.BAND_10, 2110000, 4150, 4749, 1710000, 22150, 22749),
+ EUTRAN_ARFCN_FREQUENCY_BAND_11(
+ EutranBand.BAND_11, 1475900, 4750, 4949, 1427900, 22750, 22949),
+ EUTRAN_ARFCN_FREQUENCY_BAND_12(
+ EutranBand.BAND_12, 729000, 5010, 5179, 699000, 23010, 23179),
+ EUTRAN_ARFCN_FREQUENCY_BAND_13(
+ EutranBand.BAND_13, 746000, 5180, 5279, 777000, 23180, 23279),
+ EUTRAN_ARFCN_FREQUENCY_BAND_14(
+ EutranBand.BAND_14, 758000, 5280, 5379, 788000, 23230, 23379),
+ EUTRAN_ARFCN_FREQUENCY_BAND_17(
+ EutranBand.BAND_17, 734000, 5730, 5849, 704000, 23730, 23849),
+ EUTRAN_ARFCN_FREQUENCY_BAND_18(
+ EutranBand.BAND_18, 860000, 5850, 5999, 815000, 23850, 23999),
+ EUTRAN_ARFCN_FREQUENCY_BAND_19(
+ EutranBand.BAND_19, 875000, 6000, 6149, 830000, 24000, 24149),
+ EUTRAN_ARFCN_FREQUENCY_BAND_20(
+ EutranBand.BAND_20, 791000, 6150, 6449, 832000, 24150, 24449),
+ EUTRAN_ARFCN_FREQUENCY_BAND_21(
+ EutranBand.BAND_21, 1495900, 6450, 6599, 1447900, 24450, 24599),
+ EUTRAN_ARFCN_FREQUENCY_BAND_22(
+ EutranBand.BAND_22, 3510000, 6600, 7399, 3410000, 24600, 25399),
+ EUTRAN_ARFCN_FREQUENCY_BAND_23(
+ EutranBand.BAND_23, 2180000, 7500, 7699, 2000000, 25500, 25699),
+ EUTRAN_ARFCN_FREQUENCY_BAND_24(
+ EutranBand.BAND_24, 1525000, 7700, 8039, 1626500, 25700, 26039),
+ EUTRAN_ARFCN_FREQUENCY_BAND_25(
+ EutranBand.BAND_25, 1930000, 8040, 8689, 1850000, 26040, 26689),
+ EUTRAN_ARFCN_FREQUENCY_BAND_26(
+ EutranBand.BAND_26, 859000, 8690, 9039, 814000, 26690, 27039),
+ EUTRAN_ARFCN_FREQUENCY_BAND_27(
+ EutranBand.BAND_27, 852000, 9040, 9209, 807000, 27040, 27209),
+ EUTRAN_ARFCN_FREQUENCY_BAND_28(
+ EutranBand.BAND_28, 758000, 9210, 9659, 703000, 27210, 27659),
+ EUTRAN_ARFCN_FREQUENCY_BAND_30(
+ EutranBand.BAND_30, 2350000, 9770, 9869, 2305000, 27660, 27759),
+ EUTRAN_ARFCN_FREQUENCY_BAND_31(
+ EutranBand.BAND_31, 462500, 9870, 9919, 452500, 27760, 27809),
+ EUTRAN_ARFCN_FREQUENCY_BAND_33(
+ EutranBand.BAND_33, 1900000, 36000, 36199, 1900000, 36000, 36199),
+ EUTRAN_ARFCN_FREQUENCY_BAND_34(
+ EutranBand.BAND_34, 2010000, 36200, 36349, 2010000, 36200, 36349),
+ EUTRAN_ARFCN_FREQUENCY_BAND_35(
+ EutranBand.BAND_35, 1850000, 36350, 36949, 1850000, 36350, 36949),
+ EUTRAN_ARFCN_FREQUENCY_BAND_36(
+ EutranBand.BAND_36, 1930000, 36950, 37549, 1930000, 36950, 37549),
+ EUTRAN_ARFCN_FREQUENCY_BAND_37(
+ EutranBand.BAND_37, 1910000, 37550, 37749, 1910000, 37550, 37749),
+ EUTRAN_ARFCN_FREQUENCY_BAND_38(
+ EutranBand.BAND_38, 2570000, 37750, 38249, 2570000, 37750, 38249),
+ EUTRAN_ARFCN_FREQUENCY_BAND_39(
+ EutranBand.BAND_39, 1880000, 38250, 38649, 1880000, 38250, 38649),
+ EUTRAN_ARFCN_FREQUENCY_BAND_40(
+ EutranBand.BAND_40, 2300000, 38650, 39649, 2300000, 38650, 39649),
+ EUTRAN_ARFCN_FREQUENCY_BAND_41(
+ EutranBand.BAND_41, 2496000, 39650, 41589, 2496000, 39650, 41589),
+ EUTRAN_ARFCN_FREQUENCY_BAND_42(
+ EutranBand.BAND_42, 3400000, 41950, 43589, 3400000, 41950, 43589),
+ EUTRAN_ARFCN_FREQUENCY_BAND_43(
+ EutranBand.BAND_43, 3600000, 43950, 45589, 3600000, 43950, 45589),
+ EUTRAN_ARFCN_FREQUENCY_BAND_44(
+ EutranBand.BAND_44, 703000, 45590, 46589, 703000, 45590, 46589),
+ EUTRAN_ARFCN_FREQUENCY_BAND_45(
+ EutranBand.BAND_45, 1447000, 46590, 46789, 1447000, 46590, 46789),
+ EUTRAN_ARFCN_FREQUENCY_BAND_46(
+ EutranBand.BAND_46, 5150000, 46790, 54539, 5150000, 46790, 54539),
+ EUTRAN_ARFCN_FREQUENCY_BAND_47(
+ EutranBand.BAND_47, 5855000, 54540, 55239, 5855000, 54540, 55239),
+ EUTRAN_ARFCN_FREQUENCY_BAND_48(
+ EutranBand.BAND_48, 3550000, 55240, 56739, 3550000, 55240, 56739),
+ EUTRAN_ARFCN_FREQUENCY_BAND_49(
+ EutranBand.BAND_49, 3550000, 56740, 58239, 3550000, 56740, 58239),
+ EUTRAN_ARFCN_FREQUENCY_BAND_50(
+ EutranBand.BAND_50, 1432000, 58240, 59089, 1432000, 58240, 59089),
+ EUTRAN_ARFCN_FREQUENCY_BAND_51(
+ EutranBand.BAND_51, 1427000, 59090, 59139, 1427000, 59090, 59139),
+ EUTRAN_ARFCN_FREQUENCY_BAND_52(
+ EutranBand.BAND_52, 3300000, 59140, 60139, 3300000, 59140, 60139),
+ EUTRAN_ARFCN_FREQUENCY_BAND_53(
+ EutranBand.BAND_53, 2483500, 60140, 60254, 2483500, 60140, 60254),
+ EUTRAN_ARFCN_FREQUENCY_BAND_65(
+ EutranBand.BAND_65, 2110000, 65536, 66435, 1920000, 131072, 131971),
+ EUTRAN_ARFCN_FREQUENCY_BAND_66(
+ EutranBand.BAND_66, 2110000, 66436, 67335, 1710000, 131972, 132671),
+ EUTRAN_ARFCN_FREQUENCY_BAND_68(
+ EutranBand.BAND_68, 753000, 67536, 67835, 698000, 132672, 132971),
+ EUTRAN_ARFCN_FREQUENCY_BAND_70(
+ EutranBand.BAND_70, 1995000, 68336, 68585, 1695000, 132972, 133121),
+ EUTRAN_ARFCN_FREQUENCY_BAND_71(
+ EutranBand.BAND_71, 617000, 68586, 68935, 663000, 133122, 133471),
+ EUTRAN_ARFCN_FREQUENCY_BAND_72(
+ EutranBand.BAND_72, 461000, 68936, 68985, 451000, 133472, 133521),
+ EUTRAN_ARFCN_FREQUENCY_BAND_73(
+ EutranBand.BAND_73, 460000, 68986, 69035, 450000, 133522, 133571),
+ EUTRAN_ARFCN_FREQUENCY_BAND_74(
+ EutranBand.BAND_74, 1475000, 69036, 69465, 1427000, 133572, 134001),
+ EUTRAN_ARFCN_FREQUENCY_BAND_85(
+ EutranBand.BAND_85, 728000, 70366, 70545, 698000, 134002, 134181),
+ EUTRAN_ARFCN_FREQUENCY_BAND_87(
+ EutranBand.BAND_87, 420000, 70546, 70595, 410000, 134182, 134231),
+ EUTRAN_ARFCN_FREQUENCY_BAND_88(
+ EutranBand.BAND_88, 422000, 70596, 70645, 412000, 134231, 134280);
+
+ EutranBandArfcnFrequency(int band, int downlinkLowKhz, int downlinkOffset,
+ int downlinkRange, int uplinkLowKhz, int uplinkOffset,
+ int uplinkRange) {
+ this.band = band;
+ this.downlinkLowKhz = downlinkLowKhz;
+ this.downlinkOffset = downlinkOffset;
+ this.uplinkLowKhz = uplinkLowKhz;
+ this.uplinkOffset = uplinkOffset;
+ this.downlinkRange = downlinkRange;
+ this.uplinkRange = uplinkRange;
+ }
+
+ int band;
+ int downlinkLowKhz;
+ int downlinkOffset;
+ int uplinkLowKhz;
+ int uplinkOffset;
+ int downlinkRange;
+ int uplinkRange;
+ }
+
+ /**
* Frequency bands for CDMA2000.
* http://www.3gpp2.org/Public_html/Specs/C.S0057-E_v1.0_Bandclass_Specification.pdf
* @hide
@@ -320,7 +693,7 @@ public final class AccessNetworkConstants {
* https://www.etsi.org/deliver/etsi_ts/138100_138199/13810102/15.08.00_60/ts_13810102v150800p.pdf
*/
public static final class NgranBands {
- /** 3GPP TS 38.101-1, Version 16.2.0, Table 5.2-1: FR1 bands */
+ /** 3GPP TS 38.101-1, Version 16.5.0, Table 5.2-1: FR1 bands */
public static final int BAND_1 = android.hardware.radio.V1_5.NgranBands.BAND_1;
public static final int BAND_2 = android.hardware.radio.V1_5.NgranBands.BAND_2;
public static final int BAND_3 = android.hardware.radio.V1_5.NgranBands.BAND_3;
@@ -332,6 +705,7 @@ public final class AccessNetworkConstants {
public static final int BAND_18 = android.hardware.radio.V1_5.NgranBands.BAND_18;
public static final int BAND_20 = android.hardware.radio.V1_5.NgranBands.BAND_20;
public static final int BAND_25 = android.hardware.radio.V1_5.NgranBands.BAND_25;
+ public static final int BAND_26 = android.hardware.radio.V1_6.NgranBands.BAND_26;
public static final int BAND_28 = android.hardware.radio.V1_5.NgranBands.BAND_28;
public static final int BAND_29 = android.hardware.radio.V1_5.NgranBands.BAND_29;
public static final int BAND_30 = android.hardware.radio.V1_5.NgranBands.BAND_30;
@@ -340,9 +714,11 @@ public final class AccessNetworkConstants {
public static final int BAND_39 = android.hardware.radio.V1_5.NgranBands.BAND_39;
public static final int BAND_40 = android.hardware.radio.V1_5.NgranBands.BAND_40;
public static final int BAND_41 = android.hardware.radio.V1_5.NgranBands.BAND_41;
+ public static final int BAND_46 = android.hardware.radio.V1_6.NgranBands.BAND_46;
public static final int BAND_48 = android.hardware.radio.V1_5.NgranBands.BAND_48;
public static final int BAND_50 = android.hardware.radio.V1_5.NgranBands.BAND_50;
public static final int BAND_51 = android.hardware.radio.V1_5.NgranBands.BAND_51;
+ public static final int BAND_53 = android.hardware.radio.V1_6.NgranBands.BAND_53;
public static final int BAND_65 = android.hardware.radio.V1_5.NgranBands.BAND_65;
public static final int BAND_66 = android.hardware.radio.V1_5.NgranBands.BAND_66;
public static final int BAND_70 = android.hardware.radio.V1_5.NgranBands.BAND_70;
@@ -366,6 +742,7 @@ public final class AccessNetworkConstants {
public static final int BAND_93 = android.hardware.radio.V1_5.NgranBands.BAND_93;
public static final int BAND_94 = android.hardware.radio.V1_5.NgranBands.BAND_94;
public static final int BAND_95 = android.hardware.radio.V1_5.NgranBands.BAND_95;
+ public static final int BAND_96 = android.hardware.radio.V1_6.NgranBands.BAND_96;
/** 3GPP TS 38.101-2, Version 16.2.0, Table 5.2-1: FR2 bands */
public static final int BAND_257 = android.hardware.radio.V1_5.NgranBands.BAND_257;
@@ -390,6 +767,7 @@ public final class AccessNetworkConstants {
BAND_18,
BAND_20,
BAND_25,
+ BAND_26,
BAND_28,
BAND_29,
BAND_30,
@@ -398,9 +776,11 @@ public final class AccessNetworkConstants {
BAND_39,
BAND_40,
BAND_41,
+ BAND_46,
BAND_48,
BAND_50,
BAND_51,
+ BAND_53,
BAND_65,
BAND_66,
BAND_70,
@@ -424,6 +804,7 @@ public final class AccessNetworkConstants {
BAND_93,
BAND_94,
BAND_95,
+ BAND_96,
BAND_257,
BAND_258,
BAND_260,
@@ -464,7 +845,8 @@ public final class AccessNetworkConstants {
value = {
FREQUENCY_RANGE_GROUP_UNKNOWN,
FREQUENCY_RANGE_GROUP_1,
- FREQUENCY_RANGE_GROUP_2})
+ FREQUENCY_RANGE_GROUP_2
+ })
public @interface FrequencyRangeGroup {}
/**
@@ -489,6 +871,7 @@ public final class AccessNetworkConstants {
case BAND_18:
case BAND_20:
case BAND_25:
+ case BAND_26:
case BAND_28:
case BAND_29:
case BAND_30:
@@ -497,9 +880,11 @@ public final class AccessNetworkConstants {
case BAND_39:
case BAND_40:
case BAND_41:
+ case BAND_46:
case BAND_48:
case BAND_50:
case BAND_51:
+ case BAND_53:
case BAND_65:
case BAND_66:
case BAND_70:
@@ -523,6 +908,7 @@ public final class AccessNetworkConstants {
case BAND_93:
case BAND_94:
case BAND_95:
+ case BAND_96:
return FREQUENCY_RANGE_GROUP_1;
case BAND_257:
case BAND_258:
@@ -538,6 +924,33 @@ public final class AccessNetworkConstants {
private NgranBands() {}
}
+ /**
+ * 3GPP TS 38.104 Table 5.4.2.1-1 NR-ARFCN parameters for the global frequency raster.
+ *
+ * @hide
+ */
+ enum NgranArfcnFrequency {
+
+ NGRAN_ARFCN_FREQUENCY_RANGE_1(5, 0, 0, 0, 599999),
+ NGRAN_ARFCN_FREQUENCY_RANGE_2(15, 3000000, 600000, 600000, 2016666),
+ NGRAN_ARFCN_FREQUENCY_RANGE_3(60, 24250080, 2016667, 2016667, 3279165);
+
+ NgranArfcnFrequency(int globalKhz, int rangeOffset, int arfcnOffset,
+ int rangeFirst, int rangeLast) {
+ this.globalKhz = globalKhz;
+ this.rangeOffset = rangeOffset;
+ this.arfcnOffset = arfcnOffset;
+ this.rangeFirst = rangeFirst;
+ this.rangeLast = rangeLast;
+ }
+
+ int globalKhz;
+ int rangeOffset;
+ int arfcnOffset;
+ int rangeFirst;
+ int rangeLast;
+ }
+
/** @hide */
private AccessNetworkConstants() {};
}
diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java
index 7661a32f6d5b..f29f3bd352be 100644
--- a/telephony/java/android/telephony/AccessNetworkUtils.java
+++ b/telephony/java/android/telephony/AccessNetworkUtils.java
@@ -4,12 +4,20 @@ import static android.telephony.ServiceState.DUPLEX_MODE_FDD;
import static android.telephony.ServiceState.DUPLEX_MODE_TDD;
import static android.telephony.ServiceState.DUPLEX_MODE_UNKNOWN;
+import android.telephony.AccessNetworkConstants.EutranBandArfcnFrequency;
import android.telephony.AccessNetworkConstants.EutranBand;
import android.telephony.AccessNetworkConstants.GeranBand;
+import android.telephony.AccessNetworkConstants.GeranBandArfcnFrequency;
+import android.telephony.AccessNetworkConstants.NgranArfcnFrequency;
+import android.telephony.AccessNetworkConstants.NgranBands;
import android.telephony.AccessNetworkConstants.UtranBand;
+import android.telephony.AccessNetworkConstants.UtranBandArfcnFrequency;
import android.telephony.ServiceState.DuplexMode;
+import android.util.Log;
import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
/**
* Utilities to map between radio constants.
@@ -22,9 +30,27 @@ public class AccessNetworkUtils {
private AccessNetworkUtils() {}
public static final int INVALID_BAND = -1;
+ public static final int INVALID_FREQUENCY = -1;
/** ISO country code of Japan. */
private static final String JAPAN_ISO_COUNTRY_CODE = "jp";
+ private static final String TAG = "AccessNetworkUtils";
+
+ private static final int FREQUENCY_KHZ = 1000;
+ private static final int FREQUENCY_RANGE_LOW_KHZ = 1000000;
+ private static final int FREQUENCY_RANGE_MID_KHZ = 3000000;
+ private static final int FREQUENCY_RANGE_HIGH_KHZ = 6000000;
+
+ private static final Set<Integer> UARFCN_NOT_GENERAL_BAND;
+ static {
+ UARFCN_NOT_GENERAL_BAND = new HashSet<Integer>();
+ UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_A);
+ UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_B);
+ UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_C);
+ UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_D);
+ UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_E);
+ UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_F);
+ }
/**
* Gets the duplex mode for the given EUTRAN operating band.
@@ -325,4 +351,403 @@ public class AccessNetworkUtils {
}
return INVALID_BAND;
}
+
+ /**
+ * Get geran bands from {@link PhysicalChannelConfig#getBand()}
+ */
+ public static int getFrequencyRangeGroupFromGeranBand(@GeranBand.GeranBands int band) {
+ switch (band) {
+ case GeranBand.BAND_T380:
+ case GeranBand.BAND_T410:
+ case GeranBand.BAND_450:
+ case GeranBand.BAND_480:
+ case GeranBand.BAND_710:
+ case GeranBand.BAND_750:
+ case GeranBand.BAND_T810:
+ case GeranBand.BAND_850:
+ case GeranBand.BAND_P900:
+ case GeranBand.BAND_E900:
+ case GeranBand.BAND_R900:
+ case GeranBand.BAND_ER900:
+ return ServiceState.FREQUENCY_RANGE_LOW;
+ case GeranBand.BAND_DCS1800:
+ case GeranBand.BAND_PCS1900:
+ return ServiceState.FREQUENCY_RANGE_MID;
+ default:
+ return ServiceState.FREQUENCY_RANGE_UNKNOWN;
+ }
+ }
+
+ /**
+ * Get utran bands from {@link PhysicalChannelConfig#getBand()}
+ */
+ public static int getFrequencyRangeGroupFromUtranBand(@UtranBand.UtranBands int band) {
+ switch (band) {
+ case UtranBand.BAND_5:
+ case UtranBand.BAND_6:
+ case UtranBand.BAND_8:
+ case UtranBand.BAND_12:
+ case UtranBand.BAND_13:
+ case UtranBand.BAND_14:
+ case UtranBand.BAND_19:
+ case UtranBand.BAND_20:
+ case UtranBand.BAND_26:
+ return ServiceState.FREQUENCY_RANGE_LOW;
+ case UtranBand.BAND_1:
+ case UtranBand.BAND_2:
+ case UtranBand.BAND_3:
+ case UtranBand.BAND_4:
+ case UtranBand.BAND_7:
+ case UtranBand.BAND_9:
+ case UtranBand.BAND_10:
+ case UtranBand.BAND_11:
+ case UtranBand.BAND_21:
+ case UtranBand.BAND_25:
+ case UtranBand.BAND_A:
+ case UtranBand.BAND_B:
+ case UtranBand.BAND_C:
+ case UtranBand.BAND_D:
+ case UtranBand.BAND_E:
+ case UtranBand.BAND_F:
+ return ServiceState.FREQUENCY_RANGE_MID;
+ case UtranBand.BAND_22:
+ return ServiceState.FREQUENCY_RANGE_HIGH;
+ default:
+ return ServiceState.FREQUENCY_RANGE_UNKNOWN;
+ }
+ }
+
+ /**
+ * Get eutran bands from {@link PhysicalChannelConfig#getBand()}
+ * 3GPP TS 36.101 Table 5.5 EUTRA operating bands
+ */
+ public static int getFrequencyRangeGroupFromEutranBand(@EutranBand.EutranBands int band) {
+ switch (band) {
+ case EutranBand.BAND_5:
+ case EutranBand.BAND_6:
+ case EutranBand.BAND_8:
+ case EutranBand.BAND_12:
+ case EutranBand.BAND_13:
+ case EutranBand.BAND_14:
+ case EutranBand.BAND_17:
+ case EutranBand.BAND_18:
+ case EutranBand.BAND_19:
+ case EutranBand.BAND_20:
+ case EutranBand.BAND_26:
+ case EutranBand.BAND_27:
+ case EutranBand.BAND_28:
+ case EutranBand.BAND_31:
+ case EutranBand.BAND_44:
+ case EutranBand.BAND_50:
+ case EutranBand.BAND_51:
+ case EutranBand.BAND_68:
+ case EutranBand.BAND_71:
+ case EutranBand.BAND_72:
+ case EutranBand.BAND_73:
+ case EutranBand.BAND_85:
+ case EutranBand.BAND_87:
+ case EutranBand.BAND_88:
+ return ServiceState.FREQUENCY_RANGE_LOW;
+ case EutranBand.BAND_1:
+ case EutranBand.BAND_2:
+ case EutranBand.BAND_3:
+ case EutranBand.BAND_4:
+ case EutranBand.BAND_7:
+ case EutranBand.BAND_9:
+ case EutranBand.BAND_10:
+ case EutranBand.BAND_11:
+ case EutranBand.BAND_21:
+ case EutranBand.BAND_23:
+ case EutranBand.BAND_24:
+ case EutranBand.BAND_25:
+ case EutranBand.BAND_30:
+ case EutranBand.BAND_33:
+ case EutranBand.BAND_34:
+ case EutranBand.BAND_35:
+ case EutranBand.BAND_36:
+ case EutranBand.BAND_37:
+ case EutranBand.BAND_38:
+ case EutranBand.BAND_39:
+ case EutranBand.BAND_40:
+ case EutranBand.BAND_41:
+ case EutranBand.BAND_45:
+ case EutranBand.BAND_53:
+ case EutranBand.BAND_65:
+ case EutranBand.BAND_66:
+ case EutranBand.BAND_70:
+ case EutranBand.BAND_74:
+ return ServiceState.FREQUENCY_RANGE_MID;
+ case EutranBand.BAND_22:
+ case EutranBand.BAND_42:
+ case EutranBand.BAND_43:
+ case EutranBand.BAND_46:
+ case EutranBand.BAND_47:
+ case EutranBand.BAND_48:
+ case EutranBand.BAND_49:
+ case EutranBand.BAND_52:
+ return ServiceState.FREQUENCY_RANGE_HIGH;
+ default:
+ return ServiceState.FREQUENCY_RANGE_UNKNOWN;
+ }
+ }
+
+ /**
+ * Get ngran band from {@link PhysicalChannelConfig#getBand()}
+ * 3GPP TS 38.104 Table 5.2-1 NR operating bands in FR1
+ * 3GPP TS 38.104 Table 5.2-2 NR operating bands in FR2
+ */
+ public static int getFrequencyRangeGroupFromNrBand(@NgranBands.NgranBand int band) {
+ switch (band) {
+ case NgranBands.BAND_5:
+ case NgranBands.BAND_8:
+ case NgranBands.BAND_12:
+ case NgranBands.BAND_14:
+ case NgranBands.BAND_18:
+ case NgranBands.BAND_20:
+ case NgranBands.BAND_26:
+ case NgranBands.BAND_28:
+ case NgranBands.BAND_29:
+ case NgranBands.BAND_71:
+ case NgranBands.BAND_81:
+ case NgranBands.BAND_82:
+ case NgranBands.BAND_83:
+ case NgranBands.BAND_89:
+ return ServiceState.FREQUENCY_RANGE_LOW;
+ case NgranBands.BAND_1:
+ case NgranBands.BAND_2:
+ case NgranBands.BAND_3:
+ case NgranBands.BAND_7:
+ case NgranBands.BAND_25:
+ case NgranBands.BAND_30:
+ case NgranBands.BAND_34:
+ case NgranBands.BAND_38:
+ case NgranBands.BAND_39:
+ case NgranBands.BAND_40:
+ case NgranBands.BAND_41:
+ case NgranBands.BAND_50:
+ case NgranBands.BAND_51:
+ case NgranBands.BAND_53:
+ case NgranBands.BAND_65:
+ case NgranBands.BAND_66:
+ case NgranBands.BAND_70:
+ case NgranBands.BAND_74:
+ case NgranBands.BAND_75:
+ case NgranBands.BAND_76:
+ case NgranBands.BAND_80:
+ case NgranBands.BAND_84:
+ case NgranBands.BAND_86:
+ case NgranBands.BAND_90:
+ case NgranBands.BAND_91:
+ case NgranBands.BAND_92:
+ case NgranBands.BAND_93:
+ case NgranBands.BAND_94:
+ case NgranBands.BAND_95:
+ return ServiceState.FREQUENCY_RANGE_MID;
+ case NgranBands.BAND_46:
+ case NgranBands.BAND_48:
+ case NgranBands.BAND_77:
+ case NgranBands.BAND_78:
+ case NgranBands.BAND_79:
+ return ServiceState.FREQUENCY_RANGE_HIGH;
+ case NgranBands.BAND_96:
+ case NgranBands.BAND_257:
+ case NgranBands.BAND_258:
+ case NgranBands.BAND_260:
+ case NgranBands.BAND_261:
+ return ServiceState.FREQUENCY_RANGE_MMWAVE;
+ default:
+ return ServiceState.FREQUENCY_RANGE_UNKNOWN;
+ }
+ }
+
+ /**
+ * 3GPP TS 38.104 Table 5.4.2.1-1 NR-ARFCN parameters for the global frequency raster.
+ * Formula of NR-ARFCN convert to actual frequency:
+ * Actual frequency(kHz) = (RANGE_OFFSET + GLOBAL_KHZ * (ARFCN - ARFCN_OFFSET))
+ */
+ public static int getFrequencyFromNrArfcn(int nrArfcn) {
+
+ int globalKhz = 0;
+ int rangeOffset = 0;
+ int arfcnOffset = 0;
+ for (NgranArfcnFrequency nrArfcnFrequency : AccessNetworkConstants.
+ NgranArfcnFrequency.values()) {
+ if (nrArfcn >= nrArfcnFrequency.rangeFirst
+ && nrArfcn <= nrArfcnFrequency.rangeLast) {
+ globalKhz = nrArfcnFrequency.globalKhz;
+ rangeOffset = nrArfcnFrequency.rangeOffset;
+ arfcnOffset = nrArfcnFrequency.arfcnOffset;
+ break;
+ }
+ }
+ return rangeOffset + globalKhz * (nrArfcn - arfcnOffset);
+ }
+
+ /**
+ * Get actual frequency from E-UTRA ARFCN.
+ */
+ public static int getFrequencyFromEarfcn(int band, int earfcn, boolean isUplink) {
+
+ int low = 0;
+ int offset = 0;
+ for (EutranBandArfcnFrequency earfcnFrequency : EutranBandArfcnFrequency.values()) {
+ if (band == earfcnFrequency.band) {
+ if (isInEarfcnRange(earfcn, earfcnFrequency, isUplink)) {
+ low = isUplink ? earfcnFrequency.uplinkLowKhz : earfcnFrequency.downlinkLowKhz;
+ offset = isUplink ? earfcnFrequency.uplinkOffset
+ : earfcnFrequency.downlinkOffset;
+ break;
+ } else {
+ Log.e(TAG, "Band and the range of EARFCN are not consistent.");
+ return INVALID_FREQUENCY;
+ }
+ }
+ }
+ return convertEarfcnToFrequency(low, earfcn, offset);
+ }
+
+ /**
+ * 3GPP TS 36.101 Table 5.7.3-1 E-UTRA channel numbers.
+ * Formula of E-UTRA ARFCN convert to actual frequency:
+ * Actual frequency(kHz) = (DOWNLINK_LOW + 0.1 * (ARFCN - DOWNLINK_OFFSET)) * FREQUENCY_KHZ
+ * Actual frequency(kHz) = (UPLINK_LOW + 0.1 * (ARFCN - UPLINK_OFFSET)) * FREQUENCY_KHZ
+ */
+ private static int convertEarfcnToFrequency(int low, int earfcn, int offset) {
+ return low + 100 * (earfcn - offset);
+ }
+
+ private static boolean isInEarfcnRange(int earfcn, EutranBandArfcnFrequency earfcnFrequency,
+ boolean isUplink) {
+ if (isUplink) {
+ return earfcn >= earfcnFrequency.uplinkOffset && earfcn <= earfcnFrequency.uplinkRange;
+ } else {
+ return earfcn >= earfcnFrequency.downlinkOffset
+ && earfcn <= earfcnFrequency.downlinkRange;
+ }
+ }
+
+ /**
+ * Get actual frequency from UTRA ARFCN.
+ */
+ public static int getFrequencyFromUarfcn(int band, int uarfcn, boolean isUplink) {
+
+ int offsetKhz = 0;
+ for (UtranBandArfcnFrequency uarfcnFrequency : AccessNetworkConstants.
+ UtranBandArfcnFrequency.values()) {
+ if (band == uarfcnFrequency.band) {
+ if (isInUarfcnRange(uarfcn, uarfcnFrequency, isUplink)) {
+ offsetKhz = isUplink ? uarfcnFrequency.uplinkOffset
+ : uarfcnFrequency.downlinkOffset;
+ break;
+ } else {
+ Log.e(TAG, "Band and the range of UARFCN are not consistent.");
+ return INVALID_FREQUENCY;
+ }
+ }
+ }
+
+ if (!UARFCN_NOT_GENERAL_BAND.contains(band)) {
+ return convertUarfcnToFrequency(offsetKhz, uarfcn);
+ } else {
+ return convertUarfcnTddToFrequency(band, uarfcn);
+ }
+ }
+
+ /**
+ * 3GPP TS 25.101, Table 5.1 UARFCN definition (general).
+ * Formula of UTRA ARFCN convert to actual frequency:
+ * For general bands:
+ * Downlink actual frequency(kHz) = (DOWNLINK_OFFSET + 0.2 * ARFCN) * FREQUENCY_KHZ
+ * Uplink actual frequency(kHz) = (UPLINK_OFFSET + 0.2 * ARFCN) * FREQUENCY_KHZ
+ */
+ private static int convertUarfcnToFrequency(int offsetKhz, int uarfcn) {
+ return offsetKhz + (200 * uarfcn);
+ }
+
+ /**
+ * 3GPP TS 25.102, Table 5.2 UTRA Absolute Radio Frequency Channel Number 1.28 Mcps TDD Option.
+ * For FDD bands A, B, C, E, F:
+ * Actual frequency(kHz) = 5 * ARFCN * FREQUENCY_KHZ
+ * For TDD bands D:
+ * Actual frequency(kHz) = (5 * (ARFCN - 2150.1MHz)) * FREQUENCY_KHZ
+ */
+ private static int convertUarfcnTddToFrequency(int band, int uarfcn) {
+ if (band != UtranBand.BAND_D) {
+ return 5 * uarfcn * FREQUENCY_KHZ;
+ } else {
+ return 5 * ((FREQUENCY_KHZ * uarfcn) - 2150100);
+ }
+ }
+
+ private static boolean isInUarfcnRange(int uarfcn, UtranBandArfcnFrequency uarfcnFrequency,
+ boolean isUplink) {
+ if (isUplink) {
+ return uarfcn >= uarfcnFrequency.uplinkRangeFirst
+ && uarfcn <= uarfcnFrequency.uplinkRangeLast;
+ } else {
+ if (uarfcnFrequency.downlinkRangeFirst != 0 && uarfcnFrequency.downlinkRangeLast != 0) {
+ return uarfcn >= uarfcnFrequency.downlinkRangeFirst
+ && uarfcn <= uarfcnFrequency.downlinkRangeLast;
+ } else {
+ // BAND_C, BAND_D, BAND_E and BAND_F do not have the downlink range.
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Get actual frequency from GERAN ARFCN.
+ */
+ public static int getFrequencyFromArfcn(int band, int arfcn, boolean isUplink) {
+
+ int uplinkFrequencyFirst = 0;
+ int arfcnOffset = 0;
+ int downlinkOffset = 0;
+ int frequency = 0;
+ for (GeranBandArfcnFrequency arfcnFrequency : AccessNetworkConstants.
+ GeranBandArfcnFrequency.values()) {
+ if (band == arfcnFrequency.band) {
+ if (arfcn >= arfcnFrequency.arfcnRangeFirst
+ && arfcn <= arfcnFrequency.arfcnRangeLast) {
+ uplinkFrequencyFirst = arfcnFrequency.uplinkFrequencyFirst;
+ downlinkOffset = arfcnFrequency.downlinkOffset;
+ arfcnOffset = arfcnFrequency.arfcnOffset;
+ frequency = convertArfcnToFrequency(arfcn, uplinkFrequencyFirst,
+ arfcnOffset);
+ break;
+ } else {
+ Log.e(TAG, "Band and the range of ARFCN are not consistent.");
+ return INVALID_FREQUENCY;
+ }
+ }
+ }
+
+ return isUplink ? frequency : frequency + downlinkOffset;
+ }
+
+ /**
+ * 3GPP TS 45.005 Table 2-1 Dynamically mapped ARFCN
+ * Formula of Geran ARFCN convert to actual frequency:
+ * Uplink actual frequency(kHz) =
+ * (UPLINK_FREQUENCY_FIRST + 0.2 * (ARFCN - ARFCN_RANGE_FIRST)) * FREQUENCY_KHZ
+ * Downlink actual frequency(kHz) = Uplink actual frequency + 10
+ */
+ private static int convertArfcnToFrequency(int arfcn, int uplinkFrequencyFirstKhz,
+ int arfcnOffset) {
+ return uplinkFrequencyFirstKhz + 200 * (arfcn - arfcnOffset);
+ }
+
+ public static int getFrequencyRangeFromArfcn(int frequency) {
+ if (frequency < FREQUENCY_RANGE_LOW_KHZ) {
+ return ServiceState.FREQUENCY_RANGE_LOW;
+ } else if (frequency < FREQUENCY_RANGE_MID_KHZ
+ && frequency >= FREQUENCY_RANGE_LOW_KHZ) {
+ return ServiceState.FREQUENCY_RANGE_MID;
+ } else if (frequency < FREQUENCY_RANGE_HIGH_KHZ
+ && frequency >= FREQUENCY_RANGE_MID_KHZ) {
+ return ServiceState.FREQUENCY_RANGE_HIGH;
+ } else {
+ return ServiceState.FREQUENCY_RANGE_MMWAVE;
+ }
+ }
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 74b2aad5293e..3a9896a5a91d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2774,6 +2774,30 @@ public class CarrierConfigManager {
public static final String IMSI_KEY_DOWNLOAD_URL_STRING = "imsi_key_download_url_string";
/**
+ * String representation of a carrier's public key used for IMSI encryption for ePDG. If this
+ * is provided, the device will use it as a fallback when no key exists on device, but the key
+ * download will still initiate.
+ * Example string:
+ * "-----BEGIN CERTIFICATE-----\nabcde12345abcde12345abcde12345abcde1234
+ * 5abcde12345abcde12345\nabcde12345abcde12345abcde12345abcde12345a\n-----END CERTIFICATE-----"
+ * @hide
+ */
+ public static final String IMSI_CARRIER_PUBLIC_KEY_EPDG_STRING =
+ "imsi_carrier_public_key_epdg_string";
+
+ /**
+ * String representation of a carrier's public key used for IMSI encryption for WLAN. If this
+ * is provided, the device will use it as a fallback when no key exists on device, but the key
+ * download will still initiate.
+ * Example string:
+ * "-----BEGIN CERTIFICATE-----\nabcde12345abcde12345abcde12345abcde1234
+ * 5abcde12345abcde12345\nabcde12345abcde12345abcde12345abcde12345a\n-----END CERTIFICATE-----"
+ * @hide
+ */
+ public static final String IMSI_CARRIER_PUBLIC_KEY_WLAN_STRING =
+ "imsi_carrier_public_key_wlan_string";
+
+ /**
* Identifies if the key is available for WLAN or EPDG or both. The value is a bitmask.
* 0 indicates that neither EPDG or WLAN is enabled.
* 1 indicates that key type TelephonyManager#KEY_TYPE_EPDG is enabled.
@@ -4077,6 +4101,24 @@ public class CarrierConfigManager {
"use_lower_mtu_value_if_both_received";
/**
+ * Determines the default RTT mode.
+ *
+ * Upon first boot, when the user has not yet set a value for their preferred RTT mode,
+ * the value of this config will be sent to the IMS stack. Valid values are the same as for
+ * {@link Settings.Secure#RTT_CALLING_MODE}.
+ *
+ * @hide
+ */
+ public static final String KEY_DEFAULT_RTT_MODE_INT =
+ "default_rtt_mode_int";
+
+ /**
+ * Indicates whether RTT is supported while roaming.
+ */
+ public static final String KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL =
+ "rtt_supported_while_roaming_bool";
+
+ /**
* Indicates if auto-configuration server is used for the RCS config
* Reference: GSMA RCC.14
*/
@@ -4433,6 +4475,8 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false);
sDefaults.putInt(IMSI_KEY_AVAILABILITY_INT, 0);
sDefaults.putString(IMSI_KEY_DOWNLOAD_URL_STRING, null);
+ sDefaults.putString(IMSI_CARRIER_PUBLIC_KEY_EPDG_STRING, null);
+ sDefaults.putString(IMSI_CARRIER_PUBLIC_KEY_WLAN_STRING, null);
sDefaults.putBoolean(KEY_CONVERT_CDMA_CALLER_ID_MMI_CODES_WHILE_ROAMING_ON_3GPP_BOOL,
false);
sDefaults.putStringArray(KEY_NON_ROAMING_OPERATOR_STRING_ARRAY, null);
@@ -4441,6 +4485,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false);
sDefaults.putBoolean(KEY_TTY_SUPPORTED_BOOL, true);
sDefaults.putBoolean(KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL, false);
+ sDefaults.putBoolean(KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL, false);
sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
sDefaults.putBoolean(KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL, true);
sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null);
@@ -4628,6 +4673,7 @@ public class CarrierConfigManager {
sDefaults.putString(KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING, "");
sDefaults.putBoolean(KEY_USE_LOWER_MTU_VALUE_IF_BOTH_RECEIVED, false);
sDefaults.putBoolean(KEY_USE_ACS_FOR_RCS_BOOL, false);
+ sDefaults.putInt(KEY_DEFAULT_RTT_MODE_INT, 0);
}
/**
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index d502da9fb9ec..99a77ae5d133 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -915,6 +915,8 @@ public final class DataFailCause {
public static final int IPV6_PREFIX_UNAVAILABLE = 0x8CA;
/** System preference change back to SRAT during handoff */
public static final int HANDOFF_PREFERENCE_CHANGED = 0x8CB;
+ /** Data call fail due to the slice not being allowed for the data call. */
+ public static final int SLICE_REJECTED = 0x8CC;
//IKE error notifications message as specified in 3GPP TS 24.302 (Section 8.1.2.2).
@@ -985,7 +987,7 @@ public final class DataFailCause {
* the authentication failed.
*/
public static final int IWLAN_IKEV2_AUTH_FAILURE = 0x4001;
- /** IKE message timeout, tunnel setup failed due to no response from EPDG */
+ /** IKE message timeout, tunnel setup failed due to no response from EPDG */
public static final int IWLAN_IKEV2_MSG_TIMEOUT = 0x4002;
/** IKE Certification validation failure */
public static final int IWLAN_IKEV2_CERT_INVALID = 0x4003;
@@ -1419,6 +1421,7 @@ public final class DataFailCause {
sFailCauseMap.put(VSNCP_RECONNECT_NOT_ALLOWED, "VSNCP_RECONNECT_NOT_ALLOWED");
sFailCauseMap.put(IPV6_PREFIX_UNAVAILABLE, "IPV6_PREFIX_UNAVAILABLE");
sFailCauseMap.put(HANDOFF_PREFERENCE_CHANGED, "HANDOFF_PREFERENCE_CHANGED");
+ sFailCauseMap.put(SLICE_REJECTED, "SLICE_REJECTED");
sFailCauseMap.put(IWLAN_PDN_CONNECTION_REJECTION, "IWLAN_PDN_CONNECTION_REJECTION");
sFailCauseMap.put(IWLAN_MAX_CONNECTION_REACHED, "IWLAN_MAX_CONNECTION_REACHED");
sFailCauseMap.put(IWLAN_SEMANTIC_ERROR_IN_THE_TFT_OPERATION,
diff --git a/telephony/java/android/telephony/ImsiEncryptionInfo.java b/telephony/java/android/telephony/ImsiEncryptionInfo.java
index 75a79d62d2aa..4978692d3964 100644
--- a/telephony/java/android/telephony/ImsiEncryptionInfo.java
+++ b/telephony/java/android/telephony/ImsiEncryptionInfo.java
@@ -163,8 +163,8 @@ public final class ImsiEncryptionInfo implements Parcelable {
public String toString(){
return "[ImsiEncryptionInfo "
+ "mcc=" + mcc
- + "mnc=" + mnc
- + "publicKey=" + publicKey
+ + " mnc=" + mnc
+ + " publicKey=" + publicKey
+ ", keyIdentifier=" + keyIdentifier
+ ", keyType=" + keyType
+ ", expirationTime=" + expirationTime
diff --git a/telephony/java/android/telephony/PhoneCapability.java b/telephony/java/android/telephony/PhoneCapability.java
index b785037e51c1..6571858fc4ae 100644
--- a/telephony/java/android/telephony/PhoneCapability.java
+++ b/telephony/java/android/telephony/PhoneCapability.java
@@ -28,8 +28,6 @@ import java.util.Objects;
/**
* Define capability of a modem group. That is, the capabilities
* are shared between those modems defined by list of modem IDs.
- *
- * @hide
*/
public final class PhoneCapability implements Parcelable {
// Hardcoded default DSDS capability.
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index ed09d538a3b1..1273aa3abbc9 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -478,7 +478,9 @@ public class PhoneNumberUtils {
/**
* Compare phone numbers a and b, return true if they're identical enough for caller ID purposes.
+ * @deprecated use {@link #areSamePhoneNumber(String, String, String)} instead
*/
+ @Deprecated
public static boolean compare(String a, String b) {
// We've used loose comparation at least Eclair, which may change in the future.
@@ -489,7 +491,9 @@ public class PhoneNumberUtils {
* Compare phone numbers a and b, and return true if they're identical
* enough for caller ID purposes. Checks a resource to determine whether
* to use a strict or loose comparison algorithm.
+ * @deprecated use {@link #areSamePhoneNumber(String, String, String)} instead
*/
+ @Deprecated
public static boolean compare(Context context, String a, String b) {
boolean useStrict = context.getResources().getBoolean(
com.android.internal.R.bool.config_use_strict_phone_number_comparation);
@@ -3218,7 +3222,7 @@ public class PhoneNumberUtils {
}
// The conversion map is not defined (this is default). Skip conversion.
- if (sConvertToEmergencyMap == null || sConvertToEmergencyMap.length == 0 ) {
+ if (sConvertToEmergencyMap == null || sConvertToEmergencyMap.length == 0) {
return number;
}
@@ -3254,4 +3258,47 @@ public class PhoneNumberUtils {
}
return number;
}
+
+ /**
+ * Determines if two phone numbers are the same.
+ * <p>
+ * Matching is based on <a href="https://github.com/google/libphonenumber>libphonenumber</a>.
+ * Unlike {@link #compare(String, String)}, matching takes into account national
+ * dialing plans rather than simply matching the last 7 digits of the two phone numbers. As a
+ * result, it is expected that some numbers which would match using the previous method will no
+ * longer match using this new approach.
+ *
+ * @param number1
+ * @param number2
+ * @param defaultCountryIso The lowercase two letter ISO 3166-1 country code. Used when parsing
+ * the phone numbers where it is not possible to determine the country
+ * associated with a phone number based on the number alone. It
+ * is recommended to pass in
+ * {@link TelephonyManager#getNetworkCountryIso()}.
+ * @return True if the two given phone number are same.
+ */
+ public static boolean areSamePhoneNumber(@NonNull String number1,
+ @NonNull String number2, @NonNull String defaultCountryIso) {
+ PhoneNumberUtil util = PhoneNumberUtil.getInstance();
+ PhoneNumber n1;
+ PhoneNumber n2;
+ defaultCountryIso = defaultCountryIso.toUpperCase();
+ try {
+ n1 = util.parseAndKeepRawInput(number1, defaultCountryIso);
+ n2 = util.parseAndKeepRawInput(number2, defaultCountryIso);
+ } catch (NumberParseException e) {
+ return false;
+ }
+
+ PhoneNumberUtil.MatchType matchType = util.isNumberMatch(n1, n2);
+ if (matchType == PhoneNumberUtil.MatchType.EXACT_MATCH
+ || matchType == PhoneNumberUtil.MatchType.NSN_MATCH) {
+ return true;
+ } else if (matchType == PhoneNumberUtil.MatchType.SHORT_NSN_MATCH) {
+ return (n1.getNationalNumber() == n2.getNationalNumber()
+ && n1.getCountryCode() == n2.getCountryCode());
+ } else {
+ return false;
+ }
+ }
}
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index af62ba4b93a1..9fb098ea8758 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -17,6 +17,8 @@
package android.telephony;
import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.Annotation.NetworkType;
@@ -26,12 +28,10 @@ import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Objects;
-/**
- * @hide
- */
public final class PhysicalChannelConfig implements Parcelable {
// TODO(b/72993578) consolidate these enums in a central location.
+ /** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef({CONNECTION_PRIMARY_SERVING, CONNECTION_SECONDARY_SERVING, CONNECTION_UNKNOWN})
public @interface ConnectionStatus {}
@@ -47,7 +47,25 @@ public final class PhysicalChannelConfig implements Parcelable {
public static final int CONNECTION_SECONDARY_SERVING = 2;
/** Connection status is unknown. */
- public static final int CONNECTION_UNKNOWN = Integer.MAX_VALUE;
+ public static final int CONNECTION_UNKNOWN = -1;
+
+ /** Channel number is unknown. */
+ public static final int CHANNEL_NUMBER_UNKNOWN = -1;
+
+ /** Physical Cell Id is unknown. */
+ public static final int PHYSICAL_CELL_ID_UNKNOWN = -1;
+
+ /** Physical Cell Id's maximum value is 1007. */
+ public static final int PHYSICAL_CELL_ID_MAXIMUM_VALUE = 1007;
+
+ /** Cell bandwidth is unknown. */
+ public static final int CELL_BANDWIDTH_UNKNOWN = 0;
+
+ /** The frequency is unknown. */
+ public static final int FREQUENCY_UNKNOWN = -1;
+
+ /** The band is unknown. */
+ public static final int BAND_UNKNOWN = 0;
/**
* Connection status of the cell.
@@ -58,15 +76,20 @@ public final class PhysicalChannelConfig implements Parcelable {
private int mCellConnectionStatus;
/**
- * Cell bandwidth, in kHz.
+ * Downlink cell bandwidth, in kHz.
*/
private int mCellBandwidthDownlinkKhz;
/**
+ * Uplink cell bandwidth, in kHz.
+ */
+ private int mCellBandwidthUplinkKhz;
+
+ /**
* The radio technology for this physical channel.
*/
@NetworkType
- private int mRat;
+ private int mNetworkType;
/**
* The rough frequency range for this physical channel.
@@ -75,9 +98,24 @@ public final class PhysicalChannelConfig implements Parcelable {
private int mFrequencyRange;
/**
- * The absolute radio frequency channel number, {@link Integer#MAX_VALUE} if unknown.
+ * The frequency of Downlink.
*/
- private int mChannelNumber;
+ private int mDownlinkFrequency;
+
+ /**
+ * The frequency of Uplink.
+ */
+ private int mUplinkFrequency;
+
+ /**
+ * Downlink Absolute Radio Frequency Channel Number
+ */
+ private int mDownlinkChannelNumber;
+
+ /**
+ * Uplink Absolute Radio Frequency Channel Number
+ */
+ private int mUplinkChannelNumber;
/**
* A list of data calls mapped to this physical channel. An empty list means the physical
@@ -86,51 +124,81 @@ public final class PhysicalChannelConfig implements Parcelable {
private int[] mContextIds;
/**
- * The physical cell identifier for this cell - PCI, PSC, {@link Integer#MAX_VALUE} if known.
+ * The physical cell identifier for this cell - PCI, PSC, {@link #PHYSICAL_CELL_ID_UNKNOWN}
*/
private int mPhysicalCellId;
+ /**
+ * This is the band which is being used.
+ */
+ private int mBand;
+
@Override
public int describeContents() {
return 0;
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mCellConnectionStatus);
dest.writeInt(mCellBandwidthDownlinkKhz);
- dest.writeInt(mRat);
- dest.writeInt(mChannelNumber);
+ dest.writeInt(mCellBandwidthUplinkKhz);
+ dest.writeInt(mNetworkType);
+ dest.writeInt(mDownlinkChannelNumber);
+ dest.writeInt(mUplinkChannelNumber);
dest.writeInt(mFrequencyRange);
dest.writeIntArray(mContextIds);
dest.writeInt(mPhysicalCellId);
+ dest.writeInt(mBand);
}
/**
- * @return Cell bandwidth, in kHz
+ * @return Downlink cell bandwidth in kHz, {@link #CELL_BANDWIDTH_UNKNOWN} if unknown.
*/
- public int getCellBandwidthDownlink() {
+ @IntRange(from = 1)
+ public int getCellBandwidthDownlinkKhz() {
return mCellBandwidthDownlinkKhz;
}
/**
+ * @return Uplink cell bandwidth in kHz, {@link #CELL_BANDWIDTH_UNKNOWN} if unknown.
+ */
+ @IntRange(from = 1)
+ public int getCellBandwidthUplinkKhz() {
+ return mCellBandwidthUplinkKhz;
+ }
+
+ /**
* Get the list of data call ids mapped to this physical channel. This list is sorted into
* ascending numerical order. Each id in this list must match the id in
* {@link com.android.internal.telephony.dataconnection.DataConnection}. An empty list means the
* physical channel has no data call mapped to it.
*
- * @return an integer list indicates the data call ids.
+ * @return an integer list indicates the data call ids,
+ * @hide
*/
public int[] getContextIds() {
return mContextIds;
}
/**
- * @return the rough frequency range for this physical channel.
+ * @return the absolute radio frequency channel number for this physical channel,
+ * {@link #CHANNEL_NUMBER_UNKNOWN} if unknown.
+ * @deprecated Use {@link #getDownlinkChannelNumber()} to get the channel number.
+ */
+ @Deprecated
+ public int getChannelNumber() {
+ return getDownlinkChannelNumber();
+ }
+
+ /**
+ * @return the rough frequency range for this physical channel,
+ * {@link ServiceState#FREQUENCY_RANGE_UNKNOWN} if unknown.
* @see {@link ServiceState#FREQUENCY_RANGE_LOW}
* @see {@link ServiceState#FREQUENCY_RANGE_MID}
* @see {@link ServiceState#FREQUENCY_RANGE_HIGH}
* @see {@link ServiceState#FREQUENCY_RANGE_MMWAVE}
+ * @hide
*/
@ServiceState.FrequencyRange
public int getFrequencyRange() {
@@ -138,11 +206,48 @@ public final class PhysicalChannelConfig implements Parcelable {
}
/**
- * @return the absolute radio frequency channel number for this physical channel,
- * {@link Integer#MAX_VALUE} if unknown.
+ * @return Downlink Absolute Radio Frequency Channel Number,
+ * {@link #CHANNEL_NUMBER_UNKNOWN} if unknown.
*/
- public int getChannelNumber() {
- return mChannelNumber;
+ @IntRange(from = 0)
+ public int getDownlinkChannelNumber() {
+ return mDownlinkChannelNumber;
+ }
+
+ /**
+ * @return Uplink Absolute Radio Frequency Channel Number,
+ * {@link #CHANNEL_NUMBER_UNKNOWN} if unknown.
+ */
+ @IntRange(from = 0)
+ public int getUplinkChannelNumber() {
+ return mUplinkChannelNumber;
+ }
+
+ /**
+ * The valid bands are {@link AccessNetworkConstants.GeranBand},
+ * {@link AccessNetworkConstants.UtranBand}, {@link AccessNetworkConstants.EutranBand} and
+ * {@link AccessNetworkConstants.NgranBands}.
+ *
+ * @return the frequency band, {@link #BAND_UNKNOWN} if unknown. */
+ @IntRange(from = 1, to = 261)
+ public int getBand() {
+ return mBand;
+ }
+
+ /**
+ * @return The downlink frequency in kHz, {@link #FREQUENCY_UNKNOWN} if unknown.
+ */
+ @IntRange(from = 0)
+ public int getDownlinkFrequencyKhz() {
+ return mDownlinkFrequency;
+ }
+
+ /**
+ * @return The uplink frequency in kHz, {@link #FREQUENCY_UNKNOWN} if unknown.
+ */
+ @IntRange(from = 0)
+ public int getUplinkFrequencyKhz() {
+ return mUplinkFrequency;
}
/**
@@ -152,19 +257,24 @@ public final class PhysicalChannelConfig implements Parcelable {
* In EUTRAN, this value is physical layer cell identity. The range is [0, 503].
* Reference: 3GPP TS 36.211 section 6.11.
*
- * In 5G RAN, this value is physical layer cell identity. The range is [0, 1008].
+ * In 5G RAN, this value is physical layer cell identity. The range is [0, 1007].
* Reference: 3GPP TS 38.211 section 7.4.2.1.
*
- * @return the physical cell identifier for this cell, {@link Integer#MAX_VALUE} if unknown.
+ * @return the physical cell identifier for this cell, {@link #PHYSICAL_CELL_ID_UNKNOWN}
+ * if {@link android.telephony.CellInfo#UNAVAILABLE}.
*/
+ @IntRange(from = 0, to = 1007)
public int getPhysicalCellId() {
return mPhysicalCellId;
}
- /**The radio technology for this physical channel. */
+ /**
+ * @return The network type for this physical channel,
+ * {@link TelephonyManager#NETWORK_TYPE_UNKNOWN} if unknown.
+ */
@NetworkType
- public int getRat() {
- return mRat;
+ public int getNetworkType() {
+ return mNetworkType;
}
/**
@@ -174,14 +284,17 @@ public final class PhysicalChannelConfig implements Parcelable {
* @see #CONNECTION_SECONDARY_SERVING
* @see #CONNECTION_UNKNOWN
*
- * @return Connection status of the cell
+ * @return Connection status of the cell, {@link #CONNECTION_UNKNOWN} if unknown.
*/
@ConnectionStatus
public int getConnectionStatus() {
return mCellConnectionStatus;
}
- /** @return String representation of the connection status */
+ /**
+ * @return String representation of the connection status
+ * @hide
+ */
private String getConnectionStatusString() {
switch(mCellConnectionStatus) {
case CONNECTION_PRIMARY_SERVING:
@@ -195,6 +308,97 @@ public final class PhysicalChannelConfig implements Parcelable {
}
}
+ private void setDownlinkFrequency() {
+ switch (mNetworkType) {
+ case TelephonyManager.NETWORK_TYPE_NR:
+ mDownlinkFrequency = AccessNetworkUtils.getFrequencyFromNrArfcn(
+ mDownlinkChannelNumber);
+ break;
+ case TelephonyManager.NETWORK_TYPE_LTE:
+ mDownlinkFrequency = AccessNetworkUtils.getFrequencyFromEarfcn(
+ mBand, mDownlinkChannelNumber, false);
+ break;
+ case TelephonyManager.NETWORK_TYPE_HSPAP:
+ case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+ case TelephonyManager.NETWORK_TYPE_UMTS:
+ case TelephonyManager.NETWORK_TYPE_HSDPA:
+ case TelephonyManager.NETWORK_TYPE_HSUPA:
+ case TelephonyManager.NETWORK_TYPE_HSPA:
+ mDownlinkFrequency = AccessNetworkUtils.getFrequencyFromUarfcn(
+ mBand, mDownlinkChannelNumber, false);
+ break;
+ case TelephonyManager.NETWORK_TYPE_GPRS:
+ case TelephonyManager.NETWORK_TYPE_EDGE:
+ case TelephonyManager.NETWORK_TYPE_GSM:
+ mDownlinkFrequency = AccessNetworkUtils.getFrequencyFromArfcn(
+ mBand, mDownlinkChannelNumber, false);
+ break;
+ }
+ }
+
+ private void setUplinkFrequency() {
+ switch (mNetworkType){
+ case TelephonyManager.NETWORK_TYPE_NR:
+ mUplinkFrequency = mDownlinkFrequency;
+ break;
+ case TelephonyManager.NETWORK_TYPE_LTE:
+ mUplinkFrequency = AccessNetworkUtils.getFrequencyFromEarfcn(
+ mBand, mUplinkChannelNumber, true);
+ break;
+ case TelephonyManager.NETWORK_TYPE_HSPAP:
+ case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+ case TelephonyManager.NETWORK_TYPE_UMTS:
+ case TelephonyManager.NETWORK_TYPE_HSDPA:
+ case TelephonyManager.NETWORK_TYPE_HSUPA:
+ case TelephonyManager.NETWORK_TYPE_HSPA:
+ mUplinkFrequency = AccessNetworkUtils.getFrequencyFromUarfcn(
+ mBand, mUplinkChannelNumber, true);
+ break;
+ case TelephonyManager.NETWORK_TYPE_GPRS:
+ case TelephonyManager.NETWORK_TYPE_EDGE:
+ case TelephonyManager.NETWORK_TYPE_GSM:
+ mUplinkFrequency = AccessNetworkUtils.getFrequencyFromArfcn(
+ mBand, mUplinkChannelNumber, true);
+ break;
+ }
+ }
+
+ private void setFrequencyRange() {
+ if (mFrequencyRange != ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+ return;
+ }
+
+ switch (mNetworkType) {
+ case TelephonyManager.NETWORK_TYPE_NR:
+ mFrequencyRange = AccessNetworkUtils.getFrequencyRangeGroupFromNrBand(mBand);
+ break;
+ case TelephonyManager.NETWORK_TYPE_LTE:
+ mFrequencyRange = AccessNetworkUtils.getFrequencyRangeGroupFromEutranBand(mBand);
+ break;
+ case TelephonyManager.NETWORK_TYPE_HSPAP:
+ case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+ case TelephonyManager.NETWORK_TYPE_UMTS:
+ case TelephonyManager.NETWORK_TYPE_HSDPA:
+ case TelephonyManager.NETWORK_TYPE_HSUPA:
+ case TelephonyManager.NETWORK_TYPE_HSPA:
+ mFrequencyRange = AccessNetworkUtils.getFrequencyRangeGroupFromUtranBand(mBand);
+ break;
+ case TelephonyManager.NETWORK_TYPE_GPRS:
+ case TelephonyManager.NETWORK_TYPE_EDGE:
+ case TelephonyManager.NETWORK_TYPE_GSM:
+ mFrequencyRange = AccessNetworkUtils.getFrequencyRangeGroupFromGeranBand(mBand);
+ break;
+ default:
+ mFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
+ break;
+ }
+
+ if (mFrequencyRange == ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+ mFrequencyRange = AccessNetworkUtils.getFrequencyRangeFromArfcn(
+ mDownlinkFrequency);
+ }
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -208,30 +412,37 @@ public final class PhysicalChannelConfig implements Parcelable {
PhysicalChannelConfig config = (PhysicalChannelConfig) o;
return mCellConnectionStatus == config.mCellConnectionStatus
&& mCellBandwidthDownlinkKhz == config.mCellBandwidthDownlinkKhz
- && mRat == config.mRat
+ && mCellBandwidthUplinkKhz == config.mCellBandwidthUplinkKhz
+ && mNetworkType == config.mNetworkType
&& mFrequencyRange == config.mFrequencyRange
- && mChannelNumber == config.mChannelNumber
+ && mDownlinkChannelNumber == config.mDownlinkChannelNumber
+ && mUplinkChannelNumber == config.mUplinkChannelNumber
&& mPhysicalCellId == config.mPhysicalCellId
- && Arrays.equals(mContextIds, config.mContextIds);
+ && Arrays.equals(mContextIds, config.mContextIds)
+ && mBand == config.mBand
+ && mDownlinkFrequency == config.mDownlinkFrequency
+ && mUplinkFrequency == config.mUplinkFrequency;
}
@Override
public int hashCode() {
return Objects.hash(
- mCellConnectionStatus, mCellBandwidthDownlinkKhz, mRat, mFrequencyRange,
- mChannelNumber, mPhysicalCellId, mContextIds);
+ mCellConnectionStatus, mCellBandwidthDownlinkKhz, mCellBandwidthUplinkKhz,
+ mNetworkType, mFrequencyRange, mDownlinkChannelNumber, mUplinkChannelNumber,
+ mContextIds, mPhysicalCellId, mBand, mDownlinkFrequency, mUplinkFrequency);
}
- public static final @android.annotation.NonNull Parcelable.Creator<PhysicalChannelConfig> CREATOR =
- new Parcelable.Creator<PhysicalChannelConfig>() {
- public PhysicalChannelConfig createFromParcel(Parcel in) {
- return new PhysicalChannelConfig(in);
- }
+ public static final
+ @android.annotation.NonNull Parcelable.Creator<PhysicalChannelConfig> CREATOR =
+ new Parcelable.Creator<PhysicalChannelConfig>() {
+ public PhysicalChannelConfig createFromParcel(Parcel in) {
+ return new PhysicalChannelConfig(in);
+ }
- public PhysicalChannelConfig[] newArray(int size) {
- return new PhysicalChannelConfig[size];
- }
- };
+ public PhysicalChannelConfig[] newArray(int size) {
+ return new PhysicalChannelConfig[size];
+ }
+ };
@Override
public String toString() {
@@ -240,16 +451,26 @@ public final class PhysicalChannelConfig implements Parcelable {
.append(getConnectionStatusString())
.append(",mCellBandwidthDownlinkKhz=")
.append(mCellBandwidthDownlinkKhz)
- .append(",mRat=")
- .append(TelephonyManager.getNetworkTypeName(mRat))
+ .append(",mCellBandwidthUplinkKhz=")
+ .append(mCellBandwidthUplinkKhz)
+ .append(",mNetworkType=")
+ .append(TelephonyManager.getNetworkTypeName(mNetworkType))
.append(",mFrequencyRange=")
.append(ServiceState.frequencyRangeToString(mFrequencyRange))
- .append(",mChannelNumber=")
- .append(mChannelNumber)
+ .append(",mDownlinkChannelNumber=")
+ .append(mDownlinkChannelNumber)
+ .append(",mUplinkChannelNumber=")
+ .append(mUplinkChannelNumber)
.append(",mContextIds=")
.append(Arrays.toString(mContextIds))
.append(",mPhysicalCellId=")
.append(mPhysicalCellId)
+ .append(",mBand=")
+ .append(mBand)
+ .append(",mDownlinkFrequency=")
+ .append(mDownlinkFrequency)
+ .append(",mUplinkFrequency=")
+ .append(mUplinkFrequency)
.append("}")
.toString();
}
@@ -257,89 +478,143 @@ public final class PhysicalChannelConfig implements Parcelable {
private PhysicalChannelConfig(Parcel in) {
mCellConnectionStatus = in.readInt();
mCellBandwidthDownlinkKhz = in.readInt();
- mRat = in.readInt();
- mChannelNumber = in.readInt();
+ mCellBandwidthUplinkKhz = in.readInt();
+ mNetworkType = in.readInt();
+ mDownlinkChannelNumber = in.readInt();
+ mUplinkChannelNumber = in.readInt();
mFrequencyRange = in.readInt();
mContextIds = in.createIntArray();
mPhysicalCellId = in.readInt();
+ mBand = in.readInt();
+ if (mBand > BAND_UNKNOWN) {
+ setDownlinkFrequency();
+ setUplinkFrequency();
+ setFrequencyRange();
+ }
}
private PhysicalChannelConfig(Builder builder) {
mCellConnectionStatus = builder.mCellConnectionStatus;
mCellBandwidthDownlinkKhz = builder.mCellBandwidthDownlinkKhz;
- mRat = builder.mRat;
- mChannelNumber = builder.mChannelNumber;
+ mCellBandwidthUplinkKhz = builder.mCellBandwidthUplinkKhz;
+ mNetworkType = builder.mNetworkType;
+ mDownlinkChannelNumber = builder.mDownlinkChannelNumber;
+ mUplinkChannelNumber = builder.mUplinkChannelNumber;
mFrequencyRange = builder.mFrequencyRange;
mContextIds = builder.mContextIds;
mPhysicalCellId = builder.mPhysicalCellId;
+ mBand = builder.mBand;
+ if (mBand > BAND_UNKNOWN) {
+ setDownlinkFrequency();
+ setUplinkFrequency();
+ setFrequencyRange();
+ }
}
- /** The builder of {@code PhysicalChannelConfig}. */
+ /**
+ * The builder of {@code PhysicalChannelConfig}.
+ * @hide
+ */
public static final class Builder {
- private int mRat;
+ private int mNetworkType;
private int mFrequencyRange;
- private int mChannelNumber;
+ private int mDownlinkChannelNumber;
+ private int mUplinkChannelNumber;
private int mCellBandwidthDownlinkKhz;
+ private int mCellBandwidthUplinkKhz;
private int mCellConnectionStatus;
private int[] mContextIds;
private int mPhysicalCellId;
+ private int mBand;
- /** @hide */
public Builder() {
- mRat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
+ mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
mFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
- mChannelNumber = Integer.MAX_VALUE;
- mCellBandwidthDownlinkKhz = 0;
+ mDownlinkChannelNumber = CHANNEL_NUMBER_UNKNOWN;
+ mUplinkChannelNumber = CHANNEL_NUMBER_UNKNOWN;
+ mCellBandwidthDownlinkKhz = CELL_BANDWIDTH_UNKNOWN;
+ mCellBandwidthUplinkKhz = CELL_BANDWIDTH_UNKNOWN;
mCellConnectionStatus = CONNECTION_UNKNOWN;
mContextIds = new int[0];
- mPhysicalCellId = Integer.MAX_VALUE;
+ mPhysicalCellId = PHYSICAL_CELL_ID_UNKNOWN;
+ mBand = BAND_UNKNOWN;
}
- /** @hide */
public PhysicalChannelConfig build() {
return new PhysicalChannelConfig(this);
}
- /** @hide */
- public Builder setRat(int rat) {
- this.mRat = rat;
+ public @NonNull Builder setNetworkType(@NetworkType int networkType) {
+ if (!TelephonyManager.isNetworkTypeValid(networkType)) {
+ throw new IllegalArgumentException("Network type: " + networkType + " is invalid.");
+ }
+ mNetworkType = networkType;
+ return this;
+ }
+
+ public @NonNull Builder setFrequencyRange(int frequencyRange) {
+ if (!ServiceState.isFrequencyRangeValid(frequencyRange)) {
+ throw new IllegalArgumentException("Frequency range: " + frequencyRange +
+ " is invalid.");
+ }
+ mFrequencyRange = frequencyRange;
+ return this;
+ }
+
+ public @NonNull Builder setDownlinkChannelNumber(int downlinkChannelNumber) {
+ mDownlinkChannelNumber = downlinkChannelNumber;
return this;
}
- /** @hide */
- public Builder setFrequencyRange(int frequencyRange) {
- this.mFrequencyRange = frequencyRange;
+ public @NonNull Builder setUplinkChannelNumber(int uplinkChannelNumber) {
+ mUplinkChannelNumber = uplinkChannelNumber;
return this;
}
- /** @hide */
- public Builder setChannelNumber(int channelNumber) {
- this.mChannelNumber = channelNumber;
+ public @NonNull Builder setCellBandwidthDownlinkKhz(int cellBandwidthDownlinkKhz) {
+ if (cellBandwidthDownlinkKhz < CELL_BANDWIDTH_UNKNOWN) {
+ throw new IllegalArgumentException("Cell downlink bandwidth(kHz): " +
+ cellBandwidthDownlinkKhz + " is invalid.");
+ }
+ mCellBandwidthDownlinkKhz = cellBandwidthDownlinkKhz;
return this;
}
- /** @hide */
- public Builder setCellBandwidthDownlinkKhz(int cellBandwidthDownlinkKhz) {
- this.mCellBandwidthDownlinkKhz = cellBandwidthDownlinkKhz;
+ public @NonNull Builder setCellBandwidthUplinkKhz(int cellBandwidthUplinkKhz) {
+ if (cellBandwidthUplinkKhz < CELL_BANDWIDTH_UNKNOWN) {
+ throw new IllegalArgumentException("Cell uplink bandwidth(kHz): "+
+ cellBandwidthUplinkKhz +" is invalid.");
+ }
+ mCellBandwidthUplinkKhz = cellBandwidthUplinkKhz;
return this;
}
- /** @hide */
- public Builder setCellConnectionStatus(int connectionStatus) {
- this.mCellConnectionStatus = connectionStatus;
+ public @NonNull Builder setCellConnectionStatus(int connectionStatus) {
+ mCellConnectionStatus = connectionStatus;
return this;
}
- /** @hide */
- public Builder setContextIds(int[] contextIds) {
+ public @NonNull Builder setContextIds(int[] contextIds) {
if (contextIds != null) Arrays.sort(contextIds);
- this.mContextIds = contextIds;
+ mContextIds = contextIds;
return this;
}
- /** @hide */
- public Builder setPhysicalCellId(int physicalCellId) {
- this.mPhysicalCellId = physicalCellId;
+ public @NonNull Builder setPhysicalCellId(int physicalCellId) {
+ if (physicalCellId > PHYSICAL_CELL_ID_MAXIMUM_VALUE) {
+ throw new IllegalArgumentException("Physical cell Id: " + physicalCellId +
+ " is over limit.");
+ }
+ mPhysicalCellId = physicalCellId;
+ return this;
+ }
+
+ public @NonNull Builder setBand(int band) {
+ if (band <= BAND_UNKNOWN) {
+ throw new IllegalArgumentException("Band: " + band +
+ " is invalid.");
+ }
+ mBand = band;
return this;
}
}
diff --git a/telephony/java/android/telephony/PreciseDisconnectCause.java b/telephony/java/android/telephony/PreciseDisconnectCause.java
index 250d9e8b212e..3b4cf75e7919 100644
--- a/telephony/java/android/telephony/PreciseDisconnectCause.java
+++ b/telephony/java/android/telephony/PreciseDisconnectCause.java
@@ -121,7 +121,7 @@ public final class PreciseDisconnectCause {
public static final int BEARER_CAPABILITY_NOT_AUTHORIZED = 57;
/** The requested bearer capability is not available at this time. */
public static final int BEARER_NOT_AVAIL = 58;
- /** The service option is not availble at this time. */
+ /** The service option is not available at this time. */
public static final int SERVICE_OPTION_NOT_AVAILABLE = 63;
/** The equipment sending this cause does not support the bearer capability requested. */
public static final int BEARER_SERVICE_NOT_IMPLEMENTED = 65;
diff --git a/telephony/java/android/telephony/RadioInterfaceCapabilities.java b/telephony/java/android/telephony/RadioInterfaceCapabilities.java
new file mode 100644
index 000000000000..7c7eb9fbbeb2
--- /dev/null
+++ b/telephony/java/android/telephony/RadioInterfaceCapabilities.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.util.ArraySet;
+
+/**
+ * Contains the set of supported capabilities that the Radio Interface supports on this device.
+ *
+ * @hide
+ */
+public class RadioInterfaceCapabilities {
+
+ private final ArraySet<String> mSupportedCapabilities;
+
+
+ public RadioInterfaceCapabilities() {
+ mSupportedCapabilities = new ArraySet<>();
+ }
+
+ /**
+ * Marks a capability as supported
+ *
+ * @param capabilityName the name of the capability
+ */
+ public void addSupportedCapability(
+ @TelephonyManager.RadioInterfaceCapability String capabilityName) {
+ mSupportedCapabilities.add(capabilityName);
+ }
+
+ /**
+ * Whether the capability is supported
+ *
+ * @param capabilityName the name of the capability
+ */
+ public boolean isSupported(String capabilityName) {
+ return mSupportedCapabilities.contains(capabilityName);
+ }
+}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index dedb1afa2495..f110daecd952 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -2111,4 +2111,23 @@ public class ServiceState implements Parcelable {
}
return false;
}
+
+ /**
+ * The frequency range is valid or not.
+ *
+ * @param frequencyRange The frequency range {@link FrequencyRange}.
+ * @return {@code true} if valid, {@code false} otherwise.
+ *
+ * @hide
+ */
+ public static boolean isFrequencyRangeValid(int frequencyRange) {
+ if (frequencyRange == FREQUENCY_RANGE_LOW
+ || frequencyRange == FREQUENCY_RANGE_MID
+ || frequencyRange == FREQUENCY_RANGE_HIGH
+ || frequencyRange == FREQUENCY_RANGE_MMWAVE) {
+ return true;
+ } else {
+ return false;
+ }
+ }
}
diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.aidl b/telephony/java/android/telephony/SignalStrengthUpdateRequest.aidl
new file mode 100644
index 000000000000..a45de2e58dd1
--- /dev/null
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright (C) 2020 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony;
+
+parcelable SignalStrengthUpdateRequest;
diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
new file mode 100644
index 000000000000..af67ed279fab
--- /dev/null
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Request used to register {@link SignalThresholdInfo} to be notified when the signal strength
+ * breach the specified thresholds.
+ */
+public final class SignalStrengthUpdateRequest implements Parcelable {
+ /**
+ * List of SignalThresholdInfo for the request.
+ */
+ private final List<SignalThresholdInfo> mSignalThresholdInfos;
+
+ /**
+ * Whether the reporting is required for thresholds in the request while device is idle.
+ */
+ private final boolean mIsReportingRequestedWhileIdle;
+
+ /**
+ * Whether the reporting requested for system thresholds while device is idle.
+ *
+ * System signal thresholds are loaded from carrier config items and mainly used for UI
+ * displaying. By default, they are ignored when device is idle. When setting the value to true,
+ * modem will continue reporting signal strength changes over the system signal thresholds even
+ * device is idle.
+ *
+ * This should only set to true by the system caller.
+ */
+ private final boolean mIsSystemThresholdReportingRequestedWhileIdle;
+
+ /**
+ * A IBinder object as a token for server side to check if the request client is still living.
+ */
+ private final IBinder mLiveToken;
+
+ private SignalStrengthUpdateRequest(
+ @NonNull List<SignalThresholdInfo> signalThresholdInfos,
+ boolean isReportingRequestedWhileIdle,
+ boolean isSystemThresholdReportingRequestedWhileIdle) {
+ validate(signalThresholdInfos);
+
+ mSignalThresholdInfos = signalThresholdInfos;
+ mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle;
+ mIsSystemThresholdReportingRequestedWhileIdle =
+ isSystemThresholdReportingRequestedWhileIdle;
+ mLiveToken = new Binder();
+ }
+
+ /**
+ * Builder class to create {@link SignalStrengthUpdateRequest} object.
+ */
+ public static final class Builder {
+ private List<SignalThresholdInfo> mSignalThresholdInfos = null;
+ private boolean mIsReportingRequestedWhileIdle = false;
+ private boolean mIsSystemThresholdReportingRequestedWhileIdle = false;
+
+ /**
+ * Set the collection of SignalThresholdInfo for the builder object
+ *
+ * @param signalThresholdInfos the collection of SignalThresholdInfo
+ *
+ * @return the builder to facilitate the chaining
+ */
+ public @NonNull Builder setSignalThresholdInfos(
+ @NonNull Collection<SignalThresholdInfo> signalThresholdInfos) {
+ Objects.requireNonNull(signalThresholdInfos,
+ "SignalThresholdInfo collection must not be null");
+ for (SignalThresholdInfo info : signalThresholdInfos) {
+ Objects.requireNonNull(info,
+ "SignalThresholdInfo in the collection must not be null");
+ }
+
+ mSignalThresholdInfos = new ArrayList<>(signalThresholdInfos);
+ // Sort the collection with RAN ascending order, make the ordering not matter for equals
+ mSignalThresholdInfos.sort(
+ Comparator.comparingInt(SignalThresholdInfo::getRadioAccessNetworkType));
+ return this;
+ }
+
+ /**
+ * Set the builder object if require reporting on thresholds in this request when device is
+ * idle.
+ *
+ * @param isReportingRequestedWhileIdle true if request reporting when device is idle
+ *
+ * @return the builder to facilitate the chaining
+ */
+ public @NonNull Builder setReportingRequestedWhileIdle(
+ boolean isReportingRequestedWhileIdle) {
+ mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle;
+ return this;
+ }
+
+ /**
+ * Set the builder object if require reporting on the system thresholds when device is idle.
+ *
+ * This can only used by the system caller.
+ *
+ * @param isSystemThresholdReportingRequestedWhileIdle true if request reporting on the
+ * system thresholds when device is idle
+ * @return the builder to facilitate the chaining
+ * @hide
+ */
+ public @NonNull Builder setSystemThresholdReportingRequestedWhileIdle(
+ boolean isSystemThresholdReportingRequestedWhileIdle) {
+ mIsSystemThresholdReportingRequestedWhileIdle =
+ isSystemThresholdReportingRequestedWhileIdle;
+ return this;
+ }
+
+ /**
+ * Build a {@link SignalStrengthUpdateRequest} object.
+ *
+ * @return the SignalStrengthUpdateRequest object
+ *
+ * @throws IllegalArgumentException if the SignalThresholdInfo collection is empty size, the
+ * radio access network type in the collection is not unique
+ */
+ public @NonNull SignalStrengthUpdateRequest build() {
+ return new SignalStrengthUpdateRequest(mSignalThresholdInfos,
+ mIsReportingRequestedWhileIdle, mIsSystemThresholdReportingRequestedWhileIdle);
+ }
+ }
+
+ private SignalStrengthUpdateRequest(Parcel in) {
+ mSignalThresholdInfos = in.createTypedArrayList(SignalThresholdInfo.CREATOR);
+ mIsReportingRequestedWhileIdle = in.readBoolean();
+ mIsSystemThresholdReportingRequestedWhileIdle = in.readBoolean();
+ mLiveToken = in.readStrongBinder();
+ }
+
+ /**
+ * Get the collection of SignalThresholdInfo in the request.
+ *
+ * @return the collection of SignalThresholdInfo
+ */
+ @NonNull
+ public Collection<SignalThresholdInfo> getSignalThresholdInfos() {
+ return Collections.unmodifiableList(mSignalThresholdInfos);
+ }
+
+ /**
+ * Get whether reporting is requested for the threshold in the request while device is idle.
+ *
+ * @return true if reporting requested while device is idle
+ */
+ public boolean isReportingRequestedWhileIdle() {
+ return mIsReportingRequestedWhileIdle;
+ }
+
+ /**
+ * @return true if reporting requested for system thresholds while device is idle
+ *
+ * @hide
+ */
+ public boolean isSystemThresholdReportingRequestedWhileIdle() {
+ return mIsSystemThresholdReportingRequestedWhileIdle;
+ }
+
+ /*
+ * @return the live token of the request
+ *
+ * @hide
+ */
+ public @NonNull IBinder getLiveToken() {
+ return mLiveToken;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeTypedList(mSignalThresholdInfos);
+ dest.writeBoolean(mIsReportingRequestedWhileIdle);
+ dest.writeBoolean(mIsSystemThresholdReportingRequestedWhileIdle);
+ dest.writeStrongBinder(mLiveToken);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) return true;
+
+ if (!(other instanceof SignalStrengthUpdateRequest)) {
+ return false;
+ }
+
+ SignalStrengthUpdateRequest request = (SignalStrengthUpdateRequest) other;
+ return mSignalThresholdInfos.equals(request.mSignalThresholdInfos)
+ && mIsReportingRequestedWhileIdle == request.mIsReportingRequestedWhileIdle
+ && mIsSystemThresholdReportingRequestedWhileIdle
+ == request.mIsSystemThresholdReportingRequestedWhileIdle;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSignalThresholdInfos, mIsReportingRequestedWhileIdle,
+ mIsSystemThresholdReportingRequestedWhileIdle);
+ }
+
+ public static final @NonNull Parcelable.Creator<SignalStrengthUpdateRequest> CREATOR =
+ new Parcelable.Creator<SignalStrengthUpdateRequest>() {
+ @Override
+ public SignalStrengthUpdateRequest createFromParcel(Parcel source) {
+ return new SignalStrengthUpdateRequest(source);
+ }
+
+ @Override
+ public SignalStrengthUpdateRequest[] newArray(int size) {
+ return new SignalStrengthUpdateRequest[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return new StringBuilder("SignalStrengthUpdateRequest{")
+ .append("mSignalThresholdInfos=")
+ .append(mSignalThresholdInfos)
+ .append(" mIsReportingRequestedWhileIdle=")
+ .append(mIsReportingRequestedWhileIdle)
+ .append(" mIsSystemThresholdReportingRequestedWhileIdle=")
+ .append(mIsSystemThresholdReportingRequestedWhileIdle)
+ .append(" mLiveToken")
+ .append(mLiveToken)
+ .append("}").toString();
+ }
+
+ /**
+ * Throw IAE when the RAN in the collection is not unique.
+ */
+ private static void validate(Collection<SignalThresholdInfo> infos) {
+ Set<Integer> uniqueRan = new HashSet<>(infos.size());
+ for (SignalThresholdInfo info : infos) {
+ final int ran = info.getRadioAccessNetworkType();
+ if (!uniqueRan.add(ran)) {
+ throw new IllegalArgumentException("RAN: " + ran + " is not unique");
+ }
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/SignalThresholdInfo.java b/telephony/java/android/telephony/SignalThresholdInfo.java
index f6f6d75c37c6..0059ad6c2426 100644
--- a/telephony/java/android/telephony/SignalThresholdInfo.java
+++ b/telephony/java/android/telephony/SignalThresholdInfo.java
@@ -28,101 +28,109 @@ import java.util.Objects;
/**
* Defines the threshold value of the signal strength.
- * @hide
*/
-public class SignalThresholdInfo implements Parcelable {
+public final class SignalThresholdInfo implements Parcelable {
+
+ /**
+ * Unknown signal measurement type.
+ */
+ public static final int SIGNAL_MEASUREMENT_TYPE_UNKNOWN = 0;
+
/**
* Received Signal Strength Indication.
* Range: -113 dBm and -51 dBm
- * Used RAN: GERAN, CDMA2000
+ * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#GERAN},
+ * {@link AccessNetworkConstants.AccessNetworkType#CDMA2000}
* Reference: 3GPP TS 27.007 section 8.5.
*/
- public static final int SIGNAL_RSSI = 1;
+ public static final int SIGNAL_MEASUREMENT_TYPE_RSSI = 1;
/**
* Received Signal Code Power.
* Range: -120 dBm to -25 dBm;
- * Used RAN: UTRAN
+ * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#UTRAN}
* Reference: 3GPP TS 25.123, section 9.1.1.1
*/
- public static final int SIGNAL_RSCP = 2;
+ public static final int SIGNAL_MEASUREMENT_TYPE_RSCP = 2;
/**
* Reference Signal Received Power.
* Range: -140 dBm to -44 dBm;
- * Used RAN: EUTRAN
+ * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#EUTRAN}
* Reference: 3GPP TS 36.133 9.1.4
*/
- public static final int SIGNAL_RSRP = 3;
+ public static final int SIGNAL_MEASUREMENT_TYPE_RSRP = 3;
/**
* Reference Signal Received Quality
- * Range: -20 dB to -3 dB;
- * Used RAN: EUTRAN
+ * Range: -34 dB to 3 dB;
+ * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#EUTRAN}
* Reference: 3GPP TS 36.133 9.1.7
*/
- public static final int SIGNAL_RSRQ = 4;
+ public static final int SIGNAL_MEASUREMENT_TYPE_RSRQ = 4;
/**
* Reference Signal Signal to Noise Ratio
* Range: -20 dB to 30 dB;
- * Used RAN: EUTRAN
+ * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#EUTRAN}
*/
- public static final int SIGNAL_RSSNR = 5;
+ public static final int SIGNAL_MEASUREMENT_TYPE_RSSNR = 5;
/**
* 5G SS reference signal received power.
* Range: -140 dBm to -44 dBm.
- * Used RAN: NGRAN
+ * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#NGRAN}
* Reference: 3GPP TS 38.215.
*/
- public static final int SIGNAL_SSRSRP = 6;
+ public static final int SIGNAL_MEASUREMENT_TYPE_SSRSRP = 6;
/**
* 5G SS reference signal received quality.
- * Range: -20 dB to -3 dB.
- * Used RAN: NGRAN
- * Reference: 3GPP TS 38.215.
+ * Range: -43 dB to 20 dB.
+ * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#NGRAN}
+ * Reference: 3GPP TS 38.133 section 10.1.11.1.
*/
- public static final int SIGNAL_SSRSRQ = 7;
+ public static final int SIGNAL_MEASUREMENT_TYPE_SSRSRQ = 7;
/**
* 5G SS signal-to-noise and interference ratio.
* Range: -23 dB to 40 dB
- * Used RAN: NGRAN
+ * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#NGRAN}
* Reference: 3GPP TS 38.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1.
*/
- public static final int SIGNAL_SSSINR = 8;
+ public static final int SIGNAL_MEASUREMENT_TYPE_SSSINR = 8;
/** @hide */
- @IntDef(prefix = { "SIGNAL_" }, value = {
- SIGNAL_RSSI,
- SIGNAL_RSCP,
- SIGNAL_RSRP,
- SIGNAL_RSRQ,
- SIGNAL_RSSNR,
- SIGNAL_SSRSRP,
- SIGNAL_SSRSRQ,
- SIGNAL_SSSINR
+ @IntDef(prefix = {"SIGNAL_MEASUREMENT_TYPE_"}, value = {
+ SIGNAL_MEASUREMENT_TYPE_UNKNOWN,
+ SIGNAL_MEASUREMENT_TYPE_RSSI,
+ SIGNAL_MEASUREMENT_TYPE_RSCP,
+ SIGNAL_MEASUREMENT_TYPE_RSRP,
+ SIGNAL_MEASUREMENT_TYPE_RSRQ,
+ SIGNAL_MEASUREMENT_TYPE_RSSNR,
+ SIGNAL_MEASUREMENT_TYPE_SSRSRP,
+ SIGNAL_MEASUREMENT_TYPE_SSRSRQ,
+ SIGNAL_MEASUREMENT_TYPE_SSSINR
})
@Retention(RetentionPolicy.SOURCE)
- public @interface SignalMeasurementType {}
+ public @interface SignalMeasurementType {
+ }
@SignalMeasurementType
- private int mSignalMeasurement;
+ private final int mSignalMeasurementType;
/**
* A hysteresis time in milliseconds to prevent flapping.
* A value of 0 disables hysteresis
*/
- private int mHysteresisMs;
+ private final int mHysteresisMs;
/**
* An interval in dB defining the required magnitude change between reports.
* hysteresisDb must be smaller than the smallest threshold delta.
* An interval value of 0 disables hysteresis.
*/
- private int mHysteresisDb;
+ private final int mHysteresisDb;
/**
* List of threshold values.
@@ -130,60 +138,399 @@ public class SignalThresholdInfo implements Parcelable {
* The threshold values for which to apply criteria.
* A vector size of 0 disables the use of thresholds for reporting.
*/
- private int[] mThresholds = null;
+ private final int[] mThresholds;
/**
* {@code true} means modem must trigger the report based on the criteria;
* {@code false} means modem must not trigger the report based on the criteria.
*/
- private boolean mIsEnabled = true;
+ private final boolean mIsEnabled;
+
+ /**
+ * The radio access network type associated with the signal thresholds.
+ */
+ @AccessNetworkConstants.RadioAccessNetworkType
+ private final int mRan;
/**
* Indicates the hysteresisMs is disabled.
+ *
+ * @hide
*/
public static final int HYSTERESIS_MS_DISABLED = 0;
/**
* Indicates the hysteresisDb is disabled.
+ *
+ * @hide
*/
public static final int HYSTERESIS_DB_DISABLED = 0;
+
+ /**
+ * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSSI}.
+ *
+ * @hide
+ */
+ public static final int SIGNAL_RSSI_MIN_VALUE = -113;
+
+ /**
+ * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSSI}.
+ *
+ * @hide
+ */
+ public static final int SIGNAL_RSSI_MAX_VALUE = -51;
+
+ /**
+ * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSCP}.
+ *
+ * @hide
+ */
+ public static final int SIGNAL_RSCP_MIN_VALUE = -120;
+
+ /**
+ * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSCP}.
+ *
+ * @hide
+ */
+ public static final int SIGNAL_RSCP_MAX_VALUE = -25;
+
+ /**
+ * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSRP}.
+ *
+ * @hide
+ */
+ public static final int SIGNAL_RSRP_MIN_VALUE = -140;
+
+ /**
+ * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSRP}.
+ *
+ * @hide
+ */
+ public static final int SIGNAL_RSRP_MAX_VALUE = -44;
+
+ /**
+ * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSRQ}.
+ *
+ * @hide
+ */
+ public static final int SIGNAL_RSRQ_MIN_VALUE = -34;
+
+ /**
+ * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSRQ}.
+ *
+ * @hide
+ */
+ public static final int SIGNAL_RSRQ_MAX_VALUE = 3;
+
+ /**
+ * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSSNR}.
+ *
+ * @hide
+ */
+ public static final int SIGNAL_RSSNR_MIN_VALUE = -20;
+
+ /**
+ * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSSNR}.
+ *
+ * @hide
+ */
+ public static final int SIGNAL_RSSNR_MAX_VALUE = 30;
+
+ /**
+ * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_SSRSRP}.
+ *
+ * @hide
+ */
+ public static final int SIGNAL_SSRSRP_MIN_VALUE = -140;
+
+ /**
+ * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_SSRSRP}.
+ *
+ * @hide
+ */
+ public static final int SIGNAL_SSRSRP_MAX_VALUE = -44;
+
+ /**
+ * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_SSRSRQ}.
+ *
+ * @hide
+ */
+ public static final int SIGNAL_SSRSRQ_MIN_VALUE = -43;
+
+ /**
+ * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_SSRSRQ}.
+ *
+ * @hide
+ */
+ public static final int SIGNAL_SSRSRQ_MAX_VALUE = 20;
+
+ /**
+ * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_SSSINR}.
+ *
+ * @hide
+ */
+ public static final int SIGNAL_SSSINR_MIN_VALUE = -23;
+
+ /**
+ * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_SSSINR}.
+ *
+ * @hide
+ */
+ public static final int SIGNAL_SSSINR_MAX_VALUE = 40;
+
+ /**
+ * The minimum number of thresholds allowed in each SignalThresholdInfo.
+ *
+ * @hide
+ */
+ public static final int MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED = 1;
+
+ /**
+ * The maximum number of thresholds allowed in each SignalThresholdInfo.
+ *
+ * @hide
+ */
+ public static final int MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED = 4;
+
/**
* Constructor
*
- * @param signalMeasurement Signal Measurement Type
- * @param hysteresisMs hysteresisMs
- * @param hysteresisDb hysteresisDb
- * @param thresholds threshold value
- * @param isEnabled isEnabled
- */
- public SignalThresholdInfo(@SignalMeasurementType int signalMeasurement,
- int hysteresisMs, int hysteresisDb, @NonNull int [] thresholds, boolean isEnabled) {
- mSignalMeasurement = signalMeasurement;
+ * @param ran Radio Access Network type
+ * @param signalMeasurementType Signal Measurement Type
+ * @param hysteresisMs hysteresisMs
+ * @param hysteresisDb hysteresisDb
+ * @param thresholds threshold value
+ * @param isEnabled isEnabled
+ */
+ private SignalThresholdInfo(@AccessNetworkConstants.RadioAccessNetworkType int ran,
+ @SignalMeasurementType int signalMeasurementType, int hysteresisMs, int hysteresisDb,
+ @NonNull int[] thresholds, boolean isEnabled) {
+ Objects.requireNonNull(thresholds, "thresholds must not be null");
+ validateRanWithMeasurementType(ran, signalMeasurementType);
+ validateThresholdRange(signalMeasurementType, thresholds);
+
+ mRan = ran;
+ mSignalMeasurementType = signalMeasurementType;
mHysteresisMs = hysteresisMs < 0 ? HYSTERESIS_MS_DISABLED : hysteresisMs;
mHysteresisDb = hysteresisDb < 0 ? HYSTERESIS_DB_DISABLED : hysteresisDb;
- mThresholds = thresholds == null ? null : thresholds.clone();
+ mThresholds = thresholds;
mIsEnabled = isEnabled;
}
- public @SignalMeasurementType int getSignalMeasurement() {
- return mSignalMeasurement;
+ /**
+ * Builder class to create {@link SignalThresholdInfo} objects.
+ */
+ public static final class Builder {
+ private int mRan = AccessNetworkConstants.AccessNetworkType.UNKNOWN;
+ private int mSignalMeasurementType = SIGNAL_MEASUREMENT_TYPE_UNKNOWN;
+ private int mHysteresisMs = HYSTERESIS_MS_DISABLED;
+ private int mHysteresisDb = HYSTERESIS_DB_DISABLED;
+ private int[] mThresholds = null;
+ private boolean mIsEnabled = false;
+
+ /**
+ * Set the radio access network type for the builder instance.
+ *
+ * @param ran The radio access network type
+ * @return the builder to facilitate the chaining
+ */
+ public @NonNull Builder setRadioAccessNetworkType(
+ @AccessNetworkConstants.RadioAccessNetworkType int ran) {
+ mRan = ran;
+ return this;
+ }
+
+ /**
+ * Set the signal measurement type for the builder instance.
+ *
+ * @param signalMeasurementType The signal measurement type
+ * @return the builder to facilitate the chaining
+ */
+ public @NonNull Builder setSignalMeasurementType(
+ @SignalMeasurementType int signalMeasurementType) {
+ mSignalMeasurementType = signalMeasurementType;
+ return this;
+ }
+
+ /**
+ * Set the hysteresis time in milliseconds to prevent flapping. A value of 0 disables
+ * hysteresis.
+ *
+ * @param hysteresisMs the hysteresis time in milliseconds
+ * @return the builder to facilitate the chaining
+ * @hide
+ */
+ public @NonNull Builder setHysteresisMs(int hysteresisMs) {
+ mHysteresisMs = hysteresisMs;
+ return this;
+ }
+
+ /**
+ * Set the interval in dB defining the required magnitude change between reports. A value of
+ * zero disabled dB-based hysteresis restrictions.
+ *
+ * @param hysteresisDb the interval in dB
+ * @return the builder to facilitate the chaining
+ * @hide
+ */
+ public @NonNull Builder setHysteresisDb(int hysteresisDb) {
+ mHysteresisDb = hysteresisDb;
+ return this;
+ }
+
+ /**
+ * Set the signal strength thresholds of the corresponding signal measurement type.
+ *
+ * The range and unit must reference specific SignalMeasurementType. The length of the
+ * thresholds should between the numbers return from
+ * {@link #getMinimumNumberOfThresholdsAllowed()} and
+ * {@link #getMaximumNumberOfThresholdsAllowed()}. An IllegalArgumentException will throw
+ * otherwise.
+ *
+ * @param thresholds array of integer as the signal threshold values
+ * @return the builder to facilitate the chaining
+ *
+ * @see #SIGNAL_MEASUREMENT_TYPE_RSSI
+ * @see #SIGNAL_MEASUREMENT_TYPE_RSCP
+ * @see #SIGNAL_MEASUREMENT_TYPE_RSRP
+ * @see #SIGNAL_MEASUREMENT_TYPE_RSRQ
+ * @see #SIGNAL_MEASUREMENT_TYPE_RSSNR
+ * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRP
+ * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRQ
+ * @see #SIGNAL_MEASUREMENT_TYPE_SSSINR
+ * @see #getThresholds() for more details on signal strength thresholds
+ */
+ public @NonNull Builder setThresholds(@NonNull int[] thresholds) {
+ Objects.requireNonNull(thresholds, "thresholds must not be null");
+ if (thresholds.length < MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED
+ || thresholds.length > MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED) {
+ throw new IllegalArgumentException(
+ "thresholds length must between " + MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED
+ + " and " + MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED);
+ }
+ mThresholds = thresholds.clone();
+ Arrays.sort(mThresholds);
+ return this;
+ }
+
+ /**
+ * Set the signal strength thresholds for the corresponding signal measurement type without
+ * the length limitation.
+ *
+ * @param thresholds array of integer as the signal threshold values
+ * @return the builder to facilitate the chaining
+ *
+ * @hide
+ */
+ public @NonNull Builder setThresholdsUnlimited(@NonNull int[] thresholds) {
+ Objects.requireNonNull(thresholds, "thresholds must not be null");
+ mThresholds = thresholds.clone();
+ Arrays.sort(mThresholds);
+ return this;
+ }
+
+
+ /**
+ * Set if the modem should trigger the report based on the criteria.
+ *
+ * @param isEnabled true if the modem should trigger the report based on the criteria
+ * @return the builder to facilitate the chaining
+ * @hide
+ */
+ public @NonNull Builder setIsEnabled(boolean isEnabled) {
+ mIsEnabled = isEnabled;
+ return this;
+ }
+
+ /**
+ * Build {@link SignalThresholdInfo} object.
+ *
+ * @return the SignalThresholdInfo object build out
+ *
+ * @throws IllegalArgumentException if the signal measurement type is invalid, any value in
+ * the thresholds is out of range, or the RAN is not allowed to set with the signal
+ * measurement type
+ */
+ public @NonNull SignalThresholdInfo build() {
+ return new SignalThresholdInfo(mRan, mSignalMeasurementType, mHysteresisMs,
+ mHysteresisDb, mThresholds, mIsEnabled);
+ }
+ }
+
+ /**
+ * Get the radio access network type.
+ *
+ * @return radio access network type
+ */
+ public @AccessNetworkConstants.RadioAccessNetworkType int getRadioAccessNetworkType() {
+ return mRan;
+ }
+
+ /**
+ * Get the signal measurement type.
+ *
+ * @return the SignalMeasurementType value
+ */
+ public @SignalMeasurementType int getSignalMeasurementType() {
+ return mSignalMeasurementType;
}
+ /** @hide */
public int getHysteresisMs() {
return mHysteresisMs;
}
+ /** @hide */
public int getHysteresisDb() {
return mHysteresisDb;
}
+ /** @hide */
public boolean isEnabled() {
return mIsEnabled;
}
- public int[] getThresholds() {
- return mThresholds == null ? null : mThresholds.clone();
+ /**
+ * Get the signal strength thresholds.
+ *
+ * Signal strength thresholds are a list of integer used for suggesting signal level and signal
+ * reporting criteria. The range and unit must reference specific SignalMeasurementType.
+ *
+ * Please refer to https://source.android.com/devices/tech/connect/signal-strength on how signal
+ * strength thresholds are used for signal strength reporting.
+ *
+ * @return array of integer of the signal thresholds
+ *
+ * @see #SIGNAL_MEASUREMENT_TYPE_RSSI
+ * @see #SIGNAL_MEASUREMENT_TYPE_RSCP
+ * @see #SIGNAL_MEASUREMENT_TYPE_RSRP
+ * @see #SIGNAL_MEASUREMENT_TYPE_RSRQ
+ * @see #SIGNAL_MEASUREMENT_TYPE_RSSNR
+ * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRP
+ * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRQ
+ * @see #SIGNAL_MEASUREMENT_TYPE_SSSINR
+ */
+ public @NonNull int[] getThresholds() {
+ return mThresholds.clone();
+ }
+
+ /**
+ * Get the minimum number of thresholds allowed in each SignalThresholdInfo.
+ *
+ * @return the minimum number of thresholds allowed
+ */
+ public static int getMinimumNumberOfThresholdsAllowed() {
+ return MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED;
+ }
+
+ /**
+ * Get the maximum number of threshold allowed in each SignalThresholdInfo.
+ *
+ * @return the maximum number of thresholds allowed
+ */
+ public static int getMaximumNumberOfThresholdsAllowed() {
+ return MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED;
}
@Override
@@ -192,8 +539,9 @@ public class SignalThresholdInfo implements Parcelable {
}
@Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mSignalMeasurement);
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeInt(mRan);
+ out.writeInt(mSignalMeasurementType);
out.writeInt(mHysteresisMs);
out.writeInt(mHysteresisDb);
out.writeIntArray(mThresholds);
@@ -201,7 +549,8 @@ public class SignalThresholdInfo implements Parcelable {
}
private SignalThresholdInfo(Parcel in) {
- mSignalMeasurement = in.readInt();
+ mRan = in.readInt();
+ mSignalMeasurementType = in.readInt();
mHysteresisMs = in.readInt();
mHysteresisDb = in.readInt();
mThresholds = in.createIntArray();
@@ -217,7 +566,8 @@ public class SignalThresholdInfo implements Parcelable {
}
SignalThresholdInfo other = (SignalThresholdInfo) o;
- return mSignalMeasurement == other.mSignalMeasurement
+ return mRan == other.mRan
+ && mSignalMeasurementType == other.mSignalMeasurementType
&& mHysteresisMs == other.mHysteresisMs
&& mHysteresisDb == other.mHysteresisDb
&& Arrays.equals(mThresholds, other.mThresholds)
@@ -226,8 +576,8 @@ public class SignalThresholdInfo implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(
- mSignalMeasurement, mHysteresisMs, mHysteresisDb, mThresholds, mIsEnabled);
+ return Objects.hash(mRan, mSignalMeasurementType, mHysteresisMs, mHysteresisDb, mThresholds,
+ mIsEnabled);
}
public static final @NonNull Parcelable.Creator<SignalThresholdInfo> CREATOR =
@@ -246,11 +596,83 @@ public class SignalThresholdInfo implements Parcelable {
@Override
public String toString() {
return new StringBuilder("SignalThresholdInfo{")
- .append("mSignalMeasurement=").append(mSignalMeasurement)
- .append("mHysteresisMs=").append(mSignalMeasurement)
- .append("mHysteresisDb=").append(mHysteresisDb)
- .append("mThresholds=").append(Arrays.toString(mThresholds))
- .append("mIsEnabled=").append(mIsEnabled)
- .append("}").toString();
+ .append("mRan=").append(mRan)
+ .append(" mSignalMeasurementType=").append(mSignalMeasurementType)
+ .append(" mHysteresisMs=").append(mHysteresisMs)
+ .append(" mHysteresisDb=").append(mHysteresisDb)
+ .append(" mThresholds=").append(Arrays.toString(mThresholds))
+ .append(" mIsEnabled=").append(mIsEnabled)
+ .append("}").toString();
+ }
+
+ /**
+ * Return true if signal measurement type is valid and the threshold value is in range.
+ */
+ private static boolean isValidThreshold(@SignalMeasurementType int type, int threshold) {
+ switch (type) {
+ case SIGNAL_MEASUREMENT_TYPE_RSSI:
+ return threshold >= SIGNAL_RSSI_MIN_VALUE && threshold <= SIGNAL_RSSI_MAX_VALUE;
+ case SIGNAL_MEASUREMENT_TYPE_RSCP:
+ return threshold >= SIGNAL_RSCP_MIN_VALUE && threshold <= SIGNAL_RSCP_MAX_VALUE;
+ case SIGNAL_MEASUREMENT_TYPE_RSRP:
+ return threshold >= SIGNAL_RSRP_MIN_VALUE && threshold <= SIGNAL_RSRP_MAX_VALUE;
+ case SIGNAL_MEASUREMENT_TYPE_RSRQ:
+ return threshold >= SIGNAL_RSRQ_MIN_VALUE && threshold <= SIGNAL_RSRQ_MAX_VALUE;
+ case SIGNAL_MEASUREMENT_TYPE_RSSNR:
+ return threshold >= SIGNAL_RSSNR_MIN_VALUE && threshold <= SIGNAL_RSSNR_MAX_VALUE;
+ case SIGNAL_MEASUREMENT_TYPE_SSRSRP:
+ return threshold >= SIGNAL_SSRSRP_MIN_VALUE && threshold <= SIGNAL_SSRSRP_MAX_VALUE;
+ case SIGNAL_MEASUREMENT_TYPE_SSRSRQ:
+ return threshold >= SIGNAL_SSRSRQ_MIN_VALUE && threshold <= SIGNAL_SSRSRQ_MAX_VALUE;
+ case SIGNAL_MEASUREMENT_TYPE_SSSINR:
+ return threshold >= SIGNAL_SSSINR_MIN_VALUE && threshold <= SIGNAL_SSSINR_MAX_VALUE;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Return true if the radio access type is allowed to set with the measurement type.
+ */
+ private static boolean isValidRanWithMeasurementType(
+ @AccessNetworkConstants.RadioAccessNetworkType int ran,
+ @SignalMeasurementType int type) {
+ switch (type) {
+ case SIGNAL_MEASUREMENT_TYPE_RSSI:
+ return ran == AccessNetworkConstants.AccessNetworkType.GERAN
+ || ran == AccessNetworkConstants.AccessNetworkType.CDMA2000;
+ case SIGNAL_MEASUREMENT_TYPE_RSCP:
+ return ran == AccessNetworkConstants.AccessNetworkType.UTRAN;
+ case SIGNAL_MEASUREMENT_TYPE_RSRP:
+ case SIGNAL_MEASUREMENT_TYPE_RSRQ:
+ case SIGNAL_MEASUREMENT_TYPE_RSSNR:
+ return ran == AccessNetworkConstants.AccessNetworkType.EUTRAN;
+ case SIGNAL_MEASUREMENT_TYPE_SSRSRP:
+ case SIGNAL_MEASUREMENT_TYPE_SSRSRQ:
+ case SIGNAL_MEASUREMENT_TYPE_SSSINR:
+ return ran == AccessNetworkConstants.AccessNetworkType.NGRAN;
+ default:
+ return false;
+ }
+ }
+
+ private void validateRanWithMeasurementType(
+ @AccessNetworkConstants.RadioAccessNetworkType int ran,
+ @SignalMeasurementType int signalMeasurement) {
+ if (!isValidRanWithMeasurementType(ran, signalMeasurement)) {
+ throw new IllegalArgumentException(
+ "invalid RAN: " + ran + " with signal measurement type: " + signalMeasurement);
+ }
+ }
+
+ private void validateThresholdRange(@SignalMeasurementType int signalMeasurement,
+ int[] thresholds) {
+ for (int threshold : thresholds) {
+ if (!isValidThreshold(signalMeasurement, threshold)) {
+ throw new IllegalArgumentException(
+ "invalid signal measurement type: " + signalMeasurement
+ + " with threshold: " + threshold);
+ }
+ }
}
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index bcc2c67bd8e7..b958bff6d00b 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -345,7 +345,6 @@ public final class SmsManager {
* where this operation may fail.
* </p>
*
- *
* @param destinationAddress the address to send the message to
* @param scAddress is the service center address or null to use
* the current default SMSC
@@ -358,7 +357,6 @@ public final class SmsManager {
* <code>RESULT_ERROR_RADIO_OFF</code><br>
* <code>RESULT_ERROR_NULL_PDU</code><br>
* <code>RESULT_ERROR_NO_SERVICE</code><br>
- * <code>RESULT_ERROR_NO_SERVICE</code><br>
* <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
* <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
* <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
@@ -473,7 +471,6 @@ public final class SmsManager {
* <code>RESULT_ERROR_RADIO_OFF</code><br>
* <code>RESULT_ERROR_NULL_PDU</code><br>
* <code>RESULT_ERROR_NO_SERVICE</code><br>
- * <code>RESULT_ERROR_NO_SERVICE</code><br>
* <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
* <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
* <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
@@ -862,22 +859,20 @@ public final class SmsManager {
* where this operation may fail.
* </p>
*
- *
* @param destinationAddress the address to send the message to
* @param scAddress is the service center address or null to use
- * the current default SMSC
+ * the current default SMSC
* @param parts an <code>ArrayList</code> of strings that, in order,
- * comprise the original message
+ * comprise the original message
* @param sentIntents if not null, an <code>ArrayList</code> of
- * <code>PendingIntent</code>s (one for each message part) that is
- * broadcast when the corresponding message part has been sent.
- * The result code will be <code>Activity.RESULT_OK</code> for success,
- * or one of these errors:<br>
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been sent.
+ * The result code will be <code>Activity.RESULT_OK</code> for success,
+ * or one of these errors:<br>
* <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
* <code>RESULT_ERROR_RADIO_OFF</code><br>
* <code>RESULT_ERROR_NULL_PDU</code><br>
* <code>RESULT_ERROR_NO_SERVICE</code><br>
- * <code>RESULT_ERROR_NO_SERVICE</code><br>
* <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
* <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
* <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
@@ -933,14 +928,14 @@ public final class SmsManager {
* For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
* the sentIntent may include the extra "errorCode" containing a radio technology specific
* value, generally only useful for troubleshooting.<br>
- * The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applications,
- * which cause smaller number of SMS to be sent in checking period.
+ * The per-application based SMS control checks sentIntent. If sentIntent
+ * is NULL the caller will be checked against all unknown applications,
+ * which cause smaller number of SMS to be sent in checking period.
* @param deliveryIntents if not null, an <code>ArrayList</code> of
- * <code>PendingIntent</code>s (one for each message part) that is
- * broadcast when the corresponding message part has been delivered
- * to the recipient. The raw pdu of the status report is in the
- * extended data ("pdu").
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been delivered
+ * to the recipient. The raw pdu of the status report is in the
+ * extended data ("pdu").
*
* @throws IllegalArgumentException if destinationAddress or data are empty
*/
@@ -1123,22 +1118,21 @@ public final class SmsManager {
* boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
* where this operation may fail.
* </p>
-
+ *
* @param destinationAddress the address to send the message to
* @param scAddress is the service center address or null to use
- * the current default SMSC
+ * the current default SMSC
* @param parts an <code>ArrayList</code> of strings that, in order,
- * comprise the original message
+ * comprise the original message
* @param sentIntents if not null, an <code>ArrayList</code> of
- * <code>PendingIntent</code>s (one for each message part) that is
- * broadcast when the corresponding message part has been sent.
- * The result code will be <code>Activity.RESULT_OK</code> for success,
- * or one of these errors:<br>
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been sent.
+ * The result code will be <code>Activity.RESULT_OK</code> for success,
+ * or one of these errors:<br>
* <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
* <code>RESULT_ERROR_RADIO_OFF</code><br>
* <code>RESULT_ERROR_NULL_PDU</code><br>
* <code>RESULT_ERROR_NO_SERVICE</code><br>
- * <code>RESULT_ERROR_NO_SERVICE</code><br>
* <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
* <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
* <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
@@ -1194,14 +1188,14 @@ public final class SmsManager {
* For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
* the sentIntent may include the extra "errorCode" containing a radio technology specific
* value, generally only useful for troubleshooting.<br>
- * The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applications,
- * which cause smaller number of SMS to be sent in checking period.
+ * The per-application based SMS control checks sentIntent. If sentIntent
+ * is NULL the caller will be checked against all unknown applications,
+ * which cause smaller number of SMS to be sent in checking period.
* @param deliveryIntents if not null, an <code>ArrayList</code> of
- * <code>PendingIntent</code>s (one for each message part) that is
- * broadcast when the corresponding message part has been delivered
- * to the recipient. The raw pdu of the status report is in the
- * extended data ("pdu").
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been delivered
+ * to the recipient. The raw pdu of the status report is in the
+ * extended data ("pdu").
* @param priority Priority level of the message
* Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
* ---------------------------------
@@ -1340,7 +1334,6 @@ public final class SmsManager {
* <code>RESULT_ERROR_RADIO_OFF</code><br>
* <code>RESULT_ERROR_NULL_PDU</code><br>
* <code>RESULT_ERROR_NO_SERVICE</code><br>
- * <code>RESULT_ERROR_NO_SERVICE</code><br>
* <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
* <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
* <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
diff --git a/telephony/java/android/telephony/TelephonyDisplayInfo.java b/telephony/java/android/telephony/TelephonyDisplayInfo.java
index 3d5c6aad1042..1fcb504e7895 100644
--- a/telephony/java/android/telephony/TelephonyDisplayInfo.java
+++ b/telephony/java/android/telephony/TelephonyDisplayInfo.java
@@ -29,6 +29,10 @@ import java.util.Objects;
* information is provided in accordance with carrier policy and branding preferences; it is not
* necessarily a precise or accurate representation of the current state and should be treated
* accordingly.
+ * To be notified of changes in TelephonyDisplayInfo, use
+ * {@link TelephonyManager#registerPhoneStateListener} with a {@link PhoneStateListener}
+ * that implements {@link PhoneStateListener.DisplayInfoChangedListener}.
+ * Override the onDisplayInfoChanged() method to handle the broadcast.
*/
public final class TelephonyDisplayInfo implements Parcelable {
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index c05e90b28fa8..646744da5336 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -120,10 +120,12 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -155,6 +157,7 @@ import java.util.function.Consumer;
public class TelephonyManager {
private static final String TAG = "TelephonyManager";
+ private TelephonyRegistryManager mTelephonyRegistryMgr;
/**
* To expand the error codes for {@link TelephonyManager#updateAvailableNetworks} and
* {@link TelephonyManager#setPreferredOpportunisticDataSubscription}.
@@ -5569,8 +5572,7 @@ public class TelephonyManager {
//
/**
- * Registers a listener object to receive notification of changes
- * in specified telephony states.
+ * Registers a listener object to receive notification of changes in specified telephony states.
* <p>
* To register a listener, pass a {@link PhoneStateListener} and specify at least one telephony
* state of interest in the events argument.
@@ -5580,13 +5582,15 @@ public class TelephonyManager {
* values.
* <p>
* To un-register a listener, pass the listener object and set the events argument to
- * {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0).
+ * {@link PhoneStateListener#LISTEN_NONE} (0).
*
* If this TelephonyManager object has been created with {@link #createForSubscriptionId},
* applies to the given subId. Otherwise, applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}. To listen events for multiple subIds,
+ * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}. To listen events for multiple subIds,
* pass a separate listener object to each TelephonyManager object created with
- * {@link #createForSubscriptionId}.
+ * {@link #createForSubscriptionId}. Only {@link PhoneStateListener#LISTEN_CALL_STATE} event can
+ * be used to receive changes for all subIds through
+ * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}.
*
* Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
* call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
@@ -5596,23 +5600,28 @@ public class TelephonyManager {
* instability. If a process has registered too many listeners without unregistering them, it
* may encounter an {@link IllegalStateException} when trying to register more listeners.
*
- * @param listener The {@link PhoneStateListener} object to register
- * (or unregister)
- * @param events The telephony state(s) of interest to the listener,
- * as a bitwise-OR combination of {@link PhoneStateListener}
- * LISTEN_ flags.
+ * @param listener The {@link PhoneStateListener} object to register (or unregister)
+ * @param events The telephony state(s) of interest to the listener, as a bitwise-OR combination
+ * of {@link PhoneStateListener} LISTEN_ flags.
+ * @deprecated Use {@link #registerPhoneStateListener(Executor, PhoneStateListener)}.
*/
+ @Deprecated
public void listen(PhoneStateListener listener, int events) {
- if (mContext == null) return;
- boolean notifyNow = (getITelephony() != null);
- TelephonyRegistryManager telephonyRegistry =
- (TelephonyRegistryManager)
- mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
- if (telephonyRegistry != null) {
- telephonyRegistry.listenForSubscriber(mSubId, getOpPackageName(), getAttributionTag(),
- listener, events, notifyNow);
+ if (!listener.isExecutorSet()) {
+ throw new IllegalStateException("PhoneStateListener should be created on a thread "
+ + "with Looper.myLooper() != null");
+ }
+ boolean notifyNow = getITelephony() != null;
+ mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
+ if (mTelephonyRegistryMgr != null) {
+ if (events != PhoneStateListener.LISTEN_NONE) {
+ mTelephonyRegistryMgr.registerPhoneStateListenerWithEvents(mSubId,
+ getOpPackageName(), getAttributionTag(), listener, events, notifyNow);
+ } else {
+ unregisterPhoneStateListener(listener);
+ }
} else {
- Rlog.w(TAG, "telephony registry not ready.");
+ throw new IllegalStateException("telephony service is null.");
}
}
@@ -7448,18 +7457,23 @@ public class TelephonyManager {
}
/**
- * Set IMS registration state
+ * Set IMS registration state on all active subscriptions.
+ * <p/>
+ * Use {@link android.telephony.ims.stub.ImsRegistrationImplBase#onRegistered} and
+ * {@link android.telephony.ims.stub.ImsRegistrationImplBase#onDeregistered} to set Ims
+ * registration state instead.
+ *
+ * @param registered whether ims is registered
*
- * @param Registration state
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public void setImsRegistrationState(boolean registered) {
+ public void setImsRegistrationState(final boolean registered) {
try {
- ITelephony telephony = getITelephony();
+ final ITelephony telephony = getITelephony();
if (telephony != null)
telephony.setImsRegistrationState(registered);
- } catch (RemoteException e) {
+ } catch (final RemoteException e) {
}
}
@@ -8689,11 +8703,18 @@ public class TelephonyManager {
*/
public static final int CALL_COMPOSER_STATUS_ON = 1;
+ /**
+ * Call composer status indicating that sending/receiving pictures is disabled.
+ * All other attachments are still enabled in this state.
+ */
+ public static final int CALL_COMPOSER_STATUS_ON_NO_PICTURES = 2;
+
/** @hide */
@IntDef(prefix = {"CALL_COMPOSER_STATUS_"},
value = {
CALL_COMPOSER_STATUS_ON,
CALL_COMPOSER_STATUS_OFF,
+ CALL_COMPOSER_STATUS_ON_NO_PICTURES,
})
public @interface CallComposerStatus {}
@@ -8701,8 +8722,9 @@ public class TelephonyManager {
* Set the user-set status for enriched calling with call composer.
*
* @param status user-set status for enriched calling with call composer;
- * it must be a value of either {@link #CALL_COMPOSER_STATUS_ON}
- * or {@link #CALL_COMPOSER_STATUS_OFF}.
+ * it must be any of {@link #CALL_COMPOSER_STATUS_ON}
+ * {@link #CALL_COMPOSER_STATUS_OFF},
+ * or {@link #CALL_COMPOSER_STATUS_ON_NO_PICTURES}
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
* given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
@@ -8712,7 +8734,8 @@ public class TelephonyManager {
*/
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void setCallComposerStatus(@CallComposerStatus int status) {
- if (status != CALL_COMPOSER_STATUS_ON && status != CALL_COMPOSER_STATUS_OFF) {
+ if (status > CALL_COMPOSER_STATUS_ON_NO_PICTURES
+ || status < CALL_COMPOSER_STATUS_OFF) {
throw new IllegalArgumentException("requested status is invalid");
}
try {
@@ -8734,8 +8757,9 @@ public class TelephonyManager {
*
* @throws SecurityException if the caller does not have the permission.
*
- * @return the user-set status for enriched calling with call composer either
- * {@link #CALL_COMPOSER_STATUS_ON} or {@link #CALL_COMPOSER_STATUS_OFF}.
+ * @return the user-set status for enriched calling with call composer, any of
+ * {@link #CALL_COMPOSER_STATUS_ON}, {@link #CALL_COMPOSER_STATUS_OFF}, or
+ * {@link #CALL_COMPOSER_STATUS_ON_NO_PICTURES}.
*/
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @CallComposerStatus int getCallComposerStatus() {
@@ -9438,9 +9462,16 @@ public class TelephonyManager {
* @return true if mobile data is enabled.
*/
@RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE,
- android.Manifest.permission.MODIFY_PHONE_STATE})
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_STATE})
public boolean isDataEnabled() {
- return getDataEnabled(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
+ try {
+ return isDataEnabledForReason(DATA_ENABLED_REASON_USER);
+ } catch (IllegalStateException ise) {
+ // TODO(b/176163590): Remove this catch once TelephonyManager is booting safely.
+ Log.e(TAG, "Error calling #isDataEnabled, returning default (false).", ise);
+ return false;
+ }
}
/**
@@ -9685,7 +9716,7 @@ public class TelephonyManager {
@SystemApi
public boolean getDataEnabled(int subId) {
try {
- return isDataEnabledForReason(DATA_ENABLED_REASON_USER);
+ return isDataEnabledForReason(subId, DATA_ENABLED_REASON_USER);
} catch (RuntimeException e) {
Log.e(TAG, "Error calling isDataEnabledForReason e:" + e);
}
@@ -14313,6 +14344,40 @@ public class TelephonyManager {
return Collections.emptyList();
}
+ /** @hide */
+ @IntDef(prefix = {"RADIO_INTERFACE_CAPABILITY_"},
+ value = {})
+ public @interface RadioInterfaceCapability {}
+
+ /**
+ * Whether the device supports a given capability on the radio interface.
+ *
+ * If the capability is not in the set of radio interface capabilities, false is returned.
+ *
+ * @param capability the name of the capability to check for
+ * @return the availability of the capability
+ *
+ * @hide
+ */
+ public boolean isRadioInterfaceCapabilitySupported(
+ @NonNull @RadioInterfaceCapability String capability) {
+ try {
+ if (capability == null) return false;
+
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.isRadioInterfaceCapabilitySupported(capability);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ if (!isSystemProcess()) {
+ ex.rethrowAsRuntimeException();
+ }
+ }
+ return false;
+ }
+
/**
* Indicates that the thermal mitigation request was completed successfully.
*
@@ -14583,4 +14648,165 @@ public class TelephonyManager {
e.execute(() -> callback.onAuthenticationFailure(GBA_FAILURE_REASON_FEATURE_NOT_READY));
}
}
+
+ /**
+ * Registers a listener object to receive notification of changes in specified telephony states.
+ * <p>
+ * To register a listener, pass a {@link PhoneStateListener} which implements
+ * interfaces of events. For example,
+ * FakeServiceStateChangedListener extends {@link PhoneStateListener} implements
+ * {@link PhoneStateListener.ServiceStateChangedListener}.
+ *
+ * At registration, and when a specified telephony state changes, the telephony manager invokes
+ * the appropriate callback method on the listener object and passes the current (updated)
+ * values.
+ * <p>
+ *
+ * If this TelephonyManager object has been created with {@link #createForSubscriptionId},
+ * applies to the given subId. Otherwise, applies to
+ * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}. To listen events for multiple subIds,
+ * pass a separate listener object to each TelephonyManager object created with
+ * {@link #createForSubscriptionId}. Only {@link PhoneStateListener.CallStateChangedListener}
+ * can be used to receive changes for all subIds through
+ * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}.
+ *
+ * Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
+ * call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
+ * {@link SecurityException} will be thrown otherwise.
+ *
+ * This API should be used sparingly -- large numbers of listeners will cause system
+ * instability. If a process has registered too many listeners without unregistering them, it
+ * may encounter an {@link IllegalStateException} when trying to register more listeners.
+ *
+ * @param executor The executor of where the callback will execute.
+ * @param listener The {@link PhoneStateListener} object to register.
+ */
+ public void registerPhoneStateListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull PhoneStateListener listener) {
+ if (executor == null || listener == null) {
+ throw new IllegalArgumentException("PhoneStateListener and executor must be non-null");
+ }
+ mTelephonyRegistryMgr = (TelephonyRegistryManager)
+ mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
+ if (mTelephonyRegistryMgr != null) {
+ mTelephonyRegistryMgr.registerPhoneStateListener(executor, mSubId,
+ getOpPackageName(), getAttributionTag(), listener, getITelephony() != null);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ }
+
+ /**
+ * Unregister an existing {@link PhoneStateListener}.
+ *
+ * @param listener The {@link PhoneStateListener} object to unregister.
+ */
+ public void unregisterPhoneStateListener(@NonNull PhoneStateListener listener) {
+
+ if (mContext == null) {
+ throw new IllegalStateException("telephony service is null.");
+ }
+
+ mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
+ if (mTelephonyRegistryMgr != null) {
+ mTelephonyRegistryMgr.unregisterPhoneStateListener(mSubId, getOpPackageName(),
+ getAttributionTag(), listener, getITelephony() != null);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ }
+
+ /**
+ * The network type is valid or not.
+ *
+ * @param networkType The network type {@link NetworkType}.
+ * @return {@code true} if valid, {@code false} otherwise.
+ *
+ * @hide
+ */
+ public static boolean isNetworkTypeValid(@NetworkType int networkType) {
+ return networkType >= TelephonyManager.NETWORK_TYPE_UNKNOWN &&
+ networkType <= TelephonyManager.NETWORK_TYPE_NR;
+ }
+
+ /**
+ * Set a {@link SignalStrengthUpdateRequest} to receive notification when signal quality
+ * measurements breach the specified thresholds.
+ *
+ * To be notified, set the signal strength update request and then register
+ * {@link TelephonyManager#listen(PhoneStateListener, int)} with
+ * {@link PhoneStateListener#LISTEN_SIGNAL_STRENGTHS}. The notification will arrive through
+ * {@link PhoneStateListener#onSignalStrengthsChanged(SignalStrength)}.
+ *
+ * To stop receiving the notification over the specified thresholds, pass the same
+ * {@link SignalStrengthUpdateRequest} object to
+ * {@link #clearSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)}.
+ *
+ * System will clean up the {@link SignalStrengthUpdateRequest} if the caller process died
+ * without calling {@link #clearSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)}.
+ *
+ * If this TelephonyManager object has been created with {@link #createForSubscriptionId},
+ * applies to the given subId. Otherwise, applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}. To request for multiple subIds,
+ * pass a request object to each TelephonyManager object created with
+ * {@link #createForSubscriptionId}.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * or that the calling app has carrier privileges (see
+ * {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * Note that the thresholds in the request will be used on a best-effort basis; the system may
+ * modify requests to multiplex various request sources or to optimize power consumption. The
+ * caller should not expect to be notified with the exactly the same thresholds.
+ *
+ * @see #clearSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)
+ *
+ * @param request the SignalStrengthUpdateRequest to be set into the System
+ *
+ * @throws IllegalStateException if a new request is set with same subId from the same caller
+ */
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void setSignalStrengthUpdateRequest(@NonNull SignalStrengthUpdateRequest request) {
+ Objects.requireNonNull(request, "request must not be null");
+
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ service.setSignalStrengthUpdateRequest(getSubId(), request, getOpPackageName());
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#setSignalStrengthUpdateRequest", e);
+ }
+ }
+
+ /**
+ * Clear a {@link SignalStrengthUpdateRequest} from the system.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * or that the calling app has carrier privileges (see
+ * {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * <p>If the given request was not set before, this operation is a no-op.
+ *
+ * @see #setSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)
+ *
+ * @param request the SignalStrengthUpdateRequest to be cleared from the System
+ */
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void clearSignalStrengthUpdateRequest(@NonNull SignalStrengthUpdateRequest request) {
+ Objects.requireNonNull(request, "request must not be null");
+
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ service.clearSignalStrengthUpdateRequest(getSubId(), request, getOpPackageName());
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#clearSignalStrengthUpdateRequest", e);
+ }
+ }
}
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index 8348502586a5..46ec4a39fd21 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -136,6 +136,7 @@ public final class DataCallResponse implements Parcelable {
private final int mPduSessionId;
private final Qos mDefaultQos;
private final List<QosSession> mQosSessions;
+ private final SliceInfo mSliceInfo;
/**
* @param cause Data call fail cause. {@link DataFailCause#NONE} indicates no error.
@@ -186,6 +187,7 @@ public final class DataCallResponse implements Parcelable {
mPduSessionId = PDU_SESSION_ID_NOT_SET;
mDefaultQos = null;
mQosSessions = new ArrayList<>();
+ mSliceInfo = null;
}
private DataCallResponse(@DataFailureCause int cause, long suggestedRetryTime, int id,
@@ -194,7 +196,8 @@ public final class DataCallResponse implements Parcelable {
@Nullable List<InetAddress> dnsAddresses, @Nullable List<InetAddress> gatewayAddresses,
@Nullable List<InetAddress> pcscfAddresses, int mtu, int mtuV4, int mtuV6,
@HandoverFailureMode int handoverFailureMode, int pduSessionId,
- @Nullable Qos defaultQos, @Nullable List<QosSession> qosSessions) {
+ @Nullable Qos defaultQos, @Nullable List<QosSession> qosSessions,
+ @Nullable SliceInfo sliceInfo) {
mCause = cause;
mSuggestedRetryTime = suggestedRetryTime;
mId = id;
@@ -216,6 +219,7 @@ public final class DataCallResponse implements Parcelable {
mPduSessionId = pduSessionId;
mDefaultQos = defaultQos;
mQosSessions = qosSessions;
+ mSliceInfo = sliceInfo;
}
/** @hide */
@@ -243,6 +247,7 @@ public final class DataCallResponse implements Parcelable {
mDefaultQos = source.readParcelable(Qos.class.getClassLoader());
mQosSessions = new ArrayList<>();
source.readList(mQosSessions, QosSession.class.getClassLoader());
+ mSliceInfo = source.readParcelable(SliceInfo.class.getClassLoader());
}
/**
@@ -368,7 +373,7 @@ public final class DataCallResponse implements Parcelable {
}
/**
- * @return default QOS of the data call received from the network
+ * @return default QOS of the data connection received from the network
*
* @hide
*/
@@ -379,16 +384,24 @@ public final class DataCallResponse implements Parcelable {
}
/**
- * @return All the dedicated bearer QOS sessions of the data call received from the network
+ * @return All the dedicated bearer QOS sessions of the data connection received from the
+ * network.
*
* @hide
*/
-
@NonNull
public List<QosSession> getQosSessions() {
return mQosSessions;
}
+ /**
+ * @return The slice info related to this data connection.
+ */
+ @Nullable
+ public SliceInfo getSliceInfo() {
+ return mSliceInfo;
+ }
+
@NonNull
@Override
public String toString() {
@@ -411,6 +424,7 @@ public final class DataCallResponse implements Parcelable {
.append(" pduSessionId=").append(getPduSessionId())
.append(" defaultQos=").append(mDefaultQos)
.append(" qosSessions=").append(mQosSessions)
+ .append(" sliceInfo=").append(mSliceInfo)
.append("}");
return sb.toString();
}
@@ -454,7 +468,8 @@ public final class DataCallResponse implements Parcelable {
&& mHandoverFailureMode == other.mHandoverFailureMode
&& mPduSessionId == other.mPduSessionId
&& isQosSame
- && isQosSessionsSame;
+ && isQosSessionsSame
+ && Objects.equals(mSliceInfo, other.mSliceInfo);
}
@Override
@@ -462,7 +477,7 @@ public final class DataCallResponse implements Parcelable {
return Objects.hash(mCause, mSuggestedRetryTime, mId, mLinkStatus, mProtocolType,
mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses, mPcscfAddresses,
mMtu, mMtuV4, mMtuV6, mHandoverFailureMode, mPduSessionId, mDefaultQos,
- mQosSessions);
+ mQosSessions, mSliceInfo);
}
@Override
@@ -493,6 +508,7 @@ public final class DataCallResponse implements Parcelable {
dest.writeParcelable((NrQos)mDefaultQos, flags);
}
dest.writeList(mQosSessions);
+ dest.writeParcelable(mSliceInfo, flags);
}
public static final @android.annotation.NonNull Parcelable.Creator<DataCallResponse> CREATOR =
@@ -576,6 +592,8 @@ public final class DataCallResponse implements Parcelable {
private List<QosSession> mQosSessions = new ArrayList<>();
+ private SliceInfo mSliceInfo;
+
/**
* Default constructor for Builder.
*/
@@ -799,6 +817,21 @@ public final class DataCallResponse implements Parcelable {
}
/**
+ * The Slice used for this data connection.
+ * <p/>
+ * If a handover occurs from EPDG to 5G,
+ * this is the {@link SliceInfo} used in {@link DataService#setupDataCall}.
+ *
+ * @param sliceInfo the slice info for the data call
+ *
+ * @return The same instance of the builder.
+ */
+ public @NonNull Builder setSliceInfo(@Nullable SliceInfo sliceInfo) {
+ mSliceInfo = sliceInfo;
+ return this;
+ }
+
+ /**
* Build the DataCallResponse.
*
* @return the DataCallResponse object.
@@ -807,7 +840,7 @@ public final class DataCallResponse implements Parcelable {
return new DataCallResponse(mCause, mSuggestedRetryTime, mId, mLinkStatus,
mProtocolType, mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses,
mPcscfAddresses, mMtu, mMtuV4, mMtuV6, mHandoverFailureMode, mPduSessionId,
- mDefaultQos, mQosSessions);
+ mDefaultQos, mQosSessions, mSliceInfo);
}
}
}
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 2ec965101930..03c2ef9d9baa 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -194,13 +194,19 @@ public abstract class DataService extends Service {
* The standard range of values are 1-15 while 0 means no pdu session id
* was attached to this call. Reference: 3GPP TS 24.007 section
* 11.2.3.1b.
+ * @param sliceInfo used within the data connection when a handover occurs from EPDG to 5G.
+ * The value is null unless the access network is
+ * {@link android.telephony.AccessNetworkConstants.AccessNetworkType#NGRAN} and a
+ * handover is occurring from EPDG to 5G. If the slice passed is rejected, then
+ * {@link DataCallResponse#getCause()} is
+ * {@link android.telephony.DataFailCause#SLICE_REJECTED}.
* @param callback The result callback for this request.
*/
public void setupDataCall(int accessNetworkType, @NonNull DataProfile dataProfile,
boolean isRoaming, boolean allowRoaming,
@SetupDataReason int reason,
@Nullable LinkProperties linkProperties,
- @IntRange(from = 0, to = 15) int pduSessionId,
+ @IntRange(from = 0, to = 15) int pduSessionId, @Nullable SliceInfo sliceInfo,
@NonNull DataServiceCallback callback) {
/* Call the old version since the new version isn't supported */
setupDataCall(accessNetworkType, dataProfile, isRoaming, allowRoaming, reason,
@@ -392,10 +398,11 @@ public abstract class DataService extends Service {
public final int reason;
public final LinkProperties linkProperties;
public final int pduSessionId;
+ public final SliceInfo sliceInfo;
public final IDataServiceCallback callback;
SetupDataCallRequest(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
boolean allowRoaming, int reason, LinkProperties linkProperties,
- int pduSessionId, IDataServiceCallback callback) {
+ int pduSessionId, SliceInfo sliceInfo, IDataServiceCallback callback) {
this.accessNetworkType = accessNetworkType;
this.dataProfile = dataProfile;
this.isRoaming = isRoaming;
@@ -403,6 +410,7 @@ public abstract class DataService extends Service {
this.linkProperties = linkProperties;
this.reason = reason;
this.pduSessionId = pduSessionId;
+ this.sliceInfo = sliceInfo;
this.callback = callback;
}
}
@@ -513,6 +521,7 @@ public abstract class DataService extends Service {
setupDataCallRequest.dataProfile, setupDataCallRequest.isRoaming,
setupDataCallRequest.allowRoaming, setupDataCallRequest.reason,
setupDataCallRequest.linkProperties, setupDataCallRequest.pduSessionId,
+ setupDataCallRequest.sliceInfo,
(setupDataCallRequest.callback != null)
? new DataServiceCallback(setupDataCallRequest.callback)
: null);
@@ -676,10 +685,12 @@ public abstract class DataService extends Service {
@Override
public void setupDataCall(int slotIndex, int accessNetworkType, DataProfile dataProfile,
boolean isRoaming, boolean allowRoaming, int reason,
- LinkProperties linkProperties, int pduSessionId, IDataServiceCallback callback) {
+ LinkProperties linkProperties, int pduSessionId, SliceInfo sliceInfo,
+ IDataServiceCallback callback) {
mHandler.obtainMessage(DATA_SERVICE_REQUEST_SETUP_DATA_CALL, slotIndex, 0,
new SetupDataCallRequest(accessNetworkType, dataProfile, isRoaming,
- allowRoaming, reason, linkProperties, pduSessionId, callback))
+ allowRoaming, reason, linkProperties, pduSessionId, sliceInfo,
+ callback))
.sendToTarget();
}
diff --git a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.aidl b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.aidl
new file mode 100644
index 000000000000..da31f9864cf1
--- /dev/null
+++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ package android.telephony.data;
+
+ parcelable EpsBearerQosSessionAttributes; \ No newline at end of file
diff --git a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
new file mode 100644
index 000000000000..041edc00c4d2
--- /dev/null
+++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.net.QosSessionAttributes;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Provides Qos attributes of an EPS bearer.
+ *
+ * {@hide}
+ */
+@SystemApi
+public final class EpsBearerQosSessionAttributes implements Parcelable, QosSessionAttributes {
+ private static final String TAG = EpsBearerQosSessionAttributes.class.getSimpleName();
+ private final int mQci;
+ private final long mMaxUplinkBitRate;
+ private final long mMaxDownlinkBitRate;
+ private final long mGuaranteedUplinkBitRate;
+ private final long mGuaranteedDownlinkBitRate;
+ @NonNull private final List<InetSocketAddress> mRemoteAddresses;
+
+ /**
+ * Quality of Service Class Identifier (QCI), see 3GPP TS 23.203 and 29.212.
+ * The allowed values are standard values(1-9, 65-68, 69-70, 75, 79-80, 82-85)
+ * defined in the spec and operator specific values in the range 128-254.
+ *
+ * @return the qci of the session
+ */
+ public int getQci() {
+ return mQci;
+ }
+
+ /**
+ * Minimum bit rate in kbps that is guaranteed to be provided by the network on the uplink.
+ *
+ * see 3GPP TS 23.107 section 6.4.3.1
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the guaranteed bit rate in kbps
+ */
+ public long getGuaranteedUplinkBitRate() {
+ return mGuaranteedUplinkBitRate;
+ }
+
+ /**
+ * Minimum bit rate in kbps that is guaranteed to be provided by the network on the downlink.
+ *
+ * see 3GPP TS 23.107 section 6.4.3.1
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the guaranteed bit rate in kbps
+ */
+ public long getGuaranteedDownlinkBitRate() {
+ return mGuaranteedDownlinkBitRate;
+ }
+
+ /**
+ * The maximum kbps that the network will accept.
+ *
+ * see 3GPP TS 23.107 section 6.4.3.1
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the max uplink bit rate in kbps
+ */
+ public long getMaxUplinkBitRate() {
+ return mMaxUplinkBitRate;
+ }
+
+ /**
+ * The maximum kbps that the network can provide.
+ *
+ * see 3GPP TS 23.107 section 6.4.3.1
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the max downlink bit rate in kbps
+ */
+ public long getMaxDownlinkBitRate() {
+ return mMaxDownlinkBitRate;
+ }
+
+ /**
+ * List of remote addresses associated with the Qos Session. The given uplink bit rates apply
+ * to this given list of remote addresses.
+ *
+ * Note: In the event that the list is empty, it is assumed that the uplink bit rates apply to
+ * all remote addresses that are not contained in a different set of attributes.
+ *
+ * @return list of remote socket addresses that the attributes apply to
+ */
+ @NonNull
+ public List<InetSocketAddress> getRemoteAddresses() {
+ return mRemoteAddresses;
+ }
+
+ /**
+ * ..ctor for attributes
+ *
+ * @param qci quality class indicator
+ * @param maxDownlinkBitRate the max downlink bit rate in kbps
+ * @param maxUplinkBitRate the max uplink bit rate in kbps
+ * @param guaranteedDownlinkBitRate the guaranteed downlink bit rate in kbps
+ * @param guaranteedUplinkBitRate the guaranteed uplink bit rate in kbps
+ * @param remoteAddresses the remote addresses that the uplink bit rates apply to
+ *
+ * @hide
+ */
+ public EpsBearerQosSessionAttributes(final int qci,
+ final long maxDownlinkBitRate, final long maxUplinkBitRate,
+ final long guaranteedDownlinkBitRate, final long guaranteedUplinkBitRate,
+ @NonNull final List<InetSocketAddress> remoteAddresses) {
+ Objects.requireNonNull(remoteAddresses, "remoteAddress must be non-null");
+ mQci = qci;
+ mMaxDownlinkBitRate = maxDownlinkBitRate;
+ mMaxUplinkBitRate = maxUplinkBitRate;
+ mGuaranteedDownlinkBitRate = guaranteedDownlinkBitRate;
+ mGuaranteedUplinkBitRate = guaranteedUplinkBitRate;
+
+ final List<InetSocketAddress> remoteAddressesTemp = copySocketAddresses(remoteAddresses);
+ mRemoteAddresses = Collections.unmodifiableList(remoteAddressesTemp);
+ }
+
+ private static List<InetSocketAddress> copySocketAddresses(
+ @NonNull final List<InetSocketAddress> remoteAddresses) {
+ final List<InetSocketAddress> remoteAddressesTemp = new ArrayList<>();
+ for (final InetSocketAddress socketAddress : remoteAddresses) {
+ if (socketAddress != null && socketAddress.getAddress() != null) {
+ remoteAddressesTemp.add(socketAddress);
+ }
+ }
+ return remoteAddressesTemp;
+ }
+
+ private EpsBearerQosSessionAttributes(@NonNull final Parcel in) {
+ mQci = in.readInt();
+ mMaxDownlinkBitRate = in.readLong();
+ mMaxUplinkBitRate = in.readLong();
+ mGuaranteedDownlinkBitRate = in.readLong();
+ mGuaranteedUplinkBitRate = in.readLong();
+
+ final int size = in.readInt();
+ final List<InetSocketAddress> remoteAddresses = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ final byte[] addressBytes = in.createByteArray();
+ final int port = in.readInt();
+ try {
+ remoteAddresses.add(
+ new InetSocketAddress(InetAddress.getByAddress(addressBytes), port));
+ } catch (final UnknownHostException e) {
+ // Impossible case since we filter out null values in the ..ctor
+ Log.e(TAG, "unable to unparcel remote address at index: " + i, e);
+ }
+ }
+ mRemoteAddresses = Collections.unmodifiableList(remoteAddresses);
+ }
+
+ /**
+ * Creates attributes based off of a parcel
+ * @param in the parcel
+ * @return the attributes
+ */
+ @NonNull
+ public static EpsBearerQosSessionAttributes create(@NonNull final Parcel in) {
+ return new EpsBearerQosSessionAttributes(in);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+ dest.writeInt(mQci);
+ dest.writeLong(mMaxDownlinkBitRate);
+ dest.writeLong(mMaxUplinkBitRate);
+ dest.writeLong(mGuaranteedDownlinkBitRate);
+ dest.writeLong(mGuaranteedUplinkBitRate);
+
+ final int size = mRemoteAddresses.size();
+ dest.writeInt(size);
+ for (int i = 0; i < size; i++) {
+ final InetSocketAddress address = mRemoteAddresses.get(i);
+ dest.writeByteArray(address.getAddress().getAddress());
+ dest.writeInt(address.getPort());
+ }
+ }
+
+ @NonNull
+ public static final Creator<EpsBearerQosSessionAttributes> CREATOR =
+ new Creator<EpsBearerQosSessionAttributes>() {
+ @NonNull
+ @Override
+ public EpsBearerQosSessionAttributes createFromParcel(@NonNull final Parcel in) {
+ return new EpsBearerQosSessionAttributes(in);
+ }
+
+ @NonNull
+ @Override
+ public EpsBearerQosSessionAttributes[] newArray(final int size) {
+ return new EpsBearerQosSessionAttributes[size];
+ }
+ };
+}
diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl
index 3f1f033d6f11..e0b9a1a9bb5a 100644
--- a/telephony/java/android/telephony/data/IDataService.aidl
+++ b/telephony/java/android/telephony/data/IDataService.aidl
@@ -19,6 +19,7 @@ package android.telephony.data;
import android.net.LinkProperties;
import android.telephony.data.DataProfile;
import android.telephony.data.IDataServiceCallback;
+import android.telephony.data.SliceInfo;
/**
* {@hide}
@@ -29,7 +30,7 @@ oneway interface IDataService
void removeDataServiceProvider(int slotId);
void setupDataCall(int slotId, int accessNetwork, in DataProfile dataProfile, boolean isRoaming,
boolean allowRoaming, int reason, in LinkProperties linkProperties,
- int pduSessionId, IDataServiceCallback callback);
+ int pduSessionId, in SliceInfo sliceInfo, IDataServiceCallback callback);
void deactivateDataCall(int slotId, int cid, int reason, IDataServiceCallback callback);
void setInitialAttachApn(int slotId, in DataProfile dataProfile, boolean isRoaming,
IDataServiceCallback callback);
diff --git a/telephony/java/android/telephony/data/SliceInfo.aidl b/telephony/java/android/telephony/data/SliceInfo.aidl
new file mode 100644
index 000000000000..286ea5e4f8c7
--- /dev/null
+++ b/telephony/java/android/telephony/data/SliceInfo.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** @hide */
+package android.telephony.data;
+
+parcelable SliceInfo;
diff --git a/telephony/java/android/telephony/data/SliceInfo.java b/telephony/java/android/telephony/data/SliceInfo.java
new file mode 100644
index 000000000000..51857a7b4908
--- /dev/null
+++ b/telephony/java/android/telephony/data/SliceInfo.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Represents a S-NSSAI as defined in 3GPP TS 24.501.
+ *
+ * @hide
+ */
+@SystemApi
+public final class SliceInfo implements Parcelable {
+ /**
+ * When set on a Slice Differentiator, this value indicates that there is no corresponding
+ * Slice.
+ */
+ public static final int SLICE_DIFFERENTIATOR_NO_SLICE = -1;
+
+ /**
+ * Indicates that the service type is not present.
+ */
+ public static final int SLICE_SERVICE_TYPE_NONE = 0;
+
+ /**
+ * Slice suitable for the handling of 5G enhanced Mobile Broadband.
+ */
+ public static final int SLICE_SERVICE_TYPE_EMBB = 1;
+
+ /**
+ * Slice suitable for the handling of ultra-reliable low latency communications.
+ */
+ public static final int SLICE_SERVICE_TYPE_URLLC = 2;
+
+ /**
+ * Slice suitable for the handling of massive IoT.
+ */
+ public static final int SLICE_SERVICE_TYPE_MIOT = 3;
+
+ /**
+ * The min acceptable value for a Slice Differentiator
+ */
+ @SuppressLint("MinMaxConstant")
+ public static final int MIN_SLICE_DIFFERENTIATOR = -1;
+
+ /**
+ * The max acceptable value for a Slice Differentiator
+ */
+ @SuppressLint("MinMaxConstant")
+ public static final int MAX_SLICE_DIFFERENTIATOR = 0xFFFFFE;
+
+ /** @hide */
+ @IntDef(prefix = { "SLICE_SERVICE_TYPE_" }, value = {
+ SLICE_SERVICE_TYPE_NONE,
+ SLICE_SERVICE_TYPE_EMBB,
+ SLICE_SERVICE_TYPE_URLLC,
+ SLICE_SERVICE_TYPE_MIOT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SliceServiceType {}
+
+
+ @SliceServiceType
+ private final int mSliceServiceType;
+ @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+ private final int mSliceDifferentiator;
+ @SliceServiceType
+ private final int mMappedHplmnSliceServiceType;
+ @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+ private final int mMappedHplmnSliceDifferentiator;
+
+ private SliceInfo(@SliceServiceType int sliceServiceType,
+ int sliceDifferentiator, int mappedHplmnSliceServiceType,
+ int mappedHplmnSliceDifferentiator) {
+ mSliceServiceType = sliceServiceType;
+ mSliceDifferentiator = sliceDifferentiator;
+ mMappedHplmnSliceDifferentiator = mappedHplmnSliceDifferentiator;
+ mMappedHplmnSliceServiceType = mappedHplmnSliceServiceType;
+ }
+
+ /**
+ * The type of service provided by the slice.
+ * <p/>
+ * see: 3GPP TS 24.501 Section 9.11.2.8.
+ */
+ @SliceServiceType
+ public int getSliceServiceType() {
+ return mSliceServiceType;
+ }
+
+ /**
+ * Identifies the slice from others with the same Slice Service Type.
+ * <p/>
+ * Returns {@link #SLICE_DIFFERENTIATOR_NO_SLICE} if {@link #getSliceServiceType} returns
+ * {@link #SLICE_SERVICE_TYPE_NONE}.
+ * <p/>
+ * see: 3GPP TS 24.501 Section 9.11.2.8.
+ */
+ @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+ public int getSliceDifferentiator() {
+ return mSliceDifferentiator;
+ }
+
+ /**
+ * Corresponds to a Slice Info (S-NSSAI) of the HPLMN.
+ * <p/>
+ * see: 3GPP TS 24.501 Section 9.11.2.8.
+ */
+ @SliceServiceType
+ public int getMappedHplmnSliceServiceType() {
+ return mMappedHplmnSliceServiceType;
+ }
+
+ /**
+ * This Slice Differentiator corresponds to a {@link SliceInfo} (S-NSSAI) of the HPLMN;
+ * {@link #getSliceDifferentiator()} is mapped to this value.
+ * <p/>
+ * Returns {@link #SLICE_DIFFERENTIATOR_NO_SLICE} if either of the following are true:
+ * <ul>
+ * <li>{@link #getSliceDifferentiator()} returns {@link #SLICE_DIFFERENTIATOR_NO_SLICE}</li>
+ * <li>{@link #getMappedHplmnSliceServiceType()} returns {@link #SLICE_SERVICE_TYPE_NONE}</li>
+ * </ul>
+ * <p/>
+ * see: 3GPP TS 24.501 Section 9.11.2.8.
+ */
+ @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+ public int getMappedHplmnSliceDifferentiator() {
+ return mMappedHplmnSliceDifferentiator;
+ }
+
+ private SliceInfo(@NonNull Parcel in) {
+ mSliceServiceType = in.readInt();
+ mSliceDifferentiator = in.readInt();
+ mMappedHplmnSliceServiceType = in.readInt();
+ mMappedHplmnSliceDifferentiator = in.readInt();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mSliceServiceType);
+ dest.writeInt(mSliceDifferentiator);
+ dest.writeInt(mMappedHplmnSliceServiceType);
+ dest.writeInt(mMappedHplmnSliceDifferentiator);
+ }
+
+ public static final @android.annotation.NonNull Parcelable.Creator<SliceInfo> CREATOR =
+ new Parcelable.Creator<SliceInfo>() {
+ @Override
+ @NonNull
+ public SliceInfo createFromParcel(@NonNull Parcel source) {
+ return new SliceInfo(source);
+ }
+
+ @Override
+ @NonNull
+ public SliceInfo[] newArray(int size) {
+ return new SliceInfo[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return "SliceInfo{"
+ + "mSliceServiceType=" + sliceServiceTypeToString(mSliceServiceType)
+ + ", mSliceDifferentiator=" + mSliceDifferentiator
+ + ", mMappedHplmnSliceServiceType="
+ + sliceServiceTypeToString(mMappedHplmnSliceServiceType)
+ + ", mMappedHplmnSliceDifferentiator=" + mMappedHplmnSliceDifferentiator
+ + '}';
+ }
+
+ private static String sliceServiceTypeToString(@SliceServiceType int sliceServiceType) {
+ switch(sliceServiceType) {
+ case SLICE_SERVICE_TYPE_NONE:
+ return "NONE";
+ case SLICE_SERVICE_TYPE_EMBB:
+ return "EMBB";
+ case SLICE_SERVICE_TYPE_URLLC:
+ return "URLLC";
+ case SLICE_SERVICE_TYPE_MIOT:
+ return "MIOT";
+ default:
+ return Integer.toString(sliceServiceType);
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ SliceInfo sliceInfo = (SliceInfo) o;
+ return mSliceServiceType == sliceInfo.mSliceServiceType
+ && mSliceDifferentiator == sliceInfo.mSliceDifferentiator
+ && mMappedHplmnSliceServiceType == sliceInfo.mMappedHplmnSliceServiceType
+ && mMappedHplmnSliceDifferentiator == sliceInfo.mMappedHplmnSliceDifferentiator;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSliceServiceType, mSliceDifferentiator, mMappedHplmnSliceServiceType,
+ mMappedHplmnSliceDifferentiator);
+ }
+
+ /**
+ * Provides a convenient way to set the fields of a {@link SliceInfo} when creating a
+ * new instance.
+ *
+ * <p>The example below shows how you might create a new {@code SliceInfo}:
+ *
+ * <pre><code>
+ *
+ * SliceInfo response = new SliceInfo.Builder()
+ * .setSliceServiceType(SLICE_SERVICE_TYPE_URLLC)
+ * .build();
+ * </code></pre>
+ */
+ public static final class Builder {
+ @SliceServiceType
+ private int mSliceServiceType = SLICE_SERVICE_TYPE_NONE;
+ @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+ private int mSliceDifferentiator = SLICE_DIFFERENTIATOR_NO_SLICE;
+ @SliceServiceType
+ private int mMappedHplmnSliceServiceType = SLICE_SERVICE_TYPE_NONE;
+ @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+ private int mMappedHplmnSliceDifferentiator = SLICE_DIFFERENTIATOR_NO_SLICE;
+
+ /**
+ * Default constructor for Builder.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Set the Slice Service Type.
+ *
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setSliceServiceType(@SliceServiceType int mSliceServiceType) {
+ this.mSliceServiceType = mSliceServiceType;
+ return this;
+ }
+
+ /**
+ * Set the Slice Differentiator.
+ * <p/>
+ * A value of {@link #SLICE_DIFFERENTIATOR_NO_SLICE} indicates that there is no
+ * corresponding Slice.
+ *
+ * @throws IllegalArgumentException if the parameter is not between
+ * {@link #MIN_SLICE_DIFFERENTIATOR} and {@link #MAX_SLICE_DIFFERENTIATOR}.
+ *
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setSliceDifferentiator(
+ @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+ int sliceDifferentiator) {
+ if (sliceDifferentiator < MIN_SLICE_DIFFERENTIATOR
+ || sliceDifferentiator > MAX_SLICE_DIFFERENTIATOR) {
+ throw new IllegalArgumentException("The slice diffentiator value is out of range");
+ }
+ this.mSliceDifferentiator = sliceDifferentiator;
+ return this;
+ }
+
+ /**
+ * Set the HPLMN Slice Service Type.
+ *
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setMappedHplmnSliceServiceType(
+ @SliceServiceType int mappedHplmnSliceServiceType) {
+ this.mMappedHplmnSliceServiceType = mappedHplmnSliceServiceType;
+ return this;
+ }
+
+ /**
+ * Set the HPLMN Slice Differentiator.
+ * <p/>
+ * A value of {@link #SLICE_DIFFERENTIATOR_NO_SLICE} indicates that there is no
+ * corresponding Slice of the HPLMN.
+ *
+ * @throws IllegalArgumentException if the parameter is not between
+ * {@link #MIN_SLICE_DIFFERENTIATOR} and {@link #MAX_SLICE_DIFFERENTIATOR}.
+ *
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setMappedHplmnSliceDifferentiator(
+ @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+ int mappedHplmnSliceDifferentiator) {
+ if (mappedHplmnSliceDifferentiator < MIN_SLICE_DIFFERENTIATOR
+ || mappedHplmnSliceDifferentiator > MAX_SLICE_DIFFERENTIATOR) {
+ throw new IllegalArgumentException("The slice diffentiator value is out of range");
+ }
+ this.mMappedHplmnSliceDifferentiator = mappedHplmnSliceDifferentiator;
+ return this;
+ }
+
+ /**
+ * Build the {@link SliceInfo}.
+ *
+ * @return the {@link SliceInfo} object.
+ */
+ @NonNull
+ public SliceInfo build() {
+ return new SliceInfo(this.mSliceServiceType, this.mSliceDifferentiator,
+ this.mMappedHplmnSliceServiceType, this.mMappedHplmnSliceDifferentiator);
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/euicc/DownloadableSubscription.java b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
index 52b31d7f9611..a5150b010f57 100644
--- a/telephony/java/android/telephony/euicc/DownloadableSubscription.java
+++ b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
@@ -15,6 +15,7 @@
*/
package android.telephony.euicc;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.PendingIntent;
@@ -102,44 +103,81 @@ public final class DownloadableSubscription implements Parcelable {
this.accessRules = accessRules;
}
- /** @hide */
- @SystemApi
public static final class Builder {
@Nullable private String encodedActivationCode;
@Nullable private String confirmationCode;
@Nullable private String carrierName;
List<UiccAccessRule> accessRules;
+ /** @hide */
+ @SystemApi
public Builder() {}
- public Builder(DownloadableSubscription baseSubscription) {
+ public Builder(@NonNull DownloadableSubscription baseSubscription) {
encodedActivationCode = baseSubscription.getEncodedActivationCode();
confirmationCode = baseSubscription.getConfirmationCode();
carrierName = baseSubscription.getCarrierName();
accessRules = baseSubscription.getAccessRules();
}
+ public Builder(@NonNull String encodedActivationCode) {
+ this.encodedActivationCode = encodedActivationCode;
+ }
+
+ /**
+ * Builds a {@link DownloadableSubscription} object.
+ * @return a non-null {@link DownloadableSubscription} object.
+ */
+ @NonNull
public DownloadableSubscription build() {
return new DownloadableSubscription(encodedActivationCode, confirmationCode,
carrierName, accessRules);
}
- public Builder setEncodedActivationCode(String value) {
+ /**
+ * Sets the encoded activation code.
+ * @param value the activation code to use. An activation code can be parsed from a user
+ * scanned QR code. The format of activation code is defined in SGP.22. For
+ * example, "1$SMDP.GSMA.COM$04386-AGYFT-A74Y8-3F815$1.3.6.1.4.1.31746". For
+ * detail, see {@code com.android.euicc.data.ActivationCode}. Must not be null.
+ */
+ @NonNull
+ public Builder setEncodedActivationCode(@NonNull String value) {
encodedActivationCode = value;
return this;
}
- public Builder setConfirmationCode(String value) {
+ /**
+ * Sets the confirmation code.
+ * @param value the confirmation code to use to authenticate the carrier server got
+ * subscription download.
+ */
+ @NonNull
+ public Builder setConfirmationCode(@NonNull String value) {
confirmationCode = value;
return this;
}
- public Builder setCarrierName(String value) {
+ /**
+ * Sets the user-visible carrier name.
+ * @param value carrier name.
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public Builder setCarrierName(@NonNull String value) {
carrierName = value;
return this;
}
- public Builder setAccessRules(List<UiccAccessRule> value) {
+ /**
+ * Sets the {@link UiccAccessRule}s dictating access to this subscription.
+ * @param value A list of {@link UiccAccessRule}s.
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public Builder setAccessRules(@NonNull List<UiccAccessRule> value) {
accessRules = value;
return this;
}
diff --git a/telephony/java/android/telephony/ims/DelegateRegistrationState.java b/telephony/java/android/telephony/ims/DelegateRegistrationState.java
index 66281edc0de1..fd206c1e803f 100644
--- a/telephony/java/android/telephony/ims/DelegateRegistrationState.java
+++ b/telephony/java/android/telephony/ims/DelegateRegistrationState.java
@@ -320,4 +320,11 @@ public final class DelegateRegistrationState implements Parcelable {
public int hashCode() {
return Objects.hash(mRegisteredTags, mDeregisteringTags, mDeregisteredTags);
}
+
+ @Override
+ public String toString() {
+ return "DelegateRegistrationState{ registered={" + mRegisteredTags
+ + "}, deregistering={" + mDeregisteringTags + "}, deregistered={"
+ + mDeregisteredTags + "}}";
+ }
}
diff --git a/telephony/java/android/telephony/ims/ImsUtListener.java b/telephony/java/android/telephony/ims/ImsUtListener.java
index baa0576cdf13..754814facb71 100644
--- a/telephony/java/android/telephony/ims/ImsUtListener.java
+++ b/telephony/java/android/telephony/ims/ImsUtListener.java
@@ -178,4 +178,11 @@ public class ImsUtListener {
public ImsUtListener(IImsUtListener serviceInterface) {
mServiceInterface = serviceInterface;
}
+
+ /**
+ * @hide
+ */
+ public IImsUtListener getListenerInterface() {
+ return mServiceInterface;
+ }
}
diff --git a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
index 519d0164b0d6..5eb75e762fc9 100644
--- a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
+++ b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
@@ -19,6 +19,7 @@ package android.telephony.ims;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
+import android.annotation.SystemApi;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -34,14 +35,135 @@ import java.util.List;
* network during a SUBSCRIBE request. See RFC3863 for more information.
* @hide
*/
+@SystemApi
public final class RcsContactPresenceTuple implements Parcelable {
- /** The service id of the MMTEL */
+ /**
+ * The service ID used to indicate that MMTEL service is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
public static final String SERVICE_ID_MMTEL = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.mmtel";
- /** The service id of the Call Composer */
+ /**
+ * The service ID used to indicate that the chat(v1.0) is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_CHAT_V1 = "org.openmobilealliance:IM-session";
+
+ /**
+ * The service ID used to indicate that the chat(v2.0) is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_CHAT_V2 = "org.openmobilealliance:ChatSession";
+
+ /**
+ * The service ID used to indicate that the File Transfer is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_FT = "org.openmobilealliance:File-Transfer-HTTP";
+
+ /**
+ * The service ID used to indicate that the File Transfer over SMS is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_FT_OVER_SMS =
+ "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.ftsms";
+
+ /**
+ * The service ID used to indicate that the Geolocation Push is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_GEO_PUSH =
+ "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.geopush";
+
+ /**
+ * The service ID used to indicate that the Geolocation Push via SMS is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_GEO_PUSH_VIA_SMS =
+ "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.geosms";
+
+ /**
+ * The service ID used to indicate that the Call Composer is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
public static final String SERVICE_ID_CALL_COMPOSER =
- "org.3gpp.urn:urn-7:3gppservice.ims.icsi.gsma.callcomposer";
+ "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callcomposer";
+
+ /**
+ * The service ID used to indicate that the Post Call is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_POST_CALL =
+ "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callunanswered";
+
+ /**
+ * The service ID used to indicate that the Shared Map is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_SHARED_MAP =
+ "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.sharedmap";
+
+ /**
+ * The service ID used to indicate that the Shared Sketch is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_SHARED_SKETCH =
+ "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.sharedsketch";
+
+ /**
+ * The service ID used to indicate that the Chatbot using Session is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_CHATBOT =
+ "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.chatbot";
+
+ /**
+ * The service ID used to indicate that the Standalone Messaging is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_CHATBOT_STANDALONE =
+ " org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.chatbot.sa";
+
+ /**
+ * The service ID used to indicate that the Chatbot Role is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_CHATBOT_ROLE = "org.gsma.rcs.isbot";
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef(prefix = "SERVICE_ID_", value = {
+ SERVICE_ID_MMTEL,
+ SERVICE_ID_CHAT_V1,
+ SERVICE_ID_CHAT_V2,
+ SERVICE_ID_FT,
+ SERVICE_ID_FT_OVER_SMS,
+ SERVICE_ID_GEO_PUSH,
+ SERVICE_ID_GEO_PUSH_VIA_SMS,
+ SERVICE_ID_CALL_COMPOSER,
+ SERVICE_ID_POST_CALL,
+ SERVICE_ID_SHARED_MAP,
+ SERVICE_ID_SHARED_SKETCH,
+ SERVICE_ID_CHATBOT,
+ SERVICE_ID_CHATBOT_STANDALONE,
+ SERVICE_ID_CHATBOT_ROLE
+ })
+ public @interface ServiceId {}
/** The service capabilities is available. */
public static final String TUPLE_BASIC_STATUS_OPEN = "open";
@@ -149,6 +271,7 @@ public final class RcsContactPresenceTuple implements Parcelable {
in.readStringList(mSupportedDuplexModeList);
in.readStringList(mUnsupportedDuplexModeList);
}
+
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeBoolean(mIsAudioCapable);
@@ -217,12 +340,14 @@ public final class RcsContactPresenceTuple implements Parcelable {
/**
* Builds a RcsContactPresenceTuple instance.
+ * @param status The status associated with the service capability. See RFC3865 for more
+ * information.
* @param serviceId The OMA Presence service-id associated with this capability. See the
* OMA Presence SIMPLE specification v1.1, section 10.5.1.
* @param serviceVersion The OMA Presence version associated with the service capability.
* See the OMA Presence SIMPLE specification v1.1, section 10.5.1.
*/
- public Builder(@NonNull @BasicStatus String status, @NonNull String serviceId,
+ public Builder(@NonNull @BasicStatus String status, @NonNull @ServiceId String serviceId,
@NonNull String serviceVersion) {
mPresenceTuple = new RcsContactPresenceTuple(status, serviceId, serviceVersion);
}
@@ -230,16 +355,17 @@ public final class RcsContactPresenceTuple implements Parcelable {
/**
* The optional SIP Contact URI associated with the PIDF tuple element.
*/
- public @NonNull Builder addContactUri(@NonNull Uri contactUri) {
+ public @NonNull Builder setContactUri(@NonNull Uri contactUri) {
mPresenceTuple.mContactUri = contactUri;
return this;
}
/**
* The optional timestamp indicating the data and time of the status change of this tuple.
- * See RFC3863, section 4.1.7 for more information on the expected format.
+ * Per RFC3863 section 4.1.7, the timestamp is formatted as an IMPP datetime format
+ * string per RFC3339.
*/
- public @NonNull Builder addTimeStamp(@NonNull String timestamp) {
+ public @NonNull Builder setTimestamp(@NonNull String timestamp) {
mPresenceTuple.mTimestamp = timestamp;
return this;
}
@@ -248,7 +374,7 @@ public final class RcsContactPresenceTuple implements Parcelable {
* An optional parameter containing the description element of the service-description. See
* OMA Presence SIMPLE specification v1.1
*/
- public @NonNull Builder addDescription(@NonNull String description) {
+ public @NonNull Builder setServiceDescription(@NonNull String description) {
mPresenceTuple.mServiceDescription = description;
return this;
}
@@ -257,7 +383,7 @@ public final class RcsContactPresenceTuple implements Parcelable {
* An optional parameter containing the service capabilities of the presence tuple if they
* are present in the servcaps element.
*/
- public @NonNull Builder addServiceCapabilities(@NonNull ServiceCapabilities caps) {
+ public @NonNull Builder setServiceCapabilities(@NonNull ServiceCapabilities caps) {
mPresenceTuple.mServiceCapabilities = caps;
return this;
}
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index d4715bfeeb3e..fe855023f5d0 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -19,6 +19,7 @@ package android.telephony.ims;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -33,6 +34,7 @@ import java.util.List;
* Contains the User Capability Exchange capabilities corresponding to a contact's URI.
* @hide
*/
+@SystemApi
public final class RcsContactUceCapability implements Parcelable {
/** Contains presence information associated with the contact */
@@ -70,52 +72,46 @@ public final class RcsContactUceCapability implements Parcelable {
public @interface SourceType {}
/**
+ * Capability information for the requested contact has expired and can not be refreshed due to
+ * a temporary network error. This is a temporary error and the capabilities of the contact
+ * should be queried again at a later time.
+ */
+ public static final int REQUEST_RESULT_UNKNOWN = 0;
+
+ /**
* The requested contact was found to be offline when queried. This is only applicable to
* contact capabilities that were queried via OPTIONS requests and the network returned a
* 408/480 response.
*/
- public static final int REQUEST_RESULT_NOT_ONLINE = 0;
+ public static final int REQUEST_RESULT_NOT_ONLINE = 1;
/**
* Capability information for the requested contact was not found. The contact should not be
* considered an RCS user.
*/
- public static final int REQUEST_RESULT_NOT_FOUND = 1;
+ public static final int REQUEST_RESULT_NOT_FOUND = 2;
/**
* Capability information for the requested contact was found successfully.
*/
- public static final int REQUEST_RESULT_FOUND = 2;
-
- /**
- * Capability information for the requested contact has expired and can not be refreshed due to
- * a temporary network error. This is a temporary error and the capabilities of the contact
- * should be queried again at a later time.
- */
- public static final int REQUEST_RESULT_UNKNOWN = 3;
+ public static final int REQUEST_RESULT_FOUND = 3;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "REQUEST_RESULT_", value = {
+ REQUEST_RESULT_UNKNOWN,
REQUEST_RESULT_NOT_ONLINE,
REQUEST_RESULT_NOT_FOUND,
- REQUEST_RESULT_FOUND,
- REQUEST_RESULT_UNKNOWN
+ REQUEST_RESULT_FOUND
})
public @interface RequestResult {}
/**
- * The base class of {@link OptionsBuilder} and {@link PresenceBuilder}
- */
- public static abstract class RcsUcsCapabilityBuilder {
- public abstract @NonNull RcsContactUceCapability build();
- }
-
- /**
* Builder to help construct {@link RcsContactUceCapability} instances when capabilities were
* queried through SIP OPTIONS.
+ * @hide
*/
- public static class OptionsBuilder extends RcsUcsCapabilityBuilder {
+ public static final class OptionsBuilder {
private final RcsContactUceCapability mCapabilities;
@@ -162,7 +158,6 @@ public final class RcsContactUceCapability implements Parcelable {
/**
* @return the constructed instance.
*/
- @Override
public @NonNull RcsContactUceCapability build() {
return mCapabilities;
}
@@ -172,7 +167,7 @@ public final class RcsContactUceCapability implements Parcelable {
* Builder to help construct {@link RcsContactUceCapability} instances when capabilities were
* queried through a presence server.
*/
- public static class PresenceBuilder extends RcsUcsCapabilityBuilder {
+ public static final class PresenceBuilder {
private final RcsContactUceCapability mCapabilities;
@@ -214,7 +209,6 @@ public final class RcsContactUceCapability implements Parcelable {
/**
* @return the RcsContactUceCapability instance.
*/
- @Override
public @NonNull RcsContactUceCapability build() {
return mCapabilities;
}
@@ -284,6 +278,7 @@ public final class RcsContactUceCapability implements Parcelable {
* <p>
* Note: this is only populated if {@link #getCapabilityMechanism} is
* {@link RcsContactUceCapability#CAPABILITY_MECHANISM_OPTIONS}
+ * @hide
*/
public @NonNull List<String> getOptionsFeatureTags() {
if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) {
@@ -299,7 +294,7 @@ public final class RcsContactUceCapability implements Parcelable {
* Note: this is only populated if {@link #getCapabilityMechanism} is
* {@link RcsContactUceCapability#CAPABILITY_MECHANISM_PRESENCE}
*/
- public @NonNull List<RcsContactPresenceTuple> getPresenceTuples() {
+ public @NonNull List<RcsContactPresenceTuple> getCapabilityTuples() {
if (mCapabilityMechanism != CAPABILITY_MECHANISM_PRESENCE) {
return Collections.emptyList();
}
@@ -309,13 +304,14 @@ public final class RcsContactUceCapability implements Parcelable {
/**
* Get the RcsContactPresenceTuple associated with the given service id.
* @param serviceId The service id to get the presence tuple.
- * @return The RcsContactPresenceTuple which has the given service id.
+ * @return The RcsContactPresenceTuple which has the given service id or {@code null} if the
+ * service id does not exist in the list of presence tuples returned from the network.
*
* <p>
* Note: this is only populated if {@link #getCapabilityMechanism} is
* {@link RcsContactUceCapability#CAPABILITY_MECHANISM_PRESENCE}
*/
- public @Nullable RcsContactPresenceTuple getPresenceTuple(@NonNull String serviceId) {
+ public @Nullable RcsContactPresenceTuple getCapabilityTuple(@NonNull String serviceId) {
if (mCapabilityMechanism != CAPABILITY_MECHANISM_PRESENCE) {
return null;
}
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 6c31466c2a89..070fd799d6cc 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -63,6 +63,7 @@ public class RcsUceAdapter {
* RcsFeature should not publish capabilities or service capability requests.
* @hide
*/
+ @SystemApi
public static final int CAPABILITY_TYPE_PRESENCE_UCE = 1 << 1;
/**@hide*/
@@ -77,12 +78,14 @@ public class RcsUceAdapter {
* An unknown error has caused the request to fail.
* @hide
*/
+ @SystemApi
public static final int ERROR_GENERIC_FAILURE = 1;
/**
* The carrier network does not have UCE support enabled for this subscriber.
* @hide
*/
+ @SystemApi
public static final int ERROR_NOT_ENABLED = 2;
/**
@@ -90,12 +93,14 @@ public class RcsUceAdapter {
* 1x only currently).
* @hide
*/
+ @SystemApi
public static final int ERROR_NOT_AVAILABLE = 3;
/**
* The network has responded with SIP 403 error and a reason "User not registered."
* @hide
*/
+ @SystemApi
public static final int ERROR_NOT_REGISTERED = 4;
/**
@@ -103,12 +108,14 @@ public class RcsUceAdapter {
* presence" for this subscriber.
* @hide
*/
+ @SystemApi
public static final int ERROR_NOT_AUTHORIZED = 5;
/**
* The network has responded to this request with a SIP 403 error and no reason.
* @hide
*/
+ @SystemApi
public static final int ERROR_FORBIDDEN = 6;
/**
@@ -116,6 +123,7 @@ public class RcsUceAdapter {
* subscriber to the carrier network.
* @hide
*/
+ @SystemApi
public static final int ERROR_NOT_FOUND = 7;
/**
@@ -123,6 +131,7 @@ public class RcsUceAdapter {
* with a lower number of contact numbers. The number varies per carrier.
* @hide
*/
+ @SystemApi
// TODO: Try to integrate this into the API so that the service will split based on carrier.
public static final int ERROR_REQUEST_TOO_LARGE = 8;
@@ -130,18 +139,21 @@ public class RcsUceAdapter {
* The network did not respond to the capabilities request before the request timed out.
* @hide
*/
+ @SystemApi
public static final int ERROR_REQUEST_TIMEOUT = 9;
/**
* The request failed due to the service having insufficient memory.
* @hide
*/
+ @SystemApi
public static final int ERROR_INSUFFICIENT_MEMORY = 10;
/**
* The network was lost while trying to complete the request.
* @hide
*/
+ @SystemApi
public static final int ERROR_LOST_NETWORK = 11;
/**
@@ -149,6 +161,7 @@ public class RcsUceAdapter {
* time returned in {@link CapabilitiesCallback#onError} has elapsed.
* @hide
*/
+ @SystemApi
public static final int ERROR_SERVER_UNAVAILABLE = 12;
/**@hide*/
@@ -405,6 +418,7 @@ public class RcsUceAdapter {
* @see #requestCapabilities(Executor, List, CapabilitiesCallback)
* @hide
*/
+ @SystemApi
public interface CapabilitiesCallback {
/**
@@ -424,10 +438,10 @@ public class RcsUceAdapter {
* The pending request has resulted in an error and may need to be retried, depending on the
* error code.
* @param errorCode The reason for the framework being unable to process the request.
- * @param retryAfterMilliseconds The time in milliseconds the requesting application should
+ * @param retryIntervalMillis The time in milliseconds the requesting application should
* wait before retrying, if non-zero.
*/
- void onError(@ErrorCode int errorCode, long retryAfterMilliseconds);
+ void onError(@ErrorCode int errorCode, long retryIntervalMillis);
}
private final Context mContext;
@@ -458,9 +472,9 @@ public class RcsUceAdapter {
* {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} is enabled or else
* this operation will fail with {@link #ERROR_NOT_AVAILABLE} or {@link #ERROR_NOT_ENABLED}.
*
+ * @param contactNumbers A list of numbers that the capabilities are being requested for.
* @param executor The executor that will be used when the request is completed and the
* {@link CapabilitiesCallback} is called.
- * @param contactNumbers A list of numbers that the capabilities are being requested for.
* @param c A one-time callback for when the request for capabilities completes or there is an
* error processing the request.
* @throws ImsException if the subscription associated with this instance of
@@ -469,9 +483,10 @@ public class RcsUceAdapter {
* becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void requestCapabilities(@NonNull @CallbackExecutor Executor executor,
- @NonNull List<Uri> contactNumbers,
+ public void requestCapabilities(@NonNull List<Uri> contactNumbers,
+ @NonNull @CallbackExecutor Executor executor,
@NonNull CapabilitiesCallback c) throws ImsException {
if (c == null) {
throw new IllegalArgumentException("Must include a non-null CapabilitiesCallback.");
@@ -495,8 +510,7 @@ public class RcsUceAdapter {
public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) {
final long callingIdentity = Binder.clearCallingIdentity();
try {
- executor.execute(() ->
- c.onCapabilitiesReceived(contactCapabilities));
+ executor.execute(() -> c.onCapabilitiesReceived(contactCapabilities));
} finally {
restoreCallingIdentity(callingIdentity);
}
@@ -550,13 +564,17 @@ public class RcsUceAdapter {
* {@link #ERROR_NOT_AVAILABLE} or {@link #ERROR_NOT_ENABLED}.
*
* @param contactNumber The contact of the capabilities is being requested for.
+ * @param executor The executor that will be used when the request is completed and the
+ * {@link CapabilitiesCallback} is called.
* @param c A one-time callback for when the request for capabilities completes or there is
* an error processing the request.
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
- public void requestNetworkAvailability(@NonNull @CallbackExecutor Executor executor,
- @NonNull Uri contactNumber, @NonNull CapabilitiesCallback c) throws ImsException {
+ public void requestAvailability(@NonNull Uri contactNumber,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull CapabilitiesCallback c) throws ImsException {
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
}
@@ -569,7 +587,7 @@ public class RcsUceAdapter {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "requestNetworkAvailability: IImsRcsController is null");
+ Log.e(TAG, "requestAvailability: IImsRcsController is null");
throw new ImsException("Cannot find remote IMS service",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
@@ -579,8 +597,7 @@ public class RcsUceAdapter {
public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) {
final long callingIdentity = Binder.clearCallingIdentity();
try {
- executor.execute(() ->
- c.onCapabilitiesReceived(contactCapabilities));
+ executor.execute(() -> c.onCapabilitiesReceived(contactCapabilities));
} finally {
restoreCallingIdentity(callingIdentity);
}
@@ -606,12 +623,12 @@ public class RcsUceAdapter {
};
try {
- imsRcsController.requestNetworkAvailability(mSubId, mContext.getOpPackageName(),
+ imsRcsController.requestAvailability(mSubId, mContext.getOpPackageName(),
mContext.getAttributionTag(), contactNumber, internalCallback);
} catch (ServiceSpecificException e) {
throw new ImsException(e.toString(), e.errorCode);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling IImsRcsController#requestNetworkAvailability", e);
+ Log.e(TAG, "Error calling IImsRcsController#requestAvailability", e);
throw new ImsException("Remote IMS Service is not available",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
@@ -683,7 +700,7 @@ public class RcsUceAdapter {
if (imsRcsController == null) {
Log.e(TAG, "addOnPublishStateChangedListener : IImsRcsController is null");
throw new ImsException("Cannot find remote IMS service",
- ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
PublishStateCallbackAdapter stateCallback = addPublishStateCallback(executor, listener);
@@ -694,7 +711,7 @@ public class RcsUceAdapter {
} catch (RemoteException e) {
Log.e(TAG, "Error calling IImsRcsController#registerUcePublishStateCallback", e);
throw new ImsException("Remote IMS Service is not available",
- ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index e085dec10546..2c75368b86bf 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -25,6 +25,7 @@ import android.annotation.RequiresPermission;
import android.net.Uri;
import android.os.Binder;
import android.telephony.AccessNetworkConstants;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.ims.aidl.IImsRegistrationCallback;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -85,6 +86,22 @@ public interface RegistrationManager {
AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
}};
+ /** @hide */
+ @NonNull
+ static String registrationStateToString(
+ final @NetworkRegistrationInfo.RegistrationState int value) {
+ switch (value) {
+ case REGISTRATION_STATE_NOT_REGISTERED:
+ return "REGISTRATION_STATE_NOT_REGISTERED";
+ case REGISTRATION_STATE_REGISTERING:
+ return "REGISTRATION_STATE_REGISTERING";
+ case REGISTRATION_STATE_REGISTERED:
+ return "REGISTRATION_STATE_REGISTERED";
+ default:
+ return Integer.toString(value);
+ }
+ }
+
/**
* Callback class for receiving IMS network Registration callback events.
* @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
index 1539224dedcf..9cfa640fce18 100644
--- a/telephony/java/android/telephony/ims/SipMessage.java
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -16,12 +16,16 @@
package android.telephony.ims;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.telephony.SipMessageParsingUtils;
+
import java.util.Arrays;
import java.util.Objects;
@@ -37,9 +41,7 @@ import java.util.Objects;
public final class SipMessage implements Parcelable {
// Should not be set to true for production!
private static final boolean IS_DEBUGGING = Build.IS_ENG;
-
- private static final String[] SIP_REQUEST_METHODS = new String[] {"INVITE", "ACK", "OPTIONS",
- "BYE", "CANCEL", "REGISTER"};
+ private static final String CRLF = "\r\n";
private final String mStartLine;
private final String mHeaderSection;
@@ -72,6 +74,7 @@ public final class SipMessage implements Parcelable {
mContent = new byte[source.readInt()];
source.readByteArray(mContent);
}
+
/**
* @return The start line of the SIP message, which contains either the request-line or
* status-line.
@@ -128,34 +131,25 @@ public final class SipMessage implements Parcelable {
} else {
b.append(sanitizeStartLineRequest(mStartLine));
}
- b.append("], [");
- b.append("Header: [");
+ b.append("], Header: [");
if (IS_DEBUGGING) {
b.append(mHeaderSection);
} else {
// only identify transaction id/call ID when it is available.
b.append("***");
}
- b.append("], ");
- b.append("Content: [NOT SHOWN]");
+ b.append("], Content: ");
+ b.append(getContent().length == 0 ? "[NONE]" : "[NOT SHOWN]");
return b.toString();
}
/**
- * Start lines containing requests are formatted: METHOD SP Request-URI SP SIP-Version CRLF.
* Detect if this is a REQUEST and redact Request-URI portion here, as it contains PII.
*/
private String sanitizeStartLineRequest(String startLine) {
+ if (!SipMessageParsingUtils.isSipRequest(startLine)) return startLine;
String[] splitLine = startLine.split(" ");
- if (splitLine == null || splitLine.length == 0) {
- return "(INVALID STARTLINE)";
- }
- for (String method : SIP_REQUEST_METHODS) {
- if (splitLine[0].contains(method)) {
- return splitLine[0] + " <Request-URI> " + splitLine[2];
- }
- }
- return startLine;
+ return splitLine[0] + " <Request-URI> " + splitLine[2];
}
@Override
@@ -174,4 +168,19 @@ public final class SipMessage implements Parcelable {
result = 31 * result + Arrays.hashCode(mContent);
return result;
}
+
+ /**
+ * @return the UTF-8 encoded SIP message.
+ */
+ public @NonNull byte[] getEncodedMessage() {
+ byte[] header = new StringBuilder()
+ .append(mStartLine)
+ .append(mHeaderSection)
+ .append(CRLF)
+ .toString().getBytes(UTF_8);
+ byte[] sipMessage = new byte[header.length + mContent.length];
+ System.arraycopy(header, 0, sipMessage, 0, header.length);
+ System.arraycopy(mContent, 0, sipMessage, header.length, mContent.length);
+ return sipMessage;
+ }
}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
index 36349895c35b..7a6c28bddd09 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
@@ -52,7 +52,7 @@ interface IImsRcsController {
// ImsUceAdapter specific
void requestCapabilities(int subId, String callingPackage, String callingFeatureId,
in List<Uri> contactNumbers, IRcsUceControllerCallback c);
- void requestNetworkAvailability(int subId, String callingPackage,
+ void requestAvailability(int subId, String callingPackage,
String callingFeatureId, in Uri contactNumber,
IRcsUceControllerCallback c);
int getUcePublishState(int subId);
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
index 522ad8160870..9d919015087d 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
@@ -28,6 +28,10 @@ import android.telephony.ims.SipDelegateImsConfiguration;
import android.telephony.ims.SipDelegateManager;
import android.telephony.ims.SipMessage;
import android.telephony.ims.stub.SipDelegate;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.telephony.SipMessageParsingUtils;
import java.util.ArrayList;
import java.util.Set;
@@ -40,6 +44,7 @@ import java.util.concurrent.Executor;
* @hide
*/
public class SipDelegateAidlWrapper implements DelegateStateCallback, DelegateMessageCallback {
+ private static final String LOG_TAG = "SipDelegateAW";
private final ISipDelegate.Stub mDelegateBinder = new ISipDelegate.Stub() {
@Override
@@ -183,11 +188,15 @@ public class SipDelegateAidlWrapper implements DelegateStateCallback, DelegateMe
}
private void notifyLocalMessageFailedToBeReceived(SipMessage m, int reason) {
- //TODO: parse transaction ID or throw IllegalArgumentException if the SipMessage
- // transaction ID can not be parsed.
+ String transactionId = SipMessageParsingUtils.getTransactionId(m.getHeaderSection());
+ if (TextUtils.isEmpty(transactionId)) {
+ Log.w(LOG_TAG, "failure to parse SipMessage.");
+ throw new IllegalArgumentException("Malformed SipMessage, can not determine "
+ + "transaction ID.");
+ }
SipDelegate d = mDelegate;
if (d != null) {
- mExecutor.execute(() -> d.notifyMessageReceiveError(null, reason));
+ mExecutor.execute(() -> d.notifyMessageReceiveError(transactionId, reason));
}
}
}
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
index a35039bd7668..c877aca8ba96 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
@@ -28,9 +28,12 @@ import android.telephony.ims.SipMessage;
import android.telephony.ims.stub.DelegateConnectionMessageCallback;
import android.telephony.ims.stub.DelegateConnectionStateCallback;
import android.telephony.ims.stub.SipDelegate;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
+import com.android.internal.telephony.SipMessageParsingUtils;
+
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.Executor;
@@ -265,9 +268,13 @@ public class SipDelegateConnectionAidlWrapper implements SipDelegateConnection,
}
private void notifyLocalMessageFailedToSend(SipMessage m, int reason) {
- //TODO: parse transaction ID or throw IllegalArgumentException if the SipMessage
- // transaction ID can not be parsed.
+ String transactionId = SipMessageParsingUtils.getTransactionId(m.getHeaderSection());
+ if (TextUtils.isEmpty(transactionId)) {
+ Log.w(LOG_TAG, "sendMessage detected a malformed SipMessage and can not get a "
+ + "transaction ID.");
+ throw new IllegalArgumentException("Could not send SipMessage due to malformed header");
+ }
mExecutor.execute(() ->
- mMessageCallback.onMessageSendFailure(null, reason));
+ mMessageCallback.onMessageSendFailure(transactionId, reason));
}
}
diff --git a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
index d2cb9761a028..d9734a7475c0 100644
--- a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
+++ b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
@@ -18,15 +18,12 @@ package android.telephony.ims.stub;
import android.annotation.NonNull;
import android.annotation.SystemApi;
-import android.net.Uri;
import android.telephony.ims.ImsException;
import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.RcsUceAdapter;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.RcsFeature;
-import java.util.List;
-
/**
* The interface of the capabilities event listener for ImsService to notify the framework of the
* UCE request and status updated.
@@ -84,25 +81,4 @@ public interface CapabilityExchangeEventListener {
* Telephony stack has crashed.
*/
void onUnpublish() throws ImsException;
-
- /**
- * Inform the framework of a query for this device's UCE capabilities.
- * <p>
- * The framework will respond via the
- * {@link OptionsRequestCallback#onRespondToCapabilityRequest} or
- * {@link OptionsRequestCallback#onRespondToCapabilityRequestWithError}
- * @param contactUri The URI associated with the remote contact that is
- * requesting capabilities.
- * @param remoteCapabilities The remote contact's capability information.
- * @param callback The callback of this request which is sent from the remote user.
- * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is not
- * currently connected to the framework. This can happen if the {@link RcsFeature} is not
- * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received
- * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare
- * cases when the Telephony stack has crashed.
- * @hide
- */
- void onRemoteCapabilityRequest(@NonNull Uri contactUri,
- @NonNull List<String> remoteCapabilities,
- @NonNull OptionsRequestCallback callback) throws ImsException;
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
index 06c35eaec6dd..2e35d27614d1 100644
--- a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
@@ -23,6 +23,8 @@ import android.util.Log;
import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsEcbmListener;
+import java.util.Objects;
+
/**
* Base implementation of ImsEcbm, which implements stub versions of the methods
* in the IImsEcbm AIDL. Override the methods that your implementation of ImsEcbm supports.
@@ -36,11 +38,27 @@ import com.android.ims.internal.IImsEcbmListener;
public class ImsEcbmImplBase {
private static final String TAG = "ImsEcbmImplBase";
+ private final Object mLock = new Object();
private IImsEcbmListener mListener;
- private IImsEcbm mImsEcbm = new IImsEcbm.Stub() {
+ private final IImsEcbm mImsEcbm = new IImsEcbm.Stub() {
@Override
public void setListener(IImsEcbmListener listener) {
- mListener = listener;
+ synchronized (mLock) {
+ if (mImsEcbm != null && listener != null && Objects.equals(
+ mImsEcbm.asBinder(), listener.asBinder())) {
+ return;
+ }
+ if (listener == null) {
+ mListener = null;
+ } else if (listener != null && mListener == null) {
+ mListener = listener;
+ } else {
+ // Fail fast here instead of silently overwriting the listener to another
+ // listener due to another connection connecting.
+ throw new IllegalStateException("ImsEcbmImplBase: Listener already set by "
+ + "another connection.");
+ }
+ }
}
@Override
@@ -69,9 +87,13 @@ public class ImsEcbmImplBase {
*/
public final void enteredEcbm() {
Log.d(TAG, "Entered ECBM.");
- if (mListener != null) {
+ IImsEcbmListener listener;
+ synchronized (mLock) {
+ listener = mListener;
+ }
+ if (listener != null) {
try {
- mListener.enteredECBM();
+ listener.enteredECBM();
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -85,9 +107,13 @@ public class ImsEcbmImplBase {
*/
public final void exitedEcbm() {
Log.d(TAG, "Exited ECBM.");
- if (mListener != null) {
+ IImsEcbmListener listener;
+ synchronized (mLock) {
+ listener = mListener;
+ }
+ if (listener != null) {
try {
- mListener.exitedECBM();
+ listener.exitedECBM();
} catch (RemoteException e) {
throw new RuntimeException(e);
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
index d002903a11b6..555a47eb8200 100644
--- a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
@@ -25,6 +25,7 @@ import com.android.ims.internal.IImsExternalCallStateListener;
import com.android.ims.internal.IImsMultiEndpoint;
import java.util.List;
+import java.util.Objects;
/**
* Base implementation of ImsMultiEndpoint, which implements stub versions of the methods
@@ -41,10 +42,28 @@ public class ImsMultiEndpointImplBase {
private static final String TAG = "MultiEndpointImplBase";
private IImsExternalCallStateListener mListener;
- private IImsMultiEndpoint mImsMultiEndpoint = new IImsMultiEndpoint.Stub() {
+ private final Object mLock = new Object();
+ private final IImsMultiEndpoint mImsMultiEndpoint = new IImsMultiEndpoint.Stub() {
+
@Override
public void setListener(IImsExternalCallStateListener listener) throws RemoteException {
- mListener = listener;
+ synchronized (mLock) {
+ if (mListener != null && listener != null && Objects.equals(
+ mListener.asBinder(), listener.asBinder())) {
+ return;
+ }
+
+ if (listener == null) {
+ mListener = null;
+ } else if (listener != null && mListener == null) {
+ mListener = listener;
+ } else {
+ // Fail fast here instead of silently overwriting the listener to another
+ // listener due to another connection connecting.
+ throw new IllegalStateException("ImsMultiEndpointImplBase: Listener already"
+ + " set by another connection.");
+ }
+ }
}
@Override
@@ -65,9 +84,13 @@ public class ImsMultiEndpointImplBase {
*/
public final void onImsExternalCallStateUpdate(List<ImsExternalCallState> externalCallDialogs) {
Log.d(TAG, "ims external call state update triggered.");
- if (mListener != null) {
+ IImsExternalCallStateListener listener;
+ synchronized (mLock) {
+ listener = mListener;
+ }
+ if (listener != null) {
try {
- mListener.onImsExternalCallStateUpdate(externalCallDialogs);
+ listener.onImsExternalCallStateUpdate(externalCallDialogs);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index f5219d5b49e8..eef4fcaceeaf 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -29,6 +29,7 @@ import com.android.ims.internal.IImsUtListener;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
/**
* Base implementation of IMS UT interface, which implements stubs. Override these methods to
@@ -116,7 +117,10 @@ public class ImsUtImplBase {
*/
public static final int INVALID_RESULT = -1;
- private IImsUt.Stub mServiceImpl = new IImsUt.Stub() {
+ private final IImsUt.Stub mServiceImpl = new IImsUt.Stub() {
+ private final Object mLock = new Object();
+ private ImsUtListener mUtListener;
+
@Override
public void close() throws RemoteException {
ImsUtImplBase.this.close();
@@ -202,7 +206,26 @@ public class ImsUtImplBase {
@Override
public void setListener(IImsUtListener listener) throws RemoteException {
- ImsUtImplBase.this.setListener(new ImsUtListener(listener));
+ synchronized (mLock) {
+ if (mUtListener != null && listener != null && Objects.equals(
+ mUtListener.getListenerInterface().asBinder(), listener.asBinder())) {
+ return;
+ }
+
+ if (listener == null) {
+ mUtListener = null;
+ } else if (listener != null && mUtListener == null) {
+ mUtListener = new ImsUtListener(listener);
+ } else {
+ // This is a limitation of the current API surface, there can only be one
+ // listener connected. Fail fast instead of silently overwriting the other
+ // listener.
+ throw new IllegalStateException("ImsUtImplBase#setListener: listener already "
+ + "set by another connected interface!");
+ }
+ }
+
+ ImsUtImplBase.this.setListener(mUtListener);
}
@Override
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
index c84e23c38e97..7eba709a11da 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
@@ -24,6 +24,7 @@ import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.net.Uri;
import android.telephony.ims.ImsException;
+import android.telephony.ims.RcsUceAdapter;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.RcsFeature;
import android.util.Log;
@@ -139,18 +140,19 @@ public class RcsCapabilityExchangeImplBase {
* Provide the framework with a subsequent network response update to
* {@link #publishCapabilities(String, PublishResponseCallback)}.
*
- * @param code The SIP response code sent from the network for the operation
+ * @param sipCode The SIP response code sent from the network for the operation
* token specified.
* @param reason The optional reason response from the network. If there is a reason header
* included in the response, that should take precedence over the reason provided in the
- * status line. If the network provided no reason with the code, the string should be empty.
+ * status line. If the network provided no reason with the sip code, the string should be
+ * empty.
* @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
* not currently connected to the framework. This can happen if the {@link RcsFeature}
* is not {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received
* the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases
* when the Telephony stack has crashed.
*/
- void onNetworkResponse(@IntRange(from = 100, to = 699) int code,
+ void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode,
@NonNull String reason) throws ImsException;
}
@@ -173,7 +175,7 @@ public class RcsCapabilityExchangeImplBase {
/**
* Send the response of a SIP OPTIONS capability exchange to the framework.
- * @param code The SIP response code that was sent by the network in response
+ * @param sipCode The SIP response code that was sent by the network in response
* to the request sent by {@link #sendOptionsCapabilityRequest}.
* @param reason The optional SIP response reason sent by the network.
* If none was sent, this should be an empty string.
@@ -186,17 +188,20 @@ public class RcsCapabilityExchangeImplBase {
* {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare
* cases when the Telephony stack has crashed.
*/
- void onNetworkResponse(int code, @NonNull String reason,
+ void onNetworkResponse(int sipCode, @NonNull String reason,
@Nullable List<String> theirCaps) throws ImsException;
}
/**
* Interface used by the framework to receive the response of the subscribe request.
- * @hide
*/
public interface SubscribeResponseCallback {
/**
* Notify the framework that the command associated with this callback has failed.
+ * <p>
+ * Must only be called when there was an error generating a SUBSCRIBE request due to an
+ * IMS stack error. This is a terminating event, so no other callback event will be
+ * expected after this callback.
*
* @param code The reason why the associated command has failed.
* @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
@@ -211,27 +216,38 @@ public class RcsCapabilityExchangeImplBase {
/**
* Notify the framework of the response to the SUBSCRIBE request from
* {@link #subscribeForCapabilities(List<Uri>, SubscribeResponseCallback)}.
+ * <p>
+ * If the carrier network responds to the SUBSCRIBE request with a 2XX response, then the
+ * framework will expect the IMS stack to call {@link #onNotifyCapabilitiesUpdate},
+ * {@link #onResourceTerminated}, and {@link #onTerminated} as required for the
+ * subsequent NOTIFY responses to the subscription.
*
- * @param code The SIP response code sent from the network for the operation
+ * @param sipCode The SIP response code sent from the network for the operation
* token specified.
* @param reason The optional reason response from the network. If the network
- * provided no reason with the code, the string should be empty.
+ * provided no reason with the sip code, the string should be empty.
* @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
* not currently connected to the framework. This can happen if the
* {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the
* {@link RcsFeature} has not received the {@link ImsFeature#onFeatureReady()} callback.
* This may also happen in rare cases when the Telephony stack has crashed.
*/
- void onNetworkResponse(@IntRange(from = 100, to = 699) int code,
+ void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode,
@NonNull String reason) throws ImsException;
/**
- * Provides the framework with latest XML PIDF documents included in the
- * network response for the requested contacts' capabilities requested by the
- * Framework using {@link #requestCapabilities(List, int)}. This should be
- * called every time a new NOTIFY event is received with new capability
- * information.
+ * Notify the framework of the latest XML PIDF documents included in the network response
+ * for the requested contacts' capabilities requested by the Framework using
+ * {@link RcsUceAdapter#requestCapabilities(Executor, List<Uri>, CapabilitiesCallback)}.
+ * <p>
+ * The expected format for the PIDF XML is defined in RFC3861. Each XML document must be a
+ * "application/pidf+xml" object and start with a root <presence> element. For NOTIFY
+ * responses that contain RLMI information and potentially multiple PIDF XMLs, each
+ * PIDF XML should be separated and added as a separate item in the List. This should be
+ * called every time a new NOTIFY event is received with new capability information.
*
+ * @param pidfXmls The list of the PIDF XML data for the contact URIs that it subscribed
+ * for.
* @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
* not currently connected to the framework.
* This can happen if the {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the
@@ -242,21 +258,42 @@ public class RcsCapabilityExchangeImplBase {
void onNotifyCapabilitiesUpdate(@NonNull List<String> pidfXmls) throws ImsException;
/**
- * A resource in the resource list for the presence subscribe event has been terminated.
+ * Notify the framework that a resource in the RLMI XML contained in the NOTIFY response
+ * for the ongoing SUBSCRIBE dialog has been terminated.
* <p>
- * This allows the framework to know that there will not be any capability information for
- * a specific contact URI that they subscribed for.
+ * This will be used to notify the framework that a contact URI that the IMS stack has
+ * subscribed to on the Resource List Server has been terminated as well as the reason why.
+ * Usually this means that there will not be any capability information for the contact URI
+ * that they subscribed for. See RFC 4662 for more information.
+ *
+ * @param uriTerminatedReason The contact URIs which have been terminated. Each pair in the
+ * list is the contact URI and its terminated reason.
+ * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
+ * not currently connected to the framework.
+ * This can happen if the {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the
+ * {@link RcsFeature} {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not
+ * received the {@link ImsFeature#onFeatureReady()} callback. This may also happen in
+ * rare cases when the Telephony stack has crashed.
*/
void onResourceTerminated(
@NonNull List<Pair<Uri, String>> uriTerminatedReason) throws ImsException;
/**
- * The subscription associated with a previous #requestCapabilities operation
- * has been terminated. This will mostly be due to the subscription expiring,
- * but may also happen due to an error.
- * <p>
- * This allows the framework to know that there will no longer be any
- * capability updates for the requested operationToken.
+ * The subscription associated with a previous
+ * {@link RcsUceAdapter#requestCapabilities(Executor, List<Uri>, CapabilitiesCallback)}
+ * operation has been terminated. This will mostly be due to the network sending a final
+ * NOTIFY response due to the subscription expiring, but this may also happen due to a
+ * network error.
+ *
+ * @param reason The reason for the request being unable to process.
+ * @param retryAfterMilliseconds The time in milliseconds the requesting application should
+ * wait before retrying, if non-zero.
+ * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
+ * not currently connected to the framework.
+ * This can happen if the {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the
+ * {@link RcsFeature} {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not
+ * received the {@link ImsFeature#onFeatureReady()} callback. This may also happen in
+ * rare cases when the Telephony stack has crashed.
*/
void onTerminated(@NonNull String reason, long retryAfterMilliseconds) throws ImsException;
}
@@ -278,18 +315,23 @@ public class RcsCapabilityExchangeImplBase {
/**
* The user capabilities of one or multiple contacts have been requested by the framework.
* <p>
+ * The implementer must follow up this call with an
+ * {@link SubscribeResponseCallback#onCommandError} call to indicate this operation has failed.
* The response from the network to the SUBSCRIBE request must be sent back to the framework
- * using {@link #onSubscribeNetworkResponse(int, String, int)}. As NOTIFY requests come in from
- * the network, the requested contact’s capabilities should be sent back to the framework using
- * {@link #onSubscribeNotifyRequest} and {@link onSubscribeResourceTerminated}
+ * using {@link SubscribeResponseCallback#onNetworkResponse(int, String)}.
+ * As NOTIFY requests come in from the network, the requested contact’s capabilities should be
+ * sent back to the framework using
+ * {@link SubscribeResponseCallback#onNotifyCapabilitiesUpdate(List<String>}) and
+ * {@link SubscribeResponseCallback#onResourceTerminated(List<Pair<Uri, String>>)}
* should be called with the presence information for the contacts specified.
* <p>
- * Once the subscription is terminated, {@link #onSubscriptionTerminated} must be called for
- * the framework to finish listening for NOTIFY responses.
+ * Once the subscription is terminated,
+ * {@link SubscribeResponseCallback#onTerminated(String, long)} must be called for the
+ * framework to finish listening for NOTIFY responses.
+ *
* @param uris A {@link List} of the {@link Uri}s that the framework is requesting the UCE
* capabilities for.
* @param cb The callback of the subscribe request.
- * @hide
*/
// executor used is defined in the constructor.
@SuppressLint("ExecutorRegistration")
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 541ec040d4dd..c5ff47b1e1d3 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -49,6 +49,7 @@ import android.telephony.RadioAccessFamily;
import android.telephony.RadioAccessSpecifier;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
+import android.telephony.SignalStrengthUpdateRequest;
import android.telephony.TelephonyHistogram;
import android.telephony.VisualVoicemailSmsFilterSettings;
import android.telephony.emergency.EmergencyNumber;
@@ -2279,6 +2280,14 @@ interface ITelephony {
CarrierBandwidth getCarrierBandwidth(int subId);
/**
+ * Checks whether the device supports the given capability on the radio interface.
+ *
+ * @param capability the name of the capability
+ * @return the availability of the capability
+ */
+ boolean isRadioInterfaceCapabilitySupported(String capability);
+
+ /**
* Thermal mitigation request to control functionalities at modem.
*
* @param subId the id of the subscription
@@ -2358,6 +2367,11 @@ interface ITelephony {
boolean setCarrierSingleRegistrationEnabledOverride(int subId, String enabled);
/**
+ * Sends a device to device message; only for use through shell.
+ */
+ void sendDeviceToDeviceMessage(int message, int value);
+
+ /**
* Gets the config of RCS VoLTE single registration enabled for the carrier/subscription.
*/
boolean getCarrierSingleRegistrationEnabled(int subId);
@@ -2367,4 +2381,22 @@ interface ITelephony {
* their mobile plan.
*/
String getMobileProvisioningUrl();
+
+ /*
+ * Remove the EAB contacts from the EAB database.
+ */
+ int removeContactFromEab(int subId, String contacts);
+
+ /**
+ * Set a SignalStrengthUpdateRequest to receive notification when Signal Strength breach the
+ * specified thresholds.
+ */
+ void setSignalStrengthUpdateRequest(int subId, in SignalStrengthUpdateRequest request,
+ String callingPackage);
+
+ /**
+ * Clear a SignalStrengthUpdateRequest from system.
+ */
+ void clearSignalStrengthUpdateRequest(int subId, in SignalStrengthUpdateRequest request,
+ String callingPackage);
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 52f263fad695..76243a5799c3 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -520,6 +520,7 @@ public interface RILConstants {
int RIL_REQUEST_START_HANDOVER = 217;
int RIL_REQUEST_CANCEL_HANDOVER = 218;
int RIL_REQUEST_GET_SYSTEM_SELECTION_CHANNELS = 219;
+ int RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES = 220;
int RIL_REQUEST_SET_DATA_THROTTLING = 221;
int RIL_REQUEST_SET_ALLOWED_NETWORK_TYPE_BITMAP = 222;
int RIL_REQUEST_GET_ALLOWED_NETWORK_TYPE_BITMAP = 223;
diff --git a/test-mock/api/current.txt b/test-mock/api/current.txt
index 1110790c373f..d1a68d4e9cb2 100644
--- a/test-mock/api/current.txt
+++ b/test-mock/api/current.txt
@@ -117,6 +117,7 @@ package android.test.mock {
method public void sendOrderedBroadcast(android.content.Intent, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
method public void sendStickyBroadcast(android.content.Intent);
+ method public void sendStickyBroadcast(android.content.Intent, android.os.Bundle);
method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index cf3b03cae72e..6046d78240b6 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -493,6 +493,11 @@ public class MockContext extends Context {
}
@Override
+ public void sendStickyBroadcast(Intent intent, Bundle options) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public void sendStickyOrderedBroadcast(Intent intent,
BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
Bundle initialExtras) {
diff --git a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
index e9227e94da98..eb04f6907748 100644
--- a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
+++ b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
@@ -131,6 +131,10 @@ class PlatformCompatCommandNotInstalledTest {
assertThat(platformCompat.isChangeEnabled(TEST_CHANGE_ID, appInfo)).isEqualTo(params.result)
}
- private fun command(command: String) =
- FileReader(uiAutomation.executeShellCommand(command).fileDescriptor).readText()
+ private fun command(command: String): String {
+ val fileDescriptor = uiAutomation.executeShellCommand(command)
+ return String(ParcelFileDescriptor.AutoCloseInputStream(fileDescriptor).use {
+ inputStream -> inputStream.readBytes()
+ })
+ }
}
diff --git a/tests/StagedInstallTest/OWNERS b/tests/StagedInstallTest/OWNERS
index d825dfd7cf00..aac68e994a39 100644
--- a/tests/StagedInstallTest/OWNERS
+++ b/tests/StagedInstallTest/OWNERS
@@ -1 +1,5 @@
include /services/core/java/com/android/server/pm/OWNERS
+
+dariofreni@google.com
+ioffe@google.com
+olilan@google.com
diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp
index 373aac604b2a..c271f49ee537 100644
--- a/tests/net/common/Android.bp
+++ b/tests/net/common/Android.bp
@@ -24,6 +24,7 @@ java_library {
"androidx.test.rules",
"junit",
"mockito-target-minus-junit4",
+ "modules-utils-build",
"net-tests-utils",
"net-utils-framework-common",
"platform-test-annotations",
diff --git a/tests/net/common/java/android/net/CaptivePortalDataTest.kt b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
index 8710d23730b6..b2bcfeb9019d 100644
--- a/tests/net/common/java/android/net/CaptivePortalDataTest.kt
+++ b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
@@ -18,12 +18,15 @@ package android.net
import android.os.Build
import androidx.test.filters.SmallTest
+import com.android.modules.utils.build.SdkLevel
import com.android.testutils.assertParcelSane
import com.android.testutils.assertParcelingIsLossless
+import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.test.assertEquals
@@ -33,6 +36,9 @@ import kotlin.test.assertNotEquals
@RunWith(DevSdkIgnoreRunner::class)
@IgnoreUpTo(Build.VERSION_CODES.Q)
class CaptivePortalDataTest {
+ @Rule @JvmField
+ val ignoreRule = DevSdkIgnoreRule()
+
private val data = CaptivePortalData.Builder()
.setRefreshTime(123L)
.setUserPortalUrl(Uri.parse("https://portal.example.com/test"))
@@ -41,14 +47,19 @@ class CaptivePortalDataTest {
.setBytesRemaining(456L)
.setExpiryTime(789L)
.setCaptive(true)
- .setVenueFriendlyName("venue friendly name")
+ .apply {
+ if (SdkLevel.isAtLeastS()) {
+ setVenueFriendlyName("venue friendly name")
+ }
+ }
.build()
private fun makeBuilder() = CaptivePortalData.Builder(data)
@Test
fun testParcelUnparcel() {
- assertParcelSane(data, fieldCount = 8)
+ val fieldCount = if (SdkLevel.isAtLeastS()) 8 else 7
+ assertParcelSane(data, fieldCount)
assertParcelingIsLossless(makeBuilder().setUserPortalUrl(null).build())
assertParcelingIsLossless(makeBuilder().setVenueInfoUrl(null).build())
@@ -67,8 +78,11 @@ class CaptivePortalDataTest {
assertNotEqualsAfterChange { it.setBytesRemaining(789L) }
assertNotEqualsAfterChange { it.setExpiryTime(12L) }
assertNotEqualsAfterChange { it.setCaptive(false) }
- assertNotEqualsAfterChange { it.setVenueFriendlyName("another friendly name") }
- assertNotEqualsAfterChange { it.setVenueFriendlyName(null) }
+
+ if (SdkLevel.isAtLeastS()) {
+ assertNotEqualsAfterChange { it.setVenueFriendlyName("another friendly name") }
+ assertNotEqualsAfterChange { it.setVenueFriendlyName(null) }
+ }
}
@Test
@@ -111,7 +125,7 @@ class CaptivePortalDataTest {
assertFalse(makeBuilder().setCaptive(false).build().isCaptive)
}
- @Test
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
fun testVenueFriendlyName() {
assertEquals("venue friendly name", data.venueFriendlyName)
}
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 6b7ea66df233..5d0e016d50fa 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -42,9 +42,11 @@ import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
+import static android.os.Process.INVALID_UID;
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
+import static com.android.testutils.ParcelUtils.parcelingRoundTrip;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -53,18 +55,19 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+import android.net.wifi.WifiInfo;
import android.net.wifi.aware.DiscoverySession;
import android.net.wifi.aware.PeerHandle;
import android.net.wifi.aware.WifiAwareNetworkSpecifier;
import android.os.Build;
-import android.os.Process;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
-import androidx.core.os.BuildCompat;
import androidx.test.runner.AndroidJUnit4;
+import com.android.modules.utils.build.SdkLevel;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
@@ -89,10 +92,11 @@ public class NetworkCapabilitiesTest {
private PeerHandle mPeerHandle = Mockito.mock(PeerHandle.class);
private boolean isAtLeastR() {
- // BuildCompat.isAtLeastR() is used to check the Android version before releasing Android R.
- // Build.VERSION.SDK_INT > Build.VERSION_CODES.Q is used to check the Android version after
- // releasing Android R.
- return BuildCompat.isAtLeastR() || Build.VERSION.SDK_INT > Build.VERSION_CODES.Q;
+ return SdkLevel.isAtLeastR();
+ }
+
+ private boolean isAtLeastS() {
+ return SdkLevel.isAtLeastS();
}
@Test
@@ -324,8 +328,59 @@ public class NetworkCapabilitiesTest {
testParcelSane(netCap);
}
+ private NetworkCapabilities createNetworkCapabilitiesWithWifiInfo() {
+ // uses a real WifiInfo to test parceling of sensitive data.
+ final WifiInfo wifiInfo = new WifiInfo.Builder()
+ .setSsid("sssid1234".getBytes())
+ .setBssid("00:11:22:33:44:55")
+ .build();
+ return new NetworkCapabilities()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_EIMS)
+ .addCapability(NET_CAPABILITY_NOT_METERED)
+ .setSSID(TEST_SSID)
+ .setTransportInfo(wifiInfo)
+ .setRequestorPackageName("com.android.test")
+ .setRequestorUid(9304);
+ }
+
+ @Test
+ public void testParcelNetworkCapabilitiesWithLocationSensitiveFields() {
+ assumeTrue(isAtLeastS());
+
+ final NetworkCapabilities netCap = createNetworkCapabilitiesWithWifiInfo();
+ final NetworkCapabilities netCapWithLocationSensitiveFields =
+ new NetworkCapabilities(netCap, true);
+
+ assertParcelingIsLossless(netCapWithLocationSensitiveFields);
+ testParcelSane(netCapWithLocationSensitiveFields);
+
+ assertEquals(netCapWithLocationSensitiveFields,
+ parcelingRoundTrip(netCapWithLocationSensitiveFields));
+ }
+
+ @Test
+ public void testParcelNetworkCapabilitiesWithoutLocationSensitiveFields() {
+ assumeTrue(isAtLeastS());
+
+ final NetworkCapabilities netCap = createNetworkCapabilitiesWithWifiInfo();
+ final NetworkCapabilities netCapWithoutLocationSensitiveFields =
+ new NetworkCapabilities(netCap, false);
+
+ final NetworkCapabilities sanitizedNetCap =
+ new NetworkCapabilities(netCapWithoutLocationSensitiveFields);
+ final WifiInfo sanitizedWifiInfo = new WifiInfo.Builder()
+ .setSsid(new byte[0])
+ .setBssid(WifiInfo.DEFAULT_MAC_ADDRESS)
+ .build();
+ sanitizedNetCap.setTransportInfo(sanitizedWifiInfo);
+ assertEquals(sanitizedNetCap, parcelingRoundTrip(netCapWithoutLocationSensitiveFields));
+ }
+
private void testParcelSane(NetworkCapabilities cap) {
- if (isAtLeastR()) {
+ if (isAtLeastS()) {
+ assertParcelSane(cap, 16);
+ } else if (isAtLeastR()) {
assertParcelSane(cap, 15);
} else {
assertParcelSane(cap, 11);
@@ -639,26 +694,23 @@ public class NetworkCapabilitiesTest {
// Sequence 1: Transport + Transport + TransportInfo
NetworkCapabilities nc1 = new NetworkCapabilities();
nc1.addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI)
- .setTransportInfo(new TransportInfo() {});
+ .setTransportInfo(new TestTransportInfo());
// Sequence 2: Transport + NetworkSpecifier + Transport
NetworkCapabilities nc2 = new NetworkCapabilities();
- nc2.addTransportType(TRANSPORT_CELLULAR).setTransportInfo(new TransportInfo() {})
+ nc2.addTransportType(TRANSPORT_CELLULAR).setTransportInfo(new TestTransportInfo())
.addTransportType(TRANSPORT_WIFI);
}
@Test
public void testCombineTransportInfo() {
NetworkCapabilities nc1 = new NetworkCapabilities();
- nc1.setTransportInfo(new TransportInfo() {
- // empty
- });
+ nc1.setTransportInfo(new TestTransportInfo());
+
NetworkCapabilities nc2 = new NetworkCapabilities();
// new TransportInfo so that object is not #equals to nc1's TransportInfo (that's where
// combine fails)
- nc2.setTransportInfo(new TransportInfo() {
- // empty
- });
+ nc2.setTransportInfo(new TestTransportInfo());
try {
nc1.combineCapabilities(nc2);
@@ -761,7 +813,7 @@ public class NetworkCapabilitiesTest {
// Test default owner uid.
// If the owner uid is not set, the default value should be Process.INVALID_UID.
final NetworkCapabilities nc1 = new NetworkCapabilities.Builder().build();
- assertEquals(Process.INVALID_UID, nc1.getOwnerUid());
+ assertEquals(INVALID_UID, nc1.getOwnerUid());
// Test setAdministratorUids and getAdministratorUids.
final int[] administratorUids = {1001, 10001};
final NetworkCapabilities nc2 = new NetworkCapabilities.Builder()
@@ -906,6 +958,16 @@ public class NetworkCapabilitiesTest {
private class TestTransportInfo implements TransportInfo {
TestTransportInfo() {
}
+
+ @Override
+ public TransportInfo makeCopy(boolean parcelLocationSensitiveFields) {
+ return this;
+ }
+
+ @Override
+ public boolean hasLocationSensitiveFields() {
+ return false;
+ }
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
diff --git a/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt b/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt
new file mode 100644
index 000000000000..87cfb345e5e0
--- /dev/null
+++ b/tests/net/common/java/android/net/UnderlyingNetworkInfoTest.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 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 android.os.Build
+import androidx.test.filters.SmallTest
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.assertParcelSane
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertEquals
+
+private const val TEST_OWNER_UID = 123
+private const val TEST_IFACE = "test_tun0"
+private val TEST_IFACE_LIST = listOf("wlan0", "rmnet_data0", "eth0")
+
+@SmallTest
+@RunWith(DevSdkIgnoreRunner::class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+class UnderlyingNetworkInfoTest {
+ @Test
+ fun testParcelUnparcel() {
+ val testInfo = UnderlyingNetworkInfo(TEST_OWNER_UID, TEST_IFACE, TEST_IFACE_LIST)
+ assertEquals(TEST_OWNER_UID, testInfo.ownerUid)
+ assertEquals(TEST_IFACE, testInfo.iface)
+ assertEquals(TEST_IFACE_LIST, testInfo.underlyingIfaces)
+ assertParcelSane(testInfo, 3)
+
+ val emptyInfo = UnderlyingNetworkInfo(0, String(), listOf())
+ assertEquals(0, emptyInfo.ownerUid)
+ assertEquals(String(), emptyInfo.iface)
+ assertEquals(listOf(), emptyInfo.underlyingIfaces)
+ assertParcelSane(emptyInfo, 3)
+ }
+} \ No newline at end of file
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index 8e1875168a84..083c8c8741da 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -38,6 +38,7 @@ import android.net.metrics.IpConnectivityLog
import android.os.ConditionVariable
import android.os.IBinder
import android.os.INetworkManagementService
+import android.os.UserHandle
import android.testing.TestableContext
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -46,8 +47,6 @@ import com.android.server.ConnectivityService
import com.android.server.LocalServices
import com.android.server.NetworkAgentWrapper
import com.android.server.TestNetIdManager
-import com.android.server.connectivity.DefaultNetworkMetrics
-import com.android.server.connectivity.IpConnectivityMetrics
import com.android.server.connectivity.MockableSystemProperties
import com.android.server.connectivity.ProxyTracker
import com.android.server.net.NetworkPolicyManagerInternal
@@ -57,10 +56,13 @@ import org.junit.Before
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.AdditionalAnswers
import org.mockito.Mock
import org.mockito.Mockito.any
+import org.mockito.Mockito.anyInt
import org.mockito.Mockito.doNothing
import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.eq
import org.mockito.Mockito.mock
import org.mockito.Mockito.spy
import org.mockito.MockitoAnnotations
@@ -92,10 +94,6 @@ class ConnectivityServiceIntegrationTest {
private lateinit var netd: INetd
@Mock
private lateinit var dnsResolver: IDnsResolver
- @Mock
- private lateinit var metricsLogger: IpConnectivityMetrics.Logger
- @Mock
- private lateinit var defaultMetrics: DefaultNetworkMetrics
@Spy
private var context = TestableContext(realContext)
@@ -149,8 +147,10 @@ class ConnectivityServiceIntegrationTest {
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- doReturn(defaultMetrics).`when`(metricsLogger).defaultNetworkMetrics()
- doNothing().`when`(context).sendStickyBroadcastAsUser(any(), any(), any())
+ val asUserCtx = mock(Context::class.java, AdditionalAnswers.delegatesTo<Context>(context))
+ doReturn(UserHandle.ALL).`when`(asUserCtx).user
+ doReturn(asUserCtx).`when`(context).createContextAsUser(eq(UserHandle.ALL), anyInt())
+ doNothing().`when`(context).sendStickyBroadcast(any(), any())
networkStackClient = TestNetworkStackClient(realContext)
networkStackClient.init()
@@ -173,7 +173,6 @@ class ConnectivityServiceIntegrationTest {
private fun makeDependencies(): ConnectivityService.Dependencies {
val deps = spy(ConnectivityService.Dependencies())
doReturn(networkStackClient).`when`(deps).networkStack
- doReturn(metricsLogger).`when`(deps).metricsLogger
doReturn(mock(ProxyTracker::class.java)).`when`(deps).makeProxyTracker(any(), any())
doReturn(mock(MockableSystemProperties::class.java)).`when`(deps).systemProperties
doReturn(TestNetIdManager()).`when`(deps).makeNetIdManager()
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index 3d4dc4d67dcc..dc9e587332cb 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -31,6 +31,7 @@ import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import android.annotation.NonNull;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
@@ -40,6 +41,7 @@ import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkProvider;
import android.net.NetworkSpecifier;
+import android.net.QosFilter;
import android.net.SocketKeepalive;
import android.net.UidRange;
import android.os.ConditionVariable;
@@ -47,10 +49,12 @@ import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;
+import com.android.net.module.util.ArrayTrackRecord;
import com.android.server.connectivity.ConnectivityConstants;
import com.android.testutils.HandlerUtils;
import com.android.testutils.TestableNetworkCallback;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -71,6 +75,8 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
// start/stop. Useful when simulate KeepaliveTracker is waiting for response from modem.
private long mKeepaliveResponseDelay = 0L;
private Integer mExpectedKeepaliveSlot = null;
+ private final ArrayTrackRecord<CallbackType>.ReadHead mCallbackHistory =
+ new ArrayTrackRecord<CallbackType>().newReadHead();
public NetworkAgentWrapper(int transport, LinkProperties linkProperties,
NetworkCapabilities ncTemplate, Context context) throws Exception {
@@ -157,6 +163,20 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
}
@Override
+ public void onQosCallbackRegistered(final int qosCallbackId,
+ final @NonNull QosFilter filter) {
+ Log.i(mWrapper.mLogTag, "onQosCallbackRegistered");
+ mWrapper.mCallbackHistory.add(
+ new CallbackType.OnQosCallbackRegister(qosCallbackId, filter));
+ }
+
+ @Override
+ public void onQosCallbackUnregistered(final int qosCallbackId) {
+ Log.i(mWrapper.mLogTag, "onQosCallbackUnregistered");
+ mWrapper.mCallbackHistory.add(new CallbackType.OnQosCallbackUnregister(qosCallbackId));
+ }
+
+ @Override
protected void preventAutomaticReconnect() {
mWrapper.mPreventReconnectReceived.open();
}
@@ -279,7 +299,60 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
return mNetworkCapabilities;
}
+ public @NonNull ArrayTrackRecord<CallbackType>.ReadHead getCallbackHistory() {
+ return mCallbackHistory;
+ }
+
public void waitForIdle(long timeoutMs) {
HandlerUtils.waitForIdle(mHandlerThread, timeoutMs);
}
+
+ abstract static class CallbackType {
+ final int mQosCallbackId;
+
+ protected CallbackType(final int qosCallbackId) {
+ mQosCallbackId = qosCallbackId;
+ }
+
+ static class OnQosCallbackRegister extends CallbackType {
+ final QosFilter mFilter;
+ OnQosCallbackRegister(final int qosCallbackId, final QosFilter filter) {
+ super(qosCallbackId);
+ mFilter = filter;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ final OnQosCallbackRegister that = (OnQosCallbackRegister) o;
+ return mQosCallbackId == that.mQosCallbackId
+ && Objects.equals(mFilter, that.mFilter);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mQosCallbackId, mFilter);
+ }
+ }
+
+ static class OnQosCallbackUnregister extends CallbackType {
+ OnQosCallbackUnregister(final int qosCallbackId) {
+ super(qosCallbackId);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ final OnQosCallbackUnregister that = (OnQosCallbackUnregister) o;
+ return mQosCallbackId == that.mQosCallbackId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mQosCallbackId);
+ }
+ }
+ }
}
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index d74a621842f9..c2fddf3d9e82 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -16,6 +16,7 @@
package android.net;
+import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
@@ -31,16 +32,22 @@ import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
+import static android.net.NetworkRequest.Type.REQUEST;
+import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -49,9 +56,7 @@ import static org.mockito.Mockito.when;
import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.ApplicationInfo;
-import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
-import android.net.NetworkCapabilities;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Handler;
@@ -213,9 +218,8 @@ public class ConnectivityManagerTest {
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
// register callback
- when(mService.requestNetwork(
- any(), captor.capture(), anyInt(), any(), anyInt(), any(), nullable(String.class)))
- .thenReturn(request);
+ when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
+ any(), nullable(String.class))).thenReturn(request);
manager.requestNetwork(request, callback, handler);
// callback triggers
@@ -242,9 +246,8 @@ public class ConnectivityManagerTest {
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
// register callback
- when(mService.requestNetwork(
- any(), captor.capture(), anyInt(), any(), anyInt(), any(), nullable(String.class)))
- .thenReturn(req1);
+ when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
+ any(), nullable(String.class))).thenReturn(req1);
manager.requestNetwork(req1, callback, handler);
// callback triggers
@@ -261,9 +264,8 @@ public class ConnectivityManagerTest {
verify(callback, timeout(100).times(0)).onLosing(any(), anyInt());
// callback can be registered again
- when(mService.requestNetwork(
- any(), captor.capture(), anyInt(), any(), anyInt(), any(), nullable(String.class)))
- .thenReturn(req2);
+ when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
+ any(), nullable(String.class))).thenReturn(req2);
manager.requestNetwork(req2, callback, handler);
// callback triggers
@@ -286,7 +288,7 @@ public class ConnectivityManagerTest {
info.targetSdkVersion = VERSION_CODES.N_MR1 + 1;
when(mCtx.getApplicationInfo()).thenReturn(info);
- when(mService.requestNetwork(any(), any(), anyInt(), any(), anyInt(), any(),
+ when(mService.requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(), any(),
nullable(String.class))).thenReturn(request);
Handler handler = new Handler(Looper.getMainLooper());
@@ -340,6 +342,41 @@ public class ConnectivityManagerTest {
}
}
+ @Test
+ public void testRequestType() throws Exception {
+ final String testPkgName = "MyPackage";
+ final ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
+ when(mCtx.getOpPackageName()).thenReturn(testPkgName);
+ final NetworkRequest request = makeRequest(1);
+ final NetworkCallback callback = new ConnectivityManager.NetworkCallback();
+
+ manager.requestNetwork(request, callback);
+ verify(mService).requestNetwork(eq(request.networkCapabilities),
+ eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+ eq(testPkgName), eq(null));
+ reset(mService);
+
+ // Verify that register network callback does not calls requestNetwork at all.
+ manager.registerNetworkCallback(request, callback);
+ verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(),
+ anyInt(), any(), any());
+ verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(),
+ eq(testPkgName));
+ reset(mService);
+
+ manager.registerDefaultNetworkCallback(callback);
+ verify(mService).requestNetwork(eq(null),
+ eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+ eq(testPkgName), eq(null));
+ reset(mService);
+
+ manager.requestBackgroundNetwork(request, null, callback);
+ verify(mService).requestNetwork(eq(request.networkCapabilities),
+ eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+ eq(testPkgName), eq(null));
+ reset(mService);
+ }
+
static Message makeMessage(NetworkRequest req, int messageType) {
Bundle bundle = new Bundle();
bundle.putParcelable(NetworkRequest.class.getSimpleName(), req);
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
index 9ba56e44fe88..91fcbc0fd5d7 100644
--- a/tests/net/java/android/net/NetworkTemplateTest.kt
+++ b/tests/net/java/android/net/NetworkTemplateTest.kt
@@ -67,6 +67,7 @@ class NetworkTemplateTest {
val caps = NetworkCapabilities().apply {
setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
+ setSSID(ssid)
}
return NetworkState(info, lp, caps, mock(Network::class.java), subscriberId, ssid)
}
diff --git a/tests/net/java/android/net/QosSocketFilterTest.java b/tests/net/java/android/net/QosSocketFilterTest.java
new file mode 100644
index 000000000000..ad58960eaadd
--- /dev/null
+++ b/tests/net/java/android/net/QosSocketFilterTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+
+@RunWith(AndroidJUnit4.class)
+@androidx.test.filters.SmallTest
+public class QosSocketFilterTest {
+
+ @Test
+ public void testPortExactMatch() {
+ final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+ final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
+ assertTrue(QosSocketFilter.matchesLocalAddress(
+ new InetSocketAddress(addressA, 10), addressB, 10, 10));
+
+ }
+
+ @Test
+ public void testPortLessThanStart() {
+ final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+ final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
+ assertFalse(QosSocketFilter.matchesLocalAddress(
+ new InetSocketAddress(addressA, 8), addressB, 10, 10));
+ }
+
+ @Test
+ public void testPortGreaterThanEnd() {
+ final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+ final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
+ assertFalse(QosSocketFilter.matchesLocalAddress(
+ new InetSocketAddress(addressA, 18), addressB, 10, 10));
+ }
+
+ @Test
+ public void testPortBetweenStartAndEnd() {
+ final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+ final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
+ assertTrue(QosSocketFilter.matchesLocalAddress(
+ new InetSocketAddress(addressA, 10), addressB, 8, 18));
+ }
+
+ @Test
+ public void testAddressesDontMatch() {
+ final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+ final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.5");
+ assertFalse(QosSocketFilter.matchesLocalAddress(
+ new InetSocketAddress(addressA, 10), addressB, 10, 10));
+ }
+}
+
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index bf5a26558508..6523accf20e0 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -21,6 +21,7 @@ import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
+import static android.content.Intent.ACTION_USER_UNLOCKED;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
@@ -63,6 +64,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
@@ -166,6 +168,7 @@ import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener;
import android.net.INetworkStatsService;
+import android.net.IQosCallback;
import android.net.InetAddresses;
import android.net.InterfaceConfigurationParcel;
import android.net.IpPrefix;
@@ -189,18 +192,23 @@ import android.net.NetworkStackClient;
import android.net.NetworkState;
import android.net.NetworkTestResultParcelable;
import android.net.ProxyInfo;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosSession;
import android.net.ResolverParamsParcel;
import android.net.RouteInfo;
import android.net.RouteInfoParcel;
import android.net.SocketKeepalive;
import android.net.UidRange;
import android.net.UidRangeParcel;
+import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
import android.net.VpnManager;
import android.net.metrics.IpConnectivityLog;
import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
import android.net.util.MultinetworkPolicyTracker;
+import android.net.wifi.WifiInfo;
import android.os.BadParcelableException;
import android.os.Binder;
import android.os.Build;
@@ -216,17 +224,21 @@ import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.security.Credentials;
import android.security.KeyStore;
import android.system.Os;
import android.telephony.TelephonyManager;
+import android.telephony.data.EpsBearerQosSessionAttributes;
import android.test.mock.MockContentResolver;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
@@ -235,20 +247,19 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.app.IBatteryStats;
import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnInfo;
+import com.android.internal.net.VpnProfile;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.WakeupMessage;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
import com.android.server.connectivity.ConnectivityConstants;
-import com.android.server.connectivity.DefaultNetworkMetrics;
-import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.connectivity.MockableSystemProperties;
import com.android.server.connectivity.Nat464Xlat;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import com.android.server.connectivity.ProxyTracker;
+import com.android.server.connectivity.QosCallbackTracker;
import com.android.server.connectivity.Vpn;
import com.android.server.net.NetworkPinner;
import com.android.server.net.NetworkPolicyManagerInternal;
@@ -280,6 +291,7 @@ import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -289,13 +301,16 @@ import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -362,9 +377,9 @@ public class ConnectivityServiceTest {
private WrappedMultinetworkPolicyTracker mPolicyTracker;
private HandlerThread mAlarmManagerThread;
private TestNetIdManager mNetIdManager;
+ private QosCallbackMockHelper mQosCallbackMockHelper;
+ private QosCallbackTracker mQosCallbackTracker;
- @Mock IpConnectivityMetrics.Logger mMetricsService;
- @Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
@Mock DeviceIdleInternal mDeviceIdleInternal;
@Mock INetworkManagementService mNetworkManagementService;
@Mock INetworkStatsService mStatsService;
@@ -384,6 +399,7 @@ public class ConnectivityServiceTest {
@Mock MockableSystemProperties mSystemProperties;
@Mock EthernetManager mEthernetManager;
@Mock NetworkPolicyManager mNetworkPolicyManager;
+ @Mock KeyStore mKeyStore;
private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -410,9 +426,6 @@ public class ConnectivityServiceTest {
private class MockContext extends BroadcastInterceptingContext {
private final MockContentResolver mContentResolver;
- // Contains all registered receivers since this object was created. Useful to clear
- // them when needed, as BroadcastInterceptingContext does not provide this facility.
- private final List<BroadcastReceiver> mRegisteredReceivers = new ArrayList<>();
@Spy private Resources mResources;
private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
@@ -549,19 +562,6 @@ public class ConnectivityServiceTest {
public void setPermission(String permission, Integer granted) {
mMockedPermissions.put(permission, granted);
}
-
- @Override
- public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
- mRegisteredReceivers.add(receiver);
- return super.registerReceiver(receiver, filter);
- }
-
- public void clearRegisteredReceivers() {
- // super.unregisterReceiver is a no-op for receivers that are not registered (because
- // they haven't been registered or because they have already been unregistered).
- // For the same reason, don't bother clearing mRegisteredReceivers.
- for (final BroadcastReceiver rcv : mRegisteredReceivers) unregisterReceiver(rcv);
- }
}
private void waitForIdle() {
@@ -590,10 +590,10 @@ public class ConnectivityServiceTest {
}
// Bring up a network that we can use to send messages to ConnectivityService.
- ConditionVariable cv = registerConnectivityBroadcast(1);
+ ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- waitFor(cv);
+ b.expectBroadcast();
Network n = mWiFiNetworkAgent.getNetwork();
assertNotNull(n);
@@ -610,10 +610,10 @@ public class ConnectivityServiceTest {
@Ignore
public void verifyThatNotWaitingForIdleCausesRaceConditions() throws Exception {
// Bring up a network that we can use to send messages to ConnectivityService.
- ConditionVariable cv = registerConnectivityBroadcast(1);
+ ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- waitFor(cv);
+ b.expectBroadcast();
Network n = mWiFiNetworkAgent.getNetwork();
assertNotNull(n);
@@ -1076,7 +1076,16 @@ public class ConnectivityServiceTest {
private boolean mAgentRegistered = false;
private int mVpnType = VpnManager.TYPE_VPN_SERVICE;
- private VpnInfo mVpnInfo;
+ private UnderlyingNetworkInfo mUnderlyingNetworkInfo;
+
+ // These ConditionVariables allow tests to wait for LegacyVpnRunner to be stopped/started.
+ // TODO: this scheme is ad-hoc and error-prone because it does not fail if, for example, the
+ // test expects two starts in a row, or even if the production code calls start twice in a
+ // row. find a better solution. Simply putting a method to create a LegacyVpnRunner into
+ // Vpn.Dependencies doesn't work because LegacyVpnRunner is not a static class and has
+ // extensive access into the internals of Vpn.
+ private ConditionVariable mStartLegacyVpnCv = new ConditionVariable();
+ private ConditionVariable mStopVpnRunnerCv = new ConditionVariable();
public MockVpn(int userId) {
super(startHandlerThreadAndReturnLooper(), mServiceContext,
@@ -1091,7 +1100,7 @@ public class ConnectivityServiceTest {
return mDeviceIdleInternal;
}
},
- mNetworkManagementService, mMockNetd, userId, mock(KeyStore.class));
+ mNetworkManagementService, mMockNetd, userId, mKeyStore);
}
public void setUids(Set<UidRange> uids) {
@@ -1203,18 +1212,53 @@ public class ConnectivityServiceTest {
}
mAgentRegistered = false;
setUids(null);
+ // Remove NET_CAPABILITY_INTERNET or MockNetworkAgent will refuse to connect later on.
+ mNetworkCapabilities.removeCapability(NET_CAPABILITY_INTERNET);
mInterface = null;
}
@Override
- public synchronized VpnInfo getVpnInfo() {
- if (mVpnInfo != null) return mVpnInfo;
+ public void startLegacyVpnRunner() {
+ mStartLegacyVpnCv.open();
+ }
+
+ public void expectStartLegacyVpnRunner() {
+ assertTrue("startLegacyVpnRunner not called after " + TIMEOUT_MS + " ms",
+ mStartLegacyVpnCv.block(TIMEOUT_MS));
- return super.getVpnInfo();
+ // startLegacyVpn calls stopVpnRunnerPrivileged, which will open mStopVpnRunnerCv, just
+ // before calling startLegacyVpnRunner. Restore mStopVpnRunnerCv, so the test can expect
+ // that the VpnRunner is stopped and immediately restarted by calling
+ // expectStartLegacyVpnRunner() and expectStopVpnRunnerPrivileged() back-to-back.
+ mStopVpnRunnerCv = new ConditionVariable();
}
- private synchronized void setVpnInfo(VpnInfo vpnInfo) {
- mVpnInfo = vpnInfo;
+ @Override
+ public void stopVpnRunnerPrivileged() {
+ if (mVpnRunner != null) {
+ super.stopVpnRunnerPrivileged();
+ disconnect();
+ mStartLegacyVpnCv = new ConditionVariable();
+ }
+ mVpnRunner = null;
+ mStopVpnRunnerCv.open();
+ }
+
+ public void expectStopVpnRunnerPrivileged() {
+ assertTrue("stopVpnRunnerPrivileged not called after " + TIMEOUT_MS + " ms",
+ mStopVpnRunnerCv.block(TIMEOUT_MS));
+ }
+
+ @Override
+ public synchronized UnderlyingNetworkInfo getUnderlyingNetworkInfo() {
+ if (mUnderlyingNetworkInfo != null) return mUnderlyingNetworkInfo;
+
+ return super.getUnderlyingNetworkInfo();
+ }
+
+ private synchronized void setUnderlyingNetworkInfo(
+ UnderlyingNetworkInfo underlyingNetworkInfo) {
+ mUnderlyingNetworkInfo = underlyingNetworkInfo;
}
}
@@ -1287,10 +1331,19 @@ public class ConnectivityServiceTest {
}
}
- private static final int VPN_USER = 0;
- private static final int APP1_UID = UserHandle.getUid(VPN_USER, 10100);
- private static final int APP2_UID = UserHandle.getUid(VPN_USER, 10101);
- private static final int VPN_UID = UserHandle.getUid(VPN_USER, 10043);
+ private static final int PRIMARY_USER = 0;
+ private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100);
+ private static final int APP2_UID = UserHandle.getUid(PRIMARY_USER, 10101);
+ private static final int VPN_UID = UserHandle.getUid(PRIMARY_USER, 10043);
+ private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER, "",
+ UserInfo.FLAG_PRIMARY);
+
+ private static final int RESTRICTED_USER = 1;
+ private static final UserInfo RESTRICTED_USER_INFO = new UserInfo(RESTRICTED_USER, "",
+ UserInfo.FLAG_RESTRICTED);
+ static {
+ RESTRICTED_USER_INFO.restrictedProfileParentId = PRIMARY_USER;
+ }
@Before
public void setUp() throws Exception {
@@ -1299,12 +1352,14 @@ public class ConnectivityServiceTest {
mContext = InstrumentationRegistry.getContext();
MockitoAnnotations.initMocks(this);
- when(mMetricsService.defaultNetworkMetrics()).thenReturn(mDefaultNetworkMetrics);
- when(mUserManager.getAliveUsers()).thenReturn(
- Arrays.asList(new UserInfo[] {
- new UserInfo(VPN_USER, "", 0),
- }));
+ when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
+ when(mUserManager.getUserInfo(PRIMARY_USER)).thenReturn(PRIMARY_USER_INFO);
+ // canHaveRestrictedProfile does not take a userId. It applies to the userId of the context
+ // it was started from, i.e., PRIMARY_USER.
+ when(mUserManager.canHaveRestrictedProfile()).thenReturn(true);
+ when(mUserManager.getUserInfo(RESTRICTED_USER)).thenReturn(RESTRICTED_USER_INFO);
+
final ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
@@ -1352,6 +1407,7 @@ public class ConnectivityServiceTest {
mService.systemReadyInternal();
mockVpn(Process.myUid());
mCm.bindProcessToNetwork(null);
+ mQosCallbackTracker = mock(QosCallbackTracker.class);
// Ensure that the default setting for Captive Portals is used for most tests
setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
@@ -1374,9 +1430,9 @@ public class ConnectivityServiceTest {
doReturn(mNetworkStack).when(deps).getNetworkStack();
doReturn(mSystemProperties).when(deps).getSystemProperties();
doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
- doReturn(mMetricsService).when(deps).getMetricsLogger();
doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
doReturn(mBatteryStatsService).when(deps).getBatteryStatsService();
+ doReturn(mKeyStore).when(deps).getKeyStore();
doAnswer(inv -> {
mPolicyTracker = new WrappedMultinetworkPolicyTracker(
inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
@@ -1427,6 +1483,11 @@ public class ConnectivityServiceTest {
mEthernetNetworkAgent.disconnect();
mEthernetNetworkAgent = null;
}
+
+ if (mQosCallbackMockHelper != null) {
+ mQosCallbackMockHelper.tearDown();
+ mQosCallbackMockHelper = null;
+ }
mMockVpn.disconnect();
waitForIdle();
@@ -1513,29 +1574,79 @@ public class ConnectivityServiceTest {
}
/**
- * Return a ConditionVariable that opens when {@code count} numbers of CONNECTIVITY_ACTION
- * broadcasts are received.
+ * Class to simplify expecting broadcasts using BroadcastInterceptingContext.
+ * Ensures that the receiver is unregistered after the expected broadcast is received. This
+ * cannot be done in the BroadcastReceiver itself because BroadcastInterceptingContext runs
+ * the receivers' receive method while iterating over the list of receivers, and unregistering
+ * the receiver during iteration throws ConcurrentModificationException.
*/
- private ConditionVariable registerConnectivityBroadcast(final int count) {
+ private class ExpectedBroadcast extends CompletableFuture<Intent> {
+ private final BroadcastReceiver mReceiver;
+
+ ExpectedBroadcast(BroadcastReceiver receiver) {
+ mReceiver = receiver;
+ }
+
+ public Intent expectBroadcast(int timeoutMs) throws Exception {
+ try {
+ return get(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ fail("Expected broadcast not received after " + timeoutMs + " ms");
+ return null;
+ } finally {
+ mServiceContext.unregisterReceiver(mReceiver);
+ }
+ }
+
+ public Intent expectBroadcast() throws Exception {
+ return expectBroadcast(TIMEOUT_MS);
+ }
+
+ public void expectNoBroadcast(int timeoutMs) throws Exception {
+ waitForIdle();
+ try {
+ final Intent intent = get(timeoutMs, TimeUnit.MILLISECONDS);
+ fail("Unexpected broadcast: " + intent.getAction() + " " + intent.getExtras());
+ } catch (TimeoutException expected) {
+ } finally {
+ mServiceContext.unregisterReceiver(mReceiver);
+ }
+ }
+ }
+
+ /** Expects that {@code count} CONNECTIVITY_ACTION broadcasts are received. */
+ private ExpectedBroadcast registerConnectivityBroadcast(final int count) {
return registerConnectivityBroadcastThat(count, intent -> true);
}
- private ConditionVariable registerConnectivityBroadcastThat(final int count,
+ private ExpectedBroadcast registerConnectivityBroadcastThat(final int count,
@NonNull final Predicate<Intent> filter) {
- final ConditionVariable cv = new ConditionVariable();
final IntentFilter intentFilter = new IntentFilter(CONNECTIVITY_ACTION);
+ // AtomicReference allows receiver to access expected even though it is constructed later.
+ final AtomicReference<ExpectedBroadcast> expectedRef = new AtomicReference<>();
final BroadcastReceiver receiver = new BroadcastReceiver() {
- private int remaining = count;
- public void onReceive(Context context, Intent intent) {
- if (!filter.test(intent)) return;
- if (--remaining == 0) {
- cv.open();
- mServiceContext.unregisterReceiver(this);
- }
- }
- };
+ private int mRemaining = count;
+ public void onReceive(Context context, Intent intent) {
+ final int type = intent.getIntExtra(EXTRA_NETWORK_TYPE, -1);
+ final NetworkInfo ni = intent.getParcelableExtra(EXTRA_NETWORK_INFO);
+ Log.d(TAG, "Received CONNECTIVITY_ACTION type=" + type + " ni=" + ni);
+ if (!filter.test(intent)) return;
+ if (--mRemaining == 0) {
+ expectedRef.get().complete(intent);
+ }
+ }
+ };
+ final ExpectedBroadcast expected = new ExpectedBroadcast(receiver);
+ expectedRef.set(expected);
mServiceContext.registerReceiver(receiver, intentFilter);
- return cv;
+ return expected;
+ }
+
+ private ExpectedBroadcast expectConnectivityAction(int type, NetworkInfo.DetailedState state) {
+ return registerConnectivityBroadcastThat(1, intent ->
+ type == intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) && state.equals(
+ ((NetworkInfo) intent.getParcelableExtra(EXTRA_NETWORK_INFO))
+ .getDetailedState()));
}
@Test
@@ -1559,10 +1670,9 @@ public class ConnectivityServiceTest {
// Connect the cell agent and wait for the connected broadcast.
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.addCapability(NET_CAPABILITY_SUPL);
- final ConditionVariable cv1 = registerConnectivityBroadcastThat(1,
- intent -> intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE);
+ ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
mCellNetworkAgent.connect(true);
- waitFor(cv1);
+ b.expectBroadcast();
// Build legacy request for SUPL.
final NetworkCapabilities legacyCaps = new NetworkCapabilities();
@@ -1572,27 +1682,17 @@ public class ConnectivityServiceTest {
ConnectivityManager.REQUEST_ID_UNSET, NetworkRequest.Type.REQUEST);
// File request, withdraw it and make sure no broadcast is sent
- final ConditionVariable cv2 = registerConnectivityBroadcast(1);
+ b = registerConnectivityBroadcast(1);
final TestNetworkCallback callback = new TestNetworkCallback();
mCm.requestNetwork(legacyRequest, callback);
callback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
mCm.unregisterNetworkCallback(callback);
- assertFalse(cv2.block(800)); // 800ms long enough to at least flake if this is sent
- // As the broadcast did not fire, the receiver was not unregistered. Do this now.
- mServiceContext.clearRegisteredReceivers();
-
- // Disconnect the network and expect mobile disconnected broadcast. Use a small hack to
- // check that has been sent.
- final AtomicBoolean vanillaAction = new AtomicBoolean(false);
- final ConditionVariable cv3 = registerConnectivityBroadcastThat(1, intent -> {
- if (intent.getAction().equals(CONNECTIVITY_ACTION)) {
- vanillaAction.set(true);
- }
- return !((NetworkInfo) intent.getExtra(EXTRA_NETWORK_INFO, -1)).isConnected();
- });
+ b.expectNoBroadcast(800); // 800ms long enough to at least flake if this is sent
+
+ // Disconnect the network and expect mobile disconnected broadcast.
+ b = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
mCellNetworkAgent.disconnect();
- waitFor(cv3);
- assertTrue(vanillaAction.get());
+ b.expectBroadcast();
}
@Test
@@ -1603,9 +1703,9 @@ public class ConnectivityServiceTest {
assertNull(mCm.getActiveNetworkInfo());
assertNull(mCm.getActiveNetwork());
// Test bringing up validated cellular.
- ConditionVariable cv = registerConnectivityBroadcast(1);
+ ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
mCellNetworkAgent.connect(true);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_CELLULAR);
assertLength(2, mCm.getAllNetworks());
assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) ||
@@ -1613,9 +1713,9 @@ public class ConnectivityServiceTest {
assertTrue(mCm.getAllNetworks()[0].equals(mWiFiNetworkAgent.getNetwork()) ||
mCm.getAllNetworks()[1].equals(mWiFiNetworkAgent.getNetwork()));
// Test bringing up validated WiFi.
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
mWiFiNetworkAgent.connect(true);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_WIFI);
assertLength(2, mCm.getAllNetworks());
assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) ||
@@ -1630,9 +1730,9 @@ public class ConnectivityServiceTest {
assertLength(1, mCm.getAllNetworks());
assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());
// Test WiFi disconnect.
- cv = registerConnectivityBroadcast(1);
+ b = registerConnectivityBroadcast(1);
mWiFiNetworkAgent.disconnect();
- waitFor(cv);
+ b.expectBroadcast();
verifyNoNetwork();
}
@@ -1640,9 +1740,9 @@ public class ConnectivityServiceTest {
public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
// Test bringing up unvalidated WiFi
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ConditionVariable cv = registerConnectivityBroadcast(1);
+ ExpectedBroadcast b = registerConnectivityBroadcast(1);
mWiFiNetworkAgent.connect(false);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_WIFI);
// Test bringing up unvalidated cellular
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
@@ -1655,19 +1755,19 @@ public class ConnectivityServiceTest {
verifyActiveNetwork(TRANSPORT_WIFI);
// Test bringing up validated cellular
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
mCellNetworkAgent.connect(true);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test cellular disconnect.
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
mCellNetworkAgent.disconnect();
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_WIFI);
// Test WiFi disconnect.
- cv = registerConnectivityBroadcast(1);
+ b = registerConnectivityBroadcast(1);
mWiFiNetworkAgent.disconnect();
- waitFor(cv);
+ b.expectBroadcast();
verifyNoNetwork();
}
@@ -1675,25 +1775,25 @@ public class ConnectivityServiceTest {
public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception {
// Test bringing up unvalidated cellular.
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ConditionVariable cv = registerConnectivityBroadcast(1);
+ ExpectedBroadcast b = registerConnectivityBroadcast(1);
mCellNetworkAgent.connect(false);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test bringing up unvalidated WiFi.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
mWiFiNetworkAgent.connect(false);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_WIFI);
// Test WiFi disconnect.
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
mWiFiNetworkAgent.disconnect();
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test cellular disconnect.
- cv = registerConnectivityBroadcast(1);
+ b = registerConnectivityBroadcast(1);
mCellNetworkAgent.disconnect();
- waitFor(cv);
+ b.expectBroadcast();
verifyNoNetwork();
}
@@ -1701,24 +1801,24 @@ public class ConnectivityServiceTest {
public void testUnlingeringDoesNotValidate() throws Exception {
// Test bringing up unvalidated WiFi.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ConditionVariable cv = registerConnectivityBroadcast(1);
+ ExpectedBroadcast b = registerConnectivityBroadcast(1);
mWiFiNetworkAgent.connect(false);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_WIFI);
assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
NET_CAPABILITY_VALIDATED));
// Test bringing up validated cellular.
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
mCellNetworkAgent.connect(true);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_CELLULAR);
assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
NET_CAPABILITY_VALIDATED));
// Test cellular disconnect.
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
mCellNetworkAgent.disconnect();
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_WIFI);
// Unlingering a network should not cause it to be marked as validated.
assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
@@ -1729,25 +1829,25 @@ public class ConnectivityServiceTest {
public void testCellularOutscoresWeakWifi() throws Exception {
// Test bringing up validated cellular.
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ConditionVariable cv = registerConnectivityBroadcast(1);
+ ExpectedBroadcast b = registerConnectivityBroadcast(1);
mCellNetworkAgent.connect(true);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test bringing up validated WiFi.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
mWiFiNetworkAgent.connect(true);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_WIFI);
// Test WiFi getting really weak.
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
mWiFiNetworkAgent.adjustScore(-11);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test WiFi restoring signal strength.
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
mWiFiNetworkAgent.adjustScore(11);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_WIFI);
}
@@ -1765,9 +1865,9 @@ public class ConnectivityServiceTest {
mCellNetworkAgent.expectDisconnected();
// Test bringing up validated WiFi.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final ConditionVariable cv = registerConnectivityBroadcast(1);
+ final ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
mWiFiNetworkAgent.connect(true);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_WIFI);
// Test bringing up unvalidated cellular.
// Expect it to be torn down because it could never be the highest scoring network
@@ -1784,33 +1884,33 @@ public class ConnectivityServiceTest {
public void testCellularFallback() throws Exception {
// Test bringing up validated cellular.
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ConditionVariable cv = registerConnectivityBroadcast(1);
+ ExpectedBroadcast b = registerConnectivityBroadcast(1);
mCellNetworkAgent.connect(true);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test bringing up validated WiFi.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
mWiFiNetworkAgent.connect(true);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_WIFI);
// Reevaluate WiFi (it'll instantly fail DNS).
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
NET_CAPABILITY_VALIDATED));
mCm.reportBadNetwork(mWiFiNetworkAgent.getNetwork());
// Should quickly fall back to Cellular.
- waitFor(cv);
+ b.expectBroadcast();
assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
NET_CAPABILITY_VALIDATED));
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Reevaluate cellular (it'll instantly fail DNS).
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
NET_CAPABILITY_VALIDATED));
mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
// Should quickly fall back to WiFi.
- waitFor(cv);
+ b.expectBroadcast();
assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
NET_CAPABILITY_VALIDATED));
assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
@@ -1822,23 +1922,23 @@ public class ConnectivityServiceTest {
public void testWiFiFallback() throws Exception {
// Test bringing up unvalidated WiFi.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ConditionVariable cv = registerConnectivityBroadcast(1);
+ ExpectedBroadcast b = registerConnectivityBroadcast(1);
mWiFiNetworkAgent.connect(false);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_WIFI);
// Test bringing up validated cellular.
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
mCellNetworkAgent.connect(true);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Reevaluate cellular (it'll instantly fail DNS).
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
NET_CAPABILITY_VALIDATED));
mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
// Should quickly fall back to WiFi.
- waitFor(cv);
+ b.expectBroadcast();
assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
NET_CAPABILITY_VALIDATED));
verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1908,13 +2008,13 @@ public class ConnectivityServiceTest {
mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
// Test unvalidated networks
- ConditionVariable cv = registerConnectivityBroadcast(1);
+ ExpectedBroadcast b = registerConnectivityBroadcast(1);
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false);
genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
cellNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- waitFor(cv);
+ b.expectBroadcast();
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
// This should not trigger spurious onAvailable() callbacks, b/21762680.
@@ -1923,28 +2023,28 @@ public class ConnectivityServiceTest {
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- waitFor(cv);
+ b.expectBroadcast();
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
- cv = registerConnectivityBroadcast(2);
+ b = registerConnectivityBroadcast(2);
mWiFiNetworkAgent.disconnect();
genericNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
cellNetworkCallback.assertNoCallback();
- waitFor(cv);
+ b.expectBroadcast();
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
- cv = registerConnectivityBroadcast(1);
+ b = registerConnectivityBroadcast(1);
mCellNetworkAgent.disconnect();
genericNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- waitFor(cv);
+ b.expectBroadcast();
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
// Test validated networks
@@ -2047,10 +2147,6 @@ public class ConnectivityServiceTest {
@Test
public void testOwnerUidCannotChange() throws Exception {
- // Owner UIDs are not visible without location permission.
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
final NetworkCapabilities ncTemplate = new NetworkCapabilities();
final int originalOwnerUid = Process.myUid();
ncTemplate.setOwnerUid(originalOwnerUid);
@@ -2070,6 +2166,10 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.setNetworkCapabilities(agentCapabilities, true);
waitForIdle();
+ // Owner UIDs are not visible without location permission.
+ setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
+
// Check that the capability change has been applied but the owner UID is not modified.
NetworkCapabilities nc = mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork());
assertEquals(originalOwnerUid, nc.getOwnerUid());
@@ -2665,9 +2765,9 @@ public class ConnectivityServiceTest {
// Test bringing up validated WiFi.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final ConditionVariable cv = registerConnectivityBroadcast(1);
+ final ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
mWiFiNetworkAgent.connect(true);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_WIFI);
// Register MMS NetworkRequest
@@ -2693,9 +2793,9 @@ public class ConnectivityServiceTest {
public void testMMSonCell() throws Exception {
// Test bringing up cellular without MMS
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ConditionVariable cv = registerConnectivityBroadcast(1);
+ ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
mCellNetworkAgent.connect(false);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Register MMS NetworkRequest
@@ -3360,8 +3460,8 @@ public class ConnectivityServiceTest {
NetworkCapabilities networkCapabilities = new NetworkCapabilities();
networkCapabilities.addTransportType(TRANSPORT_WIFI)
.setNetworkSpecifier(new MatchAllNetworkSpecifier());
- mService.requestNetwork(networkCapabilities, null, 0, null,
- ConnectivityManager.TYPE_WIFI, mContext.getPackageName(),
+ mService.requestNetwork(networkCapabilities, NetworkRequest.Type.REQUEST.ordinal(),
+ null, 0, null, ConnectivityManager.TYPE_WIFI, mContext.getPackageName(),
getAttributionTag());
});
@@ -3594,10 +3694,13 @@ public class ConnectivityServiceTest {
@Test
public void testBackgroundNetworks() throws Exception {
- // Create a background request. We can't do this ourselves because ConnectivityService
- // doesn't have an API for it. So just turn on mobile data always on.
- setAlwaysOnNetworks(true);
+ // Create a cellular background request.
grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
+ final TestNetworkCallback cellBgCallback = new TestNetworkCallback();
+ mCm.requestBackgroundNetwork(new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR).build(), null, cellBgCallback);
+
+ // Make callbacks for monitoring.
final NetworkRequest request = new NetworkRequest.Builder().build();
final NetworkRequest fgRequest = new NetworkRequest.Builder()
.addCapability(NET_CAPABILITY_FOREGROUND).build();
@@ -3666,6 +3769,7 @@ public class ConnectivityServiceTest {
mCm.unregisterNetworkCallback(callback);
mCm.unregisterNetworkCallback(fgCallback);
+ mCm.unregisterNetworkCallback(cellBgCallback);
}
@Ignore // This test has instrinsic chances of spurious failures: ignore for continuous testing.
@@ -4297,15 +4401,15 @@ public class ConnectivityServiceTest {
}
private Network connectKeepaliveNetwork(LinkProperties lp) throws Exception {
- // Ensure the network is disconnected before we do anything.
+ // Ensure the network is disconnected before anything else occurs
if (mWiFiNetworkAgent != null) {
assertNull(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()));
}
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ConditionVariable cv = registerConnectivityBroadcast(1);
+ ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
mWiFiNetworkAgent.connect(true);
- waitFor(cv);
+ b.expectBroadcast();
verifyActiveNetwork(TRANSPORT_WIFI);
mWiFiNetworkAgent.sendLinkProperties(lp);
waitForIdle();
@@ -4861,10 +4965,10 @@ public class ConnectivityServiceTest {
assertNotPinnedToWifi();
// Disconnect cell and wifi.
- ConditionVariable cv = registerConnectivityBroadcast(3); // cell down, wifi up, wifi down.
+ ExpectedBroadcast b = registerConnectivityBroadcast(3); // cell down, wifi up, wifi down.
mCellNetworkAgent.disconnect();
mWiFiNetworkAgent.disconnect();
- waitFor(cv);
+ b.expectBroadcast();
// Pinning takes effect even if the pinned network is the default when the pin is set...
TestNetworkPinner.pin(mServiceContext, wifiRequest);
@@ -4874,10 +4978,10 @@ public class ConnectivityServiceTest {
assertPinnedToWifiWithWifiDefault();
// ... and is maintained even when that network is no longer the default.
- cv = registerConnectivityBroadcast(1);
+ b = registerConnectivityBroadcast(1);
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mCellNetworkAgent.connect(true);
- waitFor(cv);
+ b.expectBroadcast();
assertPinnedToWifiWithCellDefault();
}
@@ -4977,7 +5081,7 @@ public class ConnectivityServiceTest {
@Test
public void testNetworkInfoOfTypeNone() throws Exception {
- ConditionVariable broadcastCV = registerConnectivityBroadcast(1);
+ ExpectedBroadcast b = registerConnectivityBroadcast(1);
verifyNoNetwork();
TestNetworkAgentWrapper wifiAware = new TestNetworkAgentWrapper(TRANSPORT_WIFI_AWARE);
@@ -5010,9 +5114,7 @@ public class ConnectivityServiceTest {
mCm.unregisterNetworkCallback(callback);
verifyNoNetwork();
- if (broadcastCV.block(10)) {
- fail("expected no broadcast, but got CONNECTIVITY_ACTION broadcast");
- }
+ b.expectNoBroadcast(10);
}
@Test
@@ -5098,20 +5200,22 @@ public class ConnectivityServiceTest {
private void expectForceUpdateIfaces(Network[] networks, String defaultIface,
Integer vpnUid, String vpnIfname, String[] underlyingIfaces) throws Exception {
ArgumentCaptor<Network[]> networksCaptor = ArgumentCaptor.forClass(Network[].class);
- ArgumentCaptor<VpnInfo[]> vpnInfosCaptor = ArgumentCaptor.forClass(VpnInfo[].class);
+ ArgumentCaptor<UnderlyingNetworkInfo[]> vpnInfosCaptor = ArgumentCaptor.forClass(
+ UnderlyingNetworkInfo[].class);
verify(mStatsService, atLeastOnce()).forceUpdateIfaces(networksCaptor.capture(),
any(NetworkState[].class), eq(defaultIface), vpnInfosCaptor.capture());
assertSameElementsNoDuplicates(networksCaptor.getValue(), networks);
- VpnInfo[] infos = vpnInfosCaptor.getValue();
+ UnderlyingNetworkInfo[] infos = vpnInfosCaptor.getValue();
if (vpnUid != null) {
assertEquals("Should have exactly one VPN:", 1, infos.length);
- VpnInfo info = infos[0];
+ UnderlyingNetworkInfo info = infos[0];
assertEquals("Unexpected VPN owner:", (int) vpnUid, info.ownerUid);
- assertEquals("Unexpected VPN interface:", vpnIfname, info.vpnIface);
- assertSameElementsNoDuplicates(underlyingIfaces, info.underlyingIfaces);
+ assertEquals("Unexpected VPN interface:", vpnIfname, info.iface);
+ assertSameElementsNoDuplicates(underlyingIfaces,
+ info.underlyingIfaces.toArray(new String[0]));
} else {
assertEquals(0, infos.length);
return;
@@ -5172,7 +5276,7 @@ public class ConnectivityServiceTest {
waitForIdle();
verify(mStatsService, never())
.forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
- eq(new VpnInfo[0]));
+ eq(new UnderlyingNetworkInfo[0]));
reset(mStatsService);
// Roaming change should update ifaces
@@ -5255,8 +5359,8 @@ public class ConnectivityServiceTest {
// network for the VPN...
verify(mStatsService, never()).forceUpdateIfaces(any(Network[].class),
any(NetworkState[].class), any() /* anyString() doesn't match null */,
- argThat(infos -> infos[0].underlyingIfaces.length == 1
- && WIFI_IFNAME.equals(infos[0].underlyingIfaces[0])));
+ argThat(infos -> infos[0].underlyingIfaces.size() == 1
+ && WIFI_IFNAME.equals(infos[0].underlyingIfaces.get(0))));
verifyNoMoreInteractions(mStatsService);
reset(mStatsService);
@@ -5269,8 +5373,8 @@ public class ConnectivityServiceTest {
waitForIdle();
verify(mStatsService).forceUpdateIfaces(any(Network[].class),
any(NetworkState[].class), any() /* anyString() doesn't match null */,
- argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.length == 1
- && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces[0])));
+ argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.size() == 1
+ && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces.get(0))));
mEthernetNetworkAgent.disconnect();
waitForIdle();
reset(mStatsService);
@@ -5812,6 +5916,126 @@ public class ConnectivityServiceTest {
mCm.unregisterNetworkCallback(callback);
}
+ private void assertGetNetworkInfoOfGetActiveNetworkIsConnected(boolean expectedConnectivity) {
+ // What Chromium used to do before https://chromium-review.googlesource.com/2605304
+ assertEquals("Unexpected result for getActiveNetworkInfo(getActiveNetwork())",
+ expectedConnectivity, mCm.getNetworkInfo(mCm.getActiveNetwork()).isConnected());
+ }
+
+ @Test
+ public void testVpnUnderlyingNetworkSuspended() throws Exception {
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallback(callback);
+
+ // Connect a VPN.
+ mMockVpn.establishForMyUid(false /* validated */, true /* hasInternet */,
+ false /* isStrictMode */);
+ callback.expectAvailableCallbacksUnvalidated(mMockVpn);
+
+ // Connect cellular data.
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(false /* validated */);
+ callback.expectCapabilitiesThat(mMockVpn,
+ nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ && nc.hasTransport(TRANSPORT_CELLULAR));
+ callback.assertNoCallback();
+
+ assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+ .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+ assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+ assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+ assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
+
+ // Suspend the cellular network and expect the VPN to be suspended.
+ mCellNetworkAgent.suspend();
+ callback.expectCapabilitiesThat(mMockVpn,
+ nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ && nc.hasTransport(TRANSPORT_CELLULAR));
+ callback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
+ callback.assertNoCallback();
+
+ assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+ .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+ assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);
+ assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
+ // VPN's main underlying network is suspended, so no connectivity.
+ assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
+
+ // Switch to another network. The VPN should no longer be suspended.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false /* validated */);
+ callback.expectCapabilitiesThat(mMockVpn,
+ nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ && nc.hasTransport(TRANSPORT_WIFI));
+ callback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
+ callback.assertNoCallback();
+
+ assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+ .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+ assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+ assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
+
+ // Unsuspend cellular and then switch back to it. The VPN remains not suspended.
+ mCellNetworkAgent.resume();
+ callback.assertNoCallback();
+ mWiFiNetworkAgent.disconnect();
+ callback.expectCapabilitiesThat(mMockVpn,
+ nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ && nc.hasTransport(TRANSPORT_CELLULAR));
+ // Spurious double callback?
+ callback.expectCapabilitiesThat(mMockVpn,
+ nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ && nc.hasTransport(TRANSPORT_CELLULAR));
+ callback.assertNoCallback();
+
+ assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+ .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+ assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+ assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+ assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
+
+ // Suspend cellular and expect no connectivity.
+ mCellNetworkAgent.suspend();
+ callback.expectCapabilitiesThat(mMockVpn,
+ nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ && nc.hasTransport(TRANSPORT_CELLULAR));
+ callback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
+ callback.assertNoCallback();
+
+ assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+ .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+ assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);
+ assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
+ assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
+
+ // Resume cellular and expect that connectivity comes back.
+ mCellNetworkAgent.resume();
+ callback.expectCapabilitiesThat(mMockVpn,
+ nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ && nc.hasTransport(TRANSPORT_CELLULAR));
+ callback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
+ callback.assertNoCallback();
+
+ assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+ .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+ assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+ assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+ assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
+ }
+
@Test
public void testVpnNetworkActive() throws Exception {
final int uid = Process.myUid();
@@ -6186,10 +6410,7 @@ public class ConnectivityServiceTest {
&& caps.hasTransport(TRANSPORT_CELLULAR)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
&& !caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- // While the SUSPENDED callback should in theory be sent here, it is not. This is
- // a bug in ConnectivityService, but as the SUSPENDED and RESUMED callbacks have never
- // been public and are deprecated and slated for removal, there is no sense in spending
- // resources fixing this bug now.
+ vpnNetworkCallback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
// Use both again.
@@ -6201,8 +6422,7 @@ public class ConnectivityServiceTest {
&& caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
&& caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- // As above, the RESUMED callback not being sent here is a bug, but not a bug that's
- // worth anybody's time to fix.
+ vpnNetworkCallback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
// Disconnect cell. Receive update without even removing the dead network from the
@@ -6290,7 +6510,7 @@ public class ConnectivityServiceTest {
}
@Test
- public void testVpnRestrictedUsers() throws Exception {
+ public void testRestrictedProfileAffectsVpnUidRanges() throws Exception {
// NETWORK_SETTINGS is necessary to see the UID ranges in NetworkCapabilities.
mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
PERMISSION_GRANTED);
@@ -6322,19 +6542,11 @@ public class ConnectivityServiceTest {
callback.expectCapabilitiesThat(mWiFiNetworkAgent, (caps)
-> caps.hasCapability(NET_CAPABILITY_VALIDATED));
- // Create a fake restricted profile whose parent is our user ID.
- final int userId = UserHandle.getUserId(uid);
- when(mUserManager.canHaveRestrictedProfile(userId)).thenReturn(true);
- final int restrictedUserId = userId + 1;
- final UserInfo info = new UserInfo(restrictedUserId, "user", UserInfo.FLAG_RESTRICTED);
- info.restrictedProfileParentId = userId;
- assertTrue(info.isRestricted());
- when(mUserManager.getUserInfo(restrictedUserId)).thenReturn(info);
- when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, restrictedUserId))
- .thenReturn(UserHandle.getUid(restrictedUserId, VPN_UID));
+ when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER))
+ .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID));
final Intent addedIntent = new Intent(ACTION_USER_ADDED);
- addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
+ addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
// Send a USER_ADDED broadcast for it.
// The BroadcastReceiver for this broadcast checks that is being run on the handler thread.
@@ -6346,7 +6558,7 @@ public class ConnectivityServiceTest {
callback.expectCapabilitiesThat(mMockVpn, (caps)
-> caps.getUids().size() == 2
&& caps.getUids().contains(new UidRange(uid, uid))
- && caps.getUids().contains(UidRange.createForUser(restrictedUserId))
+ && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER))
&& caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_WIFI));
@@ -6356,13 +6568,13 @@ public class ConnectivityServiceTest {
callback.expectCapabilitiesThat(mMockVpn, (caps)
-> caps.getUids().size() == 2
&& caps.getUids().contains(new UidRange(uid, uid))
- && caps.getUids().contains(UidRange.createForUser(restrictedUserId))
+ && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER))
&& caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_WIFI));
// Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
- removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
+ removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
// Expect that the VPN gains the UID range for the restricted user, and that the capability
@@ -6372,53 +6584,72 @@ public class ConnectivityServiceTest {
&& caps.getUids().contains(new UidRange(uid, uid))
&& caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_WIFI));
+ }
- // Test lockdown with restricted profiles.
+ @Test
+ public void testLockdownVpnWithRestrictedProfiles() throws Exception {
+ // For ConnectivityService#setAlwaysOnVpnPackage.
mServiceContext.setPermission(
Manifest.permission.CONTROL_ALWAYS_ON_VPN, PERMISSION_GRANTED);
+ // For call Vpn#setAlwaysOnPackage.
mServiceContext.setPermission(
Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
+ // Necessary to see the UID ranges in NetworkCapabilities.
mServiceContext.setPermission(
Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ final NetworkRequest request = new NetworkRequest.Builder()
+ .removeCapability(NET_CAPABILITY_NOT_VPN)
+ .build();
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(request, callback);
+
+ final int uid = Process.myUid();
+
// Connect wifi and check that UIDs in the main and restricted profiles have network access.
- mMockVpn.disconnect();
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true /* validated */);
- final int restrictedUid = UserHandle.getUid(restrictedUserId, 42 /* appId */);
+ final int restrictedUid = UserHandle.getUid(RESTRICTED_USER, 42 /* appId */);
assertNotNull(mCm.getActiveNetworkForUid(uid));
assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
// Enable always-on VPN lockdown. The main user loses network access because no VPN is up.
final ArrayList<String> allowList = new ArrayList<>();
- mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+ mService.setAlwaysOnVpnPackage(PRIMARY_USER, ALWAYS_ON_PACKAGE, true /* lockdown */,
+ allowList);
waitForIdle();
assertNull(mCm.getActiveNetworkForUid(uid));
+ // This is arguably overspecified: a UID that is not running doesn't have an active network.
+ // But it's useful to check that non-default users do not lose network access, and to prove
+ // that the loss of connectivity below is indeed due to the restricted profile coming up.
assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
// Start the restricted profile, and check that the UID within it loses network access.
- when(mUserManager.getAliveUsers()).thenReturn(
- Arrays.asList(new UserInfo[] {
- new UserInfo(userId, "", 0),
- info
- }));
+ when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER))
+ .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID));
+ when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO,
+ RESTRICTED_USER_INFO));
// TODO: check that VPN app within restricted profile still has access, etc.
+ final Intent addedIntent = new Intent(ACTION_USER_ADDED);
+ addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
+ final Handler handler = new Handler(mCsHandlerThread.getLooper());
handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
waitForIdle();
assertNull(mCm.getActiveNetworkForUid(uid));
assertNull(mCm.getActiveNetworkForUid(restrictedUid));
// Stop the restricted profile, and check that the UID within it has network access again.
- when(mUserManager.getAliveUsers()).thenReturn(
- Arrays.asList(new UserInfo[] {
- new UserInfo(userId, "", 0),
- }));
+ when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
+
+ // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
+ final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
+ removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
waitForIdle();
assertNull(mCm.getActiveNetworkForUid(uid));
assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
- mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ mService.setAlwaysOnVpnPackage(PRIMARY_USER, null, false /* lockdown */, allowList);
waitForIdle();
}
@@ -6759,6 +6990,7 @@ public class ConnectivityServiceTest {
final int userId = UserHandle.getUserId(uid);
final ArrayList<String> allowList = new ArrayList<>();
mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+ waitForIdle();
UidRangeParcel firstHalf = new UidRangeParcel(1, VPN_UID - 1);
UidRangeParcel secondHalf = new UidRangeParcel(VPN_UID + 1, 99999);
@@ -6780,10 +7012,10 @@ public class ConnectivityServiceTest {
// Disable lockdown, expect to see the network unblocked.
mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
- expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf);
callback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
vpnUidCallback.assertNoCallback();
+ expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -6826,9 +7058,11 @@ public class ConnectivityServiceTest {
// Disable lockdown, remove our UID from the allowlist, and re-enable lockdown.
// Everything should now be blocked.
mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ waitForIdle();
expectNetworkRejectNonSecureVpn(inOrder, false, piece1, piece2, piece3);
allowList.clear();
mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+ waitForIdle();
expectNetworkRejectNonSecureVpn(inOrder, true, firstHalf, secondHalf);
defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
@@ -6906,39 +7140,262 @@ public class ConnectivityServiceTest {
mCm.unregisterNetworkCallback(vpnUidCallback);
}
+ private void setupLegacyLockdownVpn() {
+ final String profileName = "testVpnProfile";
+ final byte[] profileTag = profileName.getBytes(StandardCharsets.UTF_8);
+ when(mKeyStore.contains(Credentials.LOCKDOWN_VPN)).thenReturn(true);
+ when(mKeyStore.get(Credentials.LOCKDOWN_VPN)).thenReturn(profileTag);
+
+ final VpnProfile profile = new VpnProfile(profileName);
+ profile.name = "My VPN";
+ profile.server = "192.0.2.1";
+ profile.dnsServers = "8.8.8.8";
+ profile.type = VpnProfile.TYPE_IPSEC_XAUTH_PSK;
+ final byte[] encodedProfile = profile.encode();
+ when(mKeyStore.get(Credentials.VPN + profileName)).thenReturn(encodedProfile);
+ }
+
@Test
- public final void testLoseTrusted() throws Exception {
- final NetworkRequest trustedRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_TRUSTED)
- .build();
- final TestNetworkCallback trustedCallback = new TestNetworkCallback();
- mCm.requestNetwork(trustedRequest, trustedCallback);
+ public void testLegacyLockdownVpn() throws Exception {
+ mServiceContext.setPermission(
+ Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- trustedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
- reset(mMockNetd);
+ final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(request, callback);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- trustedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- verify(mMockNetd).networkSetDefault(eq(mWiFiNetworkAgent.getNetwork().netId));
- reset(mMockNetd);
+ final TestNetworkCallback defaultCallback = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallback(defaultCallback);
- mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
- trustedCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
- reset(mMockNetd);
+ // Pretend lockdown VPN was configured.
+ setupLegacyLockdownVpn();
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
- trustedCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- verify(mMockNetd).networkClearDefault();
+ // LockdownVpnTracker disables the Vpn teardown code and enables lockdown.
+ // Check the VPN's state before it does so.
+ assertTrue(mMockVpn.getEnableTeardown());
+ assertFalse(mMockVpn.getLockdown());
- mCm.unregisterNetworkCallback(trustedCallback);
+ // Send a USER_UNLOCKED broadcast so CS starts LockdownVpnTracker.
+ final int userId = UserHandle.getUserId(Process.myUid());
+ final Intent addedIntent = new Intent(ACTION_USER_UNLOCKED);
+ addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ final Handler handler = new Handler(mCsHandlerThread.getLooper());
+ handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
+ waitForIdle();
+
+ // Lockdown VPN disables teardown and enables lockdown.
+ assertFalse(mMockVpn.getEnableTeardown());
+ assertTrue(mMockVpn.getLockdown());
+
+ // Bring up a network.
+ // Expect nothing to happen because the network does not have an IPv4 default route: legacy
+ // VPN only supports IPv4.
+ final LinkProperties cellLp = new LinkProperties();
+ cellLp.setInterfaceName("rmnet0");
+ cellLp.addLinkAddress(new LinkAddress("2001:db8::1/64"));
+ cellLp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, "rmnet0"));
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+ mCellNetworkAgent.connect(false /* validated */);
+ callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+ waitForIdle();
+ assertNull(mMockVpn.getAgent());
+
+ // Add an IPv4 address. Ideally the VPN should start, but it doesn't because nothing calls
+ // LockdownVpnTracker#handleStateChangedLocked. This is a bug.
+ // TODO: consider fixing this.
+ cellLp.addLinkAddress(new LinkAddress("192.0.2.2/25"));
+ cellLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "rmnet0"));
+ mCellNetworkAgent.sendLinkProperties(cellLp);
+ callback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+ defaultCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+ waitForIdle();
+ assertNull(mMockVpn.getAgent());
+
+ // Disconnect, then try again with a network that supports IPv4 at connection time.
+ // Expect lockdown VPN to come up.
+ ExpectedBroadcast b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
+ mCellNetworkAgent.disconnect();
+ callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ b1.expectBroadcast();
+
+ // When lockdown VPN is active, the NetworkInfo state in CONNECTIVITY_ACTION is overwritten
+ // with the state of the VPN network. So expect a CONNECTING broadcast.
+ b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTING);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+ mCellNetworkAgent.connect(false /* validated */);
+ callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+ b1.expectBroadcast();
+ assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+ assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED);
+
+ // TODO: it would be nice if we could simply rely on the production code here, and have
+ // LockdownVpnTracker start the VPN, have the VPN code register its NetworkAgent with
+ // ConnectivityService, etc. That would require duplicating a fair bit of code from the
+ // Vpn tests around how to mock out LegacyVpnRunner. But even if we did that, this does not
+ // work for at least two reasons:
+ // 1. In this test, calling registerNetworkAgent does not actually result in an agent being
+ // registered. This is because nothing calls onNetworkMonitorCreated, which is what
+ // actually ends up causing handleRegisterNetworkAgent to be called. Code in this test
+ // that wants to register an agent must use TestNetworkAgentWrapper.
+ // 2. Even if we exposed Vpn#agentConnect to the test, and made MockVpn#agentConnect call
+ // the TestNetworkAgentWrapper code, this would deadlock because the
+ // TestNetworkAgentWrapper code cannot be called on the handler thread since it calls
+ // waitForIdle().
+ mMockVpn.expectStartLegacyVpnRunner();
+ b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
+ ExpectedBroadcast b2 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
+ mMockVpn.establishForMyUid();
+ callback.expectAvailableThenValidatedCallbacks(mMockVpn);
+ defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+ b1.expectBroadcast();
+ b2.expectBroadcast();
+ assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+ assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+
+ // Switch default network from cell to wifi. Expect VPN to disconnect and reconnect.
+ final LinkProperties wifiLp = new LinkProperties();
+ wifiLp.setInterfaceName("wlan0");
+ wifiLp.addLinkAddress(new LinkAddress("192.0.2.163/25"));
+ wifiLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "wlan0"));
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
+
+ b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
+ // Wifi is CONNECTING because the VPN isn't up yet.
+ b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTING);
+ ExpectedBroadcast b3 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
+ mWiFiNetworkAgent.connect(false /* validated */);
+ b1.expectBroadcast();
+ b2.expectBroadcast();
+ b3.expectBroadcast();
+ mMockVpn.expectStopVpnRunnerPrivileged();
+ mMockVpn.expectStartLegacyVpnRunner();
+
+ // TODO: why is wifi not blocked? Is it because when this callback is sent, the VPN is still
+ // connected, so the network is not considered blocked by the lockdown UID ranges? But the
+ // fact that a VPN is connected should only result in the VPN itself being unblocked, not
+ // any other network. Bug in isUidBlockedByVpn?
+ callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ callback.expectCapabilitiesThat(mMockVpn, nc -> nc.hasTransport(TRANSPORT_WIFI));
+ callback.expectCallback(CallbackEntry.LOST, mMockVpn);
+ defaultCallback.expectCapabilitiesThat(mMockVpn, nc -> nc.hasTransport(TRANSPORT_WIFI));
+ defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
+ defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
+
+ // While the VPN is reconnecting on the new network, everything is blocked.
+ assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+ assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED);
+
+ // The VPN comes up again on wifi.
+ b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
+ b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
+ mMockVpn.establishForMyUid();
+ callback.expectAvailableThenValidatedCallbacks(mMockVpn);
+ defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+ b1.expectBroadcast();
+ b2.expectBroadcast();
+
+ assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+
+ // Disconnect cell. Nothing much happens since it's not the default network.
+ // Whenever LockdownVpnTracker is connected, it will send a connected broadcast any time any
+ // NetworkInfo is updated. This is probably a bug.
+ // TODO: consider fixing this.
+ b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
+ mCellNetworkAgent.disconnect();
+ b1.expectBroadcast();
+ callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ defaultCallback.assertNoCallback();
+
+ assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+
+ b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
+ mWiFiNetworkAgent.disconnect();
+ callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ b1.expectBroadcast();
+ callback.expectCapabilitiesThat(mMockVpn, nc -> !nc.hasTransport(TRANSPORT_WIFI));
+ b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
+ mMockVpn.expectStopVpnRunnerPrivileged();
+ callback.expectCallback(CallbackEntry.LOST, mMockVpn);
+ b2.expectBroadcast();
+ }
+
+ /**
+ * Test mutable and requestable network capabilities such as
+ * {@link NetworkCapabilities#NET_CAPABILITY_TRUSTED} and
+ * {@link NetworkCapabilities#NET_CAPABILITY_NOT_VCN_MANAGED}. Verify that the
+ * {@code ConnectivityService} re-assign the networks accordingly.
+ */
+ @Test
+ public final void testLoseMutableAndRequestableCaps() throws Exception {
+ final int[] testCaps = new int [] {
+ NET_CAPABILITY_TRUSTED,
+ NET_CAPABILITY_NOT_VCN_MANAGED
+ };
+ for (final int testCap : testCaps) {
+ // Create requests with and without the testing capability.
+ final TestNetworkCallback callbackWithCap = new TestNetworkCallback();
+ final TestNetworkCallback callbackWithoutCap = new TestNetworkCallback();
+ mCm.requestNetwork(new NetworkRequest.Builder().addCapability(testCap).build(),
+ callbackWithCap);
+ mCm.requestNetwork(new NetworkRequest.Builder().removeCapability(testCap).build(),
+ callbackWithoutCap);
+
+ // Setup networks with testing capability and verify the default network changes.
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.addCapability(testCap);
+ mCellNetworkAgent.connect(true);
+ callbackWithCap.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ callbackWithoutCap.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
+ reset(mMockNetd);
+
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.addCapability(testCap);
+ mWiFiNetworkAgent.connect(true);
+ callbackWithCap.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+ callbackWithoutCap.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+ verify(mMockNetd).networkSetDefault(eq(mWiFiNetworkAgent.getNetwork().netId));
+ reset(mMockNetd);
+
+ // Remove the testing capability on wifi, verify the callback and default network
+ // changes back to cellular.
+ mWiFiNetworkAgent.removeCapability(testCap);
+ callbackWithCap.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ callbackWithoutCap.expectCapabilitiesWithout(testCap, mWiFiNetworkAgent);
+ // TODO: Test default network changes for NOT_VCN_MANAGED once the default request has
+ // it.
+ if (testCap == NET_CAPABILITY_TRUSTED) {
+ verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
+ reset(mMockNetd);
+ }
+
+ mCellNetworkAgent.removeCapability(testCap);
+ callbackWithCap.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ callbackWithoutCap.assertNoCallback();
+ if (testCap == NET_CAPABILITY_TRUSTED) {
+ verify(mMockNetd).networkClearDefault();
+ }
+
+ mCm.unregisterNetworkCallback(callbackWithCap);
+ mCm.unregisterNetworkCallback(callbackWithoutCap);
+ }
}
- @Ignore // 40%+ flakiness : figure out why and re-enable.
@Test
public final void testBatteryStatsNetworkType() throws Exception {
final LinkProperties cellLp = new LinkProperties();
@@ -6946,8 +7403,8 @@ public class ConnectivityServiceTest {
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
mCellNetworkAgent.connect(true);
waitForIdle();
- verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
- TYPE_MOBILE);
+ verify(mBatteryStatsService).noteNetworkInterfaceForTransports(cellLp.getInterfaceName(),
+ new int[] { TRANSPORT_CELLULAR });
reset(mBatteryStatsService);
final LinkProperties wifiLp = new LinkProperties();
@@ -6955,18 +7412,20 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
mWiFiNetworkAgent.connect(true);
waitForIdle();
- verify(mBatteryStatsService).noteNetworkInterfaceType(wifiLp.getInterfaceName(),
- TYPE_WIFI);
+ verify(mBatteryStatsService).noteNetworkInterfaceForTransports(wifiLp.getInterfaceName(),
+ new int[] { TRANSPORT_WIFI });
reset(mBatteryStatsService);
mCellNetworkAgent.disconnect();
+ mWiFiNetworkAgent.disconnect();
cellLp.setInterfaceName("wifi0");
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
mCellNetworkAgent.connect(true);
waitForIdle();
- verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
- TYPE_MOBILE);
+ verify(mBatteryStatsService).noteNetworkInterfaceForTransports(cellLp.getInterfaceName(),
+ new int[] { TRANSPORT_CELLULAR });
+ mCellNetworkAgent.disconnect();
}
/**
@@ -7039,8 +7498,8 @@ public class ConnectivityServiceTest {
assertRoutesAdded(cellNetId, ipv6Subnet, defaultRoute);
verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
verify(mMockNetd, times(1)).networkAddInterface(cellNetId, MOBILE_IFNAME);
- verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
- TYPE_MOBILE);
+ verify(mBatteryStatsService).noteNetworkInterfaceForTransports(cellLp.getInterfaceName(),
+ new int[] { TRANSPORT_CELLULAR });
networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
@@ -7060,7 +7519,8 @@ public class ConnectivityServiceTest {
// Make sure BatteryStats was not told about any v4- interfaces, as none should have
// come online yet.
waitForIdle();
- verify(mBatteryStatsService, never()).noteNetworkInterfaceType(startsWith("v4-"), anyInt());
+ verify(mBatteryStatsService, never()).noteNetworkInterfaceForTransports(startsWith("v4-"),
+ any());
verifyNoMoreInteractions(mMockNetd);
verifyNoMoreInteractions(mMockDnsResolver);
@@ -7113,8 +7573,8 @@ public class ConnectivityServiceTest {
assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8"));
for (final LinkProperties stackedLp : stackedLpsAfterChange) {
- verify(mBatteryStatsService).noteNetworkInterfaceType(stackedLp.getInterfaceName(),
- TYPE_MOBILE);
+ verify(mBatteryStatsService).noteNetworkInterfaceForTransports(
+ stackedLp.getInterfaceName(), new int[] { TRANSPORT_CELLULAR });
}
reset(mMockNetd);
when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
@@ -7249,11 +7709,11 @@ public class ConnectivityServiceTest {
// prefix discovery is never started.
LinkProperties lp = new LinkProperties(baseLp);
lp.setNat64Prefix(pref64FromRa);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp);
- mCellNetworkAgent.connect(false);
- final Network network = mCellNetworkAgent.getNetwork();
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp);
+ mWiFiNetworkAgent.connect(false);
+ final Network network = mWiFiNetworkAgent.getNetwork();
int netId = network.getNetId();
- callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+ callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString());
inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString());
inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
@@ -7262,8 +7722,8 @@ public class ConnectivityServiceTest {
// If the RA prefix is withdrawn, clatd is stopped and prefix discovery is started.
lp.setNat64Prefix(null);
- mCellNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mCellNetworkAgent, null);
+ mWiFiNetworkAgent.sendLinkProperties(lp);
+ expectNat64PrefixChange(callback, mWiFiNetworkAgent, null);
inOrder.verify(mMockNetd).clatdStop(iface);
inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
@@ -7271,8 +7731,8 @@ public class ConnectivityServiceTest {
// If the RA prefix appears while DNS discovery is in progress, discovery is stopped and
// clatd is started with the prefix from the RA.
lp.setNat64Prefix(pref64FromRa);
- mCellNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mCellNetworkAgent, pref64FromRa);
+ mWiFiNetworkAgent.sendLinkProperties(lp);
+ expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromRa);
inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString());
inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString());
@@ -7280,21 +7740,21 @@ public class ConnectivityServiceTest {
// Withdraw the RA prefix so we can test the case where an RA prefix appears after DNS
// discovery has succeeded.
lp.setNat64Prefix(null);
- mCellNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mCellNetworkAgent, null);
+ mWiFiNetworkAgent.sendLinkProperties(lp);
+ expectNat64PrefixChange(callback, mWiFiNetworkAgent, null);
inOrder.verify(mMockNetd).clatdStop(iface);
inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
mService.mNetdEventCallback.onNat64PrefixEvent(netId, true /* added */,
pref64FromDnsStr, 96);
- expectNat64PrefixChange(callback, mCellNetworkAgent, pref64FromDns);
+ expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns);
inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString());
// If an RA advertises the same prefix that was discovered by DNS, nothing happens: prefix
// discovery is not stopped, and there are no callbacks.
lp.setNat64Prefix(pref64FromDns);
- mCellNetworkAgent.sendLinkProperties(lp);
+ mWiFiNetworkAgent.sendLinkProperties(lp);
callback.assertNoCallback();
inOrder.verify(mMockNetd, never()).clatdStop(iface);
inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
@@ -7304,7 +7764,7 @@ public class ConnectivityServiceTest {
// If the RA is later withdrawn, nothing happens again.
lp.setNat64Prefix(null);
- mCellNetworkAgent.sendLinkProperties(lp);
+ mWiFiNetworkAgent.sendLinkProperties(lp);
callback.assertNoCallback();
inOrder.verify(mMockNetd, never()).clatdStop(iface);
inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
@@ -7314,8 +7774,8 @@ public class ConnectivityServiceTest {
// If the RA prefix changes, clatd is restarted and prefix discovery is stopped.
lp.setNat64Prefix(pref64FromRa);
- mCellNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mCellNetworkAgent, pref64FromRa);
+ mWiFiNetworkAgent.sendLinkProperties(lp);
+ expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromRa);
inOrder.verify(mMockNetd).clatdStop(iface);
inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
@@ -7329,8 +7789,8 @@ public class ConnectivityServiceTest {
// If the RA prefix changes, clatd is restarted and prefix discovery is not started.
lp.setNat64Prefix(newPref64FromRa);
- mCellNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mCellNetworkAgent, newPref64FromRa);
+ mWiFiNetworkAgent.sendLinkProperties(lp);
+ expectNat64PrefixChange(callback, mWiFiNetworkAgent, newPref64FromRa);
inOrder.verify(mMockNetd).clatdStop(iface);
inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
inOrder.verify(mMockNetd).clatdStart(iface, newPref64FromRa.toString());
@@ -7340,7 +7800,7 @@ public class ConnectivityServiceTest {
// If the RA prefix changes to the same value, nothing happens.
lp.setNat64Prefix(newPref64FromRa);
- mCellNetworkAgent.sendLinkProperties(lp);
+ mWiFiNetworkAgent.sendLinkProperties(lp);
callback.assertNoCallback();
assertEquals(newPref64FromRa, mCm.getLinkProperties(network).getNat64Prefix());
inOrder.verify(mMockNetd, never()).clatdStop(iface);
@@ -7354,19 +7814,19 @@ public class ConnectivityServiceTest {
// If the same prefix is learned first by DNS and then by RA, and clat is later stopped,
// (e.g., because the network disconnects) setPrefix64(netid, "") is never called.
lp.setNat64Prefix(null);
- mCellNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mCellNetworkAgent, null);
+ mWiFiNetworkAgent.sendLinkProperties(lp);
+ expectNat64PrefixChange(callback, mWiFiNetworkAgent, null);
inOrder.verify(mMockNetd).clatdStop(iface);
inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
mService.mNetdEventCallback.onNat64PrefixEvent(netId, true /* added */,
pref64FromDnsStr, 96);
- expectNat64PrefixChange(callback, mCellNetworkAgent, pref64FromDns);
+ expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns);
inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString());
inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), any());
lp.setNat64Prefix(pref64FromDns);
- mCellNetworkAgent.sendLinkProperties(lp);
+ mWiFiNetworkAgent.sendLinkProperties(lp);
callback.assertNoCallback();
inOrder.verify(mMockNetd, never()).clatdStop(iface);
inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
@@ -7377,10 +7837,10 @@ public class ConnectivityServiceTest {
// When tearing down a network, clat state is only updated after CALLBACK_LOST is fired, but
// before CONNECTIVITY_ACTION is sent. Wait for CONNECTIVITY_ACTION before verifying that
// clat has been stopped, or the test will be flaky.
- ConditionVariable cv = registerConnectivityBroadcast(1);
- mCellNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- waitFor(cv);
+ ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
+ mWiFiNetworkAgent.disconnect();
+ callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ b.expectBroadcast();
inOrder.verify(mMockNetd).clatdStop(iface);
inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
@@ -7455,10 +7915,10 @@ public class ConnectivityServiceTest {
.destroyNetworkCache(eq(mCellNetworkAgent.getNetwork().netId));
// Disconnect wifi
- ConditionVariable cv = registerConnectivityBroadcast(1);
+ ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
reset(mNetworkManagementService);
mWiFiNetworkAgent.disconnect();
- waitFor(cv);
+ b.expectBroadcast();
verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME));
// Clean up
@@ -7580,7 +8040,7 @@ public class ConnectivityServiceTest {
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
// The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
mMockVpn.establish(lp, VPN_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
@@ -7608,7 +8068,7 @@ public class ConnectivityServiceTest {
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
@@ -7624,7 +8084,7 @@ public class ConnectivityServiceTest {
lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0"));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
// The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
@@ -7639,7 +8099,7 @@ public class ConnectivityServiceTest {
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
mMockVpn.establish(lp, VPN_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
@@ -7691,7 +8151,7 @@ public class ConnectivityServiceTest {
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
- final UidRange vpnRange = UidRange.createForUser(VPN_USER);
+ final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER);
final Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
mMockVpn.establish(lp, VPN_UID, vpnRanges);
assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -7756,8 +8216,22 @@ public class ConnectivityServiceTest {
naExtraInfo.unregister();
}
+ // To avoid granting location permission bypass.
+ private void denyAllLocationPrivilegedPermissions() {
+ mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ PERMISSION_DENIED);
+ mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
+ PERMISSION_DENIED);
+ mServiceContext.setPermission(Manifest.permission.NETWORK_STACK,
+ PERMISSION_DENIED);
+ mServiceContext.setPermission(Manifest.permission.NETWORK_SETUP_WIZARD,
+ PERMISSION_DENIED);
+ }
+
private void setupLocationPermissions(
int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
+ denyAllLocationPrivilegedPermissions();
+
final ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.targetSdkVersion = targetSdk;
when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
@@ -7778,51 +8252,76 @@ public class ConnectivityServiceTest {
private int getOwnerUidNetCapsForCallerPermission(int ownerUid, int callerUid) {
final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
- return mService
- .maybeSanitizeLocationInfoForCaller(netCap, callerUid, mContext.getPackageName())
- .getOwnerUid();
+ return mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
+ netCap, callerUid, mContext.getPackageName()).getOwnerUid();
+ }
+
+ private void verifyWifiInfoCopyNetCapsForCallerPermission(
+ int callerUid, boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
+ final WifiInfo wifiInfo = mock(WifiInfo.class);
+ when(wifiInfo.hasLocationSensitiveFields()).thenReturn(true);
+ final NetworkCapabilities netCap = new NetworkCapabilities().setTransportInfo(wifiInfo);
+
+ mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
+ netCap, callerUid, mContext.getPackageName());
+ verify(wifiInfo).makeCopy(eq(shouldMakeCopyWithLocationSensitiveFieldsParcelable));
}
@Test
- public void testMaybeSanitizeLocationInfoForCallerWithFineLocationAfterQ() throws Exception {
+ public void testCreateForCallerWithLocationInfoSanitizedWithFineLocationAfterQ()
+ throws Exception {
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
final int myUid = Process.myUid();
assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+
+ verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
+ true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
}
@Test
- public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationPreQ() throws Exception {
+ public void testCreateForCallerWithLocationInfoSanitizedWithCoarseLocationPreQ()
+ throws Exception {
setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
final int myUid = Process.myUid();
assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+
+ verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
+ true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
}
@Test
- public void testMaybeSanitizeLocationInfoForCallerLocationOff() throws Exception {
+ public void testCreateForCallerWithLocationInfoSanitizedLocationOff() throws Exception {
// Test that even with fine location permission, and UIDs matching, the UID is sanitized.
setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
final int myUid = Process.myUid();
assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+
+ verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
+ false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
}
@Test
- public void testMaybeSanitizeLocationInfoForCallerWrongUid() throws Exception {
+ public void testCreateForCallerWithLocationInfoSanitizedWrongUid() throws Exception {
// Test that even with fine location permission, not being the owner leads to sanitization.
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
final int myUid = Process.myUid();
assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid + 1, myUid));
+
+ verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
+ true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
}
@Test
- public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationAfterQ() throws Exception {
+ public void testCreateForCallerWithLocationInfoSanitizedWithCoarseLocationAfterQ()
+ throws Exception {
// Test that not having fine location permission leads to sanitization.
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
@@ -7830,27 +8329,34 @@ public class ConnectivityServiceTest {
// Test that without the location permission, the owner field is sanitized.
final int myUid = Process.myUid();
assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+
+ verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
+ false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
}
@Test
- public void testMaybeSanitizeLocationInfoForCallerWithoutLocationPermission() throws Exception {
+ public void testCreateForCallerWithLocationInfoSanitizedWithoutLocationPermission()
+ throws Exception {
setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
// Test that without the location permission, the owner field is sanitized.
final int myUid = Process.myUid();
assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+
+ verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
+ false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
}
private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
throws Exception {
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
mMockVpn.setVpnType(vpnType);
- final VpnInfo vpnInfo = new VpnInfo();
- vpnInfo.ownerUid = vpnOwnerUid;
- mMockVpn.setVpnInfo(vpnInfo);
+ final UnderlyingNetworkInfo underlyingNetworkInfo =
+ new UnderlyingNetworkInfo(vpnOwnerUid, VPN_IFNAME, new ArrayList<String>());
+ mMockVpn.setUnderlyingNetworkInfo(underlyingNetworkInfo);
}
private void setupConnectionOwnerUidAsVpnApp(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
@@ -8047,11 +8553,18 @@ public class ConnectivityServiceTest {
assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
}
+ public NetworkAgentInfo fakeMobileNai(NetworkCapabilities nc) {
+ final NetworkInfo info = new NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE,
+ ConnectivityManager.getNetworkTypeName(TYPE_MOBILE),
+ TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE));
+ return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(),
+ nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, null,
+ 0, INVALID_UID, mQosCallbackTracker);
+ }
+
@Test
public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception {
- final NetworkAgentInfo naiWithoutUid =
- new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
+ final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
mServiceContext.setPermission(
android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
@@ -8064,9 +8577,7 @@ public class ConnectivityServiceTest {
@Test
public void testCheckConnectivityDiagnosticsPermissionsWrongUidPackageName() throws Exception {
- final NetworkAgentInfo naiWithoutUid =
- new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
+ final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
@@ -8079,9 +8590,7 @@ public class ConnectivityServiceTest {
@Test
public void testCheckConnectivityDiagnosticsPermissionsNoLocationPermission() throws Exception {
- final NetworkAgentInfo naiWithoutUid =
- new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
+ final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
@@ -8094,22 +8603,17 @@ public class ConnectivityServiceTest {
@Test
public void testCheckConnectivityDiagnosticsPermissionsActiveVpn() throws Exception {
- final Network network = new Network(NET_ID);
- final NetworkAgentInfo naiWithoutUid =
- new NetworkAgentInfo(null, network, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
-
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
+ final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
mMockVpn.establishForMyUid();
assertUidRangesUpdatedForMyUid(true);
// Wait for networks to connect and broadcasts to be sent before removing permissions.
waitForIdle();
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
+ setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
- assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {network}));
+ assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {naiWithoutUid.network}));
waitForIdle();
assertTrue(
"Active VPN permission not applied",
@@ -8130,9 +8634,7 @@ public class ConnectivityServiceTest {
public void testCheckConnectivityDiagnosticsPermissionsNetworkAdministrator() throws Exception {
final NetworkCapabilities nc = new NetworkCapabilities();
nc.setAdministratorUids(new int[] {Process.myUid()});
- final NetworkAgentInfo naiWithUid =
- new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null,
- mService, null, null, null, 0, INVALID_UID);
+ final NetworkAgentInfo naiWithUid = fakeMobileNai(nc);
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
@@ -8149,9 +8651,7 @@ public class ConnectivityServiceTest {
final NetworkCapabilities nc = new NetworkCapabilities();
nc.setOwnerUid(Process.myUid());
nc.setAdministratorUids(new int[] {Process.myUid()});
- final NetworkAgentInfo naiWithUid =
- new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null,
- mService, null, null, null, 0, INVALID_UID);
+ final NetworkAgentInfo naiWithUid = fakeMobileNai(nc);
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
@@ -8372,6 +8872,7 @@ public class ConnectivityServiceTest {
mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
+ waitForIdle();
final ConnectivityService.NetworkRequestInfo[] nriOutput = mService.requestsSortedById();
@@ -8417,7 +8918,7 @@ public class ConnectivityServiceTest {
lp.setInterfaceName("tun0");
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- final UidRange vpnRange = UidRange.createForUser(VPN_USER);
+ final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER);
Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
mMockVpn.establish(lp, VPN_UID, vpnRanges);
assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -8433,4 +8934,167 @@ public class ConnectivityServiceTest {
assertVpnUidRangesUpdated(true, newRanges, VPN_UID);
assertVpnUidRangesUpdated(false, vpnRanges, VPN_UID);
}
+
+ @Test
+ public void testInvalidRequestTypes() {
+ final int[] invalidReqTypeInts = new int[]{-1, NetworkRequest.Type.NONE.ordinal(),
+ NetworkRequest.Type.LISTEN.ordinal(), NetworkRequest.Type.values().length};
+ final NetworkCapabilities nc = new NetworkCapabilities().addTransportType(TRANSPORT_WIFI);
+
+ for (int reqTypeInt : invalidReqTypeInts) {
+ assertThrows("Expect throws for invalid request type " + reqTypeInt,
+ IllegalArgumentException.class,
+ () -> mService.requestNetwork(nc, reqTypeInt, null, 0, null,
+ ConnectivityManager.TYPE_NONE, mContext.getPackageName(),
+ getAttributionTag())
+ );
+ }
+ }
+
+ private class QosCallbackMockHelper {
+ @NonNull public final QosFilter mFilter;
+ @NonNull public final IQosCallback mCallback;
+ @NonNull public final TestNetworkAgentWrapper mAgentWrapper;
+ @NonNull private final List<IQosCallback> mCallbacks = new ArrayList();
+
+ QosCallbackMockHelper() throws Exception {
+ Log.d(TAG, "QosCallbackMockHelper: ");
+ mFilter = mock(QosFilter.class);
+
+ // Ensure the network is disconnected before anything else occurs
+ assertNull(mCellNetworkAgent);
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+
+ verifyActiveNetwork(TRANSPORT_CELLULAR);
+ waitForIdle();
+ final Network network = mCellNetworkAgent.getNetwork();
+
+ final Pair<IQosCallback, IBinder> pair = createQosCallback();
+ mCallback = pair.first;
+
+ when(mFilter.getNetwork()).thenReturn(network);
+ when(mFilter.validate()).thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+ mAgentWrapper = mCellNetworkAgent;
+ }
+
+ void registerQosCallback(@NonNull final QosFilter filter,
+ @NonNull final IQosCallback callback) {
+ mCallbacks.add(callback);
+ final NetworkAgentInfo nai =
+ mService.getNetworkAgentInfoForNetwork(filter.getNetwork());
+ mService.registerQosCallbackInternal(filter, callback, nai);
+ }
+
+ void tearDown() {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mService.unregisterQosCallback(mCallbacks.get(i));
+ }
+ }
+ }
+
+ private Pair<IQosCallback, IBinder> createQosCallback() {
+ final IQosCallback callback = mock(IQosCallback.class);
+ final IBinder binder = mock(Binder.class);
+ when(callback.asBinder()).thenReturn(binder);
+ when(binder.isBinderAlive()).thenReturn(true);
+ return new Pair<>(callback, binder);
+ }
+
+
+ @Test
+ public void testQosCallbackRegistration() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+ final NetworkAgentWrapper wrapper = mQosCallbackMockHelper.mAgentWrapper;
+
+ when(mQosCallbackMockHelper.mFilter.validate())
+ .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+
+ final NetworkAgentWrapper.CallbackType.OnQosCallbackRegister cbRegister1 =
+ (NetworkAgentWrapper.CallbackType.OnQosCallbackRegister)
+ wrapper.getCallbackHistory().poll(1000, x -> true);
+ assertNotNull(cbRegister1);
+
+ final int registerCallbackId = cbRegister1.mQosCallbackId;
+ mService.unregisterQosCallback(mQosCallbackMockHelper.mCallback);
+ final NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister cbUnregister;
+ cbUnregister = (NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister)
+ wrapper.getCallbackHistory().poll(1000, x -> true);
+ assertNotNull(cbUnregister);
+ assertEquals(registerCallbackId, cbUnregister.mQosCallbackId);
+ assertNull(wrapper.getCallbackHistory().poll(200, x -> true));
+ }
+
+ @Test
+ public void testQosCallbackNoRegistrationOnValidationError() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+
+ when(mQosCallbackMockHelper.mFilter.validate())
+ .thenReturn(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+ waitForIdle();
+ verify(mQosCallbackMockHelper.mCallback)
+ .onError(eq(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED));
+ }
+
+ @Test
+ public void testQosCallbackAvailableAndLost() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+ final int sessionId = 10;
+ final int qosCallbackId = 1;
+
+ when(mQosCallbackMockHelper.mFilter.validate())
+ .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+ waitForIdle();
+
+ final EpsBearerQosSessionAttributes attributes = new EpsBearerQosSessionAttributes(
+ 1, 2, 3, 4, 5, new ArrayList<>());
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionAvailable(qosCallbackId, sessionId, attributes);
+ waitForIdle();
+
+ verify(mQosCallbackMockHelper.mCallback).onQosEpsBearerSessionAvailable(argThat(session ->
+ session.getSessionId() == sessionId
+ && session.getSessionType() == QosSession.TYPE_EPS_BEARER), eq(attributes));
+
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionLost(qosCallbackId, sessionId);
+ waitForIdle();
+ verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
+ session.getSessionId() == sessionId
+ && session.getSessionType() == QosSession.TYPE_EPS_BEARER));
+ }
+
+ @Test
+ public void testQosCallbackTooManyRequests() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+
+ when(mQosCallbackMockHelper.mFilter.validate())
+ .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+ for (int i = 0; i < 100; i++) {
+ final Pair<IQosCallback, IBinder> pair = createQosCallback();
+
+ try {
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, pair.first);
+ } catch (ServiceSpecificException e) {
+ assertEquals(e.errorCode, ConnectivityManager.Errors.TOO_MANY_REQUESTS);
+ if (i < 50) {
+ fail("TOO_MANY_REQUESTS thrown too early, the count is " + i);
+ }
+
+ // As long as there is at least 50 requests, it is safe to assume it works.
+ // Note: The count isn't being tested precisely against 100 because the counter
+ // is shared with request network.
+ return;
+ }
+ }
+ fail("TOO_MANY_REQUESTS never thrown");
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 96c56e32f156..52cb836e19c8 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -34,7 +34,9 @@ import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.IDnsResolver;
import android.net.INetd;
+import android.net.LinkProperties;
import android.net.Network;
+import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkProvider;
@@ -76,6 +78,7 @@ public class LingerMonitorTest {
@Mock Context mCtx;
@Mock NetworkNotificationManager mNotifier;
@Mock Resources mResources;
+ @Mock QosCallbackTracker mQosCallbackTracker;
@Before
public void setUp() {
@@ -353,9 +356,10 @@ public class LingerMonitorTest {
NetworkCapabilities caps = new NetworkCapabilities();
caps.addCapability(0);
caps.addTransportType(transport);
- NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info, null,
- caps, 50, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
- NetworkProvider.ID_NONE, Binder.getCallingUid());
+ NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
+ new LinkProperties(), caps, 50, mCtx, null, new NetworkAgentConfig() /* config */,
+ mConnService, mNetd, mDnsResolver, mNMS, NetworkProvider.ID_NONE,
+ Binder.getCallingUid(), mQosCallbackTracker);
nai.everValidated = true;
return nai;
}
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 02a2aadc4c79..68aaaeda1b12 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -252,6 +252,7 @@ public class VpnTest {
@Test
public void testRestrictedProfilesAreAddedToVpn() {
+ if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
final Vpn vpn = createVpn(primaryUser.id);
@@ -265,6 +266,7 @@ public class VpnTest {
@Test
public void testManagedProfilesAreNotAddedToVpn() {
+ if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
setMockedUsers(primaryUser, managedProfileA);
final Vpn vpn = createVpn(primaryUser.id);
@@ -287,6 +289,7 @@ public class VpnTest {
@Test
public void testUidAllowAndDenylist() throws Exception {
+ if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
final Vpn vpn = createVpn(primaryUser.id);
final UidRange user = PRI_USER_RANGE;
final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
@@ -312,6 +315,7 @@ public class VpnTest {
@Test
public void testGetAlwaysAndOnGetLockDown() throws Exception {
+ if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
final Vpn vpn = createVpn(primaryUser.id);
// Default state.
@@ -336,6 +340,7 @@ public class VpnTest {
@Test
public void testLockdownChangingPackage() throws Exception {
+ if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
final Vpn vpn = createVpn(primaryUser.id);
final UidRange user = PRI_USER_RANGE;
@@ -363,6 +368,7 @@ public class VpnTest {
@Test
public void testLockdownAllowlist() throws Exception {
+ if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
final Vpn vpn = createVpn(primaryUser.id);
final UidRange user = PRI_USER_RANGE;
@@ -437,6 +443,7 @@ public class VpnTest {
@Test
public void testLockdownRuleRepeatability() throws Exception {
+ if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
final Vpn vpn = createVpn(primaryUser.id);
final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] {
new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)};
@@ -469,6 +476,7 @@ public class VpnTest {
@Test
public void testLockdownRuleReversibility() throws Exception {
+ if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
final Vpn vpn = createVpn(primaryUser.id);
final UidRangeParcel[] entireUser = {
new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)
@@ -1174,7 +1182,7 @@ public class VpnTest {
doAnswer(invocation -> {
final int id = (int) invocation.getArguments()[0];
return (userMap.get(id).flags & UserInfo.FLAG_ADMIN) != 0;
- }).when(mUserManager).canHaveRestrictedProfile(anyInt());
+ }).when(mUserManager).canHaveRestrictedProfile();
}
/**
diff --git a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java b/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
index 3aafe0b075f2..a058a466a4ff 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
@@ -33,8 +33,9 @@ import static android.net.NetworkStats.TAG_NONE;
import static org.junit.Assert.assertEquals;
import android.net.NetworkStats;
+import android.net.UnderlyingNetworkInfo;
-import com.android.internal.net.VpnInfo;
+import java.util.Arrays;
/** Superclass with utilities for NetworkStats(Service|Factory)Test */
abstract class NetworkStatsBaseTest {
@@ -108,15 +109,11 @@ abstract class NetworkStatsBaseTest {
assertEquals("unexpected operations", operations, entry.operations);
}
- static VpnInfo createVpnInfo(String[] underlyingIfaces) {
+ static UnderlyingNetworkInfo createVpnInfo(String[] underlyingIfaces) {
return createVpnInfo(TUN_IFACE, underlyingIfaces);
}
- static VpnInfo createVpnInfo(String vpnIface, String[] underlyingIfaces) {
- VpnInfo info = new VpnInfo();
- info.ownerUid = UID_VPN;
- info.vpnIface = vpnIface;
- info.underlyingIfaces = underlyingIfaces;
- return info;
+ static UnderlyingNetworkInfo createVpnInfo(String vpnIface, String[] underlyingIfaces) {
+ return new UnderlyingNetworkInfo(UID_VPN, vpnIface, Arrays.asList(underlyingIfaces));
}
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
index e4996d981fac..f3ae9b051e7c 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
@@ -36,13 +36,13 @@ import static org.junit.Assert.fail;
import android.content.res.Resources;
import android.net.NetworkStats;
import android.net.TrafficStats;
+import android.net.UnderlyingNetworkInfo;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.tests.net.R;
-import com.android.internal.net.VpnInfo;
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -79,7 +79,7 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
// related to networkStatsFactory is compiled to a minimal native library and loaded here.
System.loadLibrary("networkstatsfactorytestjni");
mFactory = new NetworkStatsFactory(mTestProc, false);
- mFactory.updateVpnInfos(new VpnInfo[0]);
+ mFactory.updateUnderlyingNetworkInfos(new UnderlyingNetworkInfo[0]);
}
@After
@@ -105,8 +105,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
@Test
public void testVpnRewriteTrafficThroughItself() throws Exception {
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
+ UnderlyingNetworkInfo[] underlyingNetworkInfos =
+ new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -134,8 +135,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
@Test
public void testVpnWithClat() throws Exception {
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {CLAT_PREFIX + TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos = new UnderlyingNetworkInfo[] {
+ createVpnInfo(new String[] {CLAT_PREFIX + TEST_IFACE})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
mFactory.noteStackedIface(CLAT_PREFIX + TEST_IFACE, TEST_IFACE);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
@@ -167,8 +169,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
@Test
public void testVpnWithOneUnderlyingIface() throws Exception {
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+ new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -191,8 +194,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
@Test
public void testVpnWithOneUnderlyingIfaceAndOwnTraffic() throws Exception {
// WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+ new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -219,8 +223,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
@Test
public void testVpnWithOneUnderlyingIface_withCompression() throws Exception {
// WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+ new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -242,8 +247,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
// WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
// Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
// Additionally, VPN is duplicating traffic across both WiFi and Cell.
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
- mFactory.updateVpnInfos(vpnInfos);
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+ new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -267,10 +273,10 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
public void testConcurrentVpns() throws Exception {
// Assume two VPNs are connected on two different network interfaces. VPN1 is using
// TEST_IFACE and VPN2 is using TEST_IFACE2.
- final VpnInfo[] vpnInfos = new VpnInfo[] {
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos = new UnderlyingNetworkInfo[] {
createVpnInfo(TUN_IFACE, new String[] {TEST_IFACE}),
createVpnInfo(TUN_IFACE2, new String[] {TEST_IFACE2})};
- mFactory.updateVpnInfos(vpnInfos);
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -308,8 +314,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
// WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
// Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
// Additionally, VPN is arbitrarily splitting traffic across WiFi and Cell.
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
- mFactory.updateVpnInfos(vpnInfos);
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+ new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
@@ -335,8 +342,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
// WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
// Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
// Additionally, VPN is arbitrarily splitting compressed traffic across WiFi and Cell.
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
- mFactory.updateVpnInfos(vpnInfos);
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+ new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface:
// 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
@@ -357,8 +365,9 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
public void testVpnWithIncorrectUnderlyingIface() throws Exception {
// WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2),
// but has declared only WiFi (TEST_IFACE) in its underlying network set.
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
+ final UnderlyingNetworkInfo[] underlyingNetworkInfos =
+ new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+ mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
// create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
// overhead per packet):
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index c7836297df75..dde78aa54199 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -21,7 +21,6 @@ import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.ConnectivityManager.TYPE_WIMAX;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
@@ -44,6 +43,7 @@ import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
+import static android.net.NetworkTemplate.buildTemplateWifi;
import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.net.TrafficStats.UID_REMOVED;
@@ -86,6 +86,7 @@ import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
+import android.net.UnderlyingNetworkInfo;
import android.net.netstats.provider.INetworkStatsProviderCallback;
import android.os.ConditionVariable;
import android.os.Handler;
@@ -104,7 +105,6 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.net.VpnInfo;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
@@ -146,7 +146,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
private static final String IMSI_2 = "310260";
private static final String TEST_SSID = "AndroidAP";
- private static NetworkTemplate sTemplateWifi = buildTemplateWifiWildcard();
+ private static NetworkTemplate sTemplateWifi = buildTemplateWifi(TEST_SSID);
private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
@@ -286,12 +286,12 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
-
// modify some number on wifi, and trigger poll event
incrementCurrentTime(HOUR_IN_MILLIS);
expectDefaultSettings();
@@ -329,7 +329,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -402,7 +403,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// modify some number on wifi, and trigger poll event
incrementCurrentTime(2 * HOUR_IN_MILLIS);
@@ -442,7 +444,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// create some traffic on first network
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -476,7 +479,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
.insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
forcePollAndWaitForIdle();
@@ -515,7 +519,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -567,61 +572,6 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
}
@Test
- public void testUid3gWimaxCombinedByTemplate() throws Exception {
- // pretend that network comes online
- expectDefaultSettings();
- NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
-
- // create some traffic
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
- mService.incrementOperationCount(UID_RED, 0xF00D, 5);
-
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertUidTotal(sTemplateImsi1, UID_RED, 1024L, 8L, 1024L, 8L, 5);
-
-
- // now switch over to wimax network
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- states = new NetworkState[] {buildWimaxState(TEST_IFACE2)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
-
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
- forcePollAndWaitForIdle();
-
-
- // create traffic on second network
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
- .insertEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
- .insertEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L));
- mService.incrementOperationCount(UID_RED, 0xFAAD, 5);
-
- forcePollAndWaitForIdle();
-
- // verify that ALL_MOBILE template combines both
- assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 1280L, 10L, 10);
- }
-
- @Test
public void testMobileStatsByRatType() throws Exception {
final NetworkTemplate template3g =
buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS);
@@ -637,7 +587,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
- new VpnInfo[0]);
+ new UnderlyingNetworkInfo[0]);
// Create some traffic.
incrementCurrentTime(MINUTE_IN_MILLIS);
@@ -711,7 +661,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// create some traffic for two apps
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -769,7 +720,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
NetworkStats.Entry entry1 = new NetworkStats.Entry(
TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L);
@@ -812,7 +764,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
NetworkStats.Entry uidStats = new NetworkStats.Entry(
TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
@@ -866,7 +819,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// create some initial traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -923,7 +877,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// create some initial traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -962,7 +917,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// Create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -999,7 +955,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// create some tethering traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -1055,7 +1012,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -1160,7 +1118,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
mService.registerNetworkStatsProvider("TEST", provider);
assertNotNull(cb);
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// Verifies that one requestStatsUpdate will be called during iface update.
provider.expectOnRequestStatsUpdate(0 /* unused */);
@@ -1211,7 +1170,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
expectDefaultSettings();
NetworkState[] states =
new NetworkState[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// Register custom provider and retrieve callback.
final TestableNetworkStatsProviderBinder provider =
@@ -1260,7 +1220,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
// 3G network comes online.
setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
- new VpnInfo[0]);
+ new UnderlyingNetworkInfo[0]);
// Create some traffic.
incrementCurrentTime(MINUTE_IN_MILLIS);
@@ -1330,7 +1290,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
NetworkState[] states = new NetworkState[]{
buildWifiState(true /*isMetered*/, TEST_IFACE2), buildMobile3gState(IMSI_1)};
expectNetworkStatsUidDetail(buildEmptyStats());
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
// Create some traffic on mobile network.
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -1503,6 +1464,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, !isMetered);
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
capabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+ capabilities.setSSID(TEST_SSID);
return new NetworkState(info, prop, capabilities, WIFI_NETWORK, null, TEST_SSID);
}
@@ -1524,17 +1486,6 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
return new NetworkState(info, prop, capabilities, MOBILE_NETWORK, subscriberId, null);
}
- private static NetworkState buildWimaxState(@NonNull String iface) {
- final NetworkInfo info = new NetworkInfo(TYPE_WIMAX, 0, null, null);
- info.setDetailedState(DetailedState.CONNECTED, null, null);
- final LinkProperties prop = new LinkProperties();
- prop.setInterfaceName(iface);
- final NetworkCapabilities capabilities = new NetworkCapabilities();
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
- return new NetworkState(info, prop, capabilities, MOBILE_NETWORK, null, null);
- }
-
private NetworkStats buildEmptyStats() {
return new NetworkStats(getElapsedRealtime(), 0);
}
diff --git a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
index 25bd7c06be49..1102624da031 100644
--- a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
+++ b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
@@ -29,7 +29,6 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -197,6 +196,11 @@ public class BroadcastInterceptingContext extends ContextWrapper {
}
@Override
+ public void sendStickyBroadcast(Intent intent, Bundle options) {
+ sendBroadcast(intent);
+ }
+
+ @Override
public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
sendBroadcast(intent);
}
diff --git a/tests/vcn/Android.bp b/tests/vcn/Android.bp
index 3c08d347b19a..c04ddd78e69b 100644
--- a/tests/vcn/Android.bp
+++ b/tests/vcn/Android.bp
@@ -16,6 +16,7 @@ android_test {
"frameworks-base-testutils",
"framework-protos",
"mockito-target-minus-junit4",
+ "net-tests-utils",
"platform-test-annotations",
"services.core",
],
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index dfd0c8a75172..86a15912b6b4 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -28,6 +28,7 @@ import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
@@ -39,6 +40,12 @@ public class VcnGatewayConnectionConfigTest {
NetworkCapabilities.NET_CAPABILITY_INTERNET, NetworkCapabilities.NET_CAPABILITY_MMS
};
public static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN};
+
+ static {
+ Arrays.sort(EXPOSED_CAPS);
+ Arrays.sort(UNDERLYING_CAPS);
+ }
+
public static final long[] RETRY_INTERVALS_MS =
new long[] {
TimeUnit.SECONDS.toMillis(5),
@@ -124,12 +131,13 @@ public class VcnGatewayConnectionConfigTest {
public void testBuilderAndGetters() {
final VcnGatewayConnectionConfig config = buildTestConfig();
- for (int cap : EXPOSED_CAPS) {
- config.hasExposedCapability(cap);
- }
- for (int cap : UNDERLYING_CAPS) {
- config.requiresUnderlyingCapability(cap);
- }
+ int[] exposedCaps = config.getExposedCapabilities();
+ Arrays.sort(exposedCaps);
+ assertArrayEquals(EXPOSED_CAPS, exposedCaps);
+
+ int[] underlyingCaps = config.getRequiredUnderlyingCapabilities();
+ Arrays.sort(underlyingCaps);
+ assertArrayEquals(UNDERLYING_CAPS, underlyingCaps);
assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMs());
assertEquals(MAX_MTU, config.getMaxMtu());
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
new file mode 100644
index 000000000000..f9db408462b7
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn;
+
+import static androidx.test.InstrumentationRegistry.getContext;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
+import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import java.util.concurrent.Executor;
+
+public class VcnManagerTest {
+ private static final Executor INLINE_EXECUTOR = Runnable::run;
+
+ private IVcnManagementService mMockVcnManagementService;
+ private VcnUnderlyingNetworkPolicyListener mMockPolicyListener;
+
+ private Context mContext;
+ private VcnManager mVcnManager;
+
+ @Before
+ public void setUp() {
+ mMockVcnManagementService = mock(IVcnManagementService.class);
+ mMockPolicyListener = mock(VcnUnderlyingNetworkPolicyListener.class);
+
+ mContext = getContext();
+ mVcnManager = new VcnManager(mContext, mMockVcnManagementService);
+ }
+
+ @Test
+ public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception {
+ mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, mMockPolicyListener);
+
+ ArgumentCaptor<IVcnUnderlyingNetworkPolicyListener> captor =
+ ArgumentCaptor.forClass(IVcnUnderlyingNetworkPolicyListener.class);
+ verify(mMockVcnManagementService).addVcnUnderlyingNetworkPolicyListener(captor.capture());
+
+ assertTrue(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener));
+
+ IVcnUnderlyingNetworkPolicyListener listenerWrapper = captor.getValue();
+ listenerWrapper.onPolicyChanged();
+ verify(mMockPolicyListener).onPolicyChanged();
+ }
+
+ @Test
+ public void testRemoveVcnUnderlyingNetworkPolicyListener() throws Exception {
+ mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, mMockPolicyListener);
+
+ mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ assertFalse(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener));
+ verify(mMockVcnManagementService)
+ .addVcnUnderlyingNetworkPolicyListener(
+ any(IVcnUnderlyingNetworkPolicyListener.class));
+ }
+
+ @Test
+ public void testRemoveVcnUnderlyingNetworkPolicyListenerUnknownListener() throws Exception {
+ mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ assertFalse(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener));
+ verify(mMockVcnManagementService, never())
+ .addVcnUnderlyingNetworkPolicyListener(
+ any(IVcnUnderlyingNetworkPolicyListener.class));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testAddVcnUnderlyingNetworkPolicyListenerNullExecutor() throws Exception {
+ mVcnManager.addVcnUnderlyingNetworkPolicyListener(null, mMockPolicyListener);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testAddVcnUnderlyingNetworkPolicyListenerNullListener() throws Exception {
+ mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testRemoveVcnUnderlyingNetworkPolicyListenerNullListener() {
+ mVcnManager.removeVcnUnderlyingNetworkPolicyListener(null);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy() throws Exception {
+ NetworkCapabilities nc = new NetworkCapabilities();
+ LinkProperties lp = new LinkProperties();
+ when(mMockVcnManagementService.getUnderlyingNetworkPolicy(eq(nc), eq(lp)))
+ .thenReturn(new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, nc));
+
+ VcnUnderlyingNetworkPolicy policy = mVcnManager.getUnderlyingNetworkPolicy(nc, lp);
+
+ assertFalse(policy.isTeardownRequested());
+ assertEquals(nc, policy.getMergedNetworkCapabilities());
+ verify(mMockVcnManagementService).getUnderlyingNetworkPolicy(eq(nc), eq(lp));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testGetUnderlyingNetworkPolicyNullNetworkCapabilities() throws Exception {
+ mVcnManager.getUnderlyingNetworkPolicy(null, new LinkProperties());
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testGetUnderlyingNetworkPolicyNullLinkProperties() throws Exception {
+ mVcnManager.getUnderlyingNetworkPolicy(new NetworkCapabilities(), null);
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java
new file mode 100644
index 000000000000..31561901be9e
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 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.vcn;
+
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+
+import android.net.wifi.WifiInfo;
+import android.os.Parcel;
+
+import org.junit.Test;
+
+public class VcnTransportInfoTest {
+ private static final int SUB_ID = 1;
+ private static final int NETWORK_ID = 5;
+ private static final WifiInfo WIFI_INFO =
+ new WifiInfo.Builder().setNetworkId(NETWORK_ID).build();
+
+ private static final VcnTransportInfo CELL_UNDERLYING_INFO = new VcnTransportInfo(SUB_ID);
+ private static final VcnTransportInfo WIFI_UNDERLYING_INFO = new VcnTransportInfo(WIFI_INFO);
+
+ @Test
+ public void testGetWifiInfo() {
+ assertEquals(WIFI_INFO, WIFI_UNDERLYING_INFO.getWifiInfo());
+
+ assertNull(CELL_UNDERLYING_INFO.getWifiInfo());
+ }
+
+ @Test
+ public void testGetSubId() {
+ assertEquals(SUB_ID, CELL_UNDERLYING_INFO.getSubId());
+
+ assertEquals(INVALID_SUBSCRIPTION_ID, WIFI_UNDERLYING_INFO.getSubId());
+ }
+
+ @Test
+ public void testEquals() {
+ assertEquals(CELL_UNDERLYING_INFO, CELL_UNDERLYING_INFO);
+ assertEquals(WIFI_UNDERLYING_INFO, WIFI_UNDERLYING_INFO);
+ assertNotEquals(CELL_UNDERLYING_INFO, WIFI_UNDERLYING_INFO);
+ }
+
+ @Test
+ public void testParcelUnparcel() {
+ verifyParcelingIsNull(CELL_UNDERLYING_INFO);
+ verifyParcelingIsNull(WIFI_UNDERLYING_INFO);
+ }
+
+ private void verifyParcelingIsNull(VcnTransportInfo vcnTransportInfo) {
+ Parcel parcel = Parcel.obtain();
+ vcnTransportInfo.writeToParcel(parcel, 0 /* flags */);
+ assertNull(VcnTransportInfo.CREATOR.createFromParcel(parcel));
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
new file mode 100644
index 000000000000..3ba0a1f53a9f
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn;
+
+import static com.android.testutils.ParcelUtils.assertParcelSane;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.net.NetworkCapabilities;
+
+import org.junit.Test;
+
+public class VcnUnderlyingNetworkPolicyTest {
+ private static final VcnUnderlyingNetworkPolicy DEFAULT_NETWORK_POLICY =
+ new VcnUnderlyingNetworkPolicy(
+ false /* isTearDownRequested */, new NetworkCapabilities());
+ private static final VcnUnderlyingNetworkPolicy SAMPLE_NETWORK_POLICY =
+ new VcnUnderlyingNetworkPolicy(
+ true /* isTearDownRequested */,
+ new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .build());
+
+ @Test
+ public void testEquals() {
+ assertEquals(DEFAULT_NETWORK_POLICY, DEFAULT_NETWORK_POLICY);
+ assertEquals(SAMPLE_NETWORK_POLICY, SAMPLE_NETWORK_POLICY);
+
+ assertNotEquals(DEFAULT_NETWORK_POLICY, SAMPLE_NETWORK_POLICY);
+ }
+
+ @Test
+ public void testParcelUnparcel() {
+ assertParcelSane(SAMPLE_NETWORK_POLICY, 2);
+ }
+}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 696110f01869..e26bf19488d0 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -18,15 +18,23 @@ package com.android.server;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
+import static com.android.server.vcn.VcnTestUtils.setupSystemService;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -35,8 +43,13 @@ import static org.mockito.Mockito.verify;
import android.app.AppOpsManager;
import android.content.Context;
import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
+import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
import android.net.vcn.VcnConfigTest;
+import android.net.vcn.VcnUnderlyingNetworkPolicy;
+import android.os.IBinder;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.os.Process;
@@ -55,6 +68,7 @@ import com.android.server.vcn.VcnContext;
import com.android.server.vcn.VcnNetworkProvider;
import com.android.server.vcn.util.PersistableBundleUtils;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -126,12 +140,21 @@ public class VcnManagementServiceTest {
private final VcnManagementService mVcnMgmtSvc;
+ private final IVcnUnderlyingNetworkPolicyListener mMockPolicyListener =
+ mock(IVcnUnderlyingNetworkPolicyListener.class);
+ private final IBinder mMockIBinder = mock(IBinder.class);
+
public VcnManagementServiceTest() throws Exception {
- setupSystemService(mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
- setupSystemService(mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
setupSystemService(
- mSubMgr, Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class);
- setupSystemService(mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class);
+ mMockContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+ setupSystemService(
+ mMockContext, mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
+ setupSystemService(
+ mMockContext,
+ mSubMgr,
+ Context.TELEPHONY_SUBSCRIPTION_SERVICE,
+ SubscriptionManager.class);
+ setupSystemService(mMockContext, mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class);
doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName();
@@ -169,13 +192,18 @@ public class VcnManagementServiceTest {
setupMockedCarrierPrivilege(true);
mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps);
+ doReturn(mMockIBinder).when(mMockPolicyListener).asBinder();
+
// Make sure the profiles are loaded.
mTestLooper.dispatchAll();
}
- private void setupSystemService(Object service, String name, Class<?> serviceClass) {
- doReturn(name).when(mMockContext).getSystemServiceName(serviceClass);
- doReturn(service).when(mMockContext).getSystemService(name);
+ @Before
+ public void setUp() {
+ doNothing()
+ .when(mMockContext)
+ .enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.NETWORK_FACTORY), any());
}
private void setupMockedCarrierPrivilege(boolean isPrivileged) {
@@ -438,4 +466,53 @@ public class VcnManagementServiceTest {
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
verify(vcnInstance).teardownAsynchronously();
}
+
+ @Test
+ public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception {
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ verify(mMockIBinder).linkToDeath(any(), anyInt());
+ }
+
+ @Test(expected = SecurityException.class)
+ public void testAddVcnUnderlyingNetworkPolicyListenerInvalidPermission() {
+ doThrow(new SecurityException())
+ .when(mMockContext)
+ .enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.NETWORK_FACTORY), any());
+
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+ }
+
+ @Test
+ public void testRemoveVcnUnderlyingNetworkPolicyListener() {
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+ }
+
+ @Test
+ public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() {
+ mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy() throws Exception {
+ VcnUnderlyingNetworkPolicy policy =
+ mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+ new NetworkCapabilities(), new LinkProperties());
+
+ assertFalse(policy.isTeardownRequested());
+ assertNotNull(policy.getMergedNetworkCapabilities());
+ }
+
+ @Test(expected = SecurityException.class)
+ public void testGetUnderlyingNetworkPolicyInvalidPermission() {
+ doThrow(new SecurityException())
+ .when(mMockContext)
+ .enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.NETWORK_FACTORY), any());
+
+ mVcnMgmtSvc.getUnderlyingNetworkPolicy(new NetworkCapabilities(), new LinkProperties());
+ }
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
new file mode 100644
index 000000000000..d936183e5a0b
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for VcnGatewayConnection.ConnectingState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectionTestBase {
+ private VcnIkeSession mIkeSession;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
+ mGatewayConnection.transitionTo(mGatewayConnection.mConnectingState);
+ mTestLooper.dispatchAll();
+
+ mIkeSession = mGatewayConnection.getIkeSession();
+ }
+
+ @Test
+ public void testEnterStateCreatesNewIkeSession() throws Exception {
+ verify(mDeps).newIkeSession(any(), any(), any(), any(), any());
+ }
+
+ @Test
+ public void testNullNetworkTriggersDisconnect() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(null);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).kill();
+ }
+
+ @Test
+ public void testNewNetworkTriggersReconnect() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).close();
+ verify(mIkeSession, never()).kill();
+ }
+
+ @Test
+ public void testSameNetworkDoesNotTriggerReconnect() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testChildSessionClosedTriggersDisconnect() throws Exception {
+ getChildSessionCallback().onClosed();
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).close();
+ }
+
+ @Test
+ public void testIkeSessionClosedTriggersDisconnect() throws Exception {
+ getIkeSessionCallback().onClosed();
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).close();
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
new file mode 100644
index 000000000000..4ecd21503165
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for VcnGatewayConnection.DisconnectedState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnectionTestBase {
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectedState);
+ mTestLooper.dispatchAll();
+ }
+
+ @Test
+ public void testEnterWhileNotRunningTriggersQuit() throws Exception {
+ final VcnGatewayConnection vgc =
+ new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps);
+
+ vgc.setIsRunning(false);
+ vgc.transitionTo(vgc.mDisconnectedState);
+ mTestLooper.dispatchAll();
+
+ assertNull(vgc.getCurrentState());
+ }
+
+ @Test
+ public void testNetworkChangesTriggerStateTransitions() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testNullNetworkDoesNotTriggerStateTransition() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(null);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testTeardown() throws Exception {
+ mGatewayConnection.teardownAsynchronously();
+ mTestLooper.dispatchAll();
+
+ assertNull(mGatewayConnection.getCurrentState());
+ verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any());
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
new file mode 100644
index 000000000000..d0fec55a6827
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static com.android.server.vcn.VcnGatewayConnection.TEARDOWN_TIMEOUT_SECONDS;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.verify;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.TimeUnit;
+
+/** Tests for VcnGatewayConnection.DisconnectedState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnectionTestBase {
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mGatewayConnection.setIkeSession(mGatewayConnection.buildIkeSession());
+
+ mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectingState);
+ mTestLooper.dispatchAll();
+ }
+
+ @Test
+ public void testIkeSessionClosed() throws Exception {
+ getIkeSessionCallback().onClosed();
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testTimeoutExpired() throws Exception {
+ mTestLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(TEARDOWN_TIMEOUT_SECONDS));
+ mTestLooper.dispatchAll();
+
+ verify(mMockIkeSession).kill();
+ }
+
+ @Test
+ public void testTeardown() throws Exception {
+ mGatewayConnection.teardownAsynchronously();
+ mTestLooper.dispatchAll();
+
+ // Should do nothing; already tearing down.
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
new file mode 100644
index 000000000000..b4d39bf74a4b
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
+import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
+import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.net.IpSecManager;
+import android.net.IpSecTunnelInterfaceResponse;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.ipsec.ike.ChildSessionCallback;
+import android.net.ipsec.ike.IkeSessionCallback;
+import android.net.vcn.VcnGatewayConnectionConfig;
+import android.net.vcn.VcnGatewayConnectionConfigTest;
+import android.os.ParcelUuid;
+import android.os.test.TestLooper;
+
+import com.android.server.IpSecService;
+
+import org.junit.Before;
+import org.mockito.ArgumentCaptor;
+
+import java.util.UUID;
+
+public class VcnGatewayConnectionTestBase {
+ protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID());
+ protected static final int TEST_IPSEC_TUNNEL_RESOURCE_ID = 1;
+ protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
+ protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
+ new UnderlyingNetworkRecord(
+ new Network(0),
+ new NetworkCapabilities(),
+ new LinkProperties(),
+ false /* blocked */);
+ protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 =
+ new UnderlyingNetworkRecord(
+ new Network(1),
+ new NetworkCapabilities(),
+ new LinkProperties(),
+ false /* blocked */);
+
+ @NonNull protected final Context mContext;
+ @NonNull protected final TestLooper mTestLooper;
+ @NonNull protected final VcnNetworkProvider mVcnNetworkProvider;
+ @NonNull protected final VcnContext mVcnContext;
+ @NonNull protected final VcnGatewayConnectionConfig mConfig;
+ @NonNull protected final VcnGatewayConnection.Dependencies mDeps;
+ @NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker;
+
+ @NonNull protected final IpSecService mIpSecSvc;
+
+ protected VcnIkeSession mMockIkeSession;
+ protected VcnGatewayConnection mGatewayConnection;
+
+ public VcnGatewayConnectionTestBase() {
+ mContext = mock(Context.class);
+ mTestLooper = new TestLooper();
+ mVcnNetworkProvider = mock(VcnNetworkProvider.class);
+ mVcnContext = mock(VcnContext.class);
+ mConfig = VcnGatewayConnectionConfigTest.buildTestConfig();
+ mDeps = mock(VcnGatewayConnection.Dependencies.class);
+ mUnderlyingNetworkTracker = mock(UnderlyingNetworkTracker.class);
+
+ mIpSecSvc = mock(IpSecService.class);
+ setupIpSecManager(mContext, mIpSecSvc);
+
+ doReturn(mContext).when(mVcnContext).getContext();
+ doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
+ doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
+
+ doReturn(mUnderlyingNetworkTracker)
+ .when(mDeps)
+ .newUnderlyingNetworkTracker(any(), any(), any());
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ IpSecTunnelInterfaceResponse resp =
+ new IpSecTunnelInterfaceResponse(
+ IpSecManager.Status.OK,
+ TEST_IPSEC_TUNNEL_RESOURCE_ID,
+ TEST_IPSEC_TUNNEL_IFACE);
+ doReturn(resp).when(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any());
+
+ mMockIkeSession = mock(VcnIkeSession.class);
+ doReturn(mMockIkeSession).when(mDeps).newIkeSession(any(), any(), any(), any(), any());
+
+ mGatewayConnection = new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps);
+ }
+
+ protected IkeSessionCallback getIkeSessionCallback() {
+ ArgumentCaptor<IkeSessionCallback> captor =
+ ArgumentCaptor.forClass(IkeSessionCallback.class);
+ verify(mDeps).newIkeSession(any(), any(), any(), captor.capture(), any());
+ return captor.getValue();
+ }
+
+ protected ChildSessionCallback getChildSessionCallback() {
+ ArgumentCaptor<ChildSessionCallback> captor =
+ ArgumentCaptor.forClass(ChildSessionCallback.class);
+ verify(mDeps).newIkeSession(any(), any(), any(), any(), captor.capture());
+ return captor.getValue();
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java b/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java
new file mode 100644
index 000000000000..2b1080650d6d
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static org.mockito.Mockito.doReturn;
+
+import android.content.Context;
+import android.net.IpSecManager;
+
+import com.android.server.IpSecService;
+
+public class VcnTestUtils {
+ /** Mock system services by directly mocking the *Manager interface. */
+ public static void setupSystemService(
+ Context mockContext, Object service, String name, Class<?> serviceClass) {
+ doReturn(name).when(mockContext).getSystemServiceName(serviceClass);
+ doReturn(service).when(mockContext).getSystemService(name);
+ }
+
+ /** Mock IpSecService by mocking the underlying service binder. */
+ public static IpSecManager setupIpSecManager(Context mockContext, IpSecService service) {
+ doReturn(Context.IPSEC_SERVICE).when(mockContext).getSystemServiceName(IpSecManager.class);
+
+ final IpSecManager ipSecMgr = new IpSecManager(mockContext, service);
+ doReturn(ipSecMgr).when(mockContext).getSystemService(Context.IPSEC_SERVICE);
+
+ // Return to ensure this doesn't get reaped.
+ return ipSecMgr;
+ }
+}
diff --git a/tools/stringslint/stringslint.py b/tools/stringslint/stringslint.py
index afe91cda37b0..15088fc81e88 100644
--- a/tools/stringslint/stringslint.py
+++ b/tools/stringslint/stringslint.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
+#-*- coding: utf-8 -*-
# Copyright (C) 2018 The Android Open Source Project
#
@@ -33,9 +34,6 @@ In general:
import re, sys, codecs
import lxml.etree as ET
-reload(sys)
-sys.setdefaultencoding('utf8')
-
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
def format(fg=None, bg=None, bright=False, bold=False, dim=False, reset=False):
@@ -118,7 +116,7 @@ def lint(path):
raw = f.read()
if len(raw.strip()) == 0:
return warnings
- tree = ET.fromstring(raw)
+ tree = ET.fromstring(bytes(raw, encoding='utf-8'))
root = tree #tree.getroot()
last_comment = None
@@ -231,6 +229,6 @@ for b in before:
if len(after) > 0:
for a in sorted(after.keys()):
- print after[a]
- print
+ print(after[a])
+ print()
sys.exit(1)
diff --git a/tools/stringslint/stringslint_sha.sh b/tools/stringslint/stringslint_sha.sh
index bd80bb4e6f3f..bd0569873197 100755
--- a/tools/stringslint/stringslint_sha.sh
+++ b/tools/stringslint/stringslint_sha.sh
@@ -1,5 +1,5 @@
#!/bin/bash
LOCAL_DIR="$( dirname ${BASH_SOURCE} )"
git show --name-only --pretty=format: $1 | grep values/strings.xml | while read file; do
- python $LOCAL_DIR/stringslint.py <(git show $1:$file) <(git show $1^:$file)
+ python3 $LOCAL_DIR/stringslint.py <(git show $1:$file) <(git show $1^:$file)
done