summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp8
-rw-r--r--GAME_MANAGER_OWNERS2
-rw-r--r--StubLibraries.bp1
-rw-r--r--apex/blobstore/README.md125
-rw-r--r--apex/media/framework/java/android/media/MediaTranscodingManager.java19
-rw-r--r--boot/boot-image-profile.txt17
-rw-r--r--cmds/am/src/com/android/commands/am/Instrument.java2
-rw-r--r--cmds/bootanimation/BootAnimation.cpp2
-rw-r--r--cmds/idmap2/OWNERS4
-rw-r--r--config/README.md13
-rwxr-xr-xconfig/generate-preloaded-classes.sh39
-rw-r--r--config/preloaded-classes-extra14
-rw-r--r--core/api/Android.bp10
-rw-r--r--core/api/current.txt251
-rw-r--r--core/api/module-lib-current.txt23
-rw-r--r--core/api/system-current.txt9
-rw-r--r--core/api/test-current.txt2
-rw-r--r--core/java/Android.bp4
-rw-r--r--core/java/android/accounts/Account.java7
-rw-r--r--core/java/android/app/Activity.java5
-rw-r--r--core/java/android/app/ActivityThread.java12
-rw-r--r--core/java/android/app/OWNERS2
-rw-r--r--core/java/android/appwidget/AppWidgetHostView.java5
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java42
-rw-r--r--core/java/android/bluetooth/BluetoothCodecConfig.java497
-rw-r--r--core/java/android/bluetooth/BluetoothCodecStatus.java111
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java5
-rw-r--r--core/java/android/bluetooth/BluetoothGatt.java215
-rw-r--r--core/java/android/bluetooth/BluetoothGattCallback.java84
-rw-r--r--core/java/android/bluetooth/BluetoothGattCharacteristic.java35
-rw-r--r--core/java/android/bluetooth/BluetoothGattDescriptor.java7
-rw-r--r--core/java/android/bluetooth/BluetoothGattServer.java78
-rw-r--r--core/java/android/bluetooth/BluetoothLeBroadcast.java287
-rw-r--r--core/java/android/bluetooth/BluetoothProfile.java11
-rw-r--r--core/java/android/bluetooth/BluetoothSocket.java3
-rw-r--r--core/java/android/bluetooth/BluetoothStatusCodes.java84
-rw-r--r--core/java/android/bluetooth/le/AdvertiseData.java58
-rw-r--r--core/java/android/bluetooth/le/BluetoothLeAdvertiser.java3
-rw-r--r--core/java/android/bluetooth/le/TransportBlock.java155
-rw-r--r--core/java/android/bluetooth/le/TransportDiscoveryData.java168
-rw-r--r--core/java/android/content/Context.java42
-rw-r--r--core/java/android/content/Intent.java4
-rw-r--r--core/java/android/content/om/OWNERS2
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java2
-rw-r--r--core/java/android/content/res/OWNERS2
-rw-r--r--core/java/android/hardware/OWNERS4
-rw-r--r--core/java/android/net/IpSecAlgorithm.java9
-rw-r--r--core/java/android/net/NetworkTemplate.java63
-rw-r--r--core/java/android/net/vcn/VcnCellUnderlyingNetworkPriority.java291
-rw-r--r--core/java/android/net/vcn/VcnGatewayConnectionConfig.java97
-rw-r--r--core/java/android/net/vcn/VcnUnderlyingNetworkPriority.java181
-rw-r--r--core/java/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java120
-rw-r--r--core/java/android/nfc/cardemulation/ApduServiceInfo.java9
-rw-r--r--core/java/android/nfc/cardemulation/CardEmulation.java56
-rw-r--r--core/java/android/nfc/cardemulation/NfcFCardEmulation.java1
-rw-r--r--core/java/android/nfc/cardemulation/NfcFServiceInfo.java7
-rw-r--r--core/java/android/os/BaseBundle.java100
-rw-r--r--core/java/android/os/Binder.java191
-rw-r--r--core/java/android/os/Bundle.java49
-rw-r--r--core/java/android/os/IStatsBootstrapAtomService.aidl36
-rw-r--r--core/java/android/os/ISystemConfig.aidl4
-rw-r--r--core/java/android/os/OWNERS16
-rw-r--r--core/java/android/os/Parcel.java427
-rw-r--r--core/java/android/os/PersistableBundle.java15
-rw-r--r--core/java/android/os/ServiceManager.java11
-rw-r--r--core/java/android/os/ServiceManagerNative.java2
-rw-r--r--core/java/android/os/StatsBootstrapAtom.aidl34
-rw-r--r--core/java/android/os/StatsBootstrapAtomValue.aidl29
-rw-r--r--core/java/android/os/SystemConfigManager.java6
-rw-r--r--core/java/android/os/UpdateEngine.java5
-rw-r--r--core/java/android/os/health/HealthStats.java2
-rw-r--r--core/java/android/os/health/UidHealthStats.java6
-rw-r--r--core/java/android/os/storage/VolumeInfo.java44
-rw-r--r--core/java/android/os/vibrator/OWNERS1
-rw-r--r--core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS8
-rw-r--r--core/java/android/provider/DeviceConfig.java8
-rw-r--r--core/java/android/provider/Settings.java34
-rw-r--r--core/java/android/provider/Telephony.java9
-rw-r--r--core/java/android/telephony/PhoneStateListener.java14
-rw-r--r--core/java/android/telephony/TelephonyRegistryManager.java4
-rw-r--r--core/java/android/util/BackupUtils.java4
-rw-r--r--core/java/android/util/Log.java7
-rw-r--r--core/java/android/view/KeyEvent.java38
-rw-r--r--core/java/android/view/SurfaceControl.java10
-rw-r--r--core/java/android/view/ViewRootImpl.java4
-rw-r--r--core/java/android/view/WindowManager.java20
-rw-r--r--core/java/com/android/internal/compat/OWNERS7
-rw-r--r--core/java/com/android/internal/net/OWNERS7
-rw-r--r--core/java/com/android/internal/os/ClassLoaderFactory.java18
-rw-r--r--core/java/com/android/internal/os/Zygote.java10
-rw-r--r--core/java/com/android/internal/view/OWNERS2
-rw-r--r--core/java/com/android/server/NetworkManagementSocketTagger.java46
-rw-r--r--core/java/com/android/server/net/OWNERS8
-rw-r--r--core/jni/Android.bp1
-rw-r--r--core/jni/AndroidRuntime.cpp3
-rw-r--r--core/jni/OWNERS3
-rw-r--r--core/jni/android_os_Debug.cpp22
-rw-r--r--core/jni/android_view_SurfaceControl.cpp8
-rw-r--r--core/jni/com_android_internal_content_NativeLibraryHelper.cpp11
-rw-r--r--core/proto/android/app/OWNERS3
-rw-r--r--core/proto/android/providers/settings/global.proto37
-rw-r--r--core/proto/android/server/windowmanagerservice.proto1
-rw-r--r--core/res/AndroidManifest.xml19
-rw-r--r--core/res/res/values/attrs.xml16
-rw-r--r--core/res/res/values/attrs_manifest.xml4
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/strings.xml125
-rw-r--r--core/res/res/values/symbols.xml5
-rw-r--r--core/tests/PlatformCompatFramework/OWNERS7
-rw-r--r--core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java56
-rw-r--r--core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java253
-rw-r--r--core/tests/coretests/OWNERS1
-rw-r--r--data/etc/privapp-permissions-platform.xml4
-rw-r--r--data/etc/services.core.protolog.json6
-rw-r--r--graphics/java/android/graphics/HardwareRenderer.java52
-rw-r--r--keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java6
-rw-r--r--libs/WindowManager/Shell/tests/OWNERS1
-rw-r--r--libs/androidfw/OWNERS2
-rw-r--r--libs/hwui/Properties.cpp19
-rw-r--r--libs/hwui/Properties.h13
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRenderer.cpp11
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp5
-rw-r--r--libs/hwui/renderthread/CanvasContext.h10
-rw-r--r--media/java/android/media/AudioManager.java164
-rw-r--r--media/java/android/media/BtProfileConnectionInfo.aidl20
-rw-r--r--media/java/android/media/BtProfileConnectionInfo.java163
-rwxr-xr-xmedia/java/android/media/IAudioService.aidl15
-rw-r--r--media/java/android/media/Image.java8
-rw-r--r--media/java/android/media/MediaCodec.java66
-rw-r--r--media/java/android/media/MediaCodecInfo.java6
-rw-r--r--media/java/android/media/PlayerBase.java7
-rw-r--r--media/jni/android_media_MediaPlayer.cpp2
-rw-r--r--media/jni/android_media_Utils.cpp1
-rw-r--r--media/native/midi/amidi.cpp10
-rw-r--r--mms/OWNERS3
-rw-r--r--omapi/aidl/Android.bp35
-rw-r--r--omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementChannel.aidl46
-rw-r--r--omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementListener.aidl40
-rw-r--r--omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementReader.aidl44
-rw-r--r--omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementService.aidl45
-rw-r--r--omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementSession.aidl48
-rw-r--r--omapi/aidl/android/se/omapi/ISecureElementChannel.aidl (renamed from core/java/android/se/omapi/ISecureElementChannel.aidl)4
-rw-r--r--omapi/aidl/android/se/omapi/ISecureElementListener.aidl (renamed from core/java/android/se/omapi/ISecureElementListener.aidl)1
-rw-r--r--omapi/aidl/android/se/omapi/ISecureElementReader.aidl (renamed from core/java/android/se/omapi/ISecureElementReader.aidl)3
-rw-r--r--omapi/aidl/android/se/omapi/ISecureElementService.aidl (renamed from core/java/android/se/omapi/ISecureElementService.aidl)14
-rw-r--r--omapi/aidl/android/se/omapi/ISecureElementSession.aidl (renamed from core/java/android/se/omapi/ISecureElementSession.aidl)10
-rw-r--r--omapi/aidl/vts/functional/AccessControlApp/Android.bp54
-rw-r--r--omapi/aidl/vts/functional/AccessControlApp/VtsHalOmapiSeAccessControlTestCases.cpp428
-rw-r--r--omapi/aidl/vts/functional/omapi/Android.bp54
-rw-r--r--omapi/aidl/vts/functional/omapi/VtsHalOmapiSeServiceV1_TargetTest.cpp609
-rw-r--r--omapi/java/Android.bp17
-rw-r--r--omapi/java/android/se/OWNERS (renamed from core/java/android/se/OWNERS)0
-rw-r--r--omapi/java/android/se/omapi/Channel.java (renamed from core/java/android/se/omapi/Channel.java)0
-rw-r--r--omapi/java/android/se/omapi/OWNERS (renamed from core/java/android/se/omapi/OWNERS)0
-rw-r--r--omapi/java/android/se/omapi/Reader.java (renamed from core/java/android/se/omapi/Reader.java)4
-rw-r--r--omapi/java/android/se/omapi/SEService.java (renamed from core/java/android/se/omapi/SEService.java)20
-rw-r--r--omapi/java/android/se/omapi/Session.java (renamed from core/java/android/se/omapi/Session.java)0
-rw-r--r--packages/CarrierDefaultApp/OWNERS3
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java10
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java2
-rw-r--r--packages/Nsd/OWNERS1
-rw-r--r--packages/Nsd/framework/Android.bp54
-rw-r--r--packages/Nsd/framework/aidl-export/android/net/nsd/NsdServiceInfo.aidl19
-rw-r--r--packages/Nsd/framework/src/android/net/nsd/INsdManager.aidl (renamed from core/java/android/net/nsd/INsdManager.aidl)13
-rw-r--r--packages/Nsd/framework/src/android/net/nsd/INsdManagerCallback.aidl39
-rw-r--r--packages/Nsd/framework/src/android/net/nsd/INsdServiceConnector.aidl35
-rw-r--r--packages/Nsd/framework/src/android/net/nsd/NsdManager.java (renamed from core/java/android/net/nsd/NsdManager.java)215
-rw-r--r--packages/Nsd/framework/src/android/net/nsd/NsdServiceInfo.java (renamed from core/java/android/net/nsd/NsdServiceInfo.java)0
-rw-r--r--packages/Nsd/service/Android.bp31
-rw-r--r--packages/Nsd/service/src/com/android/server/INativeDaemonConnectorCallbacks.java (renamed from services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java)0
-rw-r--r--packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java (renamed from services/core/java/com/android/server/NativeDaemonConnector.java)65
-rw-r--r--packages/Nsd/service/src/com/android/server/NativeDaemonConnectorException.java (renamed from services/core/java/com/android/server/NativeDaemonConnectorException.java)0
-rw-r--r--packages/Nsd/service/src/com/android/server/NativeDaemonEvent.java (renamed from services/core/java/com/android/server/NativeDaemonEvent.java)15
-rw-r--r--packages/Nsd/service/src/com/android/server/NativeDaemonTimeoutException.java (renamed from services/core/java/com/android/server/NativeDaemonTimeoutException.java)0
-rw-r--r--packages/Nsd/service/src/com/android/server/NsdService.java (renamed from services/core/java/com/android/server/NsdService.java)556
-rw-r--r--packages/Nsd/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java (renamed from services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java)0
-rw-r--r--packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp21
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java24
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java5
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java7
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java35
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java9
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java11
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/Shell/AndroidManifest.xml15
-rw-r--r--packages/Shell/res/xml/file_provider_paths.xml1
-rw-r--r--packages/Shell/src/com/android/shell/ProfcollectUploadReceiver.java98
-rw-r--r--packages/SystemUI/OWNERS4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java71
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java6
-rw-r--r--rs/jni/Android.bp54
-rw-r--r--rs/jni/Android.mk37
-rw-r--r--services/Android.bp31
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java2
-rw-r--r--services/core/Android.bp11
-rw-r--r--services/core/java/com/android/server/AppFuseMountException.java41
-rw-r--r--services/core/java/com/android/server/BatteryService.java490
-rw-r--r--services/core/java/com/android/server/BluetoothAirplaneModeListener.java3
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java8
-rw-r--r--services/core/java/com/android/server/BluetoothModeChangeHelper.java21
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java6
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java28
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java155
-rw-r--r--services/core/java/com/android/server/VcnManagementService.java2
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java5
-rw-r--r--services/core/java/com/android/server/am/SettingsToPropertiesMapper.java2
-rw-r--r--services/core/java/com/android/server/app/OWNERS1
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java603
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java363
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java123
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java117
-rw-r--r--services/core/java/com/android/server/audio/TEST_MAPPING6
-rw-r--r--services/core/java/com/android/server/biometrics/AuthService.java40
-rw-r--r--services/core/java/com/android/server/compat/OWNERS7
-rw-r--r--services/core/java/com/android/server/connectivity/NetdEventListenerService.java25
-rw-r--r--services/core/java/com/android/server/connectivity/OWNERS8
-rw-r--r--services/core/java/com/android/server/health/HealthHalCallbackHidl.java117
-rw-r--r--services/core/java/com/android/server/health/HealthInfoCallback.java31
-rw-r--r--services/core/java/com/android/server/health/HealthRegCallbackAidl.java119
-rw-r--r--services/core/java/com/android/server/health/HealthServiceWrapper.java119
-rw-r--r--services/core/java/com/android/server/health/HealthServiceWrapperAidl.java215
-rw-r--r--services/core/java/com/android/server/health/HealthServiceWrapperHidl.java313
-rw-r--r--services/core/java/com/android/server/health/Utils.java85
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java12
-rw-r--r--services/core/java/com/android/server/media/BluetoothRouteProvider.java6
-rw-r--r--services/core/java/com/android/server/net/IpConfigStore.java7
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyLogger.java80
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java686
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsFactory.java2
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java30
-rw-r--r--services/core/java/com/android/server/net/OWNERS7
-rw-r--r--services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java12
-rw-r--r--services/core/java/com/android/server/pm/permission/OWNERS6
-rw-r--r--services/core/java/com/android/server/pm/permission/Permission.java7
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java25
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java38
-rw-r--r--services/core/java/com/android/server/stats/bootstrap/StatsBootstrapAtomService.java98
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java65
-rw-r--r--services/core/java/com/android/server/storage/AppFuseBridge.java10
-rwxr-xr-xservices/core/java/com/android/server/tv/TvInputManagerService.java59
-rw-r--r--services/core/java/com/android/server/vcn/VcnGatewayConnection.java93
-rw-r--r--services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java196
-rw-r--r--services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java (renamed from services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java)337
-rw-r--r--services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java175
-rw-r--r--services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java16
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java25
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java9
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java41
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java39
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java10
-rw-r--r--services/core/java/com/android/server/wm/WallpaperWindowToken.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java15
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java140
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java10
-rw-r--r--services/core/jni/Android.bp1
-rw-r--r--services/core/jni/com_android_server_net_NetworkStatsService.cpp122
-rw-r--r--services/java/com/android/server/SystemConfigService.java7
-rw-r--r--services/java/com/android/server/SystemServer.java15
-rw-r--r--services/net/OWNERS8
-rw-r--r--services/people/java/com/android/server/people/data/CallLogQueryHelper.java3
-rw-r--r--services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java130
-rw-r--r--services/proguard.flags11
-rw-r--r--services/tests/mockingservicestests/OWNERS1
-rw-r--r--services/tests/servicestests/OWNERS1
-rw-r--r--services/tests/servicestests/src/com/android/server/BatteryServiceTest.java137
-rw-r--r--services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java39
-rw-r--r--services/tests/servicestests/src/com/android/server/health/HealthServiceWrapperTest.java242
-rw-r--r--services/tests/servicestests/src/com/android/server/health/OWNERS1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java68
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java34
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java29
-rw-r--r--telecomm/java/android/telecom/InCallService.java9
-rw-r--r--telephony/OWNERS3
-rw-r--r--telephony/common/Android.bp5
-rw-r--r--telephony/common/com/android/internal/telephony/TelephonyPermissions.java20
-rw-r--r--telephony/java/android/telephony/AvailableNetworkInfo.java106
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java164
-rw-r--r--telephony/java/android/telephony/ImsManager.java6
-rw-r--r--telephony/java/android/telephony/PhysicalChannelConfig.java5
-rw-r--r--telephony/java/android/telephony/SignalStrengthUpdateRequest.java18
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java9
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java256
-rw-r--r--telephony/java/android/telephony/data/ApnSetting.java663
-rw-r--r--telephony/java/android/telephony/data/DataProfile.java425
-rw-r--r--telephony/java/android/telephony/ims/ImsMmTelManager.java81
-rw-r--r--telephony/java/android/telephony/ims/ImsRcsManager.java68
-rw-r--r--telephony/java/android/telephony/ims/ImsStateCallback.java184
-rw-r--r--telephony/java/android/telephony/ims/SipDelegateManager.java69
-rw-r--r--telephony/java/com/android/internal/telephony/IImsStateCallback.aidl22
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl31
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java2
-rw-r--r--test-mock/Android.bp11
-rw-r--r--test-mock/jarjar-rules.txt7
-rw-r--r--tests/AttestationVerificationTest/OWNERS1
-rw-r--r--tests/FlickerTests/OWNERS3
-rw-r--r--tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java11
-rw-r--r--tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java77
-rw-r--r--tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java24
-rw-r--r--tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java77
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java26
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java6
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java4
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java6
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java84
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java11
-rw-r--r--tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java (renamed from tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java)73
-rw-r--r--tools/aapt2/OWNERS2
-rw-r--r--tools/aapt2/util/Files.cpp2
-rw-r--r--tools/aapt2/util/Files.h2
-rwxr-xr-xtools/aosp/aosp_sha.sh2
327 files changed, 12169 insertions, 5475 deletions
diff --git a/Android.bp b/Android.bp
index 00b419897f34..f8a9e0f0f393 100644
--- a/Android.bp
+++ b/Android.bp
@@ -69,6 +69,7 @@ filegroup {
// Java/AIDL sources under frameworks/base
":framework-annotations",
":framework-blobstore-sources",
+ ":framework-connectivity-nsd-sources",
":framework-core-sources",
":framework-drm-sources",
":framework-graphics-nonupdatable-sources",
@@ -82,6 +83,7 @@ filegroup {
":framework-mca-filterpacks-sources",
":framework-media-sources",
":framework-mms-sources",
+ ":framework-omapi-sources",
":framework-opengl-sources",
":framework-rs-sources",
":framework-sax-sources",
@@ -268,6 +270,7 @@ java_library {
"android.hardware.vibrator-V1.2-java",
"android.hardware.vibrator-V1.3-java",
"android.hardware.vibrator-V2-java",
+ "android.se.omapi-V1-java",
"android.system.suspend.control.internal-java",
"devicepolicyprotosnano",
@@ -328,6 +331,7 @@ java_defaults {
"TeleService-platform-compat-config",
"documents-ui-compat-config",
"calendar-provider-compat-config",
+ "contacts-provider-platform-compat-config",
],
libs: [
"app-compat-annotations",
@@ -433,11 +437,8 @@ filegroup {
"core/java/android/util/LocalLog.java",
"core/java/com/android/internal/util/HexDump.java",
"core/java/com/android/internal/util/IndentingPrintWriter.java",
- "core/java/com/android/internal/util/IState.java",
"core/java/com/android/internal/util/MessageUtils.java",
"core/java/com/android/internal/util/RingBufferIndices.java",
- "core/java/com/android/internal/util/State.java",
- "core/java/com/android/internal/util/StateMachine.java",
"core/java/com/android/internal/util/WakeupMessage.java",
"core/java/com/android/internal/util/TokenBucket.java",
],
@@ -566,6 +567,7 @@ stubs_defaults {
"android.hardware.vibrator-V1.3-java",
"framework-protos",
"art.module.public.api",
+ "sdk_module-lib_current_framework-tethering",
// There are a few classes from modules used by the core that
// need to be resolved by metalava. We use a prebuilt stub of the
// full sdk to ensure we can resolve them. If a new class gets added,
diff --git a/GAME_MANAGER_OWNERS b/GAME_MANAGER_OWNERS
new file mode 100644
index 000000000000..502a9e362202
--- /dev/null
+++ b/GAME_MANAGER_OWNERS
@@ -0,0 +1,2 @@
+lpy@google.com
+timvp@google.com
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 44c55c26153d..d090296523ed 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -318,6 +318,7 @@ java_library {
defaults: ["android-non-updatable_defaults_stubs_current"],
srcs: [":module-lib-api-stubs-docs-non-updatable"],
libs: [
+ "sdk_module-lib_current_framework-tethering",
"sdk_system_current_android",
// NOTE: The below can be removed once the prebuilt stub contains IKE.
"sdk_system_current_android.net.ipsec.ike",
diff --git a/apex/blobstore/README.md b/apex/blobstore/README.md
new file mode 100644
index 000000000000..69af436bf325
--- /dev/null
+++ b/apex/blobstore/README.md
@@ -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
+-->
+
+# BlobStore Manager
+
+## Introduction
+* BlobStoreManager is a system service added in Android R release that facilitates sharing of
+ data blobs among apps.
+* Apps that would like to share data blobs with other apps can do so by contributing those
+ data blobs with the System and can choose how they would like the System to share the data blobs
+ with other apps.
+* Apps can access data blobs shared by other apps from the System using checksum of the data blobs
+ (plus some other data attributes. More details [below](#blob-handle)).
+* The APIs provided by the BlobStoreManager are meant to reduce storage and network usage by
+ reusing the data available on the device instead of downloading the same data again and having
+ multiple copies of the same data on disk.
+* It is not meant to provide access to the data which apps otherwise would not be able to access.
+ In other words, if an app’s only means of obtaining access to certain data is through
+ BlobStoreManager, then that use case is not really intended or supported.
+* For example, if earlier an app was downloading certain shared data from a server, then by using
+ BlobStoreManager, it can first check whether or not the data is already available on the device
+ before downloading.
+
+## Concepts
+### Blob handle
+Blob handle is the identifier of the data and it is what apps need to use for referring to the
+data blobs. Currently, this is made of following bits of information:
+* SHA256 checksum of data
+* Data label: A user readable string that indicates what the data blob is.
+ This is meant to be used when surfacing a list of blobs to the user.
+* Data expiry time: A timestamp after which the data blob should be considered invalid and not
+ allowed to be accessed by any app.
+* Data tag: An opaque string associated with the blob. System does not interpret this in any way or
+ use it for any purposes other than when checking whether two Blob handle identifiers are referring
+ to the same data blob. This is meant to be used by the apps, either for categorization for
+ data blobs or for adding additional identifiers. For example, an app can add tags like
+ *machine_learning* or *media* depending on the data blob if necessary.
+
+When comparing two Blob handles, the System will compare all the pieces of information above and
+only when two Blob handles are equal, the data blobs corresponding to those identifiers are
+considered equal.
+
+### Blob sharing session
+Session is a way to allow apps to contribute data over multiple time intervals. Each session is
+associated with a unique Identifier that is created and obtained by the apps by calling
+[BlobStoreManager#createSession](https://developer.android.com/reference/android/app/blob/BlobStoreManager#createSession(android.app.blob.BlobHandle)).
+Apps can save the Identifier associated with a session and use it to open and close it
+multiple times for contributing the data. For example, if an app is downloading
+some content over the network, it can start a Session and start contributing this data to the
+System immediately and if the network connection is lost for any reason, the app can close this
+session. When the download resumes, the app can reopen the session and start contributing again.
+Note that once the entire data is contributed, the app has no reason to hold on to the Session Id.
+
+### Blob commit
+Since a data blob can be contributed in a session over multiple time intervals, an app closing a
+session does not imply that the contribution is completed. So, *commit* is added as an explicit
+event / signal for the app to indicate that the contribution of the data blob is completed.
+At this point, the System can verify the data blob does indeed correspond to the Blob handle used
+by the app and prevent the app from making any further modifications to the data blob. Once the
+data blob is committed and verified by the System, it is available for other applications to access.
+
+### Access modes
+When an application contributes a data blob to the System, it can choose to specify how it would
+like the System to share this data blob with other applications. Access modes refer to the type of
+access that apps specified when contributing a data blob. As of Android S release, there are
+four access modes:
+* Allow specific packages: Apps can specify a specific set of applications that are allowed to
+ access their data blob.
+* Allow packages with the same signature: Apps can specify that only the applications that are
+ signed with the same certificate as them can access their data blob.
+* Allow public access: Apps can specify that any other app on the device can access their data blob.
+* Allow private access: Apps can specify that no other app can access their data blob unless they
+ happen to contribute the same data blob.
+ * Note that in this case, two apps might download the same data blob and contribute to the System
+ in which case we are not saving anything in terms of bandwidth usage, but we would still be
+ saving disk usage since we would be keeping only one copy of data on disk.
+
+### Lease
+Leasing a blob is a way to specify that an application is interested in using a data blob
+and would like the System to not delete this data blob. Applications can also access a blob
+without holding a lease on it, in which case the System can choose to delete the data blob at any
+time. So, if an application wants to make sure a data blob is available for access for a certain
+period, it is recommended that the application acquire a lease on the data blob. Applications can
+either specify upfront how long they would like to hold the lease for (which is called the lease
+expiry time), or they can acquire a lease without specifying a time period and release the lease
+when they are done with the data blob.
+
+## Sharing data blobs across users
+By default, data blobs are only accessible to applications in the user in which the data blob was
+contributed, but if an application holds the permission
+[ACCESS_BLOBS_ACROSS_USERS](https://developer.android.com/reference/android/Manifest.permission#ACCESS_BLOBS_ACROSS_USERS),
+then they are allowed to access blobs that are contributed by the applications in the other users.
+As of Android S, this permission is only available to following set of applications:
+* Apps signed with the platform certificate
+* Privileged applications
+* Applications holding the
+ [ASSISTANT](https://developer.android.com/reference/android/app/role/RoleManager#ROLE_ASSISTANT)
+ role
+* Development applications
+
+Note that the access modes that applications choose while committing the data blobs still apply
+when these data blobs are accessed across users. So for example, if *appA* contributed a
+data blob in *user0* and specified to share this data blob with only a specific set of
+applications [*appB*, *appC*], then *appD* on *user10* will not be able to access this data blob
+even if the app is granted the `ACCESS_BLOBS_ACROSS_USERS` permission.
+
+When apps that are allowed to access blobs across users
+(i.e. those holding the permission `ACCESS_BLOBS_ACROSS_USERS`) try to access a data blob,
+they can do so as if it is any other data blob. In other words, the applications don’t need to
+know where the data blob is contributed, because the System will automatically check and will
+allow access if this data blob is available either on the user in which the calling application
+is running in or other users. \ No newline at end of file
diff --git a/apex/media/framework/java/android/media/MediaTranscodingManager.java b/apex/media/framework/java/android/media/MediaTranscodingManager.java
index 93d58d07f81a..1a84929c678f 100644
--- a/apex/media/framework/java/android/media/MediaTranscodingManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodingManager.java
@@ -952,6 +952,8 @@ public final class MediaTranscodingManager {
*
* @return the video track format to be used if transcoding should be performed,
* and null otherwise.
+ * @throws IllegalArgumentException if the hinted source video format contains invalid
+ * parameters.
*/
@Nullable
public MediaFormat resolveVideoFormat() {
@@ -962,20 +964,19 @@ public final class MediaTranscodingManager {
MediaFormat videoTrackFormat = new MediaFormat(mSrcVideoFormatHint);
videoTrackFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_AVC);
- int width = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_WIDTH);
- int height = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_HEIGHT);
+ int width = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_WIDTH, -1);
+ int height = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_HEIGHT, -1);
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException(
"Source Width and height must be larger than 0");
}
- float frameRate = 30.0f; // default to 30fps.
- if (mSrcVideoFormatHint.containsKey(MediaFormat.KEY_FRAME_RATE)) {
- frameRate = mSrcVideoFormatHint.getFloat(MediaFormat.KEY_FRAME_RATE);
- if (frameRate <= 0) {
- throw new IllegalArgumentException(
- "frameRate must be larger than 0");
- }
+ float frameRate =
+ mSrcVideoFormatHint.getNumber(MediaFormat.KEY_FRAME_RATE, 30.0)
+ .floatValue();
+ if (frameRate <= 0) {
+ throw new IllegalArgumentException(
+ "frameRate must be larger than 0");
}
int bitrate = getAVCBitrate(width, height, frameRate);
diff --git a/boot/boot-image-profile.txt b/boot/boot-image-profile.txt
index 5f27cc722105..82269d4a2467 100644
--- a/boot/boot-image-profile.txt
+++ b/boot/boot-image-profile.txt
@@ -2899,10 +2899,8 @@ HSPLandroid/app/assist/AssistStructure$ViewNode;->getAutofillId()Landroid/view/a
HSPLandroid/app/assist/AssistStructure$ViewNode;->getChildCount()I
HSPLandroid/app/assist/AssistStructure$ViewNode;->writeSelfToParcel(Landroid/os/Parcel;Landroid/os/PooledStringWriter;Z[FZ)I+]Landroid/view/autofill/AutofillId;Landroid/view/autofill/AutofillId;]Landroid/graphics/Matrix;Landroid/graphics/Matrix;]Landroid/app/assist/AssistStructure$ViewNodeText;Landroid/app/assist/AssistStructure$ViewNodeText;]Landroid/os/Parcel;Landroid/os/Parcel;
HSPLandroid/app/assist/AssistStructure$ViewNode;->writeString(Landroid/os/Parcel;Landroid/os/PooledStringWriter;Ljava/lang/String;)V+]Landroid/os/PooledStringWriter;Landroid/os/PooledStringWriter;]Landroid/os/Parcel;Landroid/os/Parcel;
-HSPLandroid/app/assist/AssistStructure$ViewNodeBuilder;-><init>()V
HSPLandroid/app/assist/AssistStructure$ViewNodeBuilder;->getChildCount()I
HSPLandroid/app/assist/AssistStructure$ViewNodeBuilder;->getNodeText()Landroid/app/assist/AssistStructure$ViewNodeText;
-HSPLandroid/app/assist/AssistStructure$ViewNodeBuilder;->getViewNode()Landroid/app/assist/AssistStructure$ViewNode;
HSPLandroid/app/assist/AssistStructure$ViewNodeBuilder;->newChild(I)Landroid/view/ViewStructure;
HSPLandroid/app/assist/AssistStructure$ViewNodeBuilder;->setAutofillHints([Ljava/lang/String;)V
HSPLandroid/app/assist/AssistStructure$ViewNodeBuilder;->setAutofillId(Landroid/view/autofill/AutofillId;)V
@@ -3883,8 +3881,6 @@ HSPLandroid/content/ContentResolver$ResultListener;-><init>()V
HSPLandroid/content/ContentResolver$ResultListener;-><init>(Landroid/content/ContentResolver$1;)V
HSPLandroid/content/ContentResolver$ResultListener;->onResult(Landroid/os/Bundle;)V+]Landroid/os/ParcelableException;Landroid/os/ParcelableException;]Ljava/lang/Object;Landroid/content/ContentResolver$StringResultListener;,Landroid/content/ContentResolver$UriResultListener;]Landroid/os/Bundle;Landroid/os/Bundle;]Landroid/content/ContentResolver$ResultListener;Landroid/content/ContentResolver$UriResultListener;,Landroid/content/ContentResolver$StringResultListener;
HSPLandroid/content/ContentResolver$ResultListener;->waitForResult(J)V+]Ljava/lang/Object;Landroid/content/ContentResolver$StringResultListener;
-HSPLandroid/content/ContentResolver$StringResultListener;-><init>()V
-HSPLandroid/content/ContentResolver$StringResultListener;-><init>(Landroid/content/ContentResolver$1;)V
HSPLandroid/content/ContentResolver$StringResultListener;->getResultFromBundle(Landroid/os/Bundle;)Ljava/lang/Object;+]Landroid/content/ContentResolver$StringResultListener;Landroid/content/ContentResolver$StringResultListener;
HSPLandroid/content/ContentResolver$StringResultListener;->getResultFromBundle(Landroid/os/Bundle;)Ljava/lang/String;+]Landroid/os/Bundle;Landroid/os/Bundle;
HSPLandroid/content/ContentResolver;-><init>(Landroid/content/Context;)V
@@ -7029,7 +7025,6 @@ HSPLandroid/graphics/RectF;->width()F
HSPLandroid/graphics/Region$1;->createFromParcel(Landroid/os/Parcel;)Landroid/graphics/Region;
HSPLandroid/graphics/Region$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object;+]Landroid/graphics/Region$1;Landroid/graphics/Region$1;
HSPLandroid/graphics/Region;-><init>()V
-HSPLandroid/graphics/Region;-><init>(IIII)V
HSPLandroid/graphics/Region;-><init>(J)V
HSPLandroid/graphics/Region;->access$000(Landroid/os/Parcel;)J
HSPLandroid/graphics/Region;->equals(Ljava/lang/Object;)Z
@@ -7075,7 +7070,6 @@ HSPLandroid/graphics/RenderNode;->getTranslationZ()F
HSPLandroid/graphics/RenderNode;->hasDisplayList()Z
HSPLandroid/graphics/RenderNode;->hasIdentityMatrix()Z
HSPLandroid/graphics/RenderNode;->isAttached()Z+]Landroid/graphics/RenderNode$AnimationHost;Landroid/view/ViewAnimationHostBridge;
-HSPLandroid/graphics/RenderNode;->isPivotExplicitlySet()Z
HSPLandroid/graphics/RenderNode;->offsetTopAndBottom(I)Z
HSPLandroid/graphics/RenderNode;->setAlpha(F)Z
HSPLandroid/graphics/RenderNode;->setAnimationMatrix(Landroid/graphics/Matrix;)Z+]Landroid/graphics/Matrix;Landroid/graphics/Matrix;
@@ -8283,7 +8277,6 @@ HSPLandroid/hardware/CameraStatus$1;->newArray(I)[Ljava/lang/Object;
HSPLandroid/hardware/GeomagneticField$LegendreTable;-><init>(IF)V
HSPLandroid/hardware/GeomagneticField;-><init>(FFFJ)V
HSPLandroid/hardware/GeomagneticField;->computeGeocentricCoordinates(FFF)V
-HSPLandroid/hardware/GeomagneticField;->getDeclination()F
HSPLandroid/hardware/HardwareBuffer$1;->createFromParcel(Landroid/os/Parcel;)Landroid/hardware/HardwareBuffer;
HSPLandroid/hardware/HardwareBuffer$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object;
HSPLandroid/hardware/HardwareBuffer;-><init>(J)V+]Llibcore/util/NativeAllocationRegistry;Llibcore/util/NativeAllocationRegistry;]Ljava/lang/Class;Ljava/lang/Class;]Ldalvik/system/CloseGuard;Ldalvik/system/CloseGuard;
@@ -11353,7 +11346,6 @@ HSPLandroid/media/SoundPool$Builder;->setMaxStreams(I)Landroid/media/SoundPool$B
HSPLandroid/media/SoundPool$EventHandler;->handleMessage(Landroid/os/Message;)V
HSPLandroid/media/SoundPool;-><init>(ILandroid/media/AudioAttributes;)V
HSPLandroid/media/SoundPool;-><init>(ILandroid/media/AudioAttributes;Landroid/media/SoundPool$1;)V
-HSPLandroid/media/SoundPool;->load(Ljava/lang/String;I)I
HSPLandroid/media/SoundPool;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V
HSPLandroid/media/SoundPool;->setOnLoadCompleteListener(Landroid/media/SoundPool$OnLoadCompleteListener;)V
HSPLandroid/media/SubtitleController$1;->handleMessage(Landroid/os/Message;)Z
@@ -11389,10 +11381,8 @@ HSPLandroid/media/Utils;->parseSizeRange(Ljava/lang/Object;)Landroid/util/Pair;
HSPLandroid/media/Utils;->sortDistinctRanges([Landroid/util/Range;)V
HSPLandroid/media/audiofx/AudioEffect$Descriptor;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
HSPLandroid/media/audiopolicy/AudioProductStrategy$AudioAttributesGroup;-><init>(II[Landroid/media/AudioAttributes;)V
-HSPLandroid/media/audiopolicy/AudioProductStrategy$AudioAttributesGroup;->supportsStreamType(I)Z
HSPLandroid/media/audiopolicy/AudioProductStrategy;-><init>(Ljava/lang/String;I[Landroid/media/audiopolicy/AudioProductStrategy$AudioAttributesGroup;)V
HSPLandroid/media/audiopolicy/AudioProductStrategy;->attributesMatches(Landroid/media/AudioAttributes;Landroid/media/AudioAttributes;)Z+]Landroid/media/AudioAttributes;Landroid/media/AudioAttributes;
-HSPLandroid/media/audiopolicy/AudioProductStrategy;->getAudioAttributesForLegacyStreamType(I)Landroid/media/AudioAttributes;+]Landroid/media/audiopolicy/AudioProductStrategy$AudioAttributesGroup;Landroid/media/audiopolicy/AudioProductStrategy$AudioAttributesGroup;
HSPLandroid/media/audiopolicy/AudioProductStrategy;->getAudioAttributesForStrategyWithLegacyStreamType(I)Landroid/media/AudioAttributes;
HSPLandroid/media/audiopolicy/AudioProductStrategy;->getAudioProductStrategies()Ljava/util/List;
HSPLandroid/media/audiopolicy/AudioProductStrategy;->getLegacyStreamTypeForStrategyWithAudioAttributes(Landroid/media/AudioAttributes;)I+]Landroid/media/audiopolicy/AudioProductStrategy;Landroid/media/audiopolicy/AudioProductStrategy;]Ljava/util/List;Ljava/util/ArrayList;]Ljava/util/Iterator;Ljava/util/ArrayList$Itr;
@@ -13125,7 +13115,6 @@ HSPLandroid/os/ParcelableException;-><init>(Ljava/lang/Throwable;)V
HSPLandroid/os/ParcelableParcel$1;->createFromParcel(Landroid/os/Parcel;)Landroid/os/ParcelableParcel;
HSPLandroid/os/ParcelableParcel$1;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object;
HSPLandroid/os/ParcelableParcel;-><init>(Landroid/os/Parcel;Ljava/lang/ClassLoader;)V
-HSPLandroid/os/ParcelableParcel;-><init>(Ljava/lang/ClassLoader;)V
HSPLandroid/os/ParcelableParcel;->getClassLoader()Ljava/lang/ClassLoader;
HSPLandroid/os/ParcelableParcel;->getParcel()Landroid/os/Parcel;
HSPLandroid/os/ParcelableParcel;->writeToParcel(Landroid/os/Parcel;I)V
@@ -13481,7 +13470,6 @@ HSPLandroid/os/TelephonyServiceManager;->getTelephonyServiceRegisterer()Landroid
HSPLandroid/os/Temperature;-><init>(FILjava/lang/String;I)V
HSPLandroid/os/Temperature;->getStatus()I
HSPLandroid/os/Temperature;->isValidStatus(I)Z
-HSPLandroid/os/Temperature;->isValidType(I)Z
HSPLandroid/os/ThreadLocalWorkSource$$ExternalSyntheticLambda0;->get()Ljava/lang/Object;
HSPLandroid/os/ThreadLocalWorkSource;->getToken()J+]Ljava/lang/Integer;Ljava/lang/Integer;]Ljava/lang/ThreadLocal;Ljava/lang/ThreadLocal$SuppliedThreadLocal;
HSPLandroid/os/ThreadLocalWorkSource;->getUid()I+]Ljava/lang/Integer;Ljava/lang/Integer;]Ljava/lang/ThreadLocal;Ljava/lang/ThreadLocal$SuppliedThreadLocal;
@@ -18488,7 +18476,6 @@ HSPLandroid/view/ViewRootImpl$HighContrastTextManager;-><init>(Landroid/view/Vie
HSPLandroid/view/ViewRootImpl$ImeInputStage;-><init>(Landroid/view/ViewRootImpl;Landroid/view/ViewRootImpl$InputStage;Ljava/lang/String;)V
HSPLandroid/view/ViewRootImpl$ImeInputStage;->onFinishedInputEvent(Ljava/lang/Object;Z)V
HSPLandroid/view/ViewRootImpl$ImeInputStage;->onProcess(Landroid/view/ViewRootImpl$QueuedInputEvent;)I
-HSPLandroid/view/ViewRootImpl$InputMetricsListener;-><init>(Landroid/view/ViewRootImpl;)V
HSPLandroid/view/ViewRootImpl$InputMetricsListener;->onFrameMetricsAvailable(I)V+]Landroid/view/ViewRootImpl$WindowInputEventReceiver;Landroid/view/ViewRootImpl$WindowInputEventReceiver;]Ljava/lang/StringBuilder;Ljava/lang/StringBuilder;]Landroid/view/InputEventReceiver;Landroid/view/ViewRootImpl$WindowInputEventReceiver;
HSPLandroid/view/ViewRootImpl$InputStage;-><init>(Landroid/view/ViewRootImpl;Landroid/view/ViewRootImpl$InputStage;)V
HSPLandroid/view/ViewRootImpl$InputStage;->apply(Landroid/view/ViewRootImpl$QueuedInputEvent;I)V+]Landroid/view/ViewRootImpl$InputStage;megamorphic_types
@@ -20395,7 +20382,6 @@ HSPLandroid/widget/OverScroller$SplineOverScroller;->finish()V
HSPLandroid/widget/OverScroller$SplineOverScroller;->fling(IIIII)V
HSPLandroid/widget/OverScroller$SplineOverScroller;->getSplineDeceleration(I)D
HSPLandroid/widget/OverScroller$SplineOverScroller;->getSplineFlingDistance(I)D
-HSPLandroid/widget/OverScroller$SplineOverScroller;->getSplineFlingDuration(I)I
HSPLandroid/widget/OverScroller$SplineOverScroller;->onEdgeReached()V
HSPLandroid/widget/OverScroller$SplineOverScroller;->springback(III)Z
HSPLandroid/widget/OverScroller$SplineOverScroller;->startScroll(III)V
@@ -22568,10 +22554,7 @@ HSPLcom/android/internal/widget/ILockSettings$Stub;->asInterface(Landroid/os/IBi
HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker$1;->onIsNonStrongBiometricAllowedChanged(ZI)V
HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker$1;->onStrongAuthRequiredChanged(II)V
HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker$H;->handleMessage(Landroid/os/Message;)V
-HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker;-><init>(Landroid/content/Context;)V
-HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker;-><init>(Landroid/content/Context;Landroid/os/Looper;)V
HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker;->getStrongAuthForUser(I)I+]Landroid/util/SparseIntArray;Landroid/util/SparseIntArray;
-HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker;->getStub()Landroid/app/trust/IStrongAuthTracker$Stub;
HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker;->handleIsNonStrongBiometricAllowedChanged(ZI)V
HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker;->handleStrongAuthRequiredChanged(II)V
HSPLcom/android/internal/widget/LockPatternUtils$StrongAuthTracker;->isNonStrongBiometricAllowedAfterIdleTimeout(I)Z
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index 1e72ddf8ecfc..0b439df403e0 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -545,6 +545,8 @@ public class Instrument {
mWm.setAnimationScales(oldAnims);
}
}
+ // Exit from here instead of going down the path of normal shutdown which is slow.
+ System.exit(0);
}
private static String readLogcat(long startTimeMs) {
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 3109c5c1e075..6b8a775ef838 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -1348,7 +1348,7 @@ bool BootAnimation::playAnimation(const Animation& animation) {
int err;
do {
err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, nullptr);
- } while (err<0 && errno == EINTR);
+ } while (err == EINTR);
}
checkExit();
diff --git a/cmds/idmap2/OWNERS b/cmds/idmap2/OWNERS
index 69dfcc98340d..062ffd41348a 100644
--- a/cmds/idmap2/OWNERS
+++ b/cmds/idmap2/OWNERS
@@ -1,4 +1,4 @@
set noparent
toddke@google.com
-rtmitchell@google.com
-patb@google.com \ No newline at end of file
+patb@google.com
+zyy@google.com
diff --git a/config/README.md b/config/README.md
new file mode 100644
index 000000000000..450a5c695c82
--- /dev/null
+++ b/config/README.md
@@ -0,0 +1,13 @@
+# Configuration files for ART compiling the framework
+
+* boot-image-profile.txt: A list of methods from the boot classpath to be compiled by dex2oat.
+ The order in the file is not relevant.
+* boot-profile.txt: An ordered list of methods from the boot classpath to be compiled by
+ the JIT in the order provided in the file. Used by JIT zygote, when on-device
+ signing failed.
+* dirty-image-objects: List of objects in the boot image which are known to
+ become dirty. This helps binning objects in the image file.
+* preloaded-classes: classes that will be allocated in the boot image, and
+ initialized by the zygote.
+* preloaded-classes-denylist: Classes that should not be initialized in the
+ zygote, as they have app-specific behavior.
diff --git a/config/generate-preloaded-classes.sh b/config/generate-preloaded-classes.sh
deleted file mode 100755
index b17a3660e1f1..000000000000
--- a/config/generate-preloaded-classes.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-if [ "$#" -lt 2 ]; then
- echo "Usage $0 <input classes file> <denylist file> [extra classes files]"
- exit 1
-fi
-
-# Write file headers first
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-cat "$DIR/copyright-header"
-echo "# Preloaded-classes filter file for phones.
-#
-# Classes in this file will be allocated into the boot image, and forcibly initialized in
-# the zygote during initialization. This is a trade-off, using virtual address space to share
-# common heap between apps.
-#
-# This file has been derived for mainline phone (and tablet) usage.
-#"
-
-input=$1
-denylist=$2
-shift 2
-extra_classes_files=("$@")
-
-# Disable locale to enable lexicographical sorting
-LC_ALL=C sort "$input" "${extra_classes_files[@]}" | uniq | grep -f "$denylist" -v -F -x | grep -v "\$NoPreloadHolder"
diff --git a/config/preloaded-classes-extra b/config/preloaded-classes-extra
deleted file mode 100644
index 09f393ad4844..000000000000
--- a/config/preloaded-classes-extra
+++ /dev/null
@@ -1,14 +0,0 @@
-android.icu.impl.coll.CollationRoot
-android.icu.impl.IDNA2003
-android.icu.impl.number.Parse
-android.icu.util.TimeZone
-android.media.ImageReader
-android.media.MediaCodecList
-android.media.MediaPlayer
-android.media.SoundPool
-android.text.format.Formatter
-android.text.Html$HtmlParser
-android.util.Log$PreloadHolder
-com.android.org.conscrypt.TrustedCertificateStore
-org.ccil.cowan.tagsoup.HTMLScanner
-sun.security.jca.Providers
diff --git a/core/api/Android.bp b/core/api/Android.bp
index 170febb4f766..114a957674ae 100644
--- a/core/api/Android.bp
+++ b/core/api/Android.bp
@@ -51,11 +51,17 @@ filegroup {
filegroup {
name: "non-updatable-module-lib-current.txt",
srcs: ["module-lib-current.txt"],
- visibility: ["//frameworks/base/api"],
+ visibility: [
+ "//frameworks/base/api",
+ "//cts/tests/signature/api",
+ ],
}
filegroup {
name: "non-updatable-module-lib-removed.txt",
srcs: ["module-lib-removed.txt"],
- visibility: ["//frameworks/base/api"],
+ visibility: [
+ "//frameworks/base/api",
+ "//cts/tests/signature/api",
+ ],
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 1c0144546239..8c313a25ccec 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -120,6 +120,7 @@ package android {
field @Deprecated public static final String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
field @Deprecated public static final String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
field public static final String QUERY_ALL_PACKAGES = "android.permission.QUERY_ALL_PACKAGES";
+ field public static final String READ_BASIC_PHONE_STATE = "android.permission.READ_BASIC_PHONE_STATE";
field public static final String READ_CALENDAR = "android.permission.READ_CALENDAR";
field public static final String READ_CALL_LOG = "android.permission.READ_CALL_LOG";
field public static final String READ_CONTACTS = "android.permission.READ_CONTACTS";
@@ -9023,6 +9024,72 @@ package android.bluetooth {
field public static final int TELEPHONY = 4194304; // 0x400000
}
+ public final class BluetoothCodecConfig implements android.os.Parcelable {
+ ctor public BluetoothCodecConfig(int);
+ method public int describeContents();
+ method public int getBitsPerSample();
+ method public int getChannelMode();
+ method public int getCodecPriority();
+ method public long getCodecSpecific1();
+ method public long getCodecSpecific2();
+ method public long getCodecSpecific3();
+ method public long getCodecSpecific4();
+ method public int getCodecType();
+ method public static int getMaxCodecType();
+ method public int getSampleRate();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int BITS_PER_SAMPLE_16 = 1; // 0x1
+ field public static final int BITS_PER_SAMPLE_24 = 2; // 0x2
+ field public static final int BITS_PER_SAMPLE_32 = 4; // 0x4
+ field public static final int BITS_PER_SAMPLE_NONE = 0; // 0x0
+ field public static final int CHANNEL_MODE_MONO = 1; // 0x1
+ field public static final int CHANNEL_MODE_NONE = 0; // 0x0
+ field public static final int CHANNEL_MODE_STEREO = 2; // 0x2
+ field public static final int CODEC_PRIORITY_DEFAULT = 0; // 0x0
+ field public static final int CODEC_PRIORITY_DISABLED = -1; // 0xffffffff
+ field public static final int CODEC_PRIORITY_HIGHEST = 1000000; // 0xf4240
+ field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothCodecConfig> CREATOR;
+ field public static final int SAMPLE_RATE_176400 = 16; // 0x10
+ field public static final int SAMPLE_RATE_192000 = 32; // 0x20
+ field public static final int SAMPLE_RATE_44100 = 1; // 0x1
+ field public static final int SAMPLE_RATE_48000 = 2; // 0x2
+ field public static final int SAMPLE_RATE_88200 = 4; // 0x4
+ field public static final int SAMPLE_RATE_96000 = 8; // 0x8
+ field public static final int SAMPLE_RATE_NONE = 0; // 0x0
+ field public static final int SOURCE_CODEC_TYPE_AAC = 1; // 0x1
+ field public static final int SOURCE_CODEC_TYPE_APTX = 2; // 0x2
+ field public static final int SOURCE_CODEC_TYPE_APTX_HD = 3; // 0x3
+ field public static final int SOURCE_CODEC_TYPE_INVALID = 1000000; // 0xf4240
+ field public static final int SOURCE_CODEC_TYPE_LDAC = 4; // 0x4
+ field public static final int SOURCE_CODEC_TYPE_SBC = 0; // 0x0
+ }
+
+ public static final class BluetoothCodecConfig.Builder {
+ ctor public BluetoothCodecConfig.Builder();
+ method @NonNull public android.bluetooth.BluetoothCodecConfig build();
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setBitsPerSample(int);
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setChannelMode(int);
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecPriority(int);
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecSpecific1(long);
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecSpecific2(long);
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecSpecific3(long);
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecSpecific4(long);
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setCodecType(int);
+ method @NonNull public android.bluetooth.BluetoothCodecConfig.Builder setSampleRate(int);
+ }
+
+ public final class BluetoothCodecStatus implements android.os.Parcelable {
+ ctor public BluetoothCodecStatus(@Nullable android.bluetooth.BluetoothCodecConfig, @Nullable java.util.List<android.bluetooth.BluetoothCodecConfig>, @Nullable java.util.List<android.bluetooth.BluetoothCodecConfig>);
+ method public int describeContents();
+ method @Nullable public android.bluetooth.BluetoothCodecConfig getCodecConfig();
+ method @NonNull public java.util.List<android.bluetooth.BluetoothCodecConfig> getCodecsLocalCapabilities();
+ method @NonNull public java.util.List<android.bluetooth.BluetoothCodecConfig> getCodecsSelectableCapabilities();
+ method public boolean isCodecConfigSelectable(@Nullable android.bluetooth.BluetoothCodecConfig);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothCodecStatus> CREATOR;
+ field public static final String EXTRA_CODEC_STATUS = "android.bluetooth.extra.CODEC_STATUS";
+ }
+
public final class BluetoothCsipSetCoordinator implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
method public void close();
method protected void finalize();
@@ -9125,8 +9192,10 @@ package android.bluetooth {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean requestMtu(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setCharacteristicNotification(android.bluetooth.BluetoothGattCharacteristic, boolean);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void setPreferredPhy(int, int, int);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int writeCharacteristic(@NonNull android.bluetooth.BluetoothGattCharacteristic, @NonNull byte[], int);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int writeDescriptor(@NonNull android.bluetooth.BluetoothGattDescriptor, @NonNull byte[]);
field public static final int CONNECTION_PRIORITY_BALANCED = 0; // 0x0
field public static final int CONNECTION_PRIORITY_HIGH = 1; // 0x1
field public static final int CONNECTION_PRIORITY_LOW_POWER = 2; // 0x2
@@ -9145,11 +9214,14 @@ package android.bluetooth {
public abstract class BluetoothGattCallback {
ctor public BluetoothGattCallback();
- method public void onCharacteristicChanged(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic);
- method public void onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int);
+ method @Deprecated public void onCharacteristicChanged(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic);
+ method public void onCharacteristicChanged(@NonNull android.bluetooth.BluetoothGatt, @NonNull android.bluetooth.BluetoothGattCharacteristic, @NonNull byte[]);
+ method @Deprecated public void onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int);
+ method public void onCharacteristicRead(@NonNull android.bluetooth.BluetoothGatt, @NonNull android.bluetooth.BluetoothGattCharacteristic, @NonNull byte[], int);
method public void onCharacteristicWrite(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int);
method public void onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int);
- method public void onDescriptorRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int);
+ method @Deprecated public void onDescriptorRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int);
+ method public void onDescriptorRead(@NonNull android.bluetooth.BluetoothGatt, @NonNull android.bluetooth.BluetoothGattDescriptor, int, @NonNull byte[]);
method public void onDescriptorWrite(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int);
method public void onMtuChanged(android.bluetooth.BluetoothGatt, int, int);
method public void onPhyRead(android.bluetooth.BluetoothGatt, int, int, int);
@@ -9166,20 +9238,20 @@ package android.bluetooth {
method public int describeContents();
method public android.bluetooth.BluetoothGattDescriptor getDescriptor(java.util.UUID);
method public java.util.List<android.bluetooth.BluetoothGattDescriptor> getDescriptors();
- method public Float getFloatValue(int, int);
+ method @Deprecated public Float getFloatValue(int, int);
method public int getInstanceId();
- method public Integer getIntValue(int, int);
+ method @Deprecated public Integer getIntValue(int, int);
method public int getPermissions();
method public int getProperties();
method public android.bluetooth.BluetoothGattService getService();
- method public String getStringValue(int);
+ method @Deprecated public String getStringValue(int);
method public java.util.UUID getUuid();
- method public byte[] getValue();
+ method @Deprecated public byte[] getValue();
method public int getWriteType();
- method public boolean setValue(byte[]);
- method public boolean setValue(int, int, int);
- method public boolean setValue(int, int, int, int);
- method public boolean setValue(String);
+ method @Deprecated public boolean setValue(byte[]);
+ method @Deprecated public boolean setValue(int, int, int);
+ method @Deprecated public boolean setValue(int, int, int, int);
+ method @Deprecated public boolean setValue(String);
method public void setWriteType(int);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattCharacteristic> CREATOR;
@@ -9219,8 +9291,8 @@ package android.bluetooth {
method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic();
method public int getPermissions();
method public java.util.UUID getUuid();
- method public byte[] getValue();
- method public boolean setValue(byte[]);
+ method @Deprecated public byte[] getValue();
+ method @Deprecated public boolean setValue(byte[]);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattDescriptor> CREATOR;
field public static final byte[] DISABLE_NOTIFICATION_VALUE;
@@ -9247,7 +9319,8 @@ package android.bluetooth {
method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
method public android.bluetooth.BluetoothGattService getService(java.util.UUID);
method public java.util.List<android.bluetooth.BluetoothGattService> getServices();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean notifyCharacteristicChanged(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothGattCharacteristic, boolean);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean notifyCharacteristicChanged(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothGattCharacteristic, boolean);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int notifyCharacteristicChanged(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothGattCharacteristic, boolean, @NonNull byte[]);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void readPhy(android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean removeService(android.bluetooth.BluetoothGattService);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean sendResponse(android.bluetooth.BluetoothDevice, int, int, int, byte[]);
@@ -9508,8 +9581,12 @@ package android.bluetooth {
field public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2; // 0x2
field public static final int ERROR_BLUETOOTH_NOT_ENABLED = 1; // 0x1
field public static final int ERROR_DEVICE_NOT_BONDED = 3; // 0x3
- field public static final int ERROR_FEATURE_NOT_SUPPORTED = 8; // 0x8
+ field public static final int ERROR_FEATURE_NOT_SUPPORTED = 10; // 0xa
+ field public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 101; // 0x65
+ field public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 102; // 0x66
field public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6; // 0x6
+ field public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8; // 0x8
+ field public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9; // 0x9
field public static final int ERROR_UNKNOWN = 2147483647; // 0x7fffffff
field public static final int SUCCESS = 0; // 0x0
}
@@ -9537,6 +9614,7 @@ package android.bluetooth.le {
method public java.util.Map<android.os.ParcelUuid,byte[]> getServiceData();
method @NonNull public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids();
method public java.util.List<android.os.ParcelUuid> getServiceUuids();
+ method @NonNull public java.util.List<android.bluetooth.le.TransportDiscoveryData> getTransportDiscoveryData();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.AdvertiseData> CREATOR;
}
@@ -9547,6 +9625,7 @@ package android.bluetooth.le {
method public android.bluetooth.le.AdvertiseData.Builder addServiceData(android.os.ParcelUuid, byte[]);
method @NonNull public android.bluetooth.le.AdvertiseData.Builder addServiceSolicitationUuid(@NonNull android.os.ParcelUuid);
method public android.bluetooth.le.AdvertiseData.Builder addServiceUuid(android.os.ParcelUuid);
+ method @NonNull public android.bluetooth.le.AdvertiseData.Builder addTransportDiscoveryData(@NonNull android.bluetooth.le.TransportDiscoveryData);
method public android.bluetooth.le.AdvertiseData build();
method public android.bluetooth.le.AdvertiseData.Builder setIncludeDeviceName(boolean);
method public android.bluetooth.le.AdvertiseData.Builder setIncludeTxPowerLevel(boolean);
@@ -9806,6 +9885,31 @@ package android.bluetooth.le {
method public android.bluetooth.le.ScanSettings.Builder setScanMode(int);
}
+ public final class TransportBlock implements android.os.Parcelable {
+ ctor public TransportBlock(int, int, int, @Nullable byte[]);
+ method public int describeContents();
+ method public int getOrgId();
+ method public int getTdsFlags();
+ method @Nullable public byte[] getTransportData();
+ method public int getTransportDataLength();
+ method @Nullable public byte[] toByteArray();
+ method public int totalBytes();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.TransportBlock> CREATOR;
+ }
+
+ public final class TransportDiscoveryData implements android.os.Parcelable {
+ ctor public TransportDiscoveryData(int, @NonNull java.util.List<android.bluetooth.le.TransportBlock>);
+ ctor public TransportDiscoveryData(@NonNull byte[]);
+ method public int describeContents();
+ method @NonNull public java.util.List<android.bluetooth.le.TransportBlock> getTransportBlocks();
+ method public int getTransportDataType();
+ method @Nullable public byte[] toByteArray();
+ method public int totalBytes();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.TransportDiscoveryData> CREATOR;
+ }
+
}
package android.companion {
@@ -27377,6 +27481,7 @@ package android.nfc.cardemulation {
field public static final String CATEGORY_PAYMENT = "payment";
field public static final String EXTRA_CATEGORY = "category";
field public static final String EXTRA_SERVICE_COMPONENT = "component";
+ field public static final String EXTRA_USERID = "android.nfc.cardemulation.extra.USERID";
field public static final int SELECTION_MODE_ALWAYS_ASK = 1; // 0x1
field public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2; // 0x2
field public static final int SELECTION_MODE_PREFER_DEFAULT = 0; // 0x0
@@ -31418,6 +31523,8 @@ package android.os {
method @Nullable public double[] createDoubleArray();
method @Nullable public float[] createFloatArray();
method @Nullable public int[] createIntArray();
+ method @Nullable public <T extends android.os.IInterface> T[] createInterfaceArray(@NonNull java.util.function.IntFunction<T[]>, @NonNull java.util.function.Function<android.os.IBinder,T>);
+ method @Nullable public <T extends android.os.IInterface> java.util.ArrayList<T> createInterfaceArrayList(@NonNull java.util.function.Function<android.os.IBinder,T>);
method @Nullable public long[] createLongArray();
method @Nullable public String[] createStringArray();
method @Nullable public java.util.ArrayList<java.lang.String> createStringArrayList();
@@ -31430,14 +31537,15 @@ package android.os {
method public int dataPosition();
method public int dataSize();
method public void enforceInterface(@NonNull String);
+ method public void enforceNoDataAvail();
method public boolean hasFileDescriptors();
method public boolean hasFileDescriptors(int, int);
method public byte[] marshall();
method @NonNull public static android.os.Parcel obtain();
method @NonNull public static android.os.Parcel obtain(@NonNull android.os.IBinder);
- method @Nullable public Object[] readArray(@Nullable ClassLoader);
+ method @Deprecated @Nullable public Object[] readArray(@Nullable ClassLoader);
method @Nullable public <T> T[] readArray(@Nullable ClassLoader, @NonNull Class<T>);
- method @Nullable public java.util.ArrayList readArrayList(@Nullable ClassLoader);
+ method @Deprecated @Nullable public java.util.ArrayList readArrayList(@Nullable ClassLoader);
method @Nullable public <T> java.util.ArrayList<T> readArrayList(@Nullable ClassLoader, @NonNull Class<? extends T>);
method public void readBinderArray(@NonNull android.os.IBinder[]);
method public void readBinderList(@NonNull java.util.List<android.os.IBinder>);
@@ -31455,28 +31563,33 @@ package android.os {
method public android.os.ParcelFileDescriptor readFileDescriptor();
method public float readFloat();
method public void readFloatArray(@NonNull float[]);
- method @Nullable public java.util.HashMap readHashMap(@Nullable ClassLoader);
+ method @Deprecated @Nullable public java.util.HashMap readHashMap(@Nullable ClassLoader);
+ method @Nullable public <K, V> java.util.HashMap<K,V> readHashMap(@Nullable ClassLoader, @NonNull Class<? extends K>, @NonNull Class<? extends V>);
method public int readInt();
method public void readIntArray(@NonNull int[]);
- method public void readList(@NonNull java.util.List, @Nullable ClassLoader);
+ method public <T extends android.os.IInterface> void readInterfaceArray(@NonNull T[], @NonNull java.util.function.Function<android.os.IBinder,T>);
+ method public <T extends android.os.IInterface> void readInterfaceList(@NonNull java.util.List<T>, @NonNull java.util.function.Function<android.os.IBinder,T>);
+ method @Deprecated public void readList(@NonNull java.util.List, @Nullable ClassLoader);
method public <T> void readList(@NonNull java.util.List<? super T>, @Nullable ClassLoader, @NonNull Class<T>);
method public long readLong();
method public void readLongArray(@NonNull long[]);
- method public void readMap(@NonNull java.util.Map, @Nullable ClassLoader);
- method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader);
+ method @Deprecated public void readMap(@NonNull java.util.Map, @Nullable ClassLoader);
+ method public <K, V> void readMap(@NonNull java.util.Map<? super K,? super V>, @Nullable ClassLoader, @NonNull Class<K>, @NonNull Class<V>);
+ method @Deprecated @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader);
method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader, @NonNull Class<T>);
method @Nullable public android.os.Parcelable[] readParcelableArray(@Nullable ClassLoader);
method @Nullable public <T> T[] readParcelableArray(@Nullable ClassLoader, @NonNull Class<T>);
- method @Nullable public android.os.Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader);
+ method @Deprecated @Nullable public android.os.Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader);
method @Nullable public <T> android.os.Parcelable.Creator<T> readParcelableCreator(@Nullable ClassLoader, @NonNull Class<T>);
- method @NonNull public <T extends android.os.Parcelable> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader);
+ method @Deprecated @NonNull public <T extends android.os.Parcelable> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader);
+ method @NonNull public <T> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader, @NonNull Class<T>);
method @Nullable public android.os.PersistableBundle readPersistableBundle();
method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader);
- method @Nullable public java.io.Serializable readSerializable();
+ method @Deprecated @Nullable public java.io.Serializable readSerializable();
method @Nullable public <T extends java.io.Serializable> T readSerializable(@Nullable ClassLoader, @NonNull Class<T>);
method @NonNull public android.util.Size readSize();
method @NonNull public android.util.SizeF readSizeF();
- method @Nullable public <T> android.util.SparseArray<T> readSparseArray(@Nullable ClassLoader);
+ method @Deprecated @Nullable public <T> android.util.SparseArray<T> readSparseArray(@Nullable ClassLoader);
method @Nullable public <T> android.util.SparseArray<T> readSparseArray(@Nullable ClassLoader, @NonNull Class<? extends T>);
method @Nullable public android.util.SparseBooleanArray readSparseBooleanArray();
method @Nullable public String readString();
@@ -31510,6 +31623,8 @@ package android.os {
method public void writeFloatArray(@Nullable float[]);
method public void writeInt(int);
method public void writeIntArray(@Nullable int[]);
+ method public <T extends android.os.IInterface> void writeInterfaceArray(@Nullable T[]);
+ method public <T extends android.os.IInterface> void writeInterfaceList(@Nullable java.util.List<T>);
method public void writeInterfaceToken(@NonNull String);
method public void writeList(@Nullable java.util.List);
method public void writeLong(long);
@@ -40687,6 +40802,7 @@ package android.telephony {
method @NonNull public java.util.List<java.lang.Integer> getBands();
method @NonNull public java.util.List<java.lang.String> getMccMncs();
method public int getPriority();
+ method @NonNull public java.util.List<android.telephony.RadioAccessSpecifier> getRadioAccessSpecifiers();
method public int getSubId();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.AvailableNetworkInfo> CREATOR;
@@ -40695,6 +40811,14 @@ package android.telephony {
field public static final int PRIORITY_MED = 2; // 0x2
}
+ public static final class AvailableNetworkInfo.Builder {
+ ctor public AvailableNetworkInfo.Builder(int);
+ method @NonNull public android.telephony.AvailableNetworkInfo build();
+ method @NonNull public android.telephony.AvailableNetworkInfo.Builder setMccMncs(@NonNull java.util.List<java.lang.String>);
+ method @NonNull public android.telephony.AvailableNetworkInfo.Builder setPriority(int);
+ method @NonNull public android.telephony.AvailableNetworkInfo.Builder setRadioAccessSpecifiers(@NonNull java.util.List<android.telephony.RadioAccessSpecifier>);
+ }
+
public final class BarringInfo implements android.os.Parcelable {
method public int describeContents();
method @NonNull public android.telephony.BarringInfo.BarringServiceInfo getBarringServiceInfo(int);
@@ -40728,11 +40852,11 @@ package android.telephony {
}
public class CarrierConfigManager {
- method @Nullable public android.os.PersistableBundle getConfig();
- method @Nullable public android.os.PersistableBundle getConfigByComponentForSubId(@NonNull String, int);
- method @Nullable public android.os.PersistableBundle getConfigForSubId(int);
+ method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfig();
+ method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfigByComponentForSubId(@NonNull String, int);
+ method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.os.PersistableBundle getConfigForSubId(int);
method public static boolean isConfigForIdentifiedCarrier(android.os.PersistableBundle);
- method public void notifyConfigChangedForSubId(int);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyConfigChangedForSubId(int);
field public static final String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
field public static final int CARRIER_NR_AVAILABILITY_NSA = 1; // 0x1
field public static final int CARRIER_NR_AVAILABILITY_SA = 2; // 0x2
@@ -40803,6 +40927,7 @@ package android.telephony {
field public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = "carrier_rcs_provisioning_required_bool";
field public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string";
field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
+ field public static final String KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL = "carrier_supports_opp_data_auto_provisioning_bool";
field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool";
field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
field public static final String KEY_CARRIER_USSD_METHOD_INT = "carrier_ussd_method_int";
@@ -40864,6 +40989,8 @@ package android.telephony {
field public static final String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL = "enhanced_4g_lte_on_by_default_bool";
field public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT = "enhanced_4g_lte_title_variant_int";
+ field public static final String KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT = "esim_download_retry_backoff_timer_sec_int";
+ field public static final String KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT = "esim_max_download_retry_attempts_int";
field public static final String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
field public static final String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
field public static final String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array";
@@ -40966,6 +41093,7 @@ package android.telephony {
field public static final String KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL = "show_wfc_location_privacy_policy_bool";
field public static final String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
+ field public static final String KEY_SMDP_SERVER_ADDRESS_STRING = "smdp_server_address_string";
field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
field public static final String KEY_SUPPORTS_CALL_COMPOSER_BOOL = "supports_call_composer_bool";
field public static final String KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL = "supports_device_to_device_communication_using_dtmf_bool";
@@ -42662,11 +42790,11 @@ package android.telephony {
method public int getCarrierIdFromSimMccMnc();
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.telephony.CellLocation getCellLocation();
method public int getDataActivity();
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getDataNetworkType();
+ method @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) public int getDataNetworkType();
method public int getDataState();
method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDeviceId();
method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDeviceId(int);
- method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceSoftwareVersion();
+ method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) public String getDeviceSoftwareVersion();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList(int);
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<java.lang.String> getEquivalentHomePlmns();
@@ -42719,26 +42847,26 @@ package android.telephony {
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVisualVoicemailPackageName();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailAlphaTag();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber();
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getVoiceNetworkType();
+ method @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) public int getVoiceNetworkType();
method @Nullable public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
method public boolean hasCarrierPrivileges();
method public boolean hasIccCard();
- method @Deprecated public boolean iccCloseLogicalChannel(int);
- method @Deprecated public byte[] iccExchangeSimIO(int, int, int, int, int, String);
+ method public boolean iccCloseLogicalChannel(int);
+ method public byte[] iccExchangeSimIO(int, int, int, int, int, String);
method @Deprecated public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(String);
- method @Deprecated public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(String, int);
- method @Deprecated public String iccTransmitApduBasicChannel(int, int, int, int, int, String);
- method @Deprecated public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
+ method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(String, int);
+ method public String iccTransmitApduBasicChannel(int, int, int, int, int, String);
+ method public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
method public boolean isConcurrentVoiceAndDataSupported();
method public boolean isDataCapable();
- 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, 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 @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_BASIC_PHONE_STATE}) public boolean isDataConnectionAllowed();
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) public boolean isDataEnabled();
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) public boolean isDataEnabledForReason(int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_BASIC_PHONE_STATE}) public boolean isDataRoamingEnabled();
method public boolean isEmergencyNumber(@NonNull String);
method public boolean isHearingAidCompatibilitySupported();
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isManualNetworkSelectionAllowed();
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isModemEnabledForSlot(int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isModemEnabledForSlot(int);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int isMultiSimSupported();
method public boolean isNetworkRoaming();
method public boolean isRadioInterfaceCapabilitySupported(@NonNull String);
@@ -42753,7 +42881,7 @@ package android.telephony {
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);
- method @Deprecated public String sendEnvelopeWithStatus(String);
+ method public String sendEnvelopeWithStatus(String);
method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallComposerStatus(int);
@@ -43444,8 +43572,10 @@ package android.telephony.ims {
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVoWiFiSettingEnabled();
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVtSettingEnabled();
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public void registerImsStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsStateCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
+ method public void unregisterImsStateCallback(@NonNull android.telephony.ims.ImsStateCallback);
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void unregisterMmTelCapabilityCallback(@NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback);
field public static final int WIFI_MODE_CELLULAR_PREFERRED = 1; // 0x1
field public static final int WIFI_MODE_WIFI_ONLY = 0; // 0x0
@@ -43462,7 +43592,9 @@ package android.telephony.ims {
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @NonNull public android.telephony.ims.RcsUceAdapter getUceAdapter();
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE", "android.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE"}) public void registerImsStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsStateCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
+ method public void unregisterImsStateCallback(@NonNull android.telephony.ims.ImsStateCallback);
field public static final String ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN = "android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN";
}
@@ -43661,6 +43793,19 @@ package android.telephony.ims {
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsRegistrationAttributes> CREATOR;
}
+ public abstract class ImsStateCallback {
+ ctor public ImsStateCallback();
+ method public abstract void onAvailable();
+ method public abstract void onError();
+ method public abstract void onUnavailable(int);
+ field public static final int REASON_IMS_SERVICE_DISCONNECTED = 3; // 0x3
+ field public static final int REASON_IMS_SERVICE_NOT_READY = 6; // 0x6
+ field public static final int REASON_NO_IMS_SERVICE_CONFIGURED = 4; // 0x4
+ field public static final int REASON_SUBSCRIPTION_INACTIVE = 5; // 0x5
+ field public static final int REASON_UNKNOWN_PERMANENT_ERROR = 2; // 0x2
+ field public static final int REASON_UNKNOWN_TEMPORARY_ERROR = 1; // 0x1
+ }
+
public class RcsUceAdapter {
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException;
}
@@ -47514,6 +47659,10 @@ package android.view {
field public static final int KEYCODE_CUT = 277; // 0x115
field public static final int KEYCODE_D = 32; // 0x20
field public static final int KEYCODE_DEL = 67; // 0x43
+ field public static final int KEYCODE_DEMO_APP_1 = 301; // 0x12d
+ field public static final int KEYCODE_DEMO_APP_2 = 302; // 0x12e
+ field public static final int KEYCODE_DEMO_APP_3 = 303; // 0x12f
+ field public static final int KEYCODE_DEMO_APP_4 = 304; // 0x130
field public static final int KEYCODE_DPAD_CENTER = 23; // 0x17
field public static final int KEYCODE_DPAD_DOWN = 20; // 0x14
field public static final int KEYCODE_DPAD_DOWN_LEFT = 269; // 0x10d
@@ -47545,6 +47694,10 @@ package android.view {
field public static final int KEYCODE_F7 = 137; // 0x89
field public static final int KEYCODE_F8 = 138; // 0x8a
field public static final int KEYCODE_F9 = 139; // 0x8b
+ field public static final int KEYCODE_FEATURED_APP_1 = 297; // 0x129
+ field public static final int KEYCODE_FEATURED_APP_2 = 298; // 0x12a
+ field public static final int KEYCODE_FEATURED_APP_3 = 299; // 0x12b
+ field public static final int KEYCODE_FEATURED_APP_4 = 300; // 0x12c
field public static final int KEYCODE_FOCUS = 80; // 0x50
field public static final int KEYCODE_FORWARD = 125; // 0x7d
field public static final int KEYCODE_FORWARD_DEL = 112; // 0x70
@@ -47710,6 +47863,14 @@ package android.view {
field public static final int KEYCODE_U = 49; // 0x31
field public static final int KEYCODE_UNKNOWN = 0; // 0x0
field public static final int KEYCODE_V = 50; // 0x32
+ field public static final int KEYCODE_VIDEO_APP_1 = 289; // 0x121
+ field public static final int KEYCODE_VIDEO_APP_2 = 290; // 0x122
+ field public static final int KEYCODE_VIDEO_APP_3 = 291; // 0x123
+ field public static final int KEYCODE_VIDEO_APP_4 = 292; // 0x124
+ field public static final int KEYCODE_VIDEO_APP_5 = 293; // 0x125
+ field public static final int KEYCODE_VIDEO_APP_6 = 294; // 0x126
+ field public static final int KEYCODE_VIDEO_APP_7 = 295; // 0x127
+ field public static final int KEYCODE_VIDEO_APP_8 = 296; // 0x128
field public static final int KEYCODE_VOICE_ASSIST = 231; // 0xe7
field public static final int KEYCODE_VOLUME_DOWN = 25; // 0x19
field public static final int KEYCODE_VOLUME_MUTE = 164; // 0xa4
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 49df45ac0c4f..3a35f249d177 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -113,10 +113,29 @@ package android.media {
public class AudioManager {
method public void adjustStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
method public void adjustSuggestedStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
+ method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void handleBluetoothActiveDeviceChanged(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothDevice, @NonNull android.media.BtProfileConnectionInfo);
+ method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setA2dpSuspended(boolean);
+ method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setBluetoothHeadsetProperties(@NonNull String, boolean, boolean);
+ method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpEnabled(boolean);
+ method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpSamplingRate(int);
+ method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpVolume(int);
method public void setStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
field public static final int FLAG_FROM_KEY = 4096; // 0x1000
}
+ public final class BtProfileConnectionInfo implements android.os.Parcelable {
+ method @NonNull public static android.media.BtProfileConnectionInfo a2dpInfo(boolean, int);
+ method public int describeContents();
+ method public boolean getIsLeOutput();
+ method public int getProfile();
+ method public boolean getSuppressNoisyIntent();
+ method public int getVolume();
+ method @NonNull public static android.media.BtProfileConnectionInfo hearingAidInfo(boolean);
+ method @NonNull public static android.media.BtProfileConnectionInfo leAudio(boolean, boolean);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.BtProfileConnectionInfo> CREATOR;
+ }
+
public class MediaMetadataRetriever implements java.lang.AutoCloseable {
field public static final int METADATA_KEY_VIDEO_CODEC_MIME_TYPE = 40; // 0x28
}
@@ -292,6 +311,10 @@ package android.os {
method @Nullable public android.os.IBinder getOrThrow() throws android.os.StatsServiceManager.ServiceNotFoundException;
}
+ public class SystemConfigManager {
+ method @NonNull public java.util.List<android.content.ComponentName> getEnabledComponentOverrides(@NonNull String);
+ }
+
}
package android.os.storage {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index ac6943c3915e..91b8786cc615 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -8581,7 +8581,6 @@ package android.os {
public class SystemConfigManager {
method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Set<java.lang.String> getDisabledUntilUsedPreinstalledCarrierApps();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
- method @NonNull public java.util.List<java.lang.String> getEnabledComponentOverrides(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public int[] getSystemPermissionUids(@NonNull String);
}
@@ -12056,10 +12055,10 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoiceActivationState();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmi(String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmiForSubscriber(int, String);
- method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int);
method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int, @Nullable String, int);
- method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String);
- method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String);
+ method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
@@ -13742,7 +13741,9 @@ package android.telephony.ims {
method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void createSipDelegate(@NonNull android.telephony.ims.DelegateRequest, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.stub.DelegateConnectionStateCallback, @NonNull android.telephony.ims.stub.DelegateConnectionMessageCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void destroySipDelegate(@NonNull android.telephony.ims.SipDelegateConnection, int);
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public boolean isSupported() throws android.telephony.ims.ImsException;
+ method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void registerImsStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsStateCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void triggerFullNetworkRegistration(@NonNull android.telephony.ims.SipDelegateConnection, @IntRange(from=100, to=699) int, @Nullable String);
+ method public void unregisterImsStateCallback(@NonNull android.telephony.ims.ImsStateCallback);
field public static final int DENIED_REASON_INVALID = 4; // 0x4
field public static final int DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE = 1; // 0x1
field public static final int DENIED_REASON_NOT_ALLOWED = 2; // 0x2
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 6ccdf9185517..d0e659bf36e9 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2748,7 +2748,7 @@ package android.view {
method public static String actionToString(int);
method public final void setDisplayId(int);
field public static final int FLAG_IS_ACCESSIBILITY_EVENT = 2048; // 0x800
- field public static final int LAST_KEYCODE = 288; // 0x120
+ field public static final int LAST_KEYCODE = 304; // 0x130
}
public final class KeyboardShortcutGroup implements android.os.Parcelable {
diff --git a/core/java/Android.bp b/core/java/Android.bp
index e08a4931fc7d..ca9a46847dea 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -343,7 +343,6 @@ aidl_interface {
filegroup {
name: "framework-telephony-common-shared-srcs",
srcs: [
- ":modules-utils-preconditions-srcs",
"android/os/RegistrantList.java",
"android/os/Registrant.java",
"android/util/IndentingPrintWriter.java",
@@ -355,10 +354,7 @@ filegroup {
"com/android/internal/util/BitwiseInputStream.java",
"com/android/internal/util/FastXmlSerializer.java",
"com/android/internal/util/HexDump.java",
- "com/android/internal/util/IState.java",
"com/android/internal/util/IndentingPrintWriter.java",
- "com/android/internal/util/State.java",
- "com/android/internal/util/StateMachine.java",
"com/android/internal/util/UserIcons.java",
],
}
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index 0d6a07938e95..e6cdcc0ee742 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -31,6 +31,7 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import java.util.Objects;
import java.util.Set;
/**
@@ -86,6 +87,12 @@ public class Account implements Parcelable {
if (TextUtils.isEmpty(type)) {
throw new IllegalArgumentException("the type must not be empty: " + type);
}
+ if (name.length() > 200) {
+ throw new IllegalArgumentException("account name is longer than 200 characters");
+ }
+ if (type.length() > 200) {
+ throw new IllegalArgumentException("account type is longer than 200 characters");
+ }
this.name = name;
this.type = type;
this.accessId = accessId;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index db5dcc5c264b..af59ea1d22ff 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -77,7 +77,6 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Parcelable;
import android.os.PersistableBundle;
-import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager.ServiceNotFoundException;
@@ -8788,9 +8787,7 @@ public class Activity extends ContextThemeWrapper
* the activity is visible after the screen is turned on when the lockscreen is up. In addition,
* if this flag is set and the activity calls {@link
* KeyguardManager#requestDismissKeyguard(Activity, KeyguardManager.KeyguardDismissCallback)}
- * the screen will turn on. If the screen is off and device is not secured, this flag can turn
- * screen on and dismiss keyguard to make this activity visible and resume, which can be used to
- * replace {@link PowerManager#ACQUIRE_CAUSES_WAKEUP}
+ * the screen will turn on.
*
* @param turnScreenOn {@code true} to turn on the screen; {@code false} otherwise.
*
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 6c3795d7c607..bfff27a82f5b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -464,11 +464,7 @@ public final class ActivityThread extends ClientTransactionHandler
@Override
public int hashCode() {
- return hashCode(authority, userId);
- }
-
- public static int hashCode(final String auth, final int userIdent) {
- return ((auth != null) ? auth.hashCode() : 0) ^ userIdent;
+ return ((authority != null) ? authority.hashCode() : 0) ^ userId;
}
}
@@ -490,7 +486,7 @@ public final class ActivityThread extends ClientTransactionHandler
// Note we never removes items from this map but that's okay because there are only so many
// users and so many authorities.
@GuardedBy("mGetProviderKeys")
- final SparseArray<ProviderKey> mGetProviderKeys = new SparseArray<>();
+ final ArrayMap<ProviderKey, ProviderKey> mGetProviderKeys = new ArrayMap<>();
final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
= new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>();
@@ -7020,11 +7016,11 @@ public final class ActivityThread extends ClientTransactionHandler
}
private ProviderKey getGetProviderKey(String auth, int userId) {
- final int key = ProviderKey.hashCode(auth, userId);
+ final ProviderKey key = new ProviderKey(auth, userId);
synchronized (mGetProviderKeys) {
ProviderKey lock = mGetProviderKeys.get(key);
if (lock == null) {
- lock = new ProviderKey(auth, userId);
+ lock = key;
mGetProviderKeys.put(key, lock);
}
return lock;
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 4da51c13045b..2564228f23aa 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -29,6 +29,8 @@ per-file Service* = file:/services/core/java/com/android/server/am/OWNERS
per-file SystemServiceRegistry.java = file:/services/core/java/com/android/server/am/OWNERS
per-file *UserSwitchObserver* = file:/services/core/java/com/android/server/am/OWNERS
per-file UiAutomation.java = file:/services/accessibility/OWNERS
+per-file GameManager* = file:/GAME_MANAGER_OWNERS
+per-file IGameManager* = file:/GAME_MANAGER_OWNERS
# ActivityThread
per-file ActivityThread.java = file:/services/core/java/com/android/server/am/OWNERS
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 8aa27853b462..51435796502e 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -552,6 +552,11 @@ public class AppWidgetHostView extends FrameLayout {
inflateAsync(rvToApply);
return;
}
+
+ // Prepare a local reference to the remote Context so we're ready to
+ // inflate any requested LayoutParams
+ mRemoteContext = getRemoteContext();
+
int layoutId = rvToApply.getLayoutId();
if (rvToApply.canRecycleView(mView)) {
try {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index dac8ffe5e008..2c875fee101b 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -51,7 +51,6 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.Attributable;
import android.content.AttributionSource;
import android.content.Context;
-import android.os.BatteryStats;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
@@ -59,7 +58,6 @@ import android.os.ParcelUuid;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
-import android.os.SynchronousResultReceiver;
import android.os.SystemProperties;
import android.util.Log;
import android.util.Pair;
@@ -82,7 +80,6 @@ import java.util.Set;
import java.util.UUID;
import java.util.WeakHashMap;
import java.util.concurrent.Executor;
-import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
@@ -2022,6 +2019,7 @@ public final class BluetoothAdapter {
* {@link BluetoothProfile#HEADSET},
* {@link BluetoothProfile#A2DP},
* {@link BluetoothProfile#HEARING_AID}
+ * {@link BluetoothProfile#LE_AUDIO}
* @return A list of active bluetooth devices
* @throws IllegalArgumentException If profile is not one of {@link ActiveDeviceProfile}
* @hide
@@ -2034,12 +2032,14 @@ public final class BluetoothAdapter {
public @NonNull List<BluetoothDevice> getActiveDevices(@ActiveDeviceProfile int profile) {
if (profile != BluetoothProfile.HEADSET
&& profile != BluetoothProfile.A2DP
- && profile != BluetoothProfile.HEARING_AID) {
+ && profile != BluetoothProfile.HEARING_AID
+ && profile != BluetoothProfile.LE_AUDIO) {
Log.e(TAG, "Invalid profile param value in getActiveDevices");
throw new IllegalArgumentException("Profiles must be one of "
+ "BluetoothProfile.A2DP, "
+ "BluetoothProfile.HEARING_AID, or"
- + "BluetoothProfile.HEARING_AID");
+ + "BluetoothProfile.HEARING_AID"
+ + "BluetoothProfile.LE_AUDIO");
}
try {
mServiceLock.readLock().lock();
@@ -2421,38 +2421,6 @@ public final class BluetoothAdapter {
}
/**
- * Return the record of {@link BluetoothActivityEnergyInfo} object that
- * has the activity and energy info. This can be used to ascertain what
- * the controller has been up to, since the last sample.
- *
- * @param updateType Type of info, cached vs refreshed.
- * @return a record with {@link BluetoothActivityEnergyInfo} or null if report is unavailable or
- * unsupported
- * @hide
- * @deprecated use the asynchronous {@link #requestControllerActivityEnergyInfo(ResultReceiver)}
- * instead.
- */
- @Deprecated
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) {
- SynchronousResultReceiver receiver = new SynchronousResultReceiver();
- requestControllerActivityEnergyInfo(receiver);
- try {
- SynchronousResultReceiver.Result result = receiver.awaitResult(1000);
- if (result.bundle != null) {
- return result.bundle.getParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY);
- }
- } catch (TimeoutException e) {
- Log.e(TAG, "getControllerActivityEnergyInfo timed out");
- }
- return null;
- }
-
- /**
* Request the record of {@link BluetoothActivityEnergyInfo} object that
* has the activity and energy info. This can be used to ascertain what
* the controller has been up to, since the last sample.
diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java
index 1d0bf97c34eb..9a4151adffc7 100644
--- a/core/java/android/bluetooth/BluetoothCodecConfig.java
+++ b/core/java/android/bluetooth/BluetoothCodecConfig.java
@@ -29,16 +29,14 @@ import java.util.Objects;
/**
* Represents the codec configuration for a Bluetooth A2DP source device.
+ * <p>Contains the source codec type, the codec priority, the codec sample
+ * rate, the codec bits per sample, and the codec channel mode.
+ * <p>The source codec type values are the same as those supported by the
+ * device hardware.
*
* {@see BluetoothA2dp}
- *
- * {@hide}
*/
public final class BluetoothCodecConfig implements Parcelable {
- // Add an entry for each source codec here.
- // NOTE: The values should be same as those listed in the following file:
- // hardware/libhardware/include/hardware/bt_av.h
-
/** @hide */
@IntDef(prefix = "SOURCE_CODEC_TYPE_", value = {
SOURCE_CODEC_TYPE_SBC,
@@ -46,33 +44,49 @@ public final class BluetoothCodecConfig implements Parcelable {
SOURCE_CODEC_TYPE_APTX,
SOURCE_CODEC_TYPE_APTX_HD,
SOURCE_CODEC_TYPE_LDAC,
- SOURCE_CODEC_TYPE_MAX,
SOURCE_CODEC_TYPE_INVALID
})
@Retention(RetentionPolicy.SOURCE)
public @interface SourceCodecType {}
- @UnsupportedAppUsage
+ /**
+ * Source codec type SBC. This is the mandatory source codec
+ * type.
+ */
public static final int SOURCE_CODEC_TYPE_SBC = 0;
- @UnsupportedAppUsage
+ /**
+ * Source codec type AAC.
+ */
public static final int SOURCE_CODEC_TYPE_AAC = 1;
- @UnsupportedAppUsage
+ /**
+ * Source codec type APTX.
+ */
public static final int SOURCE_CODEC_TYPE_APTX = 2;
- @UnsupportedAppUsage
+ /**
+ * Source codec type APTX HD.
+ */
public static final int SOURCE_CODEC_TYPE_APTX_HD = 3;
- @UnsupportedAppUsage
+ /**
+ * Source codec type LDAC.
+ */
public static final int SOURCE_CODEC_TYPE_LDAC = 4;
- @UnsupportedAppUsage
- public static final int SOURCE_CODEC_TYPE_MAX = 5;
-
- @UnsupportedAppUsage
+ /**
+ * Source codec type invalid. This is the default value used for codec
+ * type.
+ */
public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
+ /**
+ * Represents the count of valid source codec types. Can be accessed via
+ * {@link #getMaxCodecType}.
+ */
+ private static final int SOURCE_CODEC_TYPE_MAX = 5;
+
/** @hide */
@IntDef(prefix = "CODEC_PRIORITY_", value = {
CODEC_PRIORITY_DISABLED,
@@ -82,16 +96,24 @@ public final class BluetoothCodecConfig implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface CodecPriority {}
- @UnsupportedAppUsage
+ /**
+ * Codec priority disabled.
+ * Used to indicate that this codec is disabled and should not be used.
+ */
public static final int CODEC_PRIORITY_DISABLED = -1;
- @UnsupportedAppUsage
+ /**
+ * Codec priority default.
+ * Default value used for codec priority.
+ */
public static final int CODEC_PRIORITY_DEFAULT = 0;
- @UnsupportedAppUsage
+ /**
+ * Codec priority highest.
+ * Used to indicate the highest priority a codec can have.
+ */
public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000;
-
/** @hide */
@IntDef(prefix = "SAMPLE_RATE_", value = {
SAMPLE_RATE_NONE,
@@ -105,28 +127,42 @@ public final class BluetoothCodecConfig implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface SampleRate {}
- @UnsupportedAppUsage
+ /**
+ * Codec sample rate 0 Hz. Default value used for
+ * codec sample rate.
+ */
public static final int SAMPLE_RATE_NONE = 0;
- @UnsupportedAppUsage
+ /**
+ * Codec sample rate 44100 Hz.
+ */
public static final int SAMPLE_RATE_44100 = 0x1 << 0;
- @UnsupportedAppUsage
+ /**
+ * Codec sample rate 48000 Hz.
+ */
public static final int SAMPLE_RATE_48000 = 0x1 << 1;
- @UnsupportedAppUsage
+ /**
+ * Codec sample rate 88200 Hz.
+ */
public static final int SAMPLE_RATE_88200 = 0x1 << 2;
- @UnsupportedAppUsage
+ /**
+ * Codec sample rate 96000 Hz.
+ */
public static final int SAMPLE_RATE_96000 = 0x1 << 3;
- @UnsupportedAppUsage
+ /**
+ * Codec sample rate 176400 Hz.
+ */
public static final int SAMPLE_RATE_176400 = 0x1 << 4;
- @UnsupportedAppUsage
+ /**
+ * Codec sample rate 192000 Hz.
+ */
public static final int SAMPLE_RATE_192000 = 0x1 << 5;
-
/** @hide */
@IntDef(prefix = "BITS_PER_SAMPLE_", value = {
BITS_PER_SAMPLE_NONE,
@@ -137,19 +173,27 @@ public final class BluetoothCodecConfig implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface BitsPerSample {}
- @UnsupportedAppUsage
+ /**
+ * Codec bits per sample 0. Default value of the codec
+ * bits per sample.
+ */
public static final int BITS_PER_SAMPLE_NONE = 0;
- @UnsupportedAppUsage
+ /**
+ * Codec bits per sample 16.
+ */
public static final int BITS_PER_SAMPLE_16 = 0x1 << 0;
- @UnsupportedAppUsage
+ /**
+ * Codec bits per sample 24.
+ */
public static final int BITS_PER_SAMPLE_24 = 0x1 << 1;
- @UnsupportedAppUsage
+ /**
+ * Codec bits per sample 32.
+ */
public static final int BITS_PER_SAMPLE_32 = 0x1 << 2;
-
/** @hide */
@IntDef(prefix = "CHANNEL_MODE_", value = {
CHANNEL_MODE_NONE,
@@ -159,13 +203,20 @@ public final class BluetoothCodecConfig implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface ChannelMode {}
- @UnsupportedAppUsage
+ /**
+ * Codec channel mode NONE. Default value of the
+ * codec channel mode.
+ */
public static final int CHANNEL_MODE_NONE = 0;
- @UnsupportedAppUsage
+ /**
+ * Codec channel mode MONO.
+ */
public static final int CHANNEL_MODE_MONO = 0x1 << 0;
- @UnsupportedAppUsage
+ /**
+ * Codec channel mode STEREO.
+ */
public static final int CHANNEL_MODE_STEREO = 0x1 << 1;
private final @SourceCodecType int mCodecType;
@@ -178,6 +229,21 @@ public final class BluetoothCodecConfig implements Parcelable {
private final long mCodecSpecific3;
private final long mCodecSpecific4;
+ /**
+ * Creates a new BluetoothCodecConfig.
+ *
+ * @param codecType the source codec type
+ * @param codecPriority the priority of this codec
+ * @param sampleRate the codec sample rate
+ * @param bitsPerSample the bits per sample of this codec
+ * @param channelMode the channel mode of this codec
+ * @param codecSpecific1 the specific value 1
+ * @param codecSpecific2 the specific value 2
+ * @param codecSpecific3 the specific value 3
+ * @param codecSpecific4 the specific value 4
+ * values to 0.
+ * @hide
+ */
@UnsupportedAppUsage
public BluetoothCodecConfig(@SourceCodecType int codecType, @CodecPriority int codecPriority,
@SampleRate int sampleRate, @BitsPerSample int bitsPerSample,
@@ -195,17 +261,34 @@ public final class BluetoothCodecConfig implements Parcelable {
mCodecSpecific4 = codecSpecific4;
}
- @UnsupportedAppUsage
+ /**
+ * Creates a new BluetoothCodecConfig.
+ * <p> By default, the codec priority will be set
+ * to {@link BluetoothCodecConfig#CODEC_PRIORITY_DEFAULT}, the sample rate to
+ * {@link BluetoothCodecConfig#SAMPLE_RATE_NONE}, the bits per sample to
+ * {@link BluetoothCodecConfig#BITS_PER_SAMPLE_NONE}, the channel mode to
+ * {@link BluetoothCodecConfig#CHANNEL_MODE_NONE}, and all the codec specific
+ * values to 0.
+ *
+ * @param codecType the source codec type
+ */
public BluetoothCodecConfig(@SourceCodecType int codecType) {
- mCodecType = codecType;
- mCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
- mSampleRate = BluetoothCodecConfig.SAMPLE_RATE_NONE;
- mBitsPerSample = BluetoothCodecConfig.BITS_PER_SAMPLE_NONE;
- mChannelMode = BluetoothCodecConfig.CHANNEL_MODE_NONE;
- mCodecSpecific1 = 0;
- mCodecSpecific2 = 0;
- mCodecSpecific3 = 0;
- mCodecSpecific4 = 0;
+ this(codecType, BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
+ BluetoothCodecConfig.SAMPLE_RATE_NONE,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_NONE,
+ BluetoothCodecConfig.CHANNEL_MODE_NONE, 0, 0, 0, 0);
+ }
+
+ private BluetoothCodecConfig(Parcel in) {
+ mCodecType = in.readInt();
+ mCodecPriority = in.readInt();
+ mSampleRate = in.readInt();
+ mBitsPerSample = in.readInt();
+ mChannelMode = in.readInt();
+ mCodecSpecific1 = in.readLong();
+ mCodecSpecific2 = in.readLong();
+ mCodecSpecific3 = in.readLong();
+ mCodecSpecific4 = in.readLong();
}
@Override
@@ -226,10 +309,8 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Returns a hash based on the config values
- *
- * @return a hash based on the config values
- * @hide
+ * Returns a hash representation of this BluetoothCodecConfig
+ * based on all the config values.
*/
@Override
public int hashCode() {
@@ -239,32 +320,24 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Checks whether the object contains valid codec configuration.
- *
- * @return true if the object contains valid codec configuration, otherwise false.
- * @hide
- */
- public boolean isValid() {
- return (mSampleRate != SAMPLE_RATE_NONE)
- && (mBitsPerSample != BITS_PER_SAMPLE_NONE)
- && (mChannelMode != CHANNEL_MODE_NONE);
- }
-
- /**
* Adds capability string to an existing string.
*
- * @param prevStr the previous string with the capabilities. Can be a null pointer.
- * @param capStr the capability string to append to prevStr argument.
- * @return the result string in the form "prevStr|capStr".
+ * @param prevStr the previous string with the capabilities. Can be a {@code null} pointer
+ * @param capStr the capability string to append to prevStr argument
+ * @return the result string in the form "prevStr|capStr"
*/
- private static String appendCapabilityToString(String prevStr,
- String capStr) {
+ private static String appendCapabilityToString(@Nullable String prevStr,
+ @NonNull String capStr) {
if (prevStr == null) {
return capStr;
}
return prevStr + "|" + capStr;
}
+ /**
+ * Returns a {@link String} that describes each BluetoothCodecConfig parameter
+ * current value.
+ */
@Override
public String toString() {
String sampleRateStr = null;
@@ -331,8 +404,6 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Always returns 0
- *
* @return 0
* @hide
*/
@@ -344,20 +415,7 @@ public final class BluetoothCodecConfig implements Parcelable {
public static final @android.annotation.NonNull Parcelable.Creator<BluetoothCodecConfig> CREATOR =
new Parcelable.Creator<BluetoothCodecConfig>() {
public BluetoothCodecConfig createFromParcel(Parcel in) {
- final int codecType = in.readInt();
- final int codecPriority = in.readInt();
- final int sampleRate = in.readInt();
- final int bitsPerSample = in.readInt();
- final int channelMode = in.readInt();
- final long codecSpecific1 = in.readLong();
- final long codecSpecific2 = in.readLong();
- final long codecSpecific3 = in.readLong();
- final long codecSpecific4 = in.readLong();
- return new BluetoothCodecConfig(codecType, codecPriority,
- sampleRate, bitsPerSample,
- channelMode, codecSpecific1,
- codecSpecific2, codecSpecific3,
- codecSpecific4);
+ return new BluetoothCodecConfig(in);
}
public BluetoothCodecConfig[] newArray(int size) {
@@ -368,8 +426,8 @@ public final class BluetoothCodecConfig implements Parcelable {
/**
* Flattens the object to a parcel
*
- * @param out The Parcel in which the object should be written.
- * @param flags Additional flags about how the object should be written.
+ * @param out The Parcel in which the object should be written
+ * @param flags Additional flags about how the object should be written
*
* @hide
*/
@@ -387,9 +445,8 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Gets the codec name.
- *
- * @return the codec name
+ * Returns the codec name converted to {@link String}.
+ * @hide
*/
public @NonNull String getCodecName() {
switch (mCodecType) {
@@ -412,137 +469,100 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Gets the codec type.
- * See {@link android.bluetooth.BluetoothCodecConfig#SOURCE_CODEC_TYPE_SBC}.
- *
- * @return the codec type
+ * Returns the source codec type of this config.
*/
- @UnsupportedAppUsage
public @SourceCodecType int getCodecType() {
return mCodecType;
}
/**
+ * Returns the valid codec types count.
+ */
+ public static int getMaxCodecType() {
+ return SOURCE_CODEC_TYPE_MAX;
+ }
+
+ /**
* Checks whether the codec is mandatory.
+ * <p> The actual mandatory codec type for Android Bluetooth audio is SBC.
+ * See {@link #SOURCE_CODEC_TYPE_SBC}.
*
- * @return true if the codec is mandatory, otherwise false.
+ * @return {@code true} if the codec is mandatory, {@code false} otherwise
+ * @hide
*/
public boolean isMandatoryCodec() {
return mCodecType == SOURCE_CODEC_TYPE_SBC;
}
/**
- * Gets the codec selection priority.
- * The codec selection priority is relative to other codecs: larger value
- * means higher priority. If 0, reset to default.
- *
- * @return the codec priority
+ * Returns the codec selection priority.
+ * <p>The codec selection priority is relative to other codecs: larger value
+ * means higher priority.
*/
- @UnsupportedAppUsage
public @CodecPriority int getCodecPriority() {
return mCodecPriority;
}
/**
* Sets the codec selection priority.
- * The codec selection priority is relative to other codecs: larger value
- * means higher priority. If 0, reset to default.
+ * <p>The codec selection priority is relative to other codecs: larger value
+ * means higher priority.
*
- * @param codecPriority the codec priority
+ * @param codecPriority the priority this codec should have
* @hide
*/
- @UnsupportedAppUsage
public void setCodecPriority(@CodecPriority int codecPriority) {
mCodecPriority = codecPriority;
}
/**
- * Gets the codec sample rate. The value can be a bitmask with all
- * supported sample rates:
- * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_NONE} or
- * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_44100} or
- * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_48000} or
- * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_88200} or
- * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_96000} or
- * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_176400} or
- * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_192000}
- *
- * @return the codec sample rate
+ * Returns the codec sample rate. The value can be a bitmask with all
+ * supported sample rates.
*/
- @UnsupportedAppUsage
public @SampleRate int getSampleRate() {
return mSampleRate;
}
/**
- * Gets the codec bits per sample. The value can be a bitmask with all
- * bits per sample supported:
- * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_NONE} or
- * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_16} or
- * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_24} or
- * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_32}
- *
- * @return the codec bits per sample
+ * Returns the codec bits per sample. The value can be a bitmask with all
+ * bits per sample supported.
*/
- @UnsupportedAppUsage
public @BitsPerSample int getBitsPerSample() {
return mBitsPerSample;
}
/**
- * Gets the codec channel mode. The value can be a bitmask with all
- * supported channel modes:
- * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_NONE} or
- * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_MONO} or
- * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_STEREO}
- *
- * @return the codec channel mode
- * @hide
+ * Returns the codec channel mode. The value can be a bitmask with all
+ * supported channel modes.
*/
- @UnsupportedAppUsage
public @ChannelMode int getChannelMode() {
return mChannelMode;
}
/**
- * Gets a codec specific value1.
- *
- * @return a codec specific value1.
+ * Returns the codec specific value1.
*/
- @UnsupportedAppUsage
public long getCodecSpecific1() {
return mCodecSpecific1;
}
/**
- * Gets a codec specific value2.
- *
- * @return a codec specific value2
- * @hide
+ * Returns the codec specific value2.
*/
- @UnsupportedAppUsage
public long getCodecSpecific2() {
return mCodecSpecific2;
}
/**
- * Gets a codec specific value3.
- *
- * @return a codec specific value3
- * @hide
+ * Returns the codec specific value3.
*/
- @UnsupportedAppUsage
public long getCodecSpecific3() {
return mCodecSpecific3;
}
/**
- * Gets a codec specific value4.
- *
- * @return a codec specific value4
- * @hide
+ * Returns the codec specific value4.
*/
- @UnsupportedAppUsage
public long getCodecSpecific4() {
return mCodecSpecific4;
}
@@ -551,7 +571,7 @@ public final class BluetoothCodecConfig implements Parcelable {
* Checks whether a value set presented by a bitmask has zero or single bit
*
* @param valueSet the value set presented by a bitmask
- * @return true if the valueSet contains zero or single bit, otherwise false.
+ * @return {@code true} if the valueSet contains zero or single bit, {@code false} otherwise
* @hide
*/
private static boolean hasSingleBit(int valueSet) {
@@ -559,9 +579,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Checks whether the object contains none or single sample rate.
- *
- * @return true if the object contains none or single sample rate, otherwise false.
+ * Returns whether the object contains none or single sample rate.
* @hide
*/
public boolean hasSingleSampleRate() {
@@ -569,9 +587,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Checks whether the object contains none or single bits per sample.
- *
- * @return true if the object contains none or single bits per sample, otherwise false.
+ * Returns whether the object contains none or single bits per sample.
* @hide
*/
public boolean hasSingleBitsPerSample() {
@@ -579,9 +595,7 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Checks whether the object contains none or single channel mode.
- *
- * @return true if the object contains none or single channel mode, otherwise false.
+ * Returns whether the object contains none or single channel mode.
* @hide
*/
public boolean hasSingleChannelMode() {
@@ -589,10 +603,10 @@ public final class BluetoothCodecConfig implements Parcelable {
}
/**
- * Checks whether the audio feeding parameters are same.
+ * Checks whether the audio feeding parameters are the same.
*
* @param other the codec config to compare against
- * @return true if the audio feeding parameters are same, otherwise false
+ * @return {@code true} if the audio feeding parameters are same, {@code false} otherwise
* @hide
*/
public boolean sameAudioFeedingParameters(BluetoothCodecConfig other) {
@@ -606,7 +620,7 @@ public final class BluetoothCodecConfig implements Parcelable {
* Any parameters with NONE value will be considered to be a wildcard matching.
*
* @param other the codec config to compare against
- * @return true if the audio feeding parameters are similar, otherwise false.
+ * @return {@code true} if the audio feeding parameters are similar, {@code false} otherwise
* @hide
*/
public boolean similarCodecFeedingParameters(BluetoothCodecConfig other) {
@@ -614,18 +628,18 @@ public final class BluetoothCodecConfig implements Parcelable {
return false;
}
int sampleRate = other.mSampleRate;
- if (mSampleRate == BluetoothCodecConfig.SAMPLE_RATE_NONE
- || sampleRate == BluetoothCodecConfig.SAMPLE_RATE_NONE) {
+ if (mSampleRate == SAMPLE_RATE_NONE
+ || sampleRate == SAMPLE_RATE_NONE) {
sampleRate = mSampleRate;
}
int bitsPerSample = other.mBitsPerSample;
- if (mBitsPerSample == BluetoothCodecConfig.BITS_PER_SAMPLE_NONE
- || bitsPerSample == BluetoothCodecConfig.BITS_PER_SAMPLE_NONE) {
+ if (mBitsPerSample == BITS_PER_SAMPLE_NONE
+ || bitsPerSample == BITS_PER_SAMPLE_NONE) {
bitsPerSample = mBitsPerSample;
}
int channelMode = other.mChannelMode;
- if (mChannelMode == BluetoothCodecConfig.CHANNEL_MODE_NONE
- || channelMode == BluetoothCodecConfig.CHANNEL_MODE_NONE) {
+ if (mChannelMode == CHANNEL_MODE_NONE
+ || channelMode == CHANNEL_MODE_NONE) {
channelMode = mChannelMode;
}
return sameAudioFeedingParameters(new BluetoothCodecConfig(
@@ -636,25 +650,158 @@ public final class BluetoothCodecConfig implements Parcelable {
/**
* Checks whether the codec specific parameters are the same.
+ * <p> Currently, only AAC VBR and LDAC Playback Quality on CodecSpecific1
+ * are compared.
*
* @param other the codec config to compare against
- * @return true if the codec specific parameters are the same, otherwise false.
+ * @return {@code true} if the codec specific parameters are the same, {@code false} otherwise
* @hide
*/
public boolean sameCodecSpecificParameters(BluetoothCodecConfig other) {
if (other == null && mCodecType != other.mCodecType) {
return false;
}
- // Currently we only care about the AAC VBR and LDAC Playback Quality at CodecSpecific1
switch (mCodecType) {
case SOURCE_CODEC_TYPE_AAC:
case SOURCE_CODEC_TYPE_LDAC:
if (mCodecSpecific1 != other.mCodecSpecific1) {
return false;
}
- // fall through
default:
return true;
}
}
+
+ /**
+ * Builder for {@link BluetoothCodecConfig}.
+ * <p> By default, the codec type will be set to
+ * {@link BluetoothCodecConfig#SOURCE_CODEC_TYPE_INVALID}, the codec priority
+ * to {@link BluetoothCodecConfig#CODEC_PRIORITY_DEFAULT}, the sample rate to
+ * {@link BluetoothCodecConfig#SAMPLE_RATE_NONE}, the bits per sample to
+ * {@link BluetoothCodecConfig#BITS_PER_SAMPLE_NONE}, the channel mode to
+ * {@link BluetoothCodecConfig#CHANNEL_MODE_NONE}, and all the codec specific
+ * values to 0.
+ */
+ public static final class Builder {
+ private int mCodecType = BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID;
+ private int mCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
+ private int mSampleRate = BluetoothCodecConfig.SAMPLE_RATE_NONE;
+ private int mBitsPerSample = BluetoothCodecConfig.BITS_PER_SAMPLE_NONE;
+ private int mChannelMode = BluetoothCodecConfig.CHANNEL_MODE_NONE;
+ private long mCodecSpecific1 = 0;
+ private long mCodecSpecific2 = 0;
+ private long mCodecSpecific3 = 0;
+ private long mCodecSpecific4 = 0;
+
+ /**
+ * Set codec type for Bluetooth codec config.
+ *
+ * @param codecType of this codec
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setCodecType(@SourceCodecType int codecType) {
+ mCodecType = codecType;
+ return this;
+ }
+
+ /**
+ * Set codec priority for Bluetooth codec config.
+ *
+ * @param codecPriority of this codec
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setCodecPriority(@CodecPriority int codecPriority) {
+ mCodecPriority = codecPriority;
+ return this;
+ }
+
+ /**
+ * Set sample rate for Bluetooth codec config.
+ *
+ * @param sampleRate of this codec
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setSampleRate(@SampleRate int sampleRate) {
+ mSampleRate = sampleRate;
+ return this;
+ }
+
+ /**
+ * Set the bits per sample for Bluetooth codec config.
+ *
+ * @param bitsPerSample of this codec
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setBitsPerSample(@BitsPerSample int bitsPerSample) {
+ mBitsPerSample = bitsPerSample;
+ return this;
+ }
+
+ /**
+ * Set the channel mode for Bluetooth codec config.
+ *
+ * @param channelMode of this codec
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setChannelMode(@ChannelMode int channelMode) {
+ mChannelMode = channelMode;
+ return this;
+ }
+
+ /**
+ * Set the first codec specific values for Bluetooth codec config.
+ *
+ * @param codecSpecific1 codec specific value or 0 if default
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setCodecSpecific1(long codecSpecific1) {
+ mCodecSpecific1 = codecSpecific1;
+ return this;
+ }
+
+ /**
+ * Set the second codec specific values for Bluetooth codec config.
+ *
+ * @param codecSpecific2 codec specific value or 0 if default
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setCodecSpecific2(long codecSpecific2) {
+ mCodecSpecific2 = codecSpecific2;
+ return this;
+ }
+
+ /**
+ * Set the third codec specific values for Bluetooth codec config.
+ *
+ * @param codecSpecific3 codec specific value or 0 if default
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setCodecSpecific3(long codecSpecific3) {
+ mCodecSpecific3 = codecSpecific3;
+ return this;
+ }
+
+ /**
+ * Set the fourth codec specific values for Bluetooth codec config.
+ *
+ * @param codecSpecific4 codec specific value or 0 if default
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setCodecSpecific4(long codecSpecific4) {
+ mCodecSpecific4 = codecSpecific4;
+ return this;
+ }
+
+ /**
+ * Build {@link BluetoothCodecConfig}.
+ * @return new BluetoothCodecConfig built
+ */
+ public @NonNull BluetoothCodecConfig build() {
+ return new BluetoothCodecConfig(mCodecType, mCodecPriority,
+ mSampleRate, mBitsPerSample,
+ mChannelMode, mCodecSpecific1,
+ mCodecSpecific2, mCodecSpecific3,
+ mCodecSpecific4);
+ }
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.java b/core/java/android/bluetooth/BluetoothCodecStatus.java
index 7764ebeb2e33..02606feb3b3f 100644
--- a/core/java/android/bluetooth/BluetoothCodecStatus.java
+++ b/core/java/android/bluetooth/BluetoothCodecStatus.java
@@ -16,12 +16,13 @@
package android.bluetooth;
+import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
/**
@@ -29,8 +30,6 @@ import java.util.Objects;
* A2DP source device.
*
* {@see BluetoothA2dp}
- *
- * {@hide}
*/
public final class BluetoothCodecStatus implements Parcelable {
/**
@@ -39,22 +38,27 @@ public final class BluetoothCodecStatus implements Parcelable {
* This extra represents the current codec status of the A2DP
* profile.
*/
- @UnsupportedAppUsage
public static final String EXTRA_CODEC_STATUS =
"android.bluetooth.extra.CODEC_STATUS";
private final @Nullable BluetoothCodecConfig mCodecConfig;
- private final BluetoothCodecConfig[] mCodecsLocalCapabilities;
- private final BluetoothCodecConfig[] mCodecsSelectableCapabilities;
+ private final @Nullable List<BluetoothCodecConfig> mCodecsLocalCapabilities;
+ private final @Nullable List<BluetoothCodecConfig> mCodecsSelectableCapabilities;
public BluetoothCodecStatus(@Nullable BluetoothCodecConfig codecConfig,
- @Nullable BluetoothCodecConfig[] codecsLocalCapabilities,
- @Nullable BluetoothCodecConfig[] codecsSelectableCapabilities) {
+ @Nullable List<BluetoothCodecConfig> codecsLocalCapabilities,
+ @Nullable List<BluetoothCodecConfig> codecsSelectableCapabilities) {
mCodecConfig = codecConfig;
mCodecsLocalCapabilities = codecsLocalCapabilities;
mCodecsSelectableCapabilities = codecsSelectableCapabilities;
}
+ private BluetoothCodecStatus(Parcel in) {
+ mCodecConfig = in.readTypedObject(BluetoothCodecConfig.CREATOR);
+ mCodecsLocalCapabilities = in.createTypedArrayList(BluetoothCodecConfig.CREATOR);
+ mCodecsSelectableCapabilities = in.createTypedArrayList(BluetoothCodecConfig.CREATOR);
+ }
+
@Override
public boolean equals(@Nullable Object o) {
if (o instanceof BluetoothCodecStatus) {
@@ -68,26 +72,25 @@ public final class BluetoothCodecStatus implements Parcelable {
}
/**
- * Checks whether two arrays of capabilities contain same capabilities.
- * The order of the capabilities in each array is ignored.
+ * Checks whether two lists of capabilities contain same capabilities.
+ * The order of the capabilities in each list is ignored.
*
- * @param c1 the first array of capabilities to compare
- * @param c2 the second array of capabilities to compare
- * @return true if both arrays contain same capabilities
- * @hide
+ * @param c1 the first list of capabilities to compare
+ * @param c2 the second list of capabilities to compare
+ * @return {@code true} if both lists contain same capabilities
*/
- public static boolean sameCapabilities(BluetoothCodecConfig[] c1,
- BluetoothCodecConfig[] c2) {
+ private static boolean sameCapabilities(@Nullable List<BluetoothCodecConfig> c1,
+ @Nullable List<BluetoothCodecConfig> c2) {
if (c1 == null) {
return (c2 == null);
}
if (c2 == null) {
return false;
}
- if (c1.length != c2.length) {
+ if (c1.size() != c2.size()) {
return false;
}
- return Arrays.asList(c1).containsAll(Arrays.asList(c2));
+ return c1.containsAll(c2);
}
/**
@@ -95,10 +98,9 @@ public final class BluetoothCodecStatus implements Parcelable {
* Any parameters of the codec config with NONE value will be considered a wildcard matching.
*
* @param codecConfig the codec config to compare against
- * @return true if the codec config matches, otherwise false
- * @hide
+ * @return {@code true} if the codec config matches, {@code false} otherwise
*/
- public boolean isCodecConfigSelectable(BluetoothCodecConfig codecConfig) {
+ public boolean isCodecConfigSelectable(@Nullable BluetoothCodecConfig codecConfig) {
if (codecConfig == null || !codecConfig.hasSingleSampleRate()
|| !codecConfig.hasSingleBitsPerSample() || !codecConfig.hasSingleChannelMode()) {
return false;
@@ -128,10 +130,7 @@ public final class BluetoothCodecStatus implements Parcelable {
}
/**
- * Returns a hash based on the codec config and local capabilities
- *
- * @return a hash based on the config values
- * @hide
+ * Returns a hash based on the codec config and local capabilities.
*/
@Override
public int hashCode() {
@@ -139,17 +138,19 @@ public final class BluetoothCodecStatus implements Parcelable {
mCodecsLocalCapabilities);
}
+ /**
+ * Returns a {@link String} that describes each BluetoothCodecStatus parameter
+ * current value.
+ */
@Override
public String toString() {
return "{mCodecConfig:" + mCodecConfig
- + ",mCodecsLocalCapabilities:" + Arrays.toString(mCodecsLocalCapabilities)
- + ",mCodecsSelectableCapabilities:" + Arrays.toString(mCodecsSelectableCapabilities)
+ + ",mCodecsLocalCapabilities:" + mCodecsLocalCapabilities
+ + ",mCodecsSelectableCapabilities:" + mCodecsSelectableCapabilities
+ "}";
}
/**
- * Always returns 0
- *
* @return 0
* @hide
*/
@@ -161,16 +162,7 @@ public final class BluetoothCodecStatus implements Parcelable {
public static final @android.annotation.NonNull Parcelable.Creator<BluetoothCodecStatus> CREATOR =
new Parcelable.Creator<BluetoothCodecStatus>() {
public BluetoothCodecStatus createFromParcel(Parcel in) {
- final BluetoothCodecConfig codecConfig = in.readTypedObject(
- BluetoothCodecConfig.CREATOR);
- final BluetoothCodecConfig[] codecsLocalCapabilities = in.createTypedArray(
- BluetoothCodecConfig.CREATOR);
- final BluetoothCodecConfig[] codecsSelectableCapabilities = in.createTypedArray(
- BluetoothCodecConfig.CREATOR);
-
- return new BluetoothCodecStatus(codecConfig,
- codecsLocalCapabilities,
- codecsSelectableCapabilities);
+ return new BluetoothCodecStatus(in);
}
public BluetoothCodecStatus[] newArray(int size) {
@@ -179,47 +171,38 @@ public final class BluetoothCodecStatus implements Parcelable {
};
/**
- * Flattens the object to a parcel
+ * Flattens the object to a parcel.
*
- * @param out The Parcel in which the object should be written.
- * @param flags Additional flags about how the object should be written.
- *
- * @hide
+ * @param out The Parcel in which the object should be written
+ * @param flags Additional flags about how the object should be written
*/
@Override
- public void writeToParcel(Parcel out, int flags) {
+ public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeTypedObject(mCodecConfig, 0);
- out.writeTypedArray(mCodecsLocalCapabilities, 0);
- out.writeTypedArray(mCodecsSelectableCapabilities, 0);
+ out.writeTypedList(mCodecsLocalCapabilities);
+ out.writeTypedList(mCodecsSelectableCapabilities);
}
/**
- * Gets the current codec configuration.
- *
- * @return the current codec configuration
+ * Returns the current codec configuration.
*/
- @UnsupportedAppUsage
public @Nullable BluetoothCodecConfig getCodecConfig() {
return mCodecConfig;
}
/**
- * Gets the codecs local capabilities.
- *
- * @return an array with the codecs local capabilities
+ * Returns the codecs local capabilities.
*/
- @UnsupportedAppUsage
- public @Nullable BluetoothCodecConfig[] getCodecsLocalCapabilities() {
- return mCodecsLocalCapabilities;
+ public @NonNull List<BluetoothCodecConfig> getCodecsLocalCapabilities() {
+ return (mCodecsLocalCapabilities == null)
+ ? Collections.emptyList() : mCodecsLocalCapabilities;
}
/**
- * Gets the codecs selectable capabilities.
- *
- * @return an array with the codecs selectable capabilities
+ * Returns the codecs selectable capabilities.
*/
- @UnsupportedAppUsage
- public @Nullable BluetoothCodecConfig[] getCodecsSelectableCapabilities() {
- return mCodecsSelectableCapabilities;
+ public @NonNull List<BluetoothCodecConfig> getCodecsSelectableCapabilities() {
+ return (mCodecsSelectableCapabilities == null)
+ ? Collections.emptyList() : mCodecsSelectableCapabilities;
}
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index c71fcc637cb9..6e918bd6243d 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1340,7 +1340,10 @@ public final class BluetoothDevice implements Parcelable, Attributable {
if (alias == null) {
return getName();
}
- return alias;
+ return alias
+ .replace('\t', ' ')
+ .replace('\n', ' ')
+ .replace('\r', ' ');
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index ca898bd6a5ef..4e7c01ad2db1 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -16,6 +16,8 @@
package android.bluetooth;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
@@ -29,6 +31,8 @@ import android.os.ParcelUuid;
import android.os.RemoteException;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@@ -140,27 +144,6 @@ public final class BluetoothGatt implements BluetoothProfile {
public static final int CONNECTION_PRIORITY_LOW_POWER = 2;
/**
- * A GATT writeCharacteristic request is started successfully.
- *
- * @hide
- */
- public static final int GATT_WRITE_REQUEST_SUCCESS = 0;
-
- /**
- * A GATT writeCharacteristic request failed to start.
- *
- * @hide
- */
- public static final int GATT_WRITE_REQUEST_FAIL = 1;
-
- /**
- * A GATT writeCharacteristic request is issued to a busy remote device.
- *
- * @hide
- */
- public static final int GATT_WRITE_REQUEST_BUSY = 2;
-
- /**
* No authentication required.
*
* @hide
@@ -430,6 +413,9 @@ public final class BluetoothGatt implements BluetoothProfile {
if (callback != null) {
if (status == 0) characteristic.setValue(value);
callback.onCharacteristicRead(BluetoothGatt.this, characteristic,
+ value, status);
+ // Keep calling deprecated callback to maintain app compatibility
+ callback.onCharacteristicRead(BluetoothGatt.this, characteristic,
status);
}
}
@@ -443,7 +429,8 @@ public final class BluetoothGatt implements BluetoothProfile {
*/
@Override
@SuppressLint("AndroidFrameworkRequiresPermission")
- public void onCharacteristicWrite(String address, int status, int handle) {
+ public void onCharacteristicWrite(String address, int status, int handle,
+ byte[] value) {
if (VDBG) {
Log.d(TAG, "onCharacteristicWrite() - Device=" + address
+ " handle=" + handle + " Status=" + status);
@@ -467,12 +454,13 @@ public final class BluetoothGatt implements BluetoothProfile {
try {
final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE)
? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
- int requestStatus = GATT_WRITE_REQUEST_FAIL;
+ int requestStatus = BluetoothStatusCodes.ERROR_UNKNOWN;
for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) {
requestStatus = mService.writeCharacteristic(mClientIf, address,
handle, characteristic.getWriteType(), authReq,
- characteristic.getValue(), mAttributionSource);
- if (requestStatus != GATT_WRITE_REQUEST_BUSY) {
+ value, mAttributionSource);
+ if (requestStatus
+ != BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY) {
break;
}
try {
@@ -488,7 +476,6 @@ public final class BluetoothGatt implements BluetoothProfile {
}
mAuthRetryState = AUTH_RETRY_STATE_IDLE;
-
runOrQueueCallback(new Runnable() {
@Override
public void run() {
@@ -525,6 +512,9 @@ public final class BluetoothGatt implements BluetoothProfile {
if (callback != null) {
characteristic.setValue(value);
callback.onCharacteristicChanged(BluetoothGatt.this,
+ characteristic, value);
+ // Keep calling deprecated callback to maintain app compatibility
+ callback.onCharacteristicChanged(BluetoothGatt.this,
characteristic);
}
}
@@ -578,6 +568,9 @@ public final class BluetoothGatt implements BluetoothProfile {
final BluetoothGattCallback callback = mCallback;
if (callback != null) {
if (status == 0) descriptor.setValue(value);
+ callback.onDescriptorRead(BluetoothGatt.this, descriptor, status,
+ value);
+ // Keep calling deprecated callback to maintain app compatibility
callback.onDescriptorRead(BluetoothGatt.this, descriptor, status);
}
}
@@ -590,7 +583,8 @@ public final class BluetoothGatt implements BluetoothProfile {
*/
@Override
@SuppressLint("AndroidFrameworkRequiresPermission")
- public void onDescriptorWrite(String address, int status, int handle) {
+ public void onDescriptorWrite(String address, int status, int handle,
+ byte[] value) {
if (VDBG) {
Log.d(TAG,
"onDescriptorWrite() - Device=" + address + " handle=" + handle);
@@ -614,7 +608,7 @@ public final class BluetoothGatt implements BluetoothProfile {
final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE)
? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
mService.writeDescriptor(mClientIf, address, handle,
- authReq, descriptor.getValue(), mAttributionSource);
+ authReq, value, mAttributionSource);
mAuthRetryState++;
return;
} catch (RemoteException e) {
@@ -1194,8 +1188,8 @@ public final class BluetoothGatt implements BluetoothProfile {
* Reads the requested characteristic from the associated remote device.
*
* <p>This is an asynchronous operation. The result of the read operation
- * is reported by the {@link BluetoothGattCallback#onCharacteristicRead}
- * callback.
+ * is reported by the {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt,
+ * BluetoothGattCharacteristic, byte[], int)} callback.
*
* @param characteristic Characteristic to read from the remote device
* @return true, if the read operation was initiated successfully
@@ -1240,8 +1234,8 @@ public final class BluetoothGatt implements BluetoothProfile {
* Reads the characteristic using its UUID from the associated remote device.
*
* <p>This is an asynchronous operation. The result of the read operation
- * is reported by the {@link BluetoothGattCallback#onCharacteristicRead}
- * callback.
+ * is reported by the {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt,
+ * BluetoothGattCharacteristic, byte[], int)} callback.
*
* @param uuid UUID of characteristic to read from the remote device
* @return true, if the read operation was initiated successfully
@@ -1284,40 +1278,94 @@ public final class BluetoothGatt implements BluetoothProfile {
*
* @param characteristic Characteristic to write on the remote device
* @return true, if the write operation was initiated successfully
+ * @throws IllegalArgumentException if characteristic or its value are null
+ *
+ * @deprecated Use {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[],
+ * int)} as this is not memory safe.
*/
+ @Deprecated
@RequiresLegacyBluetoothPermission
@RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {
- if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0
- && (characteristic.getProperties()
- & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) {
+ try {
+ return writeCharacteristic(characteristic, characteristic.getValue(),
+ characteristic.getWriteType()) == BluetoothStatusCodes.SUCCESS;
+ } catch (Exception e) {
return false;
}
+ }
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ BluetoothStatusCodes.SUCCESS,
+ BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
+ BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION,
+ BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED,
+ BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
+ BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED,
+ BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY,
+ BluetoothStatusCodes.ERROR_UNKNOWN
+ })
+ public @interface WriteOperationReturnValues{}
+ /**
+ * Writes a given characteristic and its values to the associated remote device.
+ *
+ * <p>Once the write operation has been completed, the
+ * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked,
+ * reporting the result of the operation.
+ *
+ * @param characteristic Characteristic to write on the remote device
+ * @return whether the characteristic was successfully written to
+ * @throws IllegalArgumentException if characteristic or value are null
+ */
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @WriteOperationReturnValues
+ public int writeCharacteristic(@NonNull BluetoothGattCharacteristic characteristic,
+ @NonNull byte[] value, int writeType) {
+ if (characteristic == null) {
+ throw new IllegalArgumentException("characteristic must not be null");
+ }
+ if (value == null) {
+ throw new IllegalArgumentException("value must not be null");
+ }
if (VDBG) Log.d(TAG, "writeCharacteristic() - uuid: " + characteristic.getUuid());
- if (mService == null || mClientIf == 0 || characteristic.getValue() == null) return false;
+ if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0
+ && (characteristic.getProperties()
+ & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) {
+ return BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED;
+ }
+ if (mService == null || mClientIf == 0) {
+ return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
+ }
BluetoothGattService service = characteristic.getService();
- if (service == null) return false;
+ if (service == null) {
+ throw new IllegalArgumentException("Characteristic must have a non-null service");
+ }
BluetoothDevice device = service.getDevice();
- if (device == null) return false;
+ if (device == null) {
+ throw new IllegalArgumentException("Service must have a non-null device");
+ }
synchronized (mDeviceBusyLock) {
if (mDeviceBusy) {
- return false;
+ return BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY;
}
mDeviceBusy = true;
}
- int requestStatus = GATT_WRITE_REQUEST_FAIL;
+ int requestStatus = BluetoothStatusCodes.ERROR_UNKNOWN;
try {
for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) {
requestStatus = mService.writeCharacteristic(mClientIf, device.getAddress(),
- characteristic.getInstanceId(), characteristic.getWriteType(),
- AUTHENTICATION_NONE, characteristic.getValue(), mAttributionSource);
- if (requestStatus != GATT_WRITE_REQUEST_BUSY) {
+ characteristic.getInstanceId(), writeType, AUTHENTICATION_NONE, value,
+ mAttributionSource);
+ if (requestStatus != BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY) {
break;
}
try {
@@ -1330,10 +1378,10 @@ public final class BluetoothGatt implements BluetoothProfile {
synchronized (mDeviceBusyLock) {
mDeviceBusy = false;
}
- return false;
+ throw e.rethrowFromSystemServer();
}
- return requestStatus == GATT_WRITE_REQUEST_SUCCESS;
+ return requestStatus;
}
/**
@@ -1384,45 +1432,86 @@ public final class BluetoothGatt implements BluetoothProfile {
/**
* Write the value of a given descriptor to the associated remote device.
*
- * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is
- * triggered to report the result of the write operation.
+ * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is triggered to report the
+ * result of the write operation.
*
* @param descriptor Descriptor to write to the associated remote device
* @return true, if the write operation was initiated successfully
+ * @throws IllegalArgumentException if descriptor or its value are null
+ *
+ * @deprecated Use {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor, byte[])} as
+ * this is not memory safe.
*/
+ @Deprecated
@RequiresLegacyBluetoothPermission
@RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean writeDescriptor(BluetoothGattDescriptor descriptor) {
+ try {
+ return writeDescriptor(descriptor, descriptor.getValue())
+ == BluetoothStatusCodes.SUCCESS;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ /**
+ * Write the value of a given descriptor to the associated remote device.
+ *
+ * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is triggered to report the
+ * result of the write operation.
+ *
+ * @param descriptor Descriptor to write to the associated remote device
+ * @return true, if the write operation was initiated successfully
+ * @throws IllegalArgumentException if descriptor or value are null
+ */
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @WriteOperationReturnValues
+ public int writeDescriptor(@NonNull BluetoothGattDescriptor descriptor,
+ @NonNull byte[] value) {
+ if (descriptor == null) {
+ throw new IllegalArgumentException("descriptor must not be null");
+ }
+ if (value == null) {
+ throw new IllegalArgumentException("value must not be null");
+ }
if (VDBG) Log.d(TAG, "writeDescriptor() - uuid: " + descriptor.getUuid());
- if (mService == null || mClientIf == 0 || descriptor.getValue() == null) return false;
+ if (mService == null || mClientIf == 0) {
+ return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
+ }
BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
- if (characteristic == null) return false;
+ if (characteristic == null) {
+ throw new IllegalArgumentException("Descriptor must have a non-null characteristic");
+ }
BluetoothGattService service = characteristic.getService();
- if (service == null) return false;
+ if (service == null) {
+ throw new IllegalArgumentException("Characteristic must have a non-null service");
+ }
BluetoothDevice device = service.getDevice();
- if (device == null) return false;
+ if (device == null) {
+ throw new IllegalArgumentException("Service must have a non-null device");
+ }
synchronized (mDeviceBusyLock) {
- if (mDeviceBusy) return false;
+ if (mDeviceBusy) return BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY;
mDeviceBusy = true;
}
try {
- mService.writeDescriptor(mClientIf, device.getAddress(), descriptor.getInstanceId(),
- AUTHENTICATION_NONE, descriptor.getValue(), mAttributionSource);
+ return mService.writeDescriptor(mClientIf, device.getAddress(),
+ descriptor.getInstanceId(), AUTHENTICATION_NONE, value, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
synchronized (mDeviceBusyLock) {
mDeviceBusy = false;
}
- return false;
+ e.rethrowFromSystemServer();
}
-
- return true;
+ return BluetoothStatusCodes.ERROR_UNKNOWN;
}
/**
@@ -1431,9 +1520,9 @@ public final class BluetoothGatt implements BluetoothProfile {
* <p>Once a reliable write transaction has been initiated, all calls
* to {@link #writeCharacteristic} are sent to the remote device for
* verification and queued up for atomic execution. The application will
- * receive an {@link BluetoothGattCallback#onCharacteristicWrite} callback
- * in response to every {@link #writeCharacteristic} call and is responsible
- * for verifying if the value has been transmitted accurately.
+ * receive a {@link BluetoothGattCallback#onCharacteristicWrite} callback in response to every
+ * {@link #writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} call and is
+ * responsible for verifying if the value has been transmitted accurately.
*
* <p>After all characteristics have been queued up and verified,
* {@link #executeReliableWrite} will execute all writes. If a characteristic
@@ -1530,9 +1619,9 @@ public final class BluetoothGatt implements BluetoothProfile {
* Enable or disable notifications/indications for a given characteristic.
*
* <p>Once notifications are enabled for a characteristic, a
- * {@link BluetoothGattCallback#onCharacteristicChanged} callback will be
- * triggered if the remote device indicates that the given characteristic
- * has changed.
+ * {@link BluetoothGattCallback#onCharacteristicChanged(BluetoothGatt,
+ * BluetoothGattCharacteristic, byte[])} callback will be triggered if the remote device
+ * indicates that the given characteristic has changed.
*
* @param characteristic The characteristic for which to enable notifications
* @param enable Set to true to enable notifications/indications
diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java
index 1c40cff076f6..d0a5a1e729fe 100644
--- a/core/java/android/bluetooth/BluetoothGattCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattCallback.java
@@ -80,16 +80,34 @@ public abstract class BluetoothGattCallback {
/**
* Callback reporting the result of a characteristic read operation.
*
- * @param gatt GATT client invoked {@link BluetoothGatt#readCharacteristic}
+ * @param gatt GATT client invoked
+ * {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)}
* @param characteristic Characteristic that was read from the associated remote device.
- * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed
- * successfully.
+ * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed
+ * successfully.
+ * @deprecated Use {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt,
+ * BluetoothGattCharacteristic, byte[], int)} as it is memory safe
*/
+ @Deprecated
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
int status) {
}
/**
+ * Callback reporting the result of a characteristic read operation.
+ *
+ * @param gatt GATT client invoked
+ * {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)}
+ * @param characteristic Characteristic that was read from the associated remote device.
+ * @param value the value of the characteristic
+ * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed
+ * successfully.
+ */
+ public void onCharacteristicRead(@NonNull BluetoothGatt gatt, @NonNull
+ BluetoothGattCharacteristic characteristic, @NonNull byte[] value, int status) {
+ }
+
+ /**
* Callback indicating the result of a characteristic write operation.
*
* <p>If this callback is invoked while a reliable write transaction is
@@ -98,10 +116,13 @@ public abstract class BluetoothGattCallback {
* value to the desired value to be written. If the values don't match,
* the application must abort the reliable write transaction.
*
- * @param gatt GATT client invoked {@link BluetoothGatt#writeCharacteristic}
+ * @param gatt GATT client that invoked
+ * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic,
+ * byte[], int)}
* @param characteristic Characteristic that was written to the associated remote device.
- * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if the
- * operation succeeds.
+ * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if
+ * the
+ * operation succeeds.
*/
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
@@ -110,33 +131,68 @@ public abstract class BluetoothGattCallback {
/**
* Callback triggered as a result of a remote characteristic notification.
*
- * @param gatt GATT client the characteristic is associated with
+ * @param gatt GATT client the characteristic is associated with
* @param characteristic Characteristic that has been updated as a result of a remote
- * notification event.
+ * notification event.
+ * @deprecated Use {@link BluetoothGattCallback#onCharacteristicChanged(BluetoothGatt,
+ * BluetoothGattCharacteristic, byte[])} as it is memory safe by providing the characteristic
+ * value at the time of notification.
*/
+ @Deprecated
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
}
/**
+ * Callback triggered as a result of a remote characteristic notification. Note that the value
+ * within the characteristic object may have changed since receiving the remote characteristic
+ * notification, so check the parameter value for the value at the time of notification.
+ *
+ * @param gatt GATT client the characteristic is associated with
+ * @param characteristic Characteristic that has been updated as a result of a remote
+ * notification event.
+ * @param value notified characteristic value
+ */
+ public void onCharacteristicChanged(@NonNull BluetoothGatt gatt,
+ @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value) {
+ }
+
+ /**
* Callback reporting the result of a descriptor read operation.
*
- * @param gatt GATT client invoked {@link BluetoothGatt#readDescriptor}
+ * @param gatt GATT client invoked {@link BluetoothGatt#readDescriptor}
* @param descriptor Descriptor that was read from the associated remote device.
- * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed
- * successfully
+ * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed
+ * successfully
+ * @deprecated Use {@link BluetoothGattCallback#onDescriptorRead(BluetoothGatt,
+ * BluetoothGattDescriptor, int, byte[])} as it is memory safe by providing the descriptor
+ * value at the time it was read.
*/
+ @Deprecated
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
int status) {
}
/**
+ * Callback reporting the result of a descriptor read operation.
+ *
+ * @param gatt GATT client invoked {@link BluetoothGatt#readDescriptor}
+ * @param descriptor Descriptor that was read from the associated remote device.
+ * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed
+ * successfully
+ * @param value the descriptor value at the time of the read operation
+ */
+ public void onDescriptorRead(@NonNull BluetoothGatt gatt,
+ @NonNull BluetoothGattDescriptor descriptor, int status, @NonNull byte[] value) {
+ }
+
+ /**
* Callback indicating the result of a descriptor write operation.
*
- * @param gatt GATT client invoked {@link BluetoothGatt#writeDescriptor}
+ * @param gatt GATT client invoked {@link BluetoothGatt#writeDescriptor}
* @param descriptor Descriptor that was writte to the associated remote device.
- * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if the
- * operation succeeds.
+ * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if the
+ * operation succeeds.
*/
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
int status) {
diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
index 8a7d4baf5add..c5e986e895b2 100644
--- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java
+++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
@@ -451,8 +451,8 @@ public class BluetoothGattCharacteristic implements Parcelable {
* Set the write type for this characteristic
*
* <p>Setting the write type of a characteristic determines how the
- * {@link BluetoothGatt#writeCharacteristic} function write this
- * characteristic.
+ * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} function
+ * write this characteristic.
*
* @param writeType The write type to for this characteristic. Can be one of: {@link
* #WRITE_TYPE_DEFAULT}, {@link #WRITE_TYPE_NO_RESPONSE} or {@link #WRITE_TYPE_SIGNED}.
@@ -504,7 +504,10 @@ public class BluetoothGattCharacteristic implements Parcelable {
* operation or if a characteristic update notification has been received.
*
* @return Cached value of the characteristic
+ *
+ * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} instead
*/
+ @Deprecated
public byte[] getValue() {
return mValue;
}
@@ -521,7 +524,11 @@ public class BluetoothGattCharacteristic implements Parcelable {
* @param formatType The format type used to interpret the characteristic value.
* @param offset Offset at which the integer value can be found.
* @return Cached value of the characteristic or null of offset exceeds value size.
+ *
+ * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get
+ * the characteristic value
*/
+ @Deprecated
public Integer getIntValue(int formatType, int offset) {
if ((offset + getTypeLen(formatType)) > mValue.length) return null;
@@ -558,7 +565,11 @@ public class BluetoothGattCharacteristic implements Parcelable {
* @param offset Offset at which the float value can be found.
* @return Cached value of the characteristic at a given offset or null if the requested offset
* exceeds the value size.
+ *
+ * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get
+ * the characteristic value
*/
+ @Deprecated
public Float getFloatValue(int formatType, int offset) {
if ((offset + getTypeLen(formatType)) > mValue.length) return null;
@@ -580,7 +591,11 @@ public class BluetoothGattCharacteristic implements Parcelable {
*
* @param offset Offset at which the string value can be found.
* @return Cached value of the characteristic
+ *
+ * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get
+ * the characteristic value
*/
+ @Deprecated
public String getStringValue(int offset) {
if (mValue == null || offset > mValue.length) return null;
byte[] strBytes = new byte[mValue.length - offset];
@@ -599,7 +614,11 @@ public class BluetoothGattCharacteristic implements Parcelable {
* @param value New value for this characteristic
* @return true if the locally stored value has been set, false if the requested value could not
* be stored locally.
+ *
+ * @deprecated Pass the characteristic value directly into
+ * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)}
*/
+ @Deprecated
public boolean setValue(byte[] value) {
mValue = value;
return true;
@@ -613,7 +632,11 @@ public class BluetoothGattCharacteristic implements Parcelable {
* @param formatType Integer format type used to transform the value parameter
* @param offset Offset at which the value should be placed
* @return true if the locally stored value has been set
+ *
+ * @deprecated Pass the characteristic value directly into
+ * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)}
*/
+ @Deprecated
public boolean setValue(int value, int formatType, int offset) {
int len = offset + getTypeLen(formatType);
if (mValue == null) mValue = new byte[len];
@@ -660,7 +683,11 @@ public class BluetoothGattCharacteristic implements Parcelable {
* @param formatType Float format type used to transform the value parameter
* @param offset Offset at which the value should be placed
* @return true if the locally stored value has been set
+ *
+ * @deprecated Pass the characteristic value directly into
+ * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)}
*/
+ @Deprecated
public boolean setValue(int mantissa, int exponent, int formatType, int offset) {
int len = offset + getTypeLen(formatType);
if (mValue == null) mValue = new byte[len];
@@ -697,7 +724,11 @@ public class BluetoothGattCharacteristic implements Parcelable {
*
* @param value New value for this characteristic
* @return true if the locally stored value has been set
+ *
+ * @deprecated Pass the characteristic value directly into
+ * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)}
*/
+ @Deprecated
public boolean setValue(String value) {
mValue = value.getBytes();
return true;
diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.java b/core/java/android/bluetooth/BluetoothGattDescriptor.java
index ed5ea0873020..a35d5b99fd7b 100644
--- a/core/java/android/bluetooth/BluetoothGattDescriptor.java
+++ b/core/java/android/bluetooth/BluetoothGattDescriptor.java
@@ -260,7 +260,10 @@ public class BluetoothGattDescriptor implements Parcelable {
* operation.
*
* @return Cached value of the descriptor
+ *
+ * @deprecated Use {@link BluetoothGatt#readDescriptor(BluetoothGattDescriptor)} instead
*/
+ @Deprecated
public byte[] getValue() {
return mValue;
}
@@ -276,7 +279,11 @@ public class BluetoothGattDescriptor implements Parcelable {
* @param value New value for this descriptor
* @return true if the locally stored value has been set, false if the requested value could not
* be stored locally.
+ *
+ * @deprecated Pass the descriptor value directly into
+ * {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor, byte[])}
*/
+ @Deprecated
public boolean setValue(byte[] value) {
mValue = value;
return true;
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 3e799defa5e9..08e0178403f1 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -16,6 +16,8 @@
package android.bluetooth;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
@@ -26,6 +28,8 @@ import android.os.ParcelUuid;
import android.os.RemoteException;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@@ -709,33 +713,85 @@ public final class BluetoothGattServer implements BluetoothProfile {
* notification
* @return true, if the notification has been triggered successfully
* @throws IllegalArgumentException
+ *
+ * @deprecated Use {@link BluetoothGattServer#notifyCharacteristicChanged(BluetoothDevice,
+ * BluetoothGattCharacteristic, boolean, byte[])} as this is not memory safe.
*/
+ @Deprecated
@RequiresLegacyBluetoothPermission
@RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean notifyCharacteristicChanged(BluetoothDevice device,
BluetoothGattCharacteristic characteristic, boolean confirm) {
+ return notifyCharacteristicChanged(device, characteristic, confirm,
+ characteristic.getValue()) == BluetoothStatusCodes.SUCCESS;
+ }
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ BluetoothStatusCodes.SUCCESS,
+ BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
+ BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION,
+ BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED,
+ BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
+ BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED,
+ BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY,
+ BluetoothStatusCodes.ERROR_UNKNOWN
+ })
+ public @interface NotifyCharacteristicReturnValues{}
+
+ /**
+ * Send a notification or indication that a local characteristic has been
+ * updated.
+ *
+ * <p>A notification or indication is sent to the remote device to signal
+ * that the characteristic has been updated. This function should be invoked
+ * for every client that requests notifications/indications by writing
+ * to the "Client Configuration" descriptor for the given characteristic.
+ *
+ * @param device the remote device to receive the notification/indication
+ * @param characteristic the local characteristic that has been updated
+ * @param confirm {@code true} to request confirmation from the client (indication) or
+ * {@code false} to send a notification
+ * @param value the characteristic value
+ * @return whether the notification has been triggered successfully
+ * @throws IllegalArgumentException if the characteristic value or service is null
+ */
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @NotifyCharacteristicReturnValues
+ public int notifyCharacteristicChanged(@NonNull BluetoothDevice device,
+ @NonNull BluetoothGattCharacteristic characteristic, boolean confirm,
+ @NonNull byte[] value) {
if (VDBG) Log.d(TAG, "notifyCharacteristicChanged() - device: " + device.getAddress());
- if (mService == null || mServerIf == 0) return false;
+ if (mService == null || mServerIf == 0) {
+ return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
+ }
+ if (characteristic == null) {
+ throw new IllegalArgumentException("characteristic must not be null");
+ }
+ if (device == null) {
+ throw new IllegalArgumentException("device must not be null");
+ }
BluetoothGattService service = characteristic.getService();
- if (service == null) return false;
-
- if (characteristic.getValue() == null) {
- throw new IllegalArgumentException("Chracteristic value is empty. Use "
- + "BluetoothGattCharacteristic#setvalue to update");
+ if (service == null) {
+ throw new IllegalArgumentException("Characteristic must have a non-null service");
+ }
+ if (value == null) {
+ throw new IllegalArgumentException("Characteristic value must not be null");
}
try {
- mService.sendNotification(mServerIf, device.getAddress(),
+ return mService.sendNotification(mServerIf, device.getAddress(),
characteristic.getInstanceId(), confirm,
- characteristic.getValue(), mAttributionSource);
+ value, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
- return false;
+ throw e.rethrowFromSystemServer();
}
-
- return true;
}
/**
diff --git a/core/java/android/bluetooth/BluetoothLeBroadcast.java b/core/java/android/bluetooth/BluetoothLeBroadcast.java
new file mode 100644
index 000000000000..fed9f911d5b3
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothLeBroadcast.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright 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.bluetooth;
+
+import android.annotation.IntDef;
+import android.content.Context;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/**
+ * This class provides the public APIs to control the Bluetooth LE Broadcast Source profile.
+ *
+ * <p>BluetoothLeBroadcast is a proxy object for controlling the Bluetooth LE Broadcast
+ * Source Service via IPC. Use {@link BluetoothAdapter#getProfileProxy}
+ * to get the BluetoothLeBroadcast proxy object.
+ *
+ * @hide
+ */
+public final class BluetoothLeBroadcast implements BluetoothProfile {
+ private static final String TAG = "BluetoothLeBroadcast";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+
+ /**
+ * Constants used by the LE Audio Broadcast profile for the Broadcast state
+ *
+ * @hide
+ */
+ @IntDef(prefix = {"LE_AUDIO_BROADCAST_STATE_"}, value = {
+ LE_AUDIO_BROADCAST_STATE_DISABLED,
+ LE_AUDIO_BROADCAST_STATE_ENABLING,
+ LE_AUDIO_BROADCAST_STATE_ENABLED,
+ LE_AUDIO_BROADCAST_STATE_DISABLING,
+ LE_AUDIO_BROADCAST_STATE_PLAYING,
+ LE_AUDIO_BROADCAST_STATE_NOT_PLAYING
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LeAudioBroadcastState {}
+
+ /**
+ * Indicates that LE Audio Broadcast mode is currently disabled
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_STATE_DISABLED = 10;
+
+ /**
+ * Indicates that LE Audio Broadcast mode is being enabled
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_STATE_ENABLING = 11;
+
+ /**
+ * Indicates that LE Audio Broadcast mode is currently enabled
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_STATE_ENABLED = 12;
+ /**
+ * Indicates that LE Audio Broadcast mode is being disabled
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_STATE_DISABLING = 13;
+
+ /**
+ * Indicates that an LE Audio Broadcast mode is currently playing
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_STATE_PLAYING = 14;
+
+ /**
+ * Indicates that LE Audio Broadcast is currently not playing
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_STATE_NOT_PLAYING = 15;
+
+ /**
+ * Constants used by the LE Audio Broadcast profile for encryption key length
+ *
+ * @hide
+ */
+ @IntDef(prefix = {"LE_AUDIO_BROADCAST_ENCRYPTION_KEY_"}, value = {
+ LE_AUDIO_BROADCAST_ENCRYPTION_KEY_32BIT,
+ LE_AUDIO_BROADCAST_ENCRYPTION_KEY_128BIT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LeAudioEncryptionKeyLength {}
+
+ /**
+ * Indicates that the LE Audio Broadcast encryption key size is 32 bits.
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_ENCRYPTION_KEY_32BIT = 16;
+
+ /**
+ * Indicates that the LE Audio Broadcast encryption key size is 128 bits.
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_ENCRYPTION_KEY_128BIT = 17;
+
+ /**
+ * Interface for receiving events related to broadcasts
+ */
+ public interface Callback {
+ /**
+ * Called when broadcast state has changed
+ *
+ * @param prevState broadcast state before the change
+ * @param newState broadcast state after the change
+ */
+ @LeAudioBroadcastState
+ void onBroadcastStateChange(int prevState, int newState);
+ /**
+ * Called when encryption key has been updated
+ *
+ * @param success true if the key was updated successfully, false otherwise
+ */
+ void onEncryptionKeySet(boolean success);
+ }
+
+ /**
+ * Create a BluetoothLeBroadcast proxy object for interacting with the local
+ * LE Audio Broadcast Source service.
+ *
+ * @hide
+ */
+ /*package*/ BluetoothLeBroadcast(Context context,
+ BluetoothProfile.ServiceListener listener) {
+ }
+
+ /**
+ * Not supported since LE Audio Broadcasts do not establish a connection
+ *
+ * @throws UnsupportedOperationException
+ *
+ * @hide
+ */
+ @Override
+ public int getConnectionState(BluetoothDevice device) {
+ throw new UnsupportedOperationException(
+ "LE Audio Broadcasts are not connection-oriented.");
+ }
+
+ /**
+ * Not supported since LE Audio Broadcasts do not establish a connection
+ *
+ * @throws UnsupportedOperationException
+ *
+ * @hide
+ */
+ @Override
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ throw new UnsupportedOperationException(
+ "LE Audio Broadcasts are not connection-oriented.");
+ }
+
+ /**
+ * Not supported since LE Audio Broadcasts do not establish a connection
+ *
+ * @throws UnsupportedOperationException
+ *
+ * @hide
+ */
+ @Override
+ public List<BluetoothDevice> getConnectedDevices() {
+ throw new UnsupportedOperationException(
+ "LE Audio Broadcasts are not connection-oriented.");
+ }
+
+ /**
+ * Enable LE Audio Broadcast mode.
+ *
+ * Generates a new broadcast ID and enables sending of encrypted or unencrypted
+ * isochronous PDUs
+ *
+ * @hide
+ */
+ public int enableBroadcastMode() {
+ if (DBG) log("enableBroadcastMode");
+ return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED;
+ }
+
+ /**
+ * Disable LE Audio Broadcast mode.
+ *
+ * @hide
+ */
+ public int disableBroadcastMode() {
+ if (DBG) log("disableBroadcastMode");
+ return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED;
+ }
+
+ /**
+ * Get the current LE Audio broadcast state
+ *
+ * @hide
+ */
+ @LeAudioBroadcastState
+ public int getBroadcastState() {
+ if (DBG) log("getBroadcastState");
+ return LE_AUDIO_BROADCAST_STATE_DISABLED;
+ }
+
+ /**
+ * Enable LE Audio broadcast encryption
+ *
+ * @param keyLength if useExisting is true, this specifies the length of the key that should
+ * be generated
+ * @param useExisting true, if an existing key should be used
+ * false, if a new key should be generated
+ *
+ * @hide
+ */
+ @LeAudioEncryptionKeyLength
+ public int enableEncryption(boolean useExisting, int keyLength) {
+ if (DBG) log("enableEncryption useExisting=" + useExisting + " keyLength=" + keyLength);
+ return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_ENABLE_ENCRYPTION_FAILED;
+ }
+
+ /**
+ * Disable LE Audio broadcast encryption
+ *
+ * @param removeExisting true, if the existing key should be removed
+ * false, otherwise
+ *
+ * @hide
+ */
+ public int disableEncryption(boolean removeExisting) {
+ if (DBG) log("disableEncryption removeExisting=" + removeExisting);
+ return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_DISABLE_ENCRYPTION_FAILED;
+ }
+
+ /**
+ * Enable or disable LE Audio broadcast encryption
+ *
+ * @param key use the provided key if non-null, generate a new key if null
+ * @param keyLength 0 if encryption is disabled, 4 bytes (low security),
+ * 16 bytes (high security)
+ *
+ * @hide
+ */
+ @LeAudioEncryptionKeyLength
+ public int setEncryptionKey(byte[] key, int keyLength) {
+ if (DBG) log("setEncryptionKey key=" + key + " keyLength=" + keyLength);
+ return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_ENCRYPTION_KEY_FAILED;
+ }
+
+
+ /**
+ * Get the encryption key that was set before
+ *
+ * @return encryption key as a byte array or null if no encryption key was set
+ *
+ * @hide
+ */
+ public byte[] getEncryptionKey() {
+ if (DBG) log("getEncryptionKey");
+ return null;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 0cf9f9fd6f43..e047e5d81a9d 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -233,12 +233,19 @@ public interface BluetoothProfile {
int CSIP_SET_COORDINATOR = 25;
/**
+ * LE Audio Broadcast Source
+ *
+ * @hide
+ */
+ int LE_AUDIO_BROADCAST = 26;
+
+ /**
* Max profile ID. This value should be updated whenever a new profile is added to match
* the largest value assigned to a profile.
*
* @hide
*/
- int MAX_PROFILE_ID = 25;
+ int MAX_PROFILE_ID = 26;
/**
* Default priority for devices that we try to auto-connect to and
@@ -436,6 +443,8 @@ public interface BluetoothProfile {
return "OPP";
case HEARING_AID:
return "HEARING_AID";
+ case LE_AUDIO:
+ return "LE_AUDIO";
default:
return "UNKNOWN_PROFILE";
}
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 1655b62bbfec..db5b75148e88 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -18,7 +18,6 @@ package android.bluetooth;
import android.annotation.RequiresNoPermission;
import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.LocalSocket;
@@ -266,7 +265,7 @@ public final class BluetoothSocket implements Closeable {
throw new IOException("bt socket acept failed");
}
- as.mPfd = new ParcelFileDescriptor(fds[0]);
+ as.mPfd = ParcelFileDescriptor.dup(fds[0]);
as.mSocket = LocalSocket.createConnectedLocalSocket(fds[0]);
as.mSocketIS = as.mSocket.getInputStream();
as.mSocketOS = as.mSocket.getOutputStream();
diff --git a/core/java/android/bluetooth/BluetoothStatusCodes.java b/core/java/android/bluetooth/BluetoothStatusCodes.java
index 63e84eddc73f..9dafa073ab3f 100644
--- a/core/java/android/bluetooth/BluetoothStatusCodes.java
+++ b/core/java/android/bluetooth/BluetoothStatusCodes.java
@@ -79,9 +79,31 @@ public final class BluetoothStatusCodes {
public static final int ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION = 7;
/**
+ * Error code indicating that the caller does not have the
+ * {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission
+ */
+ public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8;
+
+ /**
+ * Error code indicating that the profile service is not bound. You can bind a profile service
+ * by calling {@link BluetoothAdapter#getProfileProxy}
+ */
+ public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9;
+
+ /**
* Error code indicating that the feature is not supported.
*/
- public static final int ERROR_FEATURE_NOT_SUPPORTED = 8;
+ public static final int ERROR_FEATURE_NOT_SUPPORTED = 10;
+
+ /**
+ * A GATT writeCharacteristic request is not permitted on the remote device.
+ */
+ public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 101;
+
+ /**
+ * A GATT writeCharacteristic request is issued to a busy remote device.
+ */
+ public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 102;
/**
* If another application has already requested {@link OobData} then another fetch will be
@@ -204,6 +226,66 @@ public final class BluetoothStatusCodes {
public static final int ERROR_DISCONNECT_REASON_BAD_PARAMETERS = 1109;
/**
+ * Indicates that setting the LE Audio Broadcast mode failed.
+ * <p>
+ * Example solution: Change parameters and try again. If error persists, the app can report
+ * telemetry and/or log the error in a bugreport.
+ *
+ * @hide
+ */
+ public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED = 1110;
+
+ /**
+ * Indicates that setting a new encryption key for Bluetooth LE Audio Broadcast Source failed.
+ * <p>
+ * Example solution: Change parameters and try again. If error persists, the app can report
+ * telemetry and/or log the error in a bugreport.
+ *
+ * @hide
+ */
+ public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_ENCRYPTION_KEY_FAILED = 1111;
+
+ /**
+ * Indicates that connecting to a remote Broadcast Audio Scan Service failed.
+ * <p>
+ * Example solution: Change parameters and try again. If error persists, the app can report
+ * telemetry and/or log the error in a bugreport.
+ *
+ * @hide
+ */
+ public static final int ERROR_LE_AUDIO_BROADCAST_AUDIO_SCAN_SERVICE_CONNECT_FAILED = 1112;
+
+ /**
+ * Indicates that disconnecting from a remote Broadcast Audio Scan Service failed.
+ * <p>
+ * Example solution: Change parameters and try again. If error persists, the app can report
+ * telemetry and/or log the error in a bugreport.
+ *
+ * @hide
+ */
+ public static final int ERROR_LE_AUDIO_BROADCAST_AUDIO_SCAN_SERVICE_DISCONNECT_FAILED = 1113;
+
+ /**
+ * Indicates that enabling LE Audio Broadcast encryption failed
+ * <p>
+ * Example solution: Change parameters and try again. If error persists, the app can report
+ * telemetry and/or log the error in a bugreport.
+ *
+ * @hide
+ */
+ public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_ENABLE_ENCRYPTION_FAILED = 1114;
+
+ /**
+ * Indicates that disabling LE Audio Broadcast encryption failed
+ * <p>
+ * Example solution: Change parameters and try again. If error persists, the app can report
+ * telemetry and/or log the error in a bugreport.
+ *
+ * @hide
+ */
+ public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_DISABLE_ENCRYPTION_FAILED = 1115;
+
+ /**
* Indicates that an unknown error has occurred has occurred.
*/
public static final int ERROR_UNKNOWN = Integer.MAX_VALUE;
diff --git a/core/java/android/bluetooth/le/AdvertiseData.java b/core/java/android/bluetooth/le/AdvertiseData.java
index cec658049ca5..fdf62ec3a647 100644
--- a/core/java/android/bluetooth/le/AdvertiseData.java
+++ b/core/java/android/bluetooth/le/AdvertiseData.java
@@ -25,6 +25,7 @@ import android.util.ArrayMap;
import android.util.SparseArray;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -47,6 +48,9 @@ public final class AdvertiseData implements Parcelable {
@NonNull
private final List<ParcelUuid> mServiceSolicitationUuids;
+ @Nullable
+ private final List<TransportDiscoveryData> mTransportDiscoveryData;
+
private final SparseArray<byte[]> mManufacturerSpecificData;
private final Map<ParcelUuid, byte[]> mServiceData;
private final boolean mIncludeTxPowerLevel;
@@ -54,12 +58,14 @@ public final class AdvertiseData implements Parcelable {
private AdvertiseData(List<ParcelUuid> serviceUuids,
List<ParcelUuid> serviceSolicitationUuids,
+ List<TransportDiscoveryData> transportDiscoveryData,
SparseArray<byte[]> manufacturerData,
Map<ParcelUuid, byte[]> serviceData,
boolean includeTxPowerLevel,
boolean includeDeviceName) {
mServiceUuids = serviceUuids;
mServiceSolicitationUuids = serviceSolicitationUuids;
+ mTransportDiscoveryData = transportDiscoveryData;
mManufacturerSpecificData = manufacturerData;
mServiceData = serviceData;
mIncludeTxPowerLevel = includeTxPowerLevel;
@@ -83,6 +89,17 @@ public final class AdvertiseData implements Parcelable {
}
/**
+ * Returns a list of {@link TransportDiscoveryData} within the advertisement.
+ */
+ @NonNull
+ public List<TransportDiscoveryData> getTransportDiscoveryData() {
+ if (mTransportDiscoveryData == null) {
+ return Collections.emptyList();
+ }
+ return mTransportDiscoveryData;
+ }
+
+ /**
* Returns an array of manufacturer Id and the corresponding manufacturer specific data. The
* manufacturer id is a non-negative number assigned by Bluetooth SIG.
*/
@@ -116,8 +133,8 @@ public final class AdvertiseData implements Parcelable {
*/
@Override
public int hashCode() {
- return Objects.hash(mServiceUuids, mServiceSolicitationUuids, mManufacturerSpecificData,
- mServiceData, mIncludeDeviceName, mIncludeTxPowerLevel);
+ return Objects.hash(mServiceUuids, mServiceSolicitationUuids, mTransportDiscoveryData,
+ mManufacturerSpecificData, mServiceData, mIncludeDeviceName, mIncludeTxPowerLevel);
}
/**
@@ -134,6 +151,7 @@ public final class AdvertiseData implements Parcelable {
AdvertiseData other = (AdvertiseData) obj;
return Objects.equals(mServiceUuids, other.mServiceUuids)
&& Objects.equals(mServiceSolicitationUuids, other.mServiceSolicitationUuids)
+ && Objects.equals(mTransportDiscoveryData, other.mTransportDiscoveryData)
&& BluetoothLeUtils.equals(mManufacturerSpecificData,
other.mManufacturerSpecificData)
&& BluetoothLeUtils.equals(mServiceData, other.mServiceData)
@@ -144,7 +162,8 @@ public final class AdvertiseData implements Parcelable {
@Override
public String toString() {
return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mServiceSolicitationUuids="
- + mServiceSolicitationUuids + ", mManufacturerSpecificData="
+ + mServiceSolicitationUuids + ", mTransportDiscoveryData="
+ + mTransportDiscoveryData + ", mManufacturerSpecificData="
+ BluetoothLeUtils.toString(mManufacturerSpecificData) + ", mServiceData="
+ BluetoothLeUtils.toString(mServiceData)
+ ", mIncludeTxPowerLevel=" + mIncludeTxPowerLevel + ", mIncludeDeviceName="
@@ -162,6 +181,8 @@ public final class AdvertiseData implements Parcelable {
dest.writeTypedArray(mServiceSolicitationUuids.toArray(
new ParcelUuid[mServiceSolicitationUuids.size()]), flags);
+ dest.writeTypedList(mTransportDiscoveryData);
+
// mManufacturerSpecificData could not be null.
dest.writeInt(mManufacturerSpecificData.size());
for (int i = 0; i < mManufacturerSpecificData.size(); ++i) {
@@ -197,6 +218,12 @@ public final class AdvertiseData implements Parcelable {
builder.addServiceSolicitationUuid(uuid);
}
+ List<TransportDiscoveryData> transportDiscoveryData =
+ in.createTypedArrayList(TransportDiscoveryData.CREATOR);
+ for (TransportDiscoveryData tdd : transportDiscoveryData) {
+ builder.addTransportDiscoveryData(tdd);
+ }
+
int manufacturerSize = in.readInt();
for (int i = 0; i < manufacturerSize; ++i) {
int manufacturerId = in.readInt();
@@ -223,6 +250,9 @@ public final class AdvertiseData implements Parcelable {
private List<ParcelUuid> mServiceUuids = new ArrayList<ParcelUuid>();
@NonNull
private List<ParcelUuid> mServiceSolicitationUuids = new ArrayList<ParcelUuid>();
+ @Nullable
+ private List<TransportDiscoveryData> mTransportDiscoveryData =
+ new ArrayList<TransportDiscoveryData>();
private SparseArray<byte[]> mManufacturerSpecificData = new SparseArray<byte[]>();
private Map<ParcelUuid, byte[]> mServiceData = new ArrayMap<ParcelUuid, byte[]>();
private boolean mIncludeTxPowerLevel;
@@ -256,6 +286,7 @@ public final class AdvertiseData implements Parcelable {
mServiceSolicitationUuids.add(serviceSolicitationUuid);
return this;
}
+
/**
* Add service data to advertise data.
*
@@ -274,6 +305,23 @@ public final class AdvertiseData implements Parcelable {
}
/**
+ * Add Transport Discovery Data to advertise data.
+ *
+ * @param transportDiscoveryData Transport Discovery Data, consisting of one or more
+ * Transport Blocks. Transport Discovery Data AD Type Code is already included.
+ * @throws IllegalArgumentException If the {@code transportDiscoveryData} is empty
+ */
+ @NonNull
+ public Builder addTransportDiscoveryData(
+ @NonNull TransportDiscoveryData transportDiscoveryData) {
+ if (transportDiscoveryData == null) {
+ throw new IllegalArgumentException("transportDiscoveryData is null");
+ }
+ mTransportDiscoveryData.add(transportDiscoveryData);
+ return this;
+ }
+
+ /**
* Add manufacturer specific data.
* <p>
* Please refer to the Bluetooth Assigned Numbers document provided by the <a
@@ -319,8 +367,8 @@ public final class AdvertiseData implements Parcelable {
*/
public AdvertiseData build() {
return new AdvertiseData(mServiceUuids, mServiceSolicitationUuids,
- mManufacturerSpecificData, mServiceData, mIncludeTxPowerLevel,
- mIncludeDeviceName);
+ mTransportDiscoveryData, mManufacturerSpecificData, mServiceData,
+ mIncludeTxPowerLevel, mIncludeDeviceName);
}
}
}
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 58029745ab9c..b9f8a57a75ea 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -567,6 +567,9 @@ public final class BluetoothLeAdvertiser {
+ num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT;
}
}
+ for (TransportDiscoveryData transportDiscoveryData : data.getTransportDiscoveryData()) {
+ size += OVERHEAD_BYTES_PER_FIELD + transportDiscoveryData.totalBytes();
+ }
for (ParcelUuid uuid : data.getServiceData().keySet()) {
int uuidLen = BluetoothUuid.uuidToBytes(uuid).length;
size += OVERHEAD_BYTES_PER_FIELD + uuidLen
diff --git a/core/java/android/bluetooth/le/TransportBlock.java b/core/java/android/bluetooth/le/TransportBlock.java
new file mode 100644
index 000000000000..b388beda6b3b
--- /dev/null
+++ b/core/java/android/bluetooth/le/TransportBlock.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.le;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+/**
+ * Wrapper for Transport Discovery Data Transport Blocks.
+ * This class represents a Transport Block from a Transport Discovery Data.
+ *
+ * @see TransportDiscoveryData
+ * @see AdvertiseData
+ */
+public final class TransportBlock implements Parcelable {
+ private static final String TAG = "TransportBlock";
+ private final int mOrgId;
+ private final int mTdsFlags;
+ private final int mTransportDataLength;
+ private final byte[] mTransportData;
+
+ /**
+ * Creates an instance of TransportBlock from raw data.
+ *
+ * @param orgId the Organization ID
+ * @param tdsFlags the TDS flags
+ * @param transportDataLength the total length of the Transport Data
+ * @param transportData the Transport Data
+ */
+ public TransportBlock(int orgId, int tdsFlags, int transportDataLength,
+ @Nullable byte[] transportData) {
+ mOrgId = orgId;
+ mTdsFlags = tdsFlags;
+ mTransportDataLength = transportDataLength;
+ mTransportData = transportData;
+ }
+
+ private TransportBlock(Parcel in) {
+ mOrgId = in.readInt();
+ mTdsFlags = in.readInt();
+ mTransportDataLength = in.readInt();
+ mTransportData = new byte[mTransportDataLength];
+ in.readByteArray(mTransportData);
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mOrgId);
+ dest.writeInt(mTdsFlags);
+ dest.writeInt(mTransportDataLength);
+ dest.writeByteArray(mTransportData);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Creator<TransportBlock> CREATOR = new Creator<TransportBlock>() {
+ @Override
+ public TransportBlock createFromParcel(Parcel in) {
+ return new TransportBlock(in);
+ }
+
+ @Override
+ public TransportBlock[] newArray(int size) {
+ return new TransportBlock[size];
+ }
+ };
+
+ /**
+ * Gets the Organization ID of the Transport Block which corresponds to one of the
+ * the Bluetooth SIG Assigned Numbers.
+ */
+ public int getOrgId() {
+ return mOrgId;
+ }
+
+ /**
+ * Gets the TDS flags of the Transport Block which represents the role of the device and
+ * information about its state and supported features.
+ */
+ public int getTdsFlags() {
+ return mTdsFlags;
+ }
+
+ /**
+ * Gets the total number of octets in the Transport Data field in this Transport Block.
+ */
+ public int getTransportDataLength() {
+ return mTransportDataLength;
+ }
+
+ /**
+ * Gets the Transport Data of the Transport Block which contains organization-specific data.
+ */
+ @Nullable
+ public byte[] getTransportData() {
+ return mTransportData;
+ }
+
+ /**
+ * Converts this TransportBlock to byte array
+ *
+ * @return byte array representation of this Transport Block or null if the conversion failed
+ */
+ @Nullable
+ public byte[] toByteArray() {
+ try {
+ ByteBuffer buffer = ByteBuffer.allocate(totalBytes());
+ buffer.put((byte) mOrgId);
+ buffer.put((byte) mTdsFlags);
+ buffer.put((byte) mTransportDataLength);
+ if (mTransportData != null) {
+ buffer.put(mTransportData);
+ }
+ return buffer.array();
+ } catch (BufferOverflowException e) {
+ Log.e(TAG, "Error converting to byte array: " + e.toString());
+ return null;
+ }
+ }
+
+ /**
+ * @return total byte count of this TransportBlock
+ */
+ public int totalBytes() {
+ // 3 uint8 + byte[] length
+ int size = 3 + mTransportDataLength;
+ return size;
+ }
+}
diff --git a/core/java/android/bluetooth/le/TransportDiscoveryData.java b/core/java/android/bluetooth/le/TransportDiscoveryData.java
new file mode 100644
index 000000000000..c8e97f9a823a
--- /dev/null
+++ b/core/java/android/bluetooth/le/TransportDiscoveryData.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.le;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.nio.BufferOverflowException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Wrapper for Transport Discovery Data AD Type.
+ * This class contains the Transport Discovery Data AD Type Code as well as
+ * a list of potential Transport Blocks.
+ *
+ * @see AdvertiseData
+ */
+public final class TransportDiscoveryData implements Parcelable {
+ private static final String TAG = "TransportDiscoveryData";
+ private final int mTransportDataType;
+ private final List<TransportBlock> mTransportBlocks;
+
+ /**
+ * Creates a TransportDiscoveryData instance.
+ *
+ * @param transportDataType the Transport Discovery Data AD Type
+ * @param transportBlocks the list of Transport Blocks
+ */
+ public TransportDiscoveryData(int transportDataType,
+ @NonNull List<TransportBlock> transportBlocks) {
+ mTransportDataType = transportDataType;
+ mTransportBlocks = transportBlocks;
+ }
+
+ /**
+ * Creates a TransportDiscoveryData instance from byte arrays.
+ *
+ * Uses the transport discovery data bytes and parses them into an usable class.
+ *
+ * @param transportDiscoveryData the raw discovery data
+ */
+ public TransportDiscoveryData(@NonNull byte[] transportDiscoveryData) {
+ ByteBuffer byteBuffer = ByteBuffer.wrap(transportDiscoveryData);
+ mTransportBlocks = new ArrayList();
+ if (byteBuffer.remaining() > 0) {
+ mTransportDataType = byteBuffer.get();
+ } else {
+ mTransportDataType = -1;
+ }
+ try {
+ while (byteBuffer.remaining() > 0) {
+ int orgId = byteBuffer.get();
+ int tdsFlags = byteBuffer.get();
+ int transportDataLength = byteBuffer.get();
+ byte[] transportData = new byte[transportDataLength];
+ byteBuffer.get(transportData, 0, transportDataLength);
+ mTransportBlocks.add(new TransportBlock(orgId, tdsFlags,
+ transportDataLength, transportData));
+ }
+ } catch (BufferUnderflowException e) {
+ Log.e(TAG, "Error while parsing data: " + e.toString());
+ }
+ }
+
+ private TransportDiscoveryData(Parcel in) {
+ mTransportDataType = in.readInt();
+ mTransportBlocks = in.createTypedArrayList(TransportBlock.CREATOR);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mTransportDataType);
+ dest.writeTypedList(mTransportBlocks);
+ }
+
+ public static final @NonNull Creator<TransportDiscoveryData> CREATOR =
+ new Creator<TransportDiscoveryData>() {
+ @Override
+ public TransportDiscoveryData createFromParcel(Parcel in) {
+ return new TransportDiscoveryData(in);
+ }
+
+ @Override
+ public TransportDiscoveryData[] newArray(int size) {
+ return new TransportDiscoveryData[size];
+ }
+ };
+
+ /**
+ * Gets the transport data type.
+ */
+ public int getTransportDataType() {
+ return mTransportDataType;
+ }
+
+ /**
+ * @return the list of {@link TransportBlock} in this TransportDiscoveryData
+ * or an empty list if there are no Transport Blocks
+ */
+ @NonNull
+ public List<TransportBlock> getTransportBlocks() {
+ if (mTransportBlocks == null) {
+ return Collections.emptyList();
+ }
+ return mTransportBlocks;
+ }
+
+ /**
+ * Converts this TransportDiscoveryData to byte array
+ *
+ * @return byte array representation of this Transport Discovery Data or null if the
+ * conversion failed
+ */
+ @Nullable
+ public byte[] toByteArray() {
+ try {
+ ByteBuffer buffer = ByteBuffer.allocate(totalBytes());
+ buffer.put((byte) mTransportDataType);
+ for (TransportBlock transportBlock : getTransportBlocks()) {
+ buffer.put(transportBlock.toByteArray());
+ }
+ return buffer.array();
+ } catch (BufferOverflowException e) {
+ Log.e(TAG, "Error converting to byte array: " + e.toString());
+ return null;
+ }
+ }
+
+ /**
+ * @return total byte count of this TransportDataDiscovery
+ */
+ public int totalBytes() {
+ int size = 1; // Counting Transport Data Type here.
+ for (TransportBlock transportBlock : getTransportBlocks()) {
+ size += transportBlock.totalBytes();
+ }
+ return size;
+ }
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6885c10b4889..ceba01ec62e0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5462,6 +5462,12 @@ public abstract class Context {
public static final String STATS_COMPANION_SERVICE = "statscompanion";
/**
+ * Service to assist statsd in logging atoms from bootstrap atoms.
+ * @hide
+ */
+ public static final String STATS_BOOTSTRAP_ATOM_SERVICE = "statsbootstrap";
+
+ /**
* Use with {@link #getSystemService(String)} to retrieve an {@link android.app.StatsManager}.
* @hide
*/
@@ -6441,30 +6447,24 @@ public abstract class Context {
@NonNull Configuration overrideConfiguration);
/**
- * Return a new Context object for the current Context but whose resources
- * are adjusted to match the metrics of the given Display. Each call to this method
- * returns a new instance of a Context object; Context objects are not
- * shared, however common state (ClassLoader, other Resources for the
- * same configuration) may be so the Context itself can be fairly lightweight.
- *
- * To obtain an instance of a {@link WindowManager} (see {@link #getSystemService(String)}) that
- * is configured to show windows on the given display call
- * {@link #createWindowContext(int, Bundle)} on the returned display Context or use an
- * {@link android.app.Activity}.
- *
+ * Returns a new <code>Context</code> object from the current context but with resources
+ * adjusted to match the metrics of <code>display</code>. Each call to this method
+ * returns a new instance of a context object. Context objects are not shared; however,
+ * common state (such as the {@link ClassLoader} and other resources for the same
+ * configuration) can be shared, so the <code>Context</code> itself is lightweight.
* <p>
- * Note that invoking #createDisplayContext(Display) from an UI context is not regarded
- * as an UI context. In other words, it is not suggested to access UI components (such as
- * obtain a {@link WindowManager} by {@link #getSystemService(String)})
- * from the context created from #createDisplayContext(Display).
- * </p>
- *
- * @param display A {@link Display} object specifying the display for whose metrics the
- * Context's resources should be tailored.
+ * To obtain an instance of {@link WindowManager} configured to show windows on the given
+ * display, call {@link #createWindowContext(int, Bundle)} on the returned display context,
+ * then call {@link #getSystemService(String)} or {@link #getSystemService(Class)} on the
+ * returned window context.
+ * <p>
+ * <b>Note:</b> The context returned by <code>createDisplayContext(Display)</code> is not a UI
+ * context. Do not access UI components or obtain a {@link WindowManager} from the context
+ * created by <code>createDisplayContext(Display)</code>.
*
- * @return A {@link Context} for the display.
+ * @param display The display to which the current context's resources are adjusted.
*
- * @see #getSystemService(String)
+ * @return A context for the display.
*/
@DisplayContext
public abstract Context createDisplayContext(@NonNull Display display);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d811040b6bb2..e781c2fce2b2 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1147,6 +1147,10 @@ public class Intent implements Parcelable, Cloneable {
* numbers. Applications can <strong>dial</strong> emergency numbers using
* {@link #ACTION_DIAL}, however.
*
+ * <p>Note: An app filling the {@link android.app.role.RoleManager#ROLE_DIALER} role should use
+ * {@link android.telecom.TelecomManager#placeCall(Uri, Bundle)} to place calls rather than
+ * relying on this intent.
+ *
* <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#M M}
* and above and declares as using the {@link android.Manifest.permission#CALL_PHONE}
* permission which is not granted, then attempting to use this action will
diff --git a/core/java/android/content/om/OWNERS b/core/java/android/content/om/OWNERS
index 91a0abfe711a..3669817e9844 100644
--- a/core/java/android/content/om/OWNERS
+++ b/core/java/android/content/om/OWNERS
@@ -3,4 +3,4 @@
toddke@android.com
toddke@google.com
patb@google.com
-rtmitchell@google.com
+zyy@google.com
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 2c4ff5889263..84c9fa9b375c 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -409,7 +409,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
/**
* Value for {@link #flags}: {@code true} if the application may use cleartext network traffic
- * (e.g., HTTP rather than HTTPS; WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP
+ * (e.g., HTTP rather than HTTPS; WebSockets rather than WebSockets Secure; XMPP, IMAP, SMTP
* without STARTTLS or TLS). If {@code false}, the app declares that it does not intend to use
* cleartext network traffic, in which case platform components (e.g., HTTP stacks,
* {@code DownloadManager}, {@code MediaPlayer}) will refuse app's requests to use cleartext
diff --git a/core/java/android/content/res/OWNERS b/core/java/android/content/res/OWNERS
index bc2355c6af5e..d12d920b2a54 100644
--- a/core/java/android/content/res/OWNERS
+++ b/core/java/android/content/res/OWNERS
@@ -3,4 +3,4 @@
toddke@android.com
toddke@google.com
patb@google.com
-rtmitchell@google.com
+zyy@google.com
diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS
index 2b4e4a106cec..95f13b5c1d8c 100644
--- a/core/java/android/hardware/OWNERS
+++ b/core/java/android/hardware/OWNERS
@@ -6,3 +6,7 @@ per-file *SensorPrivacy* = file:platform/frameworks/native:/libs/sensorprivacy/O
# Sensors framework
per-file *Sensor*,*Trigger* = file:platform/frameworks/native:/services/sensorservice/OWNERS
+
+# Buffers
+per-file HardwareBuffer* = file:/graphics/java/android/graphics/OWNERS
+per-file DataSpace* = file:/graphics/java/android/graphics/OWNERS
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index 7ef5bac092f6..86052484eaf6 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -232,11 +232,10 @@ public final class IpSecAlgorithm implements Parcelable {
ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, SDK_VERSION_ZERO);
ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, SDK_VERSION_ZERO);
- // STOPSHIP: b/170424293 Use Build.VERSION_CODES.S when it is defined
- ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.R + 1);
- ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.R + 1);
- ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.R + 1);
- ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.R + 1);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.S);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.S);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.S);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.S);
}
private static final Set<String> ENABLED_ALGOS =
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 74506dae329b..c906a13bf41b 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -70,9 +70,17 @@ public class NetworkTemplate implements Parcelable {
private static final String TAG = "NetworkTemplate";
/**
+ * Initial Version of the backup serializer.
+ */
+ public static final int BACKUP_VERSION_1_INIT = 1;
+ /**
+ * Version of the backup serializer that added carrier template support.
+ */
+ public static final int BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE = 2;
+ /**
* Current Version of the Backup Serializer.
*/
- private static final int BACKUP_VERSION = 1;
+ private static final int BACKUP_VERSION = BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE;
public static final int MATCH_MOBILE = 1;
public static final int MATCH_WIFI = 4;
@@ -285,6 +293,10 @@ public class NetworkTemplate implements Parcelable {
private final int mRoaming;
private final int mDefaultNetwork;
private final int mSubType;
+ /**
+ * The subscriber Id match rule defines how the template should match networks with
+ * specific subscriberId(s). See NetworkTemplate#SUBSCRIBER_ID_MATCH_RULE_* for more detail.
+ */
private final int mSubscriberIdMatchRule;
// Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}.
@@ -348,7 +360,7 @@ public class NetworkTemplate implements Parcelable {
mSubscriberIdMatchRule = subscriberIdMatchRule;
checkValidSubscriberIdMatchRule();
if (!isKnownMatchRule(matchRule)) {
- Log.e(TAG, "Unknown network template rule " + matchRule
+ throw new IllegalArgumentException("Unknown network template rule " + matchRule
+ " will not match any identity.");
}
}
@@ -777,8 +789,8 @@ public class NetworkTemplate implements Parcelable {
}
/**
- * Examine the given template and normalize if it refers to a "merged"
- * mobile subscriber. We pick the "lowest" merged subscriber as the primary
+ * Examine the given template and normalize it.
+ * We pick the "lowest" merged subscriber as the primary
* for key purposes, and expand the template to match all other merged
* subscribers.
* <p>
@@ -793,8 +805,8 @@ public class NetworkTemplate implements Parcelable {
}
/**
- * Examine the given template and normalize if it refers to a "merged"
- * mobile subscriber. We pick the "lowest" merged subscriber as the primary
+ * Examine the given template and normalize it.
+ * We pick the "lowest" merged subscriber as the primary
* for key purposes, and expand the template to match all other merged
* subscribers.
*
@@ -806,7 +818,12 @@ public class NetworkTemplate implements Parcelable {
* A, but also matches B.
*/
public static NetworkTemplate normalize(NetworkTemplate template, List<String[]> mergedList) {
- if (!template.isMatchRuleMobile()) return template;
+ // Now there are several types of network which uses SubscriberId to store network
+ // information. For instances:
+ // The TYPE_WIFI with subscriberId means that it is a merged carrier wifi network.
+ // The TYPE_CARRIER means that the network associate to specific carrier network.
+
+ if (template.mSubscriberId == null) return template;
for (String[] merged : mergedList) {
if (ArrayUtils.contains(merged, template.mSubscriberId)) {
@@ -837,11 +854,17 @@ public class NetworkTemplate implements Parcelable {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(baos);
+ if (!isPersistable()) {
+ Log.wtf(TAG, "Trying to backup non-persistable template: " + this);
+ }
+
out.writeInt(BACKUP_VERSION);
out.writeInt(mMatchRule);
BackupUtils.writeString(out, mSubscriberId);
BackupUtils.writeString(out, mNetworkId);
+ out.writeInt(mMetered);
+ out.writeInt(mSubscriberIdMatchRule);
return baos.toByteArray();
}
@@ -849,7 +872,7 @@ public class NetworkTemplate implements Parcelable {
public static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in)
throws IOException, BackupUtils.BadVersionException {
int version = in.readInt();
- if (version < 1 || version > BACKUP_VERSION) {
+ if (version < BACKUP_VERSION_1_INIT || version > BACKUP_VERSION) {
throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
}
@@ -857,11 +880,27 @@ public class NetworkTemplate implements Parcelable {
String subscriberId = BackupUtils.readString(in);
String networkId = BackupUtils.readString(in);
- if (!isKnownMatchRule(matchRule)) {
+ final int metered;
+ final int subscriberIdMatchRule;
+ if (version >= BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE) {
+ metered = in.readInt();
+ subscriberIdMatchRule = in.readInt();
+ } else {
+ // For backward compatibility, fill the missing filters from match rules.
+ metered = (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD
+ || matchRule == MATCH_CARRIER) ? METERED_YES : METERED_ALL;
+ subscriberIdMatchRule = SUBSCRIBER_ID_MATCH_RULE_EXACT;
+ }
+
+ try {
+ return new NetworkTemplate(matchRule,
+ subscriberId, new String[] { subscriberId },
+ networkId, metered, NetworkStats.ROAMING_ALL,
+ NetworkStats.DEFAULT_NETWORK_ALL, NetworkTemplate.NETWORK_TYPE_ALL,
+ NetworkTemplate.OEM_MANAGED_ALL, subscriberIdMatchRule);
+ } catch (IllegalArgumentException e) {
throw new BackupUtils.BadVersionException(
- "Restored network template contains unknown match rule " + matchRule);
+ "Restored network template contains unknown match rule " + matchRule, e);
}
-
- return new NetworkTemplate(matchRule, subscriberId, networkId);
}
}
diff --git a/core/java/android/net/vcn/VcnCellUnderlyingNetworkPriority.java b/core/java/android/net/vcn/VcnCellUnderlyingNetworkPriority.java
new file mode 100644
index 000000000000..6b33e4f45c42
--- /dev/null
+++ b/core/java/android/net/vcn/VcnCellUnderlyingNetworkPriority.java
@@ -0,0 +1,291 @@
+/*
+ * 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 com.android.internal.annotations.VisibleForTesting.Visibility;
+import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER;
+import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER;
+import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER;
+import static com.android.server.vcn.util.PersistableBundleUtils.STRING_SERIALIZER;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.PersistableBundle;
+import android.telephony.SubscriptionInfo;
+import android.telephony.TelephonyManager;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+
+// TODO: Add documents
+/** @hide */
+public final class VcnCellUnderlyingNetworkPriority extends VcnUnderlyingNetworkPriority {
+ private static final String ALLOWED_NETWORK_PLMN_IDS_KEY = "mAllowedNetworkPlmnIds";
+ @NonNull private final Set<String> mAllowedNetworkPlmnIds;
+ private static final String ALLOWED_SPECIFIC_CARRIER_IDS_KEY = "mAllowedSpecificCarrierIds";
+ @NonNull private final Set<Integer> mAllowedSpecificCarrierIds;
+
+ private static final String ALLOW_ROAMING_KEY = "mAllowRoaming";
+ private final boolean mAllowRoaming;
+
+ private static final String REQUIRE_OPPORTUNISTIC_KEY = "mRequireOpportunistic";
+ private final boolean mRequireOpportunistic;
+
+ private VcnCellUnderlyingNetworkPriority(
+ int networkQuality,
+ boolean allowMetered,
+ Set<String> allowedNetworkPlmnIds,
+ Set<Integer> allowedSpecificCarrierIds,
+ boolean allowRoaming,
+ boolean requireOpportunistic) {
+ super(NETWORK_PRIORITY_TYPE_CELL, networkQuality, allowMetered);
+ mAllowedNetworkPlmnIds = new ArraySet<>(allowedNetworkPlmnIds);
+ mAllowedSpecificCarrierIds = new ArraySet<>(allowedSpecificCarrierIds);
+ mAllowRoaming = allowRoaming;
+ mRequireOpportunistic = requireOpportunistic;
+
+ validate();
+ }
+
+ /** @hide */
+ @Override
+ protected void validate() {
+ super.validate();
+ validatePlmnIds(mAllowedNetworkPlmnIds);
+ Objects.requireNonNull(mAllowedSpecificCarrierIds, "allowedCarrierIds is null");
+ }
+
+ private static void validatePlmnIds(Set<String> allowedNetworkPlmnIds) {
+ Objects.requireNonNull(allowedNetworkPlmnIds, "allowedNetworkPlmnIds is null");
+
+ // A valid PLMN is a concatenation of MNC and MCC, and thus consists of 5 or 6 decimal
+ // digits.
+ for (String id : allowedNetworkPlmnIds) {
+ if ((id.length() == 5 || id.length() == 6) && id.matches("[0-9]+")) {
+ continue;
+ } else {
+ throw new IllegalArgumentException("Found invalid PLMN ID: " + id);
+ }
+ }
+ }
+
+ /** @hide */
+ @NonNull
+ @VisibleForTesting(visibility = Visibility.PROTECTED)
+ public static VcnCellUnderlyingNetworkPriority fromPersistableBundle(
+ @NonNull PersistableBundle in) {
+ Objects.requireNonNull(in, "PersistableBundle is null");
+
+ final int networkQuality = in.getInt(NETWORK_QUALITY_KEY);
+ final boolean allowMetered = in.getBoolean(ALLOW_METERED_KEY);
+
+ final PersistableBundle plmnIdsBundle =
+ in.getPersistableBundle(ALLOWED_NETWORK_PLMN_IDS_KEY);
+ Objects.requireNonNull(plmnIdsBundle, "plmnIdsBundle is null");
+ final Set<String> allowedNetworkPlmnIds =
+ new ArraySet<String>(
+ PersistableBundleUtils.toList(plmnIdsBundle, STRING_DESERIALIZER));
+
+ final PersistableBundle specificCarrierIdsBundle =
+ in.getPersistableBundle(ALLOWED_SPECIFIC_CARRIER_IDS_KEY);
+ Objects.requireNonNull(specificCarrierIdsBundle, "specificCarrierIdsBundle is null");
+ final Set<Integer> allowedSpecificCarrierIds =
+ new ArraySet<Integer>(
+ PersistableBundleUtils.toList(
+ specificCarrierIdsBundle, INTEGER_DESERIALIZER));
+
+ final boolean allowRoaming = in.getBoolean(ALLOW_ROAMING_KEY);
+ final boolean requireOpportunistic = in.getBoolean(REQUIRE_OPPORTUNISTIC_KEY);
+
+ return new VcnCellUnderlyingNetworkPriority(
+ networkQuality,
+ allowMetered,
+ allowedNetworkPlmnIds,
+ allowedSpecificCarrierIds,
+ allowRoaming,
+ requireOpportunistic);
+ }
+
+ /** @hide */
+ @Override
+ @NonNull
+ @VisibleForTesting(visibility = Visibility.PROTECTED)
+ public PersistableBundle toPersistableBundle() {
+ final PersistableBundle result = super.toPersistableBundle();
+
+ final PersistableBundle plmnIdsBundle =
+ PersistableBundleUtils.fromList(
+ new ArrayList<>(mAllowedNetworkPlmnIds), STRING_SERIALIZER);
+ result.putPersistableBundle(ALLOWED_NETWORK_PLMN_IDS_KEY, plmnIdsBundle);
+
+ final PersistableBundle specificCarrierIdsBundle =
+ PersistableBundleUtils.fromList(
+ new ArrayList<>(mAllowedSpecificCarrierIds), INTEGER_SERIALIZER);
+ result.putPersistableBundle(ALLOWED_SPECIFIC_CARRIER_IDS_KEY, specificCarrierIdsBundle);
+
+ result.putBoolean(ALLOW_ROAMING_KEY, mAllowRoaming);
+ result.putBoolean(REQUIRE_OPPORTUNISTIC_KEY, mRequireOpportunistic);
+
+ return result;
+ }
+
+ /** Retrieve the allowed PLMN IDs, or an empty set if any PLMN ID is acceptable. */
+ @NonNull
+ public Set<String> getAllowedPlmnIds() {
+ return Collections.unmodifiableSet(mAllowedNetworkPlmnIds);
+ }
+
+ /**
+ * Retrieve the allowed specific carrier IDs, or an empty set if any specific carrier ID is
+ * acceptable.
+ */
+ @NonNull
+ public Set<Integer> getAllowedSpecificCarrierIds() {
+ return Collections.unmodifiableSet(mAllowedSpecificCarrierIds);
+ }
+
+ /** Return if roaming is allowed. */
+ public boolean allowRoaming() {
+ return mAllowRoaming;
+ }
+
+ /** Return if requiring an opportunistic network. */
+ public boolean requireOpportunistic() {
+ return mRequireOpportunistic;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ super.hashCode(),
+ mAllowedNetworkPlmnIds,
+ mAllowedSpecificCarrierIds,
+ mAllowRoaming,
+ mRequireOpportunistic);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (!super.equals(other)) {
+ return false;
+ }
+
+ if (!(other instanceof VcnCellUnderlyingNetworkPriority)) {
+ return false;
+ }
+
+ final VcnCellUnderlyingNetworkPriority rhs = (VcnCellUnderlyingNetworkPriority) other;
+ return Objects.equals(mAllowedNetworkPlmnIds, rhs.mAllowedNetworkPlmnIds)
+ && Objects.equals(mAllowedSpecificCarrierIds, rhs.mAllowedSpecificCarrierIds)
+ && mAllowRoaming == rhs.mAllowRoaming
+ && mRequireOpportunistic == rhs.mRequireOpportunistic;
+ }
+
+ /** This class is used to incrementally build WifiNetworkPriority objects. */
+ public static class Builder extends VcnUnderlyingNetworkPriority.Builder<Builder> {
+ @NonNull private final Set<String> mAllowedNetworkPlmnIds = new ArraySet<>();
+ @NonNull private final Set<Integer> mAllowedSpecificCarrierIds = new ArraySet<>();
+
+ private boolean mAllowRoaming = false;
+ private boolean mRequireOpportunistic = false;
+
+ /** Construct a Builder object. */
+ public Builder() {}
+
+ /**
+ * Set allowed operator PLMN IDs.
+ *
+ * <p>This is used to distinguish cases where roaming agreements may dictate a different
+ * priority from a partner's networks.
+ *
+ * @param allowedNetworkPlmnIds the allowed operator PLMN IDs in String. Defaults to an
+ * empty set, allowing ANY PLMN ID. A valid PLMN is a concatenation of MNC and MCC, and
+ * thus consists of 5 or 6 decimal digits. See {@link SubscriptionInfo#getMccString()}
+ * and {@link SubscriptionInfo#getMncString()}.
+ */
+ @NonNull
+ public Builder setAllowedPlmnIds(@NonNull Set<String> allowedNetworkPlmnIds) {
+ validatePlmnIds(allowedNetworkPlmnIds);
+
+ mAllowedNetworkPlmnIds.clear();
+ mAllowedNetworkPlmnIds.addAll(allowedNetworkPlmnIds);
+ return this;
+ }
+
+ /**
+ * Set allowed specific carrier IDs.
+ *
+ * @param allowedSpecificCarrierIds the allowed specific carrier IDs. Defaults to an empty
+ * set, allowing ANY carrier ID. See {@link TelephonyManager#getSimSpecificCarrierId()}.
+ */
+ @NonNull
+ public Builder setAllowedSpecificCarrierIds(
+ @NonNull Set<Integer> allowedSpecificCarrierIds) {
+ Objects.requireNonNull(allowedSpecificCarrierIds, "allowedCarrierIds is null");
+ mAllowedSpecificCarrierIds.clear();
+ mAllowedSpecificCarrierIds.addAll(allowedSpecificCarrierIds);
+ return this;
+ }
+
+ /**
+ * Set if roaming is allowed.
+ *
+ * @param allowRoaming the flag to indicate if roaming is allowed. Defaults to {@code
+ * false}.
+ */
+ @NonNull
+ public Builder setAllowRoaming(boolean allowRoaming) {
+ mAllowRoaming = allowRoaming;
+ return this;
+ }
+
+ /**
+ * Set if requiring an opportunistic network.
+ *
+ * @param requireOpportunistic the flag to indicate if caller requires an opportunistic
+ * network. Defaults to {@code false}.
+ */
+ @NonNull
+ public Builder setRequireOpportunistic(boolean requireOpportunistic) {
+ mRequireOpportunistic = requireOpportunistic;
+ return this;
+ }
+
+ /** Build the VcnCellUnderlyingNetworkPriority. */
+ @NonNull
+ public VcnCellUnderlyingNetworkPriority build() {
+ return new VcnCellUnderlyingNetworkPriority(
+ mNetworkQuality,
+ mAllowMetered,
+ mAllowedNetworkPlmnIds,
+ mAllowedSpecificCarrierIds,
+ mAllowRoaming,
+ mRequireOpportunistic);
+ }
+
+ /** @hide */
+ @Override
+ Builder self() {
+ return this;
+ }
+ }
+}
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 752ef3e39ab6..de4ada2dbc26 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -16,6 +16,7 @@
package android.net.vcn;
import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
+import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK;
import static com.android.internal.annotations.VisibleForTesting.Visibility;
@@ -41,6 +42,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
import java.util.SortedSet;
@@ -157,6 +159,34 @@ public final class VcnGatewayConnectionConfig {
TimeUnit.MINUTES.toMillis(5),
TimeUnit.MINUTES.toMillis(15)
};
+
+ private static final LinkedHashSet<VcnUnderlyingNetworkPriority>
+ DEFAULT_UNDERLYING_NETWORK_PRIORITIES = new LinkedHashSet<>();
+
+ static {
+ DEFAULT_UNDERLYING_NETWORK_PRIORITIES.add(
+ new VcnCellUnderlyingNetworkPriority.Builder()
+ .setNetworkQuality(NETWORK_QUALITY_OK)
+ .setAllowMetered(true /* allowMetered */)
+ .setAllowRoaming(true /* allowRoaming */)
+ .setRequireOpportunistic(true /* requireOpportunistic */)
+ .build());
+
+ DEFAULT_UNDERLYING_NETWORK_PRIORITIES.add(
+ new VcnWifiUnderlyingNetworkPriority.Builder()
+ .setNetworkQuality(NETWORK_QUALITY_OK)
+ .setAllowMetered(true /* allowMetered */)
+ .build());
+
+ DEFAULT_UNDERLYING_NETWORK_PRIORITIES.add(
+ new VcnCellUnderlyingNetworkPriority.Builder()
+ .setNetworkQuality(NETWORK_QUALITY_OK)
+ .setAllowMetered(true /* allowMetered */)
+ .setAllowRoaming(true /* allowRoaming */)
+ .setRequireOpportunistic(false /* requireOpportunistic */)
+ .build());
+ }
+
private static final String GATEWAY_CONNECTION_NAME_KEY = "mGatewayConnectionName";
@NonNull private final String mGatewayConnectionName;
@@ -166,6 +196,9 @@ public final class VcnGatewayConnectionConfig {
private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities";
@NonNull private final SortedSet<Integer> mExposedCapabilities;
+ private static final String UNDERLYING_NETWORK_PRIORITIES_KEY = "mUnderlyingNetworkPriorities";
+ @NonNull private final LinkedHashSet<VcnUnderlyingNetworkPriority> mUnderlyingNetworkPriorities;
+
private static final String MAX_MTU_KEY = "mMaxMtu";
private final int mMaxMtu;
@@ -177,6 +210,7 @@ public final class VcnGatewayConnectionConfig {
@NonNull String gatewayConnectionName,
@NonNull IkeTunnelConnectionParams tunnelConnectionParams,
@NonNull Set<Integer> exposedCapabilities,
+ @NonNull LinkedHashSet<VcnUnderlyingNetworkPriority> underlyingNetworkPriorities,
@NonNull long[] retryIntervalsMs,
@IntRange(from = MIN_MTU_V6) int maxMtu) {
mGatewayConnectionName = gatewayConnectionName;
@@ -185,6 +219,11 @@ public final class VcnGatewayConnectionConfig {
mRetryIntervalsMs = retryIntervalsMs;
mMaxMtu = maxMtu;
+ mUnderlyingNetworkPriorities = new LinkedHashSet<>(underlyingNetworkPriorities);
+ if (mUnderlyingNetworkPriorities.isEmpty()) {
+ mUnderlyingNetworkPriorities.addAll(DEFAULT_UNDERLYING_NETWORK_PRIORITIES);
+ }
+
validate();
}
@@ -198,12 +237,19 @@ public final class VcnGatewayConnectionConfig {
final PersistableBundle exposedCapsBundle =
in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY);
+ final PersistableBundle networkPrioritiesBundle =
+ in.getPersistableBundle(UNDERLYING_NETWORK_PRIORITIES_KEY);
mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY);
mTunnelConnectionParams =
TunnelConnectionParamsUtils.fromPersistableBundle(tunnelConnectionParamsBundle);
mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList(
exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
+ mUnderlyingNetworkPriorities =
+ new LinkedHashSet<>(
+ PersistableBundleUtils.toList(
+ networkPrioritiesBundle,
+ VcnUnderlyingNetworkPriority::fromPersistableBundle));
mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY);
mMaxMtu = in.getInt(MAX_MTU_KEY);
@@ -221,6 +267,7 @@ public final class VcnGatewayConnectionConfig {
checkValidCapability(cap);
}
+ Objects.requireNonNull(mUnderlyingNetworkPriorities, "underlyingNetworkPriorities is null");
Objects.requireNonNull(mRetryIntervalsMs, "retryIntervalsMs was null");
validateRetryInterval(mRetryIntervalsMs);
@@ -303,6 +350,18 @@ public final class VcnGatewayConnectionConfig {
}
/**
+ * Retrieve the configured VcnUnderlyingNetworkPriority list, or a default list if it is not
+ * configured.
+ *
+ * @see Builder#setVcnUnderlyingNetworkPriorities(LinkedHashSet<VcnUnderlyingNetworkPriority>)
+ * @hide
+ */
+ @NonNull
+ public LinkedHashSet<VcnUnderlyingNetworkPriority> getVcnUnderlyingNetworkPriorities() {
+ return new LinkedHashSet<>(mUnderlyingNetworkPriorities);
+ }
+
+ /**
* Retrieves the configured retry intervals.
*
* @see Builder#setRetryIntervalsMillis(long[])
@@ -338,10 +397,15 @@ public final class VcnGatewayConnectionConfig {
PersistableBundleUtils.fromList(
new ArrayList<>(mExposedCapabilities),
PersistableBundleUtils.INTEGER_SERIALIZER);
+ final PersistableBundle networkPrioritiesBundle =
+ PersistableBundleUtils.fromList(
+ new ArrayList<>(mUnderlyingNetworkPriorities),
+ VcnUnderlyingNetworkPriority::toPersistableBundle);
result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName);
result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle);
result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle);
+ result.putPersistableBundle(UNDERLYING_NETWORK_PRIORITIES_KEY, networkPrioritiesBundle);
result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs);
result.putInt(MAX_MTU_KEY, mMaxMtu);
@@ -379,6 +443,11 @@ public final class VcnGatewayConnectionConfig {
@NonNull private final String mGatewayConnectionName;
@NonNull private final IkeTunnelConnectionParams mTunnelConnectionParams;
@NonNull private final Set<Integer> mExposedCapabilities = new ArraySet();
+
+ @NonNull
+ private final LinkedHashSet<VcnUnderlyingNetworkPriority> mUnderlyingNetworkPriorities =
+ new LinkedHashSet<>(DEFAULT_UNDERLYING_NETWORK_PRIORITIES);
+
@NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS;
private int mMaxMtu = DEFAULT_MAX_MTU;
@@ -450,6 +519,33 @@ public final class VcnGatewayConnectionConfig {
}
/**
+ * Set the VcnUnderlyingNetworkPriority list.
+ *
+ * @param underlyingNetworkPriorities a list of unique VcnUnderlyingNetworkPriorities that
+ * are ordered from most to least preferred, or an empty list to use the default
+ * prioritization. The default network prioritization is Opportunistic cellular, Carrier
+ * WiFi and Macro cellular
+ * @return
+ */
+ /** @hide */
+ @NonNull
+ public Builder setVcnUnderlyingNetworkPriorities(
+ @NonNull LinkedHashSet<VcnUnderlyingNetworkPriority> underlyingNetworkPriorities) {
+ Objects.requireNonNull(
+ mUnderlyingNetworkPriorities, "underlyingNetworkPriorities is null");
+
+ mUnderlyingNetworkPriorities.clear();
+
+ if (underlyingNetworkPriorities.isEmpty()) {
+ mUnderlyingNetworkPriorities.addAll(DEFAULT_UNDERLYING_NETWORK_PRIORITIES);
+ } else {
+ mUnderlyingNetworkPriorities.addAll(underlyingNetworkPriorities);
+ }
+
+ return this;
+ }
+
+ /**
* Set the retry interval between VCN establishment attempts upon successive failures.
*
* <p>The last retry interval will be repeated until safe mode is entered, or a connection
@@ -513,6 +609,7 @@ public final class VcnGatewayConnectionConfig {
mGatewayConnectionName,
mTunnelConnectionParams,
mExposedCapabilities,
+ mUnderlyingNetworkPriorities,
mRetryIntervalsMs,
mMaxMtu);
}
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPriority.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPriority.java
new file mode 100644
index 000000000000..82f6ae72b43c
--- /dev/null
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPriority.java
@@ -0,0 +1,181 @@
+/*
+ * 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 com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.PersistableBundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+// TODO: Add documents
+/** @hide */
+public abstract class VcnUnderlyingNetworkPriority {
+ /** @hide */
+ protected static final int NETWORK_PRIORITY_TYPE_WIFI = 1;
+ /** @hide */
+ protected static final int NETWORK_PRIORITY_TYPE_CELL = 2;
+
+ /** Denotes that network quality needs to be OK */
+ public static final int NETWORK_QUALITY_OK = 10000;
+ /** Denotes that any network quality is acceptable */
+ public static final int NETWORK_QUALITY_ANY = Integer.MAX_VALUE;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({NETWORK_QUALITY_OK, NETWORK_QUALITY_ANY})
+ public @interface NetworkQuality {}
+
+ private static final String NETWORK_PRIORITY_TYPE_KEY = "mNetworkPriorityType";
+ private final int mNetworkPriorityType;
+
+ /** @hide */
+ protected static final String NETWORK_QUALITY_KEY = "mNetworkQuality";
+ private final int mNetworkQuality;
+
+ /** @hide */
+ protected static final String ALLOW_METERED_KEY = "mAllowMetered";
+ private final boolean mAllowMetered;
+
+ /** @hide */
+ protected VcnUnderlyingNetworkPriority(
+ int networkPriorityType, int networkQuality, boolean allowMetered) {
+ mNetworkPriorityType = networkPriorityType;
+ mNetworkQuality = networkQuality;
+ mAllowMetered = allowMetered;
+ }
+
+ private static void validateNetworkQuality(int networkQuality) {
+ Preconditions.checkArgument(
+ networkQuality == NETWORK_QUALITY_ANY || networkQuality == NETWORK_QUALITY_OK,
+ "Invalid networkQuality:" + networkQuality);
+ }
+
+ /** @hide */
+ protected void validate() {
+ validateNetworkQuality(mNetworkQuality);
+ }
+
+ /** @hide */
+ @NonNull
+ @VisibleForTesting(visibility = Visibility.PROTECTED)
+ public static VcnUnderlyingNetworkPriority fromPersistableBundle(
+ @NonNull PersistableBundle in) {
+ Objects.requireNonNull(in, "PersistableBundle is null");
+
+ final int networkPriorityType = in.getInt(NETWORK_PRIORITY_TYPE_KEY);
+ switch (networkPriorityType) {
+ case NETWORK_PRIORITY_TYPE_WIFI:
+ return VcnWifiUnderlyingNetworkPriority.fromPersistableBundle(in);
+ case NETWORK_PRIORITY_TYPE_CELL:
+ return VcnCellUnderlyingNetworkPriority.fromPersistableBundle(in);
+ default:
+ throw new IllegalArgumentException(
+ "Invalid networkPriorityType:" + networkPriorityType);
+ }
+ }
+
+ /** @hide */
+ @NonNull
+ PersistableBundle toPersistableBundle() {
+ final PersistableBundle result = new PersistableBundle();
+
+ result.putInt(NETWORK_PRIORITY_TYPE_KEY, mNetworkPriorityType);
+ result.putInt(NETWORK_QUALITY_KEY, mNetworkQuality);
+ result.putBoolean(ALLOW_METERED_KEY, mAllowMetered);
+
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mNetworkPriorityType, mNetworkQuality, mAllowMetered);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (!(other instanceof VcnUnderlyingNetworkPriority)) {
+ return false;
+ }
+
+ final VcnUnderlyingNetworkPriority rhs = (VcnUnderlyingNetworkPriority) other;
+ return mNetworkPriorityType == rhs.mNetworkPriorityType
+ && mNetworkQuality == rhs.mNetworkQuality
+ && mAllowMetered == rhs.mAllowMetered;
+ }
+
+ /** Retrieve the required network quality. */
+ @NetworkQuality
+ public int getNetworkQuality() {
+ return mNetworkQuality;
+ }
+
+ /** Return if a metered network is allowed. */
+ public boolean allowMetered() {
+ return mAllowMetered;
+ }
+
+ /**
+ * This class is used to incrementally build VcnUnderlyingNetworkPriority objects.
+ *
+ * @param <T> The subclass to be built.
+ */
+ public abstract static class Builder<T extends Builder<T>> {
+ /** @hide */
+ protected int mNetworkQuality = NETWORK_QUALITY_ANY;
+ /** @hide */
+ protected boolean mAllowMetered = false;
+
+ /** @hide */
+ protected Builder() {}
+
+ /**
+ * Set the required network quality.
+ *
+ * @param networkQuality the required network quality. Defaults to NETWORK_QUALITY_ANY
+ */
+ @NonNull
+ public T setNetworkQuality(@NetworkQuality int networkQuality) {
+ validateNetworkQuality(networkQuality);
+
+ mNetworkQuality = networkQuality;
+ return self();
+ }
+
+ /**
+ * Set if a metered network is allowed.
+ *
+ * @param allowMetered the flag to indicate if a metered network is allowed, defaults to
+ * {@code false}
+ */
+ @NonNull
+ public T setAllowMetered(boolean allowMetered) {
+ mAllowMetered = allowMetered;
+ return self();
+ }
+
+ /** @hide */
+ abstract T self();
+ }
+}
diff --git a/core/java/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java b/core/java/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java
new file mode 100644
index 000000000000..fc7e7e2c4e41
--- /dev/null
+++ b/core/java/android/net/vcn/VcnWifiUnderlyingNetworkPriority.java
@@ -0,0 +1,120 @@
+/*
+ * 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 com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.PersistableBundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+
+// TODO: Add documents
+/** @hide */
+public final class VcnWifiUnderlyingNetworkPriority extends VcnUnderlyingNetworkPriority {
+ private static final String SSID_KEY = "mSsid";
+ @Nullable private final String mSsid;
+
+ private VcnWifiUnderlyingNetworkPriority(
+ int networkQuality, boolean allowMetered, String ssid) {
+ super(NETWORK_PRIORITY_TYPE_WIFI, networkQuality, allowMetered);
+ mSsid = ssid;
+
+ validate();
+ }
+
+ /** @hide */
+ @NonNull
+ @VisibleForTesting(visibility = Visibility.PROTECTED)
+ public static VcnWifiUnderlyingNetworkPriority fromPersistableBundle(
+ @NonNull PersistableBundle in) {
+ Objects.requireNonNull(in, "PersistableBundle is null");
+
+ final int networkQuality = in.getInt(NETWORK_QUALITY_KEY);
+ final boolean allowMetered = in.getBoolean(ALLOW_METERED_KEY);
+ final String ssid = in.getString(SSID_KEY);
+ return new VcnWifiUnderlyingNetworkPriority(networkQuality, allowMetered, ssid);
+ }
+
+ /** @hide */
+ @Override
+ @NonNull
+ @VisibleForTesting(visibility = Visibility.PROTECTED)
+ public PersistableBundle toPersistableBundle() {
+ final PersistableBundle result = super.toPersistableBundle();
+ result.putString(SSID_KEY, mSsid);
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), mSsid);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (!super.equals(other)) {
+ return false;
+ }
+
+ if (!(other instanceof VcnWifiUnderlyingNetworkPriority)) {
+ return false;
+ }
+
+ final VcnWifiUnderlyingNetworkPriority rhs = (VcnWifiUnderlyingNetworkPriority) other;
+ return mSsid == rhs.mSsid;
+ }
+
+ /** Retrieve the required SSID, or {@code null} if there is no requirement on SSID. */
+ @Nullable
+ public String getSsid() {
+ return mSsid;
+ }
+
+ /** This class is used to incrementally build VcnWifiUnderlyingNetworkPriority objects. */
+ public static class Builder extends VcnUnderlyingNetworkPriority.Builder<Builder> {
+ @Nullable private String mSsid;
+
+ /** Construct a Builder object. */
+ public Builder() {}
+
+ /**
+ * Set the required SSID.
+ *
+ * @param ssid the required SSID, or {@code null} if any SSID is acceptable.
+ */
+ @NonNull
+ public Builder setSsid(@Nullable String ssid) {
+ mSsid = ssid;
+ return this;
+ }
+
+ /** Build the VcnWifiUnderlyingNetworkPriority. */
+ @NonNull
+ public VcnWifiUnderlyingNetworkPriority build() {
+ return new VcnWifiUnderlyingNetworkPriority(mNetworkQuality, mAllowMetered, mSsid);
+ }
+
+ /** @hide */
+ @Override
+ Builder self() {
+ return this;
+ }
+ }
+}
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 0af322e885b1..09540132fe0d 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -528,6 +528,7 @@ public final class ApduServiceInfo implements Parcelable {
public String toString() {
StringBuilder out = new StringBuilder("ApduService: ");
out.append(getComponent());
+ out.append(", UID: " + mUid);
out.append(", description: " + mDescription);
out.append(", Static AID Groups: ");
for (AidGroup aidGroup : mStaticAidGroups.values()) {
@@ -546,7 +547,8 @@ public final class ApduServiceInfo implements Parcelable {
if (!(o instanceof ApduServiceInfo)) return false;
ApduServiceInfo thatService = (ApduServiceInfo) o;
- return thatService.getComponent().equals(this.getComponent());
+ return thatService.getComponent().equals(this.getComponent())
+ && thatService.getUid() == this.getUid();
}
@Override
@@ -619,8 +621,9 @@ public final class ApduServiceInfo implements Parcelable {
};
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println(" " + getComponent() +
- " (Description: " + getDescription() + ")");
+ pw.println(" " + getComponent()
+ + " (Description: " + getDescription() + ")"
+ + " (UID: " + getUid() + ")");
if (mOnHost) {
pw.println(" On Host Service");
} else {
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index d498535ce52c..0a9fe90f2524 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -30,6 +30,7 @@ import android.content.pm.PackageManager;
import android.nfc.INfcCardEmulation;
import android.nfc.NfcAdapter;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
@@ -83,6 +84,13 @@ public final class CardEmulation {
public static final String EXTRA_SERVICE_COMPONENT = "component";
/**
+ * The caller userId extra for {@link #ACTION_CHANGE_DEFAULT}.
+ *
+ * @see #ACTION_CHANGE_DEFAULT
+ */
+ public static final String EXTRA_USERID = "android.nfc.cardemulation.extra.USERID";
+
+ /**
* Category used for NFC payment services.
*/
public static final String CATEGORY_PAYMENT = "payment";
@@ -269,8 +277,8 @@ public final class CardEmulation {
if (CATEGORY_PAYMENT.equals(category)) {
boolean preferForeground = false;
try {
- preferForeground = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.NFC_PAYMENT_FOREGROUND) != 0;
+ preferForeground = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.NFC_PAYMENT_FOREGROUND, UserHandle.myUserId()) != 0;
} catch (SettingNotFoundException e) {
}
return preferForeground;
@@ -829,6 +837,28 @@ public final class CardEmulation {
/**
* @hide
*/
+ public boolean setDefaultForNextTap(int userId, ComponentName service) {
+ try {
+ return sService.setDefaultForNextTap(userId, service);
+ } catch (RemoteException e) {
+ // Try one more time
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return false;
+ }
+ try {
+ return sService.setDefaultForNextTap(userId, service);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach CardEmulationService.");
+ return false;
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
public List<ApduServiceInfo> getServices(String category) {
try {
return sService.getServices(mContext.getUserId(), category);
@@ -849,6 +879,28 @@ public final class CardEmulation {
}
/**
+ * @hide
+ */
+ public List<ApduServiceInfo> getServices(String category, int userId) {
+ try {
+ return sService.getServices(userId, category);
+ } catch (RemoteException e) {
+ // Try one more time
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return null;
+ }
+ try {
+ return sService.getServices(userId, category);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach CardEmulationService.");
+ return null;
+ }
+ }
+ }
+
+ /**
* A valid AID according to ISO/IEC 7816-4:
* <ul>
* <li>Has >= 5 bytes and <=16 bytes (>=10 hex chars and <= 32 hex chars)
diff --git a/core/java/android/nfc/cardemulation/NfcFCardEmulation.java b/core/java/android/nfc/cardemulation/NfcFCardEmulation.java
index 80e8579dd73f..557e41a2b103 100644
--- a/core/java/android/nfc/cardemulation/NfcFCardEmulation.java
+++ b/core/java/android/nfc/cardemulation/NfcFCardEmulation.java
@@ -25,7 +25,6 @@ import android.content.pm.PackageManager;
import android.nfc.INfcFCardEmulation;
import android.nfc.NfcAdapter;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.util.Log;
import java.util.HashMap;
diff --git a/core/java/android/nfc/cardemulation/NfcFServiceInfo.java b/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
index c2b33dd51b0c..f8f7dfe034b5 100644
--- a/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
@@ -237,6 +237,7 @@ public final class NfcFServiceInfo implements Parcelable {
public String toString() {
StringBuilder out = new StringBuilder("NfcFService: ");
out.append(getComponent());
+ out.append(", UID: " + mUid);
out.append(", description: " + mDescription);
out.append(", System Code: " + mSystemCode);
if (mDynamicSystemCode != null) {
@@ -257,6 +258,7 @@ public final class NfcFServiceInfo implements Parcelable {
NfcFServiceInfo thatService = (NfcFServiceInfo) o;
if (!thatService.getComponent().equals(this.getComponent())) return false;
+ if (thatService.getUid() != this.getUid()) return false;
if (!thatService.mSystemCode.equalsIgnoreCase(this.mSystemCode)) return false;
if (!thatService.mNfcid2.equalsIgnoreCase(this.mNfcid2)) return false;
if (!thatService.mT3tPmm.equalsIgnoreCase(this.mT3tPmm)) return false;
@@ -321,8 +323,9 @@ public final class NfcFServiceInfo implements Parcelable {
};
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println(" " + getComponent() +
- " (Description: " + getDescription() + ")");
+ pw.println(" " + getComponent()
+ + " (Description: " + getDescription() + ")"
+ + " (UID: " + getUid() + ")");
pw.println(" System Code: " + getSystemCode());
pw.println(" NFCID2: " + getNfcid2());
pw.println(" T3tPmm: " + getT3tPmm());
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 2a344f6c2b6b..ad3de25fecc2 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -103,7 +103,7 @@ public class BaseBundle {
* are unparcelled, mParcelledData willbe set to null.
*/
@UnsupportedAppUsage
- Parcel mParcelledData = null;
+ volatile Parcel mParcelledData = null;
/**
* Whether {@link #mParcelledData} was generated by native code or not.
@@ -182,13 +182,56 @@ public class BaseBundle {
* @param b a Bundle to be copied.
*/
BaseBundle(BaseBundle b) {
- copyInternal(b, false);
+ this(b, /* deep */ false);
}
/**
- * Special constructor that does not initialize the bundle.
+ * Constructs a {@link BaseBundle} containing a copy of {@code from}.
+ *
+ * @param from The bundle to be copied.
+ * @param deep Whether is a deep or shallow copy.
+ *
+ * @hide
*/
- BaseBundle(boolean doInit) {
+ BaseBundle(BaseBundle from, boolean deep) {
+ synchronized (from) {
+ mClassLoader = from.mClassLoader;
+
+ if (from.mMap != null) {
+ if (!deep) {
+ mMap = new ArrayMap<>(from.mMap);
+ } else {
+ final ArrayMap<String, Object> fromMap = from.mMap;
+ final int n = fromMap.size();
+ mMap = new ArrayMap<>(n);
+ for (int i = 0; i < n; i++) {
+ mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i)));
+ }
+ }
+ } else {
+ mMap = null;
+ }
+
+ final Parcel parcelledData;
+ if (from.mParcelledData != null) {
+ if (from.isEmptyParcel()) {
+ parcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
+ mParcelledByNative = false;
+ } else {
+ parcelledData = Parcel.obtain();
+ parcelledData.appendFrom(from.mParcelledData, 0,
+ from.mParcelledData.dataSize());
+ parcelledData.setDataPosition(0);
+ mParcelledByNative = from.mParcelledByNative;
+ }
+ } else {
+ parcelledData = null;
+ mParcelledByNative = false;
+ }
+
+ // Keep as last statement to ensure visibility of other fields
+ mParcelledData = parcelledData;
+ }
}
/**
@@ -323,8 +366,8 @@ public class BaseBundle {
} else {
mMap.erase();
}
- mParcelledData = null;
mParcelledByNative = false;
+ mParcelledData = null;
return;
}
@@ -358,8 +401,8 @@ public class BaseBundle {
if (recycleParcel) {
recycleParcel(parcelledData);
}
- mParcelledData = null;
mParcelledByNative = false;
+ mParcelledData = null;
}
if (DEBUG) {
Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
@@ -501,44 +544,7 @@ public class BaseBundle {
mMap.clear();
}
- void copyInternal(BaseBundle from, boolean deep) {
- synchronized (from) {
- if (from.mParcelledData != null) {
- if (from.isEmptyParcel()) {
- mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
- mParcelledByNative = false;
- } else {
- mParcelledData = Parcel.obtain();
- mParcelledData.appendFrom(from.mParcelledData, 0,
- from.mParcelledData.dataSize());
- mParcelledData.setDataPosition(0);
- mParcelledByNative = from.mParcelledByNative;
- }
- } else {
- mParcelledData = null;
- mParcelledByNative = false;
- }
-
- if (from.mMap != null) {
- if (!deep) {
- mMap = new ArrayMap<>(from.mMap);
- } else {
- final ArrayMap<String, Object> fromMap = from.mMap;
- final int N = fromMap.size();
- mMap = new ArrayMap<>(N);
- for (int i = 0; i < N; i++) {
- mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i)));
- }
- }
- } else {
- mMap = null;
- }
-
- mClassLoader = from.mClassLoader;
- }
- }
-
- Object deepCopyValue(Object value) {
+ private Object deepCopyValue(Object value) {
if (value == null) {
return null;
}
@@ -570,7 +576,7 @@ public class BaseBundle {
return value;
}
- ArrayList deepcopyArrayList(ArrayList from) {
+ private ArrayList deepcopyArrayList(ArrayList from) {
final int N = from.size();
ArrayList out = new ArrayList(N);
for (int i=0; i<N; i++) {
@@ -1717,9 +1723,9 @@ public class BaseBundle {
if (length < 0) {
throw new RuntimeException("Bad length in parcel: " + length);
} else if (length == 0) {
+ mParcelledByNative = false;
// Empty Bundle or end of data.
mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
- mParcelledByNative = false;
return;
} else if (length % 4 != 0) {
throw new IllegalStateException("Bundle length is not aligned by 4: " + length);
@@ -1757,8 +1763,8 @@ public class BaseBundle {
+ ": " + length + " bundle bytes starting at " + offset);
p.setDataPosition(0);
- mParcelledData = p;
mParcelledByNative = isNativeBundle;
+ mParcelledData = p;
}
/** {@hide} */
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index b677b6900d5c..b069fb336d55 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -53,7 +53,7 @@ import java.lang.reflect.Modifier;
*
* <p>Most developers will not implement this class directly, instead using the
* <a href="{@docRoot}guide/components/aidl.html">aidl</a> tool to describe the desired
- * interface, having it generate the appropriate Binder subclass. You can,
+ * interface, having it generate the appropriate Binder subclass. You can,
* however, derive directly from Binder to implement your own custom RPC
* protocol or simply instantiate a raw Binder object directly to use as a
* token that can be shared across processes.
@@ -63,17 +63,17 @@ import java.lang.reflect.Modifier;
* To use this correctly, you must be doing so within the context of a top-level
* application component (a {@link android.app.Service}, {@link android.app.Activity},
* or {@link android.content.ContentProvider}) that lets the system know your process
- * should remain running.</p>
+ * should remain running.
*
* <p>You must keep in mind the situations in which your process
* could go away, and thus require that you later re-create a new Binder and re-attach
- * it when the process starts again. For example, if you are using this within an
+ * it when the process starts again. For example, if you are using this within an
* {@link android.app.Activity}, your activity's process may be killed any time the
* activity is not started; if the activity is later re-created you will need to
* create a new Binder and hand it back to the correct place again; you need to be
* aware that your process may be started for another reason (for example to receive
* a broadcast) that will not involve re-creating the activity and thus run its code
- * to create a new Binder.</p>
+ * to create a new Binder.
*
* @see IBinder
*/
@@ -94,14 +94,15 @@ public class Binder implements IBinder {
/**
* Value to represents that a calling work source is not set.
*
- * This constatnt needs to be kept in sync with IPCThreadState::kUnsetWorkSource.
+ * <p>This constant needs to be kept in sync with IPCThreadState::kUnsetWorkSource.
*
* @hide
*/
public static final int UNSET_WORKSOURCE = -1;
/**
- * Control whether dump() calls are allowed.
+ * Control whether {@link #dump(FileDescriptor, PrintWriter, String[]) dump()}
+ * calls are allowed.
*/
private static volatile String sDumpDisabled = null;
@@ -188,7 +189,7 @@ public class Binder implements IBinder {
sObserver = observer;
}
- /** {@hide} */
+ /** @hide */
static volatile boolean sWarnOnBlocking = false;
/**
@@ -207,8 +208,8 @@ public class Binder implements IBinder {
/**
* Allow blocking calls on the given interface, overriding the requested
* value of {@link #setWarnOnBlocking(boolean)}.
- * <p>
- * This should only be rarely called when you are <em>absolutely sure</em>
+ *
+ * <p>This should only be rarely called when you are <em>absolutely sure</em>
* the remote interface is a built-in system component that can never be
* upgraded. In particular, this <em>must never</em> be called for
* interfaces hosted by package that could be upgraded or replaced,
@@ -258,7 +259,9 @@ public class Binder implements IBinder {
ThreadLocal.withInitial(() -> sWarnOnBlocking);
/**
- * Allow blocking calls for the current thread. See {@link #allowBlocking}.
+ * Allow blocking calls for the current thread.
+ *
+ * @see {@link #allowBlocking}.
*
* @hide
*/
@@ -267,7 +270,9 @@ public class Binder implements IBinder {
}
/**
- * Reset the current thread to the default blocking behavior. See {@link #defaultBlocking}.
+ * Reset the current thread to the default blocking behavior.
+ *
+ * @see {@link #defaultBlocking}.
*
* @hide
*/
@@ -286,10 +291,10 @@ public class Binder implements IBinder {
/**
* Return the ID of the process that sent you the current transaction
- * that is being processed. This pid can be used with higher-level
+ * that is being processed. This PID can be used with higher-level
* system services to determine its identity and check permissions.
* If the current thread is not currently executing an incoming transaction,
- * then its own pid is returned.
+ * then its own PID is returned.
*
* Warning: oneway transactions do not receive PID.
*/
@@ -297,11 +302,11 @@ public class Binder implements IBinder {
public static final native int getCallingPid();
/**
- * Return the Linux uid assigned to the process that sent you the
- * current transaction that is being processed. This uid can be used with
+ * Return the Linux UID assigned to the process that sent you the
+ * current transaction that is being processed. This UID can be used with
* higher-level system services to determine its identity and check
- * permissions. If the current thread is not currently executing an
- * incoming transaction, then its own uid is returned.
+ * permissions. If the current thread is not currently executing an
+ * incoming transaction, then its own UID is returned.
*/
@CriticalNative
public static final native int getCallingUid();
@@ -316,11 +321,11 @@ public class Binder implements IBinder {
public static final native boolean isDirectlyHandlingTransaction();
/**
- * Return the Linux uid assigned to the process that sent the transaction
+ * Return the Linux UID assigned to the process that sent the transaction
* currently being processed.
*
* @throws IllegalStateException if the current thread is not currently
- * executing an incoming transaction.
+ * executing an incoming transaction.
*/
public static final int getCallingUidOrThrow() {
if (!isDirectlyHandlingTransaction()) {
@@ -332,18 +337,20 @@ public class Binder implements IBinder {
/**
* Return the UserHandle assigned to the process that sent you the
- * current transaction that is being processed. This is the user
- * of the caller. It is distinct from {@link #getCallingUid()} in that a
+ * current transaction that is being processed. This is the user
+ * of the caller. It is distinct from {@link #getCallingUid()} in that a
* particular user will have multiple distinct apps running under it each
- * with their own uid. If the current thread is not currently executing an
+ * with their own UID. If the current thread is not currently executing an
* incoming transaction, then its own UserHandle is returned.
+ *
+ * @see UserHandle
*/
public static final @NonNull UserHandle getCallingUserHandle() {
return UserHandle.of(UserHandle.getUserId(getCallingUid()));
}
/**
- * Reset the identity of the incoming IPC on the current thread. This can
+ * Reset the identity of the incoming IPC on the current thread. This can
* be useful if, while handling an incoming call, you will be calling
* on interfaces of other objects that may be local to your process and
* need to do permission checks on the calls coming into them (so they
@@ -376,10 +383,10 @@ public class Binder implements IBinder {
/**
* Convenience method for running the provided action enclosed in
- * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity}
+ * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity}.
*
- * Any exception thrown by the given action will be caught and rethrown after the call to
- * {@link #restoreCallingIdentity}
+ * <p>Any exception thrown by the given action will be caught and
+ * rethrown after the call to {@link #restoreCallingIdentity}.
*
* @hide
*/
@@ -400,10 +407,10 @@ public class Binder implements IBinder {
/**
* Convenience method for running the provided action enclosed in
- * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity} returning the result
+ * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity} returning the result.
*
- * Any exception thrown by the given action will be caught and rethrown after the call to
- * {@link #restoreCallingIdentity}
+ * <p>Any exception thrown by the given action will be caught and rethrown after
+ * the call to {@link #restoreCallingIdentity}.
*
* @hide
*/
@@ -428,12 +435,13 @@ public class Binder implements IBinder {
*
* <p>The StrictMode settings are kept in two places: a Java-level
* threadlocal for libcore/Dalvik, and a native threadlocal (set
- * here) for propagation via Binder calls. This is a little
+ * here) for propagation via Binder calls. This is a little
* unfortunate, but necessary to break otherwise more unfortunate
* dependencies either of Dalvik on Android, or Android
* native-only code on Dalvik.
*
* @see StrictMode
+ *
* @hide
*/
@CriticalNative
@@ -443,6 +451,7 @@ public class Binder implements IBinder {
* Gets the current native thread-local StrictMode policy mask.
*
* @see #setThreadStrictModePolicy
+ *
* @hide
*/
@CriticalNative
@@ -459,7 +468,7 @@ public class Binder implements IBinder {
* reasons, we only support one UID. This UID represents the original user responsible for the
* binder calls.
*
- * <p>{@link Binder#restoreCallingWorkSource(long)} must always be called after setting the
+ * <p>{@link #restoreCallingWorkSource(long)} must always be called after setting the
* worksource.
*
* <p>A typical use case would be
@@ -477,16 +486,16 @@ public class Binder implements IBinder {
*
* @param workSource The original UID responsible for the binder call.
* @return token to restore original work source.
- **/
+ */
@CriticalNative
public static final native long setCallingWorkSourceUid(int workSource);
/**
* Returns the work source set by the caller.
*
- * Unlike {@link Binder#getCallingUid()}, this result of this method cannot be trusted. The
+ * <p>Unlike {@link #getCallingUid()}, this result of this method cannot be trusted. The
* caller can set the value to whatever they want. Only use this value if you trust the calling
- * uid.
+ * UID.
*
* @return The original UID responsible for the binder transaction.
*/
@@ -499,7 +508,7 @@ public class Binder implements IBinder {
* <p>The work source will be propagated for future outgoing binder transactions
* executed on this thread.
*
- * <p>{@link Binder#restoreCallingWorkSource(long)} must always be called after clearing the
+ * <p>{@link #restoreCallingWorkSource(long)} must always be called after clearing the
* worksource.
*
* <p>A typical use case would be
@@ -513,13 +522,13 @@ public class Binder implements IBinder {
* </pre>
*
* @return token to restore original work source.
- **/
+ */
@CriticalNative
public static final native long clearCallingWorkSource();
/**
* Restores the work source on this thread using a token returned by
- * {@link #setCallingWorkSourceUid(int) or {@link clearCallingWorkSource()}.
+ * {@link #setCallingWorkSourceUid(int)} or {@link #clearCallingWorkSource()}.
*
* <p>A typical use case would be
* <pre>
@@ -530,7 +539,7 @@ public class Binder implements IBinder {
* Binder.restoreCallingWorkSource(token);
* }
* </pre>
- **/
+ */
@CriticalNative
public static final native void restoreCallingWorkSource(long token);
@@ -553,7 +562,7 @@ public class Binder implements IBinder {
* Use a VINTF-stability binder w/o VINTF requirements. Should be called
* on a binder before it is sent out of process.
*
- * This must be called before the object is sent to another process.
+ * <p>This must be called before the object is sent to another process.
*
* @hide
*/
@@ -561,7 +570,7 @@ public class Binder implements IBinder {
/**
* Flush any Binder commands pending in the current thread to the kernel
- * driver. This can be
+ * driver. This can be
* useful to call before performing an operation that may block for a long
* time, to ensure that any pending object references have been released
* in order to prevent the process from holding on to objects longer than
@@ -570,7 +579,7 @@ public class Binder implements IBinder {
public static final native void flushPendingCommands();
/**
- * Add the calling thread to the IPC thread pool. This function does
+ * Add the calling thread to the IPC thread pool. This function does
* not return until the current process is exiting.
*/
public static final void joinThreadPool() {
@@ -579,6 +588,7 @@ public class Binder implements IBinder {
/**
* Returns true if the specified interface is a proxy.
+ *
* @hide
*/
public static final boolean isProxy(IInterface iface) {
@@ -588,6 +598,7 @@ public class Binder implements IBinder {
/**
* Call blocks until the number of executing binder threads is less
* than the maximum number of binder threads allowed for this process.
+ *
* @hide
*/
public static final native void blockUntilThreadAvailable();
@@ -595,7 +606,7 @@ public class Binder implements IBinder {
/**
* Default constructor just initializes the object.
*
- * If you're creating a Binder token (a Binder object without an attached interface),
+ * <p>If you're creating a Binder token (a Binder object without an attached interface),
* you should use {@link #Binder(String)} instead.
*/
public Binder() {
@@ -605,7 +616,7 @@ public class Binder implements IBinder {
/**
* Constructor for creating a raw Binder object (token) along with a descriptor.
*
- * The descriptor of binder objects usually specifies the interface they are implementing.
+ * <p>The descriptor of binder objects usually specifies the interface they are implementing.
* In case of binder tokens, no interface is implemented, and the descriptor can be used
* as a sort of tag to help identify the binder token. This will help identify remote
* references to these objects more easily when debugging.
@@ -614,7 +625,7 @@ public class Binder implements IBinder {
* Instead of creating multiple tokens with the same descriptor, consider adding a suffix to
* help identify them.
*/
- public Binder(@Nullable String descriptor) {
+ public Binder(@Nullable String descriptor) {
mObject = getNativeBBinderHolder();
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mObject);
@@ -631,9 +642,9 @@ public class Binder implements IBinder {
/**
* Convenience method for associating a specific interface with the Binder.
- * After calling, queryLocalInterface() will be implemented for you
- * to return the given owner IInterface when the corresponding
- * descriptor is requested.
+ * After calling, {@link #queryLocalInterface(String) queryLocalInterface()}
+ * will be implemented for you to return the given owner IInterface when
+ * the corresponding descriptor is requested.
*/
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
mOwner = owner;
@@ -666,8 +677,8 @@ public class Binder implements IBinder {
}
/**
- * Use information supplied to attachInterface() to return the
- * associated IInterface if it matches the requested
+ * Use information supplied to {@link #attachInterface attachInterface()}
+ * to return the associated {@link IInterface} if it matches the requested
* descriptor.
*/
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
@@ -678,14 +689,15 @@ public class Binder implements IBinder {
}
/**
- * Control disabling of dump calls in this process. This is used by the system
+ * Control disabling of dump calls in this process. This is used by the system
* process watchdog to disable incoming dump calls while it has detecting the system
- * is hung and is reporting that back to the activity controller. This is to
+ * is hung and is reporting that back to the activity controller. This is to
* prevent the controller from getting hung up on bug reports at this point.
- * @hide
*
* @param msg The message to show instead of the dump; if null, dumps are
* re-enabled.
+ *
+ * @hide
*/
public static void setDumpDisabled(String msg) {
sDumpDisabled = msg;
@@ -694,7 +706,8 @@ public class Binder implements IBinder {
/**
* Listener to be notified about each proxy-side binder call.
*
- * See {@link setProxyTransactListener}.
+ * @see {@link #setProxyTransactListener}.
+ *
* @hide
*/
@SystemApi
@@ -702,7 +715,8 @@ public class Binder implements IBinder {
/**
* Called before onTransact.
*
- * @return an object that will be passed back to #onTransactEnded (or null).
+ * @return an object that will be passed back to {@link #onTransactEnded} (or null).,
+ *
* @hide
*/
@Nullable
@@ -713,15 +727,15 @@ public class Binder implements IBinder {
/**
* Called before onTransact.
*
- * @return an object that will be passed back to #onTransactEnded (or null).
+ * @return an object that will be passed back to {@link #onTransactEnded} (or null).
*/
@Nullable
Object onTransactStarted(@NonNull IBinder binder, int transactionCode);
/**
- * Called after onTranact (even when an exception is thrown).
+ * Called after onTransact (even when an exception is thrown).
*
- * @param session The object return by #onTransactStarted.
+ * @param session The object return by {@link #onTransactStarted}.
*/
void onTransactEnded(@Nullable Object session);
}
@@ -732,16 +746,17 @@ public class Binder implements IBinder {
* <li>By default, this listener will propagate the worksource if the outgoing call happens on
* the same thread as the incoming binder call.
* <li>Custom attribution can be done by calling {@link ThreadLocalWorkSource#setUid(int)}.
+ *
* @hide
*/
public static class PropagateWorkSourceTransactListener implements ProxyTransactListener {
@Override
public Object onTransactStarted(IBinder binder, int transactionCode) {
- // Note that {@link Binder#getCallingUid()} is already set to the UID of the current
- // process when this method is called.
- //
- // We use ThreadLocalWorkSource instead. It also allows feature owners to set
- // {@link ThreadLocalWorkSource#set(int) manually to attribute resources to a UID.
+ // Note that {@link #getCallingUid()} is already set to the UID of the current
+ // process when this method is called.
+ //
+ // We use {@link ThreadLocalWorkSource} instead. It also allows feature owners to set
+ // {@link ThreadLocalWorkSource#set(int)} manually to attribute resources to a UID.
int uid = ThreadLocalWorkSource.getUid();
if (uid != ThreadLocalWorkSource.UID_NONE) {
return Binder.setCallingWorkSourceUid(uid);
@@ -770,6 +785,7 @@ public class Binder implements IBinder {
* <li>The listener is called on the critical path of the binder transaction so be careful about
* performance.
* <li>Never execute another binder transaction inside the listener.
+ *
* @hide
*/
@SystemApi
@@ -778,7 +794,7 @@ public class Binder implements IBinder {
}
/**
- * Default implementation is a stub that returns false. You will want
+ * Default implementation is a stub that returns false. You will want
* to override this to do the appropriate unmarshalling of transactions.
*
* <p>If you want to call this, call transact().
@@ -786,15 +802,14 @@ public class Binder implements IBinder {
* <p>Implementations that are returning a result should generally use
* {@link Parcel#writeNoException() Parcel.writeNoException} and
* {@link Parcel#writeException(Exception) Parcel.writeException} to propagate
- * exceptions back to the caller.</p>
+ * exceptions back to the caller.
*
- * @param code The action to perform. This should
- * be a number between {@link #FIRST_CALL_TRANSACTION} and
- * {@link #LAST_CALL_TRANSACTION}.
+ * @param code The action to perform. This should be a number between
+ * {@link #FIRST_CALL_TRANSACTION} and {@link #LAST_CALL_TRANSACTION}.
* @param data Marshalled data being received from the caller.
* @param reply If the caller is expecting a result back, it should be marshalled
* in to here.
- * @param flags Additional operation flags. Either 0 for a normal
+ * @param flags Additional operation flags. Either 0 for a normal
* RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.
*
* @return Return true on a successful call; returning false is generally used to
@@ -856,10 +871,12 @@ public class Binder implements IBinder {
* Resolves a transaction code to a human readable name.
*
* <p>Default implementation is a stub that returns null.
+ *
* <p>AIDL generated code will return the original method name.
*
* @param transactionCode The code to resolve.
* @return A human readable name.
+ *
* @hide
*/
public @Nullable String getTransactionName(int transactionCode) {
@@ -925,7 +942,7 @@ public class Binder implements IBinder {
* Print the object's state into the given stream.
*
* @param fd The raw file descriptor that the dump is being sent to.
- * @param fout The file to which you should dump your state. This will be
+ * @param fout The file to which you should dump your state. This will be
* closed for you after you return.
* @param args additional arguments to the dump request.
*/
@@ -941,6 +958,7 @@ public class Binder implements IBinder {
* @param callback Callback through which to interact with the invoking shell.
* @param resultReceiver Called when the command has finished executing, with the result code.
* @throws RemoteException
+ *
* @hide
*/
public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@@ -958,7 +976,8 @@ public class Binder implements IBinder {
*
* <p class="caution">Note: no permission checking is done before calling this method; you must
* apply any security checks as appropriate for the command being executed.
- * Consider using {@link ShellCommand} to help in the implementation.</p>
+ * Consider using {@link ShellCommand} to help in the implementation.
+ *
* @hide
*/
public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@@ -1013,7 +1032,7 @@ public class Binder implements IBinder {
* System services can implement this method to implement ADB shell commands.
*
* <p>A system binder service can implement it to handle shell commands on ADB. For example,
- * the Job Scheduler service implements it to handle <code>adb shell cmd jobscheduler</code>.
+ * the Job Scheduler service implements it to handle {@code adb shell cmd jobscheduler}.
*
* <p>Commands are only executable by ADB shell; i.e. only {@link Process#SHELL_UID} and
* {@link Process#ROOT_UID} can call them.
@@ -1022,8 +1041,8 @@ public class Binder implements IBinder {
* @param out standard output
* @param err standard error
* @param args arguments passed to the command. Can be empty. The first argument is typically
- * a subcommand, such as {@code run} for {@code adb shell cmd jobscheduler run}.
- * @return the status code returned from the <code>cmd</code> command.
+ * a subcommand, such as {@code run} for {@code adb shell cmd jobscheduler run}.
+ * @return the status code returned from the {@code cmd} command.
*
* @hide
*/
@@ -1051,7 +1070,7 @@ public class Binder implements IBinder {
public final native void setExtension(@Nullable IBinder extension);
/**
- * Default implementation rewinds the parcels and calls onTransact. On
+ * Default implementation rewinds the parcels and calls onTransact. On
* the remote side, transact calls into the binder to do the IPC.
*/
public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
@@ -1083,7 +1102,7 @@ public class Binder implements IBinder {
static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) {
if (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) {
- // Trying to send > 800k, this is way too much
+ // Trying to send > 800k, this is way too much.
StringBuilder sb = new StringBuilder();
sb.append(msg);
sb.append(": on ");
@@ -1107,7 +1126,7 @@ public class Binder implements IBinder {
private static native long getNativeBBinderHolder();
/**
- * By default, we use the calling uid since we can always trust it.
+ * By default, we use the calling UID since we can always trust it.
*/
private static volatile BinderInternal.WorkSourceProvider sWorkSourceProvider =
(x) -> Binder.getCallingUid();
@@ -1122,6 +1141,7 @@ public class Binder implements IBinder {
* <li>The callback is called on the critical path of the binder transaction so be careful about
* performance.
* <li>Never execute another binder transaction inside the callback.
+ *
* @hide
*/
public static void setWorkSourceProvider(BinderInternal.WorkSourceProvider workSourceProvider) {
@@ -1131,12 +1151,12 @@ public class Binder implements IBinder {
sWorkSourceProvider = workSourceProvider;
}
- // Entry point from android_util_Binder.cpp's onTransact
+ // Entry point from android_util_Binder.cpp's onTransact.
@UnsupportedAppUsage
private boolean execTransact(int code, long dataObj, long replyObj,
int flags) {
// At that point, the parcel request headers haven't been parsed so we do not know what
- // WorkSource the caller has set. Use calling uid as the default.
+ // {@link WorkSource} the caller has set. Use calling UID as the default.
final int callingUid = Binder.getCallingUid();
final long origWorkSource = ThreadLocalWorkSource.setUid(callingUid);
try {
@@ -1154,17 +1174,18 @@ public class Binder implements IBinder {
observer != null ? observer.callStarted(this, code, UNSET_WORKSOURCE) : null;
Parcel data = Parcel.obtain(dataObj);
Parcel reply = Parcel.obtain(replyObj);
- // theoretically, we should call transact, which will call onTransact,
+ // Theoretically, we should call transact, which will call onTransact,
// but all that does is rewind it, and we just got these from an IPC,
// so we'll just call it directly.
boolean res;
// Log any exceptions as warnings, don't silently suppress them.
- // If the call was FLAG_ONEWAY then these exceptions disappear into the ether.
+ // If the call was {@link IBinder#FLAG_ONEWAY} then these exceptions
+ // disappear into the ether.
final boolean tracingEnabled = Binder.isTracingEnabled();
try {
final BinderCallHeavyHitterWatcher heavyHitterWatcher = sHeavyHitterWatcher;
if (heavyHitterWatcher != null) {
- // Notify the heavy hitter watcher, if it's enabled
+ // Notify the heavy hitter watcher, if it's enabled.
heavyHitterWatcher.onTransaction(callingUid, getClass(), code);
}
if (tracingEnabled) {
@@ -1197,7 +1218,7 @@ public class Binder implements IBinder {
Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
}
} else {
- // Clear the parcel before writing the exception
+ // Clear the parcel before writing the exception.
reply.setDataSize(0);
reply.setDataPosition(0);
reply.writeException(e);
@@ -1209,7 +1230,7 @@ public class Binder implements IBinder {
}
if (observer != null) {
// The parcel RPC headers have been called during onTransact so we can now access
- // the worksource uid from the parcel.
+ // the worksource UID from the parcel.
final int workSourceUid = sWorkSourceProvider.resolveWorkSourceUid(
data.readCallingWorkSourceUid());
observer.callEnded(callSession, data.dataSize(), reply.dataSize(), workSourceUid);
@@ -1220,9 +1241,9 @@ public class Binder implements IBinder {
data.recycle();
// Just in case -- we are done with the IPC, so there should be no more strict
- // mode violations that have gathered for this thread. Either they have been
+ // mode violations that have gathered for this thread. Either they have been
// parceled and are now in transport off to the caller, or we are returning back
- // to the main transaction loop to wait for another incoming transaction. Either
+ // to the main transaction loop to wait for another incoming transaction. Either
// way, strict mode begone!
StrictMode.clearGatheredViolations();
return res;
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 92eb7a5d047e..b2bbfd6c163d 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -102,6 +102,18 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
}
/**
+ * Constructs a {@link Bundle} containing a copy of {@code from}.
+ *
+ * @param from The bundle to be copied.
+ * @param deep Whether is a deep or shallow copy.
+ *
+ * @hide
+ */
+ Bundle(Bundle from, boolean deep) {
+ super(from, deep);
+ }
+
+ /**
* If {@link #mParcelledData} is not null, copy the HAS FDS bit from it because it's fast.
* Otherwise (if {@link #mParcelledData} is already null), leave {@link #FLAG_HAS_FDS_KNOWN}
* unset, because scanning a map is slower. We'll do it lazily in
@@ -167,13 +179,6 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
}
/**
- * Constructs a Bundle without initializing it.
- */
- Bundle(boolean doInit) {
- super(doInit);
- }
-
- /**
* Make a Bundle for a single key/value pair.
*
* @hide
@@ -260,9 +265,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
* are referenced as-is and not copied in any way.
*/
public Bundle deepCopy() {
- Bundle b = new Bundle(false);
- b.copyInternal(this, true);
- return b;
+ return new Bundle(this, /* deep */ true);
}
/**
@@ -324,28 +327,10 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
*/
public boolean hasFileDescriptors() {
if ((mFlags & FLAG_HAS_FDS_KNOWN) == 0) {
- boolean fdFound = false; // keep going until we find one or run out of data
-
- if (mParcelledData != null) {
- if (mParcelledData.hasFileDescriptors()) {
- fdFound = true;
- }
- } else {
- // It's been unparcelled, so we need to walk the map
- for (int i=mMap.size()-1; i>=0; i--) {
- Object obj = mMap.valueAt(i);
- if (Parcel.hasFileDescriptors(obj)) {
- fdFound = true;
- break;
- }
- }
- }
-
- if (fdFound) {
- mFlags |= FLAG_HAS_FDS;
- } else {
- mFlags &= ~FLAG_HAS_FDS;
- }
+ Parcel p = mParcelledData;
+ mFlags = (Parcel.hasFileDescriptors((p != null) ? p : mMap))
+ ? mFlags | FLAG_HAS_FDS
+ : mFlags & ~FLAG_HAS_FDS;
mFlags |= FLAG_HAS_FDS_KNOWN;
}
return (mFlags & FLAG_HAS_FDS) != 0;
diff --git a/core/java/android/os/IStatsBootstrapAtomService.aidl b/core/java/android/os/IStatsBootstrapAtomService.aidl
new file mode 100644
index 000000000000..9d1df67fa19d
--- /dev/null
+++ b/core/java/android/os/IStatsBootstrapAtomService.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright 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.os;
+
+import android.os.StatsBootstrapAtom;
+
+/**
+ * IBootstrapAtomService interface exposes an interface for processes that launch in the
+ * bootstrap namespace to push atoms to statsd.
+ *
+ * @hide
+ */
+oneway interface IStatsBootstrapAtomService {
+ /**
+ * Push an atom to StatsBootstrapAtomService, which will forward it to statsd.
+ *
+ * @param atom - parcelled representation of the atom to log.
+ *
+ * Errors are reported as service specific errors.
+ */
+ void reportBootstrapAtom(in StatsBootstrapAtom atom);
+} \ No newline at end of file
diff --git a/core/java/android/os/ISystemConfig.aidl b/core/java/android/os/ISystemConfig.aidl
index d83d94a8ec77..15e3ce25122b 100644
--- a/core/java/android/os/ISystemConfig.aidl
+++ b/core/java/android/os/ISystemConfig.aidl
@@ -16,6 +16,8 @@
package android.os;
+import android.content.ComponentName;
+
/**
* Binder interface to query SystemConfig in the system server.
* {@hide}
@@ -44,5 +46,5 @@ interface ISystemConfig {
/**
* @see SystemConfigManager#getEnabledComponentOverrides
*/
- List<String> getEnabledComponentOverrides(String packageName);
+ List<ComponentName> getEnabledComponentOverrides(String packageName);
}
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 92861fba40a3..1e424d1194ae 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -1,18 +1,6 @@
# Haptics
-per-file CombinedVibrationEffect.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file CombinedVibrationEffect.java = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file ExternalVibration.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file ExternalVibration.java = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file IExternalVibrationController.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file IExternalVibratorService.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file IVibratorManagerService.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file NullVibrator.java = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file SystemVibrator.java = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file SystemVibratorManager.java = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file VibrationEffect.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file VibrationEffect.java = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file Vibrator.java = file:/services/core/java/com/android/server/vibrator/OWNERS
-per-file VibratorManager.java = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file *Vibration* = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file *Vibrator* = file:/services/core/java/com/android/server/vibrator/OWNERS
# PowerManager
per-file IPowerManager.aidl = michaelwr@google.com, santoscordon@google.com
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index dd0cb8cc62ae..8894c85fa7b4 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -62,6 +62,8 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.function.Function;
+import java.util.function.IntFunction;
import java.util.function.Supplier;
/**
@@ -178,8 +180,12 @@ import java.util.function.Supplier;
* {@link #writeStrongInterface(IInterface)}, {@link #readStrongBinder()},
* {@link #writeBinderArray(IBinder[])}, {@link #readBinderArray(IBinder[])},
* {@link #createBinderArray()},
+ * {@link #writeInterfaceArray(T[])}, {@link #readInterfaceArray(T[], Function)},
+ * {@link #createInterfaceArray(IntFunction, Function)},
* {@link #writeBinderList(List)}, {@link #readBinderList(List)},
- * {@link #createBinderArrayList()}.</p>
+ * {@link #createBinderArrayList()},
+ * {@link #writeInterfaceList(List)}, {@link #readInterfaceList(List, Function)},
+ * {@link #createInterfaceArrayList(Function)}.</p>
*
* <p>FileDescriptor objects, representing raw Linux file descriptor identifiers,
* can be written and {@link ParcelFileDescriptor} objects returned to operate
@@ -747,57 +753,70 @@ public final class Parcel {
}
/**
- * Check if the object used in {@link #readValue(ClassLoader)} / {@link #writeValue(Object)}
- * has file descriptors.
+ * Check if the object has file descriptors.
+ *
+ * <p>Objects supported are {@link Parcel} and objects that can be passed to {@link
+ * #writeValue(Object)}}
*
* <p>For most cases, it will use the self-reported {@link Parcelable#describeContents()} method
* for that.
*
- * @throws IllegalArgumentException if you provide any object not supported by above methods.
- * Most notably, if you pass {@link Parcel}, this method will throw, for that check
- * {@link Parcel#hasFileDescriptors()}
+ * @throws IllegalArgumentException if you provide any object not supported by above methods
+ * (including if the unsupported object is inside a nested container).
*
* @hide
*/
public static boolean hasFileDescriptors(Object value) {
- if (value instanceof LazyValue) {
- return ((LazyValue) value).hasFileDescriptors();
+ if (value instanceof Parcel) {
+ Parcel parcel = (Parcel) value;
+ if (parcel.hasFileDescriptors()) {
+ return true;
+ }
+ } else if (value instanceof LazyValue) {
+ LazyValue lazy = (LazyValue) value;
+ if (lazy.hasFileDescriptors()) {
+ return true;
+ }
} else if (value instanceof Parcelable) {
- if ((((Parcelable) value).describeContents()
- & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
+ Parcelable parcelable = (Parcelable) value;
+ if ((parcelable.describeContents() & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
return true;
}
- } else if (value instanceof Parcelable[]) {
- Parcelable[] array = (Parcelable[]) value;
- for (int n = array.length - 1; n >= 0; n--) {
- Parcelable p = array[n];
- if (p != null && ((p.describeContents()
- & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
+ } else if (value instanceof ArrayMap<?, ?>) {
+ ArrayMap<?, ?> map = (ArrayMap<?, ?>) value;
+ for (int i = 0, n = map.size(); i < n; i++) {
+ if (hasFileDescriptors(map.keyAt(i))
+ || hasFileDescriptors(map.valueAt(i))) {
+ return true;
+ }
+ }
+ } else if (value instanceof Map<?, ?>) {
+ Map<?, ?> map = (Map<?, ?>) value;
+ for (Map.Entry<?, ?> entry : map.entrySet()) {
+ if (hasFileDescriptors(entry.getKey())
+ || hasFileDescriptors(entry.getValue())) {
+ return true;
+ }
+ }
+ } else if (value instanceof List<?>) {
+ List<?> list = (List<?>) value;
+ for (int i = 0, n = list.size(); i < n; i++) {
+ if (hasFileDescriptors(list.get(i))) {
return true;
}
}
} else if (value instanceof SparseArray<?>) {
SparseArray<?> array = (SparseArray<?>) value;
- for (int n = array.size() - 1; n >= 0; n--) {
- Object object = array.valueAt(n);
- if (object instanceof Parcelable) {
- Parcelable p = (Parcelable) object;
- if (p != null && (p.describeContents()
- & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
- return true;
- }
+ for (int i = 0, n = array.size(); i < n; i++) {
+ if (hasFileDescriptors(array.valueAt(i))) {
+ return true;
}
}
- } else if (value instanceof ArrayList<?>) {
- ArrayList<?> array = (ArrayList<?>) value;
- for (int n = array.size() - 1; n >= 0; n--) {
- Object object = array.get(n);
- if (object instanceof Parcelable) {
- Parcelable p = (Parcelable) object;
- if (p != null && ((p.describeContents()
- & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
- return true;
- }
+ } else if (value instanceof Object[]) {
+ Object[] array = (Object[]) value;
+ for (int i = 0, n = array.length; i < n; i++) {
+ if (hasFileDescriptors(array[i])) {
+ return true;
}
}
} else {
@@ -827,6 +846,19 @@ public final class Parcel {
}
/**
+ * Verify there are no bytes left to be read on the Parcel.
+ *
+ * @throws BadParcelableException If the current position hasn't reached the end of the Parcel.
+ * When used over binder, this exception should propagate to the caller.
+ */
+ public void enforceNoDataAvail() {
+ final int n = dataAvail();
+ if (n > 0) {
+ throw new BadParcelableException("Parcel data not fully consumed, unread size: " + n);
+ }
+ }
+
+ /**
* Writes the work source uid to the request headers.
*
* <p>It requires the headers to have been written/read already to replace the work source.
@@ -1717,6 +1749,30 @@ public final class Parcel {
}
/**
+ * Flatten a homogeneous array containing an IInterface type into the parcel,
+ * at the current dataPosition() and growing dataCapacity() if needed. The
+ * type of the objects in the array must be one that implements IInterface.
+ *
+ * @param val The array of objects to be written.
+ *
+ * @see #createInterfaceArray
+ * @see #readInterfaceArray
+ * @see IInterface
+ */
+ public final <T extends IInterface> void writeInterfaceArray(
+ @SuppressLint("ArrayReturn") @Nullable T[] val) {
+ if (val != null) {
+ int N = val.length;
+ writeInt(N);
+ for (int i=0; i<N; i++) {
+ writeStrongInterface(val[i]);
+ }
+ } else {
+ writeInt(-1);
+ }
+ }
+
+ /**
* @hide
*/
public final void writeCharSequenceArray(@Nullable CharSequence[] val) {
@@ -1772,6 +1828,50 @@ public final class Parcel {
}
/**
+ * Read and return a new array of T (IInterface) from the parcel.
+ *
+ * @return the IInterface array of type T
+ * @param newArray a function to create an array of T with a given length
+ * @param asInterface a function to convert IBinder object into T (IInterface)
+ */
+ @SuppressLint({"ArrayReturn", "NullableCollection", "SamShouldBeLast"})
+ @Nullable
+ public final <T extends IInterface> T[] createInterfaceArray(
+ @NonNull IntFunction<T[]> newArray, @NonNull Function<IBinder, T> asInterface) {
+ int N = readInt();
+ if (N >= 0) {
+ T[] val = newArray.apply(N);
+ for (int i=0; i<N; i++) {
+ val[i] = asInterface.apply(readStrongBinder());
+ }
+ return val;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Read an array of T (IInterface) from a parcel.
+ *
+ * @param asInterface a function to convert IBinder object into T (IInterface)
+ *
+ * @throws BadParcelableException Throws BadParcelableException if the length of `val`
+ * mismatches the number of items in the parcel.
+ */
+ public final <T extends IInterface> void readInterfaceArray(
+ @SuppressLint("ArrayReturn") @NonNull T[] val,
+ @NonNull Function<IBinder, T> asInterface) {
+ int N = readInt();
+ if (N == val.length) {
+ for (int i=0; i<N; i++) {
+ val[i] = asInterface.apply(readStrongBinder());
+ }
+ } else {
+ throw new BadParcelableException("bad array lengths");
+ }
+ }
+
+ /**
* Flatten a List containing a particular object type into the parcel, at
* the current dataPosition() and growing dataCapacity() if needed. The
* type of the objects in the list must be one that implements Parcelable.
@@ -1885,6 +1985,28 @@ public final class Parcel {
}
/**
+ * Flatten a {@code List} containing T (IInterface) objects into this parcel
+ * at the current position. They can later be retrieved with
+ * {@link #createInterfaceArrayList} or {@link #readInterfaceList}.
+ *
+ * @see #createInterfaceArrayList
+ * @see #readInterfaceList
+ */
+ public final <T extends IInterface> void writeInterfaceList(@Nullable List<T> val) {
+ if (val == null) {
+ writeInt(-1);
+ return;
+ }
+ int N = val.size();
+ int i=0;
+ writeInt(N);
+ while (i < N) {
+ writeStrongInterface(val.get(i));
+ i++;
+ }
+ }
+
+ /**
* Flatten a {@code List} containing arbitrary {@code Parcelable} objects into this parcel
* at the current position. They can later be retrieved using
* {@link #readParcelableList(List, ClassLoader)} if required.
@@ -2881,17 +3003,45 @@ public final class Parcel {
* Please use {@link #readBundle(ClassLoader)} instead (whose data must have
* been written with {@link #writeBundle}. Read into an existing Map object
* from the parcel at the current dataPosition().
+ *
+ * @deprecated Consider using {@link #readBundle(ClassLoader)} as stated above, in case this
+ * method is still preferred use the type-safer version {@link #readMap(Map, ClassLoader,
+ * Class, Class)} starting from Android {@link Build.VERSION_CODES#TIRAMISU}.
*/
+ @Deprecated
public final void readMap(@NonNull Map outVal, @Nullable ClassLoader loader) {
- int N = readInt();
- readMapInternal(outVal, N, loader);
+ int n = readInt();
+ readMapInternal(outVal, n, loader, /* clazzKey */ null, /* clazzValue */ null);
+ }
+
+ /**
+ * Same as {@link #readMap(Map, ClassLoader)} but accepts {@code clazzKey} and
+ * {@code clazzValue} parameter as the types required for each key and value pair.
+ *
+ * @throws BadParcelableException If the item to be deserialized is not an instance of that
+ * class or any of its children class
+ */
+ public <K, V> void readMap(@NonNull Map<? super K, ? super V> outVal,
+ @Nullable ClassLoader loader, @NonNull Class<K> clazzKey,
+ @NonNull Class<V> clazzValue) {
+ Objects.requireNonNull(clazzKey);
+ Objects.requireNonNull(clazzValue);
+ int n = readInt();
+ readMapInternal(outVal, n, loader, clazzKey, clazzValue);
}
/**
* Read into an existing List object from the parcel at the current
* dataPosition(), using the given class loader to load any enclosed
* Parcelables. If it is null, the default class loader is used.
+ *
+ * @deprecated Use the type-safer version {@link #readList(List, ClassLoader, Class)} starting
+ * from Android {@link Build.VERSION_CODES#TIRAMISU}. Also consider changing the format to
+ * use {@link #readTypedList(List, Parcelable.Creator)} if possible (eg. if the items'
+ * class is final) since this is also more performant. Note that changing to the latter
+ * also requires changing the writes.
*/
+ @Deprecated
public final void readList(@NonNull List outVal, @Nullable ClassLoader loader) {
int N = readInt();
readListInternal(outVal, N, loader, /* clazz */ null);
@@ -2918,20 +3068,46 @@ public final class Parcel {
* object from the parcel at the current dataPosition(), using the given
* class loader to load any enclosed Parcelables. Returns null if
* the previously written map object was null.
+ *
+ * @deprecated Consider using {@link #readBundle(ClassLoader)} as stated above, in case this
+ * method is still preferred use the type-safer version {@link #readHashMap(ClassLoader,
+ * Class, Class)} starting from Android {@link Build.VERSION_CODES#TIRAMISU}.
*/
+ @Deprecated
@Nullable
- public final HashMap readHashMap(@Nullable ClassLoader loader)
- {
- int N = readInt();
- if (N < 0) {
+ public HashMap readHashMap(@Nullable ClassLoader loader) {
+ int n = readInt();
+ if (n < 0) {
return null;
}
- HashMap m = new HashMap(N);
- readMapInternal(m, N, loader);
+ HashMap m = new HashMap(n);
+ readMapInternal(m, n, loader, /* clazzKey */ null, /* clazzValue */ null);
return m;
}
/**
+ * Same as {@link #readHashMap(ClassLoader)} but accepts {@code clazzKey} and
+ * {@code clazzValue} parameter as the types required for each key and value pair.
+ *
+ * @throws BadParcelableException if the item to be deserialized is not an instance of that
+ * class or any of its children class
+ */
+ @SuppressLint({"ConcreteCollection", "NullableCollection"})
+ @Nullable
+ public <K, V> HashMap<K, V> readHashMap(@Nullable ClassLoader loader,
+ @NonNull Class<? extends K> clazzKey, @NonNull Class<? extends V> clazzValue) {
+ Objects.requireNonNull(clazzKey);
+ Objects.requireNonNull(clazzValue);
+ int n = readInt();
+ if (n < 0) {
+ return null;
+ }
+ HashMap<K, V> map = new HashMap<>(n);
+ readMapInternal(map, n, loader, clazzKey, clazzValue);
+ return map;
+ }
+
+ /**
* Read and return a new Bundle object from the parcel at the current
* dataPosition(). Returns null if the previously written Bundle object was
* null.
@@ -3100,7 +3276,14 @@ public final class Parcel {
* dataPosition(). Returns null if the previously written list object was
* null. The given class loader will be used to load any enclosed
* Parcelables.
+ *
+ * @deprecated Use the type-safer version {@link #readArrayList(ClassLoader, Class)} starting
+ * from Android {@link Build.VERSION_CODES#TIRAMISU}. Also consider changing the format to
+ * use {@link #createTypedArrayList(Parcelable.Creator)} if possible (eg. if the items'
+ * class is final) since this is also more performant. Note that changing to the latter
+ * also requires changing the writes.
*/
+ @Deprecated
@Nullable
public ArrayList readArrayList(@Nullable ClassLoader loader) {
return readArrayListInternal(loader, /* clazz */ null);
@@ -3127,7 +3310,14 @@ public final class Parcel {
* dataPosition(). Returns null if the previously written array was
* null. The given class loader will be used to load any enclosed
* Parcelables.
+ *
+ * @deprecated Use the type-safer version {@link #readArray(ClassLoader, Class)} starting from
+ * Android {@link Build.VERSION_CODES#TIRAMISU}. Also consider changing the format to use
+ * {@link #createTypedArray(Parcelable.Creator)} if possible (eg. if the items' class is
+ * final) since this is also more performant. Note that changing to the latter also
+ * requires changing the writes.
*/
+ @Deprecated
@Nullable
public Object[] readArray(@Nullable ClassLoader loader) {
return readArrayInternal(loader, /* clazz */ null);
@@ -3153,7 +3343,14 @@ public final class Parcel {
* dataPosition(). Returns null if the previously written list object was
* null. The given class loader will be used to load any enclosed
* Parcelables.
+ *
+ * @deprecated Use the type-safer version {@link #readSparseArray(ClassLoader, Class)} starting
+ * from Android {@link Build.VERSION_CODES#TIRAMISU}. Also consider changing the format to
+ * use {@link #createTypedSparseArray(Parcelable.Creator)} if possible (eg. if the items'
+ * class is final) since this is also more performant. Note that changing to the latter
+ * also requires changing the writes.
*/
+ @Deprecated
@Nullable
public <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader) {
return readSparseArrayInternal(loader, /* clazz */ null);
@@ -3367,6 +3564,32 @@ public final class Parcel {
}
/**
+ * Read and return a new ArrayList containing T (IInterface) objects from
+ * the parcel that was written with {@link #writeInterfaceList} at the
+ * current dataPosition(). Returns null if the
+ * previously written list object was null.
+ *
+ * @return A newly created ArrayList containing T (IInterface)
+ *
+ * @see #writeInterfaceList
+ */
+ @SuppressLint({"ConcreteCollection", "NullableCollection"})
+ @Nullable
+ public final <T extends IInterface> ArrayList<T> createInterfaceArrayList(
+ @NonNull Function<IBinder, T> asInterface) {
+ int N = readInt();
+ if (N < 0) {
+ return null;
+ }
+ ArrayList<T> l = new ArrayList<T>(N);
+ while (N > 0) {
+ l.add(asInterface.apply(readStrongBinder()));
+ N--;
+ }
+ return l;
+ }
+
+ /**
* Read into the given List items String objects that were written with
* {@link #writeStringList} at the current dataPosition().
*
@@ -3409,31 +3632,85 @@ public final class Parcel {
}
/**
+ * Read into the given List items IInterface objects that were written with
+ * {@link #writeInterfaceList} at the current dataPosition().
+ *
+ * @see #writeInterfaceList
+ */
+ public final <T extends IInterface> void readInterfaceList(@NonNull List<T> list,
+ @NonNull Function<IBinder, T> asInterface) {
+ int M = list.size();
+ int N = readInt();
+ int i = 0;
+ for (; i < M && i < N; i++) {
+ list.set(i, asInterface.apply(readStrongBinder()));
+ }
+ for (; i<N; i++) {
+ list.add(asInterface.apply(readStrongBinder()));
+ }
+ for (; i<M; i++) {
+ list.remove(N);
+ }
+ }
+
+ /**
* Read the list of {@code Parcelable} objects at the current data position into the
* given {@code list}. The contents of the {@code list} are replaced. If the serialized
* list was {@code null}, {@code list} is cleared.
*
* @see #writeParcelableList(List, int)
+ *
+ * @deprecated Use the type-safer version {@link #readParcelableList(List, ClassLoader, Class)}
+ * starting from Android {@link Build.VERSION_CODES#TIRAMISU}. Also consider changing the
+ * format to use {@link #readTypedList(List, Parcelable.Creator)} if possible (eg. if the
+ * items' class is final) since this is also more performant. Note that changing to the
+ * latter also requires changing the writes.
*/
+ @Deprecated
@NonNull
public final <T extends Parcelable> List<T> readParcelableList(@NonNull List<T> list,
@Nullable ClassLoader cl) {
- final int N = readInt();
- if (N == -1) {
+ return readParcelableListInternal(list, cl, /*clazz*/ null);
+ }
+
+ /**
+ * Same as {@link #readParcelableList(List, ClassLoader)} but accepts {@code clazz} parameter as
+ * the type required for each item.
+ *
+ * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
+ * is not an instance of that class or any of its children classes or there was an error
+ * trying to instantiate an element.
+ */
+ @NonNull
+ public <T> List<T> readParcelableList(@NonNull List<T> list,
+ @Nullable ClassLoader cl, @NonNull Class<T> clazz) {
+ Objects.requireNonNull(list);
+ Objects.requireNonNull(clazz);
+ return readParcelableListInternal(list, cl, clazz);
+ }
+
+ /**
+ * @param clazz The type of the object expected or {@code null} for performing no checks.
+ */
+ @NonNull
+ private <T> List<T> readParcelableListInternal(@NonNull List<T> list,
+ @Nullable ClassLoader cl, @Nullable Class<T> clazz) {
+ final int n = readInt();
+ if (n == -1) {
list.clear();
return list;
}
- final int M = list.size();
+ final int m = list.size();
int i = 0;
- for (; i < M && i < N; i++) {
- list.set(i, (T) readParcelable(cl));
+ for (; i < m && i < n; i++) {
+ list.set(i, (T) readParcelableInternal(cl, clazz));
}
- for (; i<N; i++) {
- list.add((T) readParcelable(cl));
+ for (; i < n; i++) {
+ list.add((T) readParcelableInternal(cl, clazz));
}
- for (; i<M; i++) {
- list.remove(N);
+ for (; i < m; i++) {
+ list.remove(n);
}
return list;
}
@@ -3912,7 +4189,13 @@ public final class Parcel {
* object has been written.
* @throws BadParcelableException Throws BadParcelableException if there
* was an error trying to instantiate the Parcelable.
+ *
+ * @deprecated Use the type-safer version {@link #readParcelable(ClassLoader, Class)} starting
+ * from Android {@link Build.VERSION_CODES#TIRAMISU}. Also consider changing the format to
+ * use {@link Parcelable.Creator#createFromParcel(Parcel)} if possible since this is also
+ * more performant. Note that changing to the latter also requires changing the writes.
*/
+ @Deprecated
@Nullable
public final <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader) {
return readParcelableInternal(loader, /* clazz */ null);
@@ -3981,7 +4264,11 @@ public final class Parcel {
* read the {@link Parcelable.Creator}.
*
* @see #writeParcelableCreator
+ *
+ * @deprecated Use the type-safer version {@link #readParcelableCreator(ClassLoader, Class)}
+ * starting from Android {@link Build.VERSION_CODES#TIRAMISU}.
*/
+ @Deprecated
@Nullable
public final Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader loader) {
return readParcelableCreatorInternal(loader, /* clazz */ null);
@@ -4142,16 +4429,25 @@ public final class Parcel {
* Read and return a new Serializable object from the parcel.
* @return the Serializable object, or null if the Serializable name
* wasn't found in the parcel.
+ *
+ * Unlike {@link #readSerializable(ClassLoader, Class)}, it uses the nearest valid class loader
+ * up the execution stack to instantiate the Serializable object.
+ *
+ * @deprecated Use the type-safer version {@link #readSerializable(ClassLoader, Class)} starting
+ * from Android {@link Build.VERSION_CODES#TIRAMISU}.
*/
+ @Deprecated
@Nullable
public Serializable readSerializable() {
return readSerializableInternal(/* loader */ null, /* clazz */ null);
}
/**
- * Same as {@link #readSerializable()} but accepts {@code loader} parameter
- * as the primary classLoader for resolving the Serializable class; and {@code clazz} parameter
- * as the required type.
+ * Same as {@link #readSerializable()} but accepts {@code loader} and {@code clazz} parameters.
+ *
+ * @param loader A ClassLoader from which to instantiate the Serializable object,
+ * or null for the default class loader.
+ * @param clazz The type of the object expected.
*
* @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
* is not an instance of that class or any of its children class or there there was an error
@@ -4161,7 +4457,8 @@ public final class Parcel {
public <T extends Serializable> T readSerializable(@Nullable ClassLoader loader,
@NonNull Class<T> clazz) {
Objects.requireNonNull(clazz);
- return readSerializableInternal(loader, clazz);
+ return readSerializableInternal(
+ loader == null ? getClass().getClassLoader() : loader, clazz);
}
/**
@@ -4315,13 +4612,23 @@ public final class Parcel {
destroy();
}
- /* package */ void readMapInternal(@NonNull Map outVal, int N,
+ /**
+ * To be replaced by {@link #readMapInternal(Map, int, ClassLoader, Class, Class)}, but keep
+ * the old API for compatibility usages.
+ */
+ /* package */ void readMapInternal(@NonNull Map outVal, int n,
@Nullable ClassLoader loader) {
- while (N > 0) {
- Object key = readValue(loader);
- Object value = readValue(loader);
+ readMapInternal(outVal, n, loader, /* clazzKey */null, /* clazzValue */null);
+ }
+
+ /* package */ <K, V> void readMapInternal(@NonNull Map<? super K, ? super V> outVal, int n,
+ @Nullable ClassLoader loader, @Nullable Class<K> clazzKey,
+ @Nullable Class<V> clazzValue) {
+ while (n > 0) {
+ K key = readValue(loader, clazzKey);
+ V value = readValue(loader, clazzValue);
outVal.put(key, value);
- N--;
+ n--;
}
}
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index 7b55e710caeb..f4edcb1317f4 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -156,10 +156,15 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
}
/**
- * Constructs a PersistableBundle without initializing it.
+ * Constructs a {@link PersistableBundle} containing a copy of {@code from}.
+ *
+ * @param from The bundle to be copied.
+ * @param deep Whether is a deep or shallow copy.
+ *
+ * @hide
*/
- PersistableBundle(boolean doInit) {
- super(doInit);
+ PersistableBundle(PersistableBundle from, boolean deep) {
+ super(from, deep);
}
/**
@@ -190,9 +195,7 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
* are referenced as-is and not copied in any way.
*/
public PersistableBundle deepCopy() {
- PersistableBundle b = new PersistableBundle(false);
- b.copyInternal(this, true);
- return b;
+ return new PersistableBundle(this, /* deep */ true);
}
/**
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 4e8418bd60ec..ba5ed4360cd7 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -298,6 +298,17 @@ public final class ServiceManager {
}
/**
+ * Register callback for service registration notifications.
+ *
+ * @throws RemoteException for underlying error.
+ * @hide
+ */
+ public static void registerForNotifications(
+ @NonNull String name, @NonNull IServiceCallback callback) throws RemoteException {
+ getIServiceManager().registerForNotifications(name, callback);
+ }
+
+ /**
* Return a list of all currently running services.
* @return an array of all currently running services, or <code>null</code> in
* case of an exception
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index 3739040eef60..2dcf67483203 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -78,7 +78,7 @@ class ServiceManagerProxy implements IServiceManager {
public void registerForNotifications(String name, IServiceCallback cb)
throws RemoteException {
- throw new RemoteException();
+ mServiceManager.registerForNotifications(name, cb);
}
public void unregisterForNotifications(String name, IServiceCallback cb)
diff --git a/core/java/android/os/StatsBootstrapAtom.aidl b/core/java/android/os/StatsBootstrapAtom.aidl
new file mode 100644
index 000000000000..47500af8eebf
--- /dev/null
+++ b/core/java/android/os/StatsBootstrapAtom.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright 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.os;
+
+import android.os.StatsBootstrapAtomValue;
+
+/*
+ * Generic encapsulation of an atom for bootstrap processes to log.
+ *
+ * @hide
+ */
+parcelable StatsBootstrapAtom {
+ /*
+ * Atom ID. Must be between 1 - 10,000.
+ */
+ int atomId;
+ /*
+ * Vector of fields in the order of the atom definition.
+ */
+ StatsBootstrapAtomValue[] values;
+ } \ No newline at end of file
diff --git a/core/java/android/os/StatsBootstrapAtomValue.aidl b/core/java/android/os/StatsBootstrapAtomValue.aidl
new file mode 100644
index 000000000000..a90dfa404ee9
--- /dev/null
+++ b/core/java/android/os/StatsBootstrapAtomValue.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 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.os;
+/*
+ * Supported field types.
+ *
+ * @hide
+ */
+union StatsBootstrapAtomValue {
+ boolean boolValue;
+ int intValue;
+ long longValue;
+ float floatValue;
+ String stringValue;
+ byte[] bytesValue;
+} \ No newline at end of file
diff --git a/core/java/android/os/SystemConfigManager.java b/core/java/android/os/SystemConfigManager.java
index a6316df0780c..cde2063fdba5 100644
--- a/core/java/android/os/SystemConfigManager.java
+++ b/core/java/android/os/SystemConfigManager.java
@@ -17,10 +17,10 @@ package android.os;
import android.Manifest;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.content.ComponentName;
import android.content.Context;
import android.util.ArraySet;
import android.util.Log;
@@ -138,9 +138,9 @@ public class SystemConfigManager {
* @return The enabled component
* {@hide}
*/
- @SystemApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@NonNull
- public List<String> getEnabledComponentOverrides(@NonNull String packageName) {
+ public List<ComponentName> getEnabledComponentOverrides(@NonNull String packageName) {
try {
return mInterface.getEnabledComponentOverrides(packageName);
} catch (RemoteException e) {
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index 3e01c53f0469..b7e3068a437c 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -238,7 +238,7 @@ public class UpdateEngine {
public static final int DISABLED = 9;
}
- private IUpdateEngine mUpdateEngine;
+ private final IUpdateEngine mUpdateEngine;
private IUpdateEngineCallback mUpdateEngineCallback = null;
private final Object mUpdateEngineCallbackLock = new Object();
@@ -248,6 +248,9 @@ public class UpdateEngine {
public UpdateEngine() {
mUpdateEngine = IUpdateEngine.Stub.asInterface(
ServiceManager.getService(UPDATE_ENGINE_SERVICE));
+ if (mUpdateEngine == null) {
+ throw new IllegalStateException("Failed to find update_engine");
+ }
}
/**
diff --git a/core/java/android/os/health/HealthStats.java b/core/java/android/os/health/HealthStats.java
index 74ce5157a548..6c648f136183 100644
--- a/core/java/android/os/health/HealthStats.java
+++ b/core/java/android/os/health/HealthStats.java
@@ -32,7 +32,7 @@ import java.util.Map;
* Each of the keys references data in one of five data types:
*
* <p>
- * A <b>measurement</b> metric contains a sinlge {@code long} value. That value may
+ * A <b>measurement</b> metric contains a single {@code long} value. That value may
* be a count, a time, or some other type of value. The unit for a measurement
* (COUNT, MS, etc) will always be in the name of the constant for the key to
* retrieve it. For example, the
diff --git a/core/java/android/os/health/UidHealthStats.java b/core/java/android/os/health/UidHealthStats.java
index afc9d78dcbd1..488a5422becc 100644
--- a/core/java/android/os/health/UidHealthStats.java
+++ b/core/java/android/os/health/UidHealthStats.java
@@ -43,14 +43,14 @@ public final class UidHealthStats {
/**
* How many milliseconds this statistics report covers in wall-clock time while the
- * device was on battery including both screen-on and screen-off time.
+ * device was on battery including only screen-off time.
*/
@HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
public static final int MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS = HealthKeys.BASE_UID + 3;
/**
* How many milliseconds this statistics report covers that the CPU was running while the
- * device was on battery including both screen-on and screen-off time.
+ * device was on battery including only screen-off time.
*/
@HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
public static final int MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS = HealthKeys.BASE_UID + 4;
@@ -65,7 +65,7 @@ public final class UidHealthStats {
/**
* Key for a TimerStat for the times a
- * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK full wake lock}
+ * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK partial wake lock}
* was acquired for this uid.
*/
@HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS)
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index f57d1574d399..39a2e1353237 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -56,11 +56,12 @@ import java.util.UUID;
* <ul>
* <li>{@link #MOUNT_FLAG_PRIMARY} means the volume provides primary external
* storage, historically found at {@code /sdcard}.
- * <li>{@link #MOUNT_FLAG_VISIBLE} means the volume is visible to third-party
- * apps for direct filesystem access. The system should send out relevant
- * storage broadcasts and index any media on visible volumes. Visible volumes
- * are considered a more stable part of the device, which is why we take the
- * time to index them. In particular, transient volumes like USB OTG devices
+ * <li>{@link #MOUNT_FLAG_VISIBLE_FOR_READ} and
+ * {@link #MOUNT_FLAG_VISIBLE_FOR_WRITE} mean the volume is visible to
+ * third-party apps for direct filesystem access. The system should send out
+ * relevant storage broadcasts and index any media on visible volumes. Visible
+ * volumes are considered a more stable part of the device, which is why we take
+ * the time to index them. In particular, transient volumes like USB OTG devices
* <em>should not</em> be marked as visible; their contents should be surfaced
* to apps through the Storage Access Framework.
* </ul>
@@ -100,7 +101,8 @@ public class VolumeInfo implements Parcelable {
public static final int STATE_BAD_REMOVAL = IVold.VOLUME_STATE_BAD_REMOVAL;
public static final int MOUNT_FLAG_PRIMARY = IVold.MOUNT_FLAG_PRIMARY;
- public static final int MOUNT_FLAG_VISIBLE = IVold.MOUNT_FLAG_VISIBLE;
+ public static final int MOUNT_FLAG_VISIBLE_FOR_READ = IVold.MOUNT_FLAG_VISIBLE_FOR_READ;
+ public static final int MOUNT_FLAG_VISIBLE_FOR_WRITE = IVold.MOUNT_FLAG_VISIBLE_FOR_WRITE;
private static SparseArray<String> sStateToEnvironment = new SparseArray<>();
private static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>();
@@ -312,17 +314,31 @@ public class VolumeInfo implements Parcelable {
return isPrimary() && (getType() == TYPE_PUBLIC);
}
+ private boolean isVisibleForRead() {
+ return (mountFlags & MOUNT_FLAG_VISIBLE_FOR_READ) != 0;
+ }
+
+ private boolean isVisibleForWrite() {
+ return (mountFlags & MOUNT_FLAG_VISIBLE_FOR_WRITE) != 0;
+ }
+
@UnsupportedAppUsage
public boolean isVisible() {
- return (mountFlags & MOUNT_FLAG_VISIBLE) != 0;
+ return isVisibleForRead() || isVisibleForWrite();
}
- public boolean isVisibleForUser(int userId) {
- if ((type == TYPE_PUBLIC || type == TYPE_STUB || type == TYPE_EMULATED)
- && mountUserId == userId) {
- return isVisible();
+ private boolean isVolumeSupportedForUser(int userId) {
+ if (mountUserId != userId) {
+ return false;
}
- return false;
+ return type == TYPE_PUBLIC || type == TYPE_STUB || type == TYPE_EMULATED;
+ }
+
+ /**
+ * Returns {@code true} if this volume is visible for {@code userId}, {@code false} otherwise.
+ */
+ public boolean isVisibleForUser(int userId) {
+ return isVolumeSupportedForUser(userId) && isVisible();
}
/**
@@ -335,12 +351,12 @@ public class VolumeInfo implements Parcelable {
}
public boolean isVisibleForRead(int userId) {
- return isVisibleForUser(userId);
+ return isVolumeSupportedForUser(userId) && isVisibleForRead();
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isVisibleForWrite(int userId) {
- return isVisibleForUser(userId);
+ return isVolumeSupportedForUser(userId) && isVisibleForWrite();
}
@UnsupportedAppUsage
diff --git a/core/java/android/os/vibrator/OWNERS b/core/java/android/os/vibrator/OWNERS
new file mode 100644
index 000000000000..b54d6bf07818
--- /dev/null
+++ b/core/java/android/os/vibrator/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS \ No newline at end of file
diff --git a/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS b/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS
new file mode 100644
index 000000000000..cb521c842816
--- /dev/null
+++ b/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS
@@ -0,0 +1,8 @@
+ewol@google.com
+hackbod@google.com
+jsharkey@google.com
+narayan@google.com
+patb@google.com
+svetoslavganov@google.com
+yamasani@google.com
+zhanghai@google.com
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 8ac5c0397734..6644f1e91f1d 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -622,6 +622,14 @@ public final class DeviceConfig {
public static final String NAMESPACE_GAME_OVERLAY = "game_overlay";
/**
+ * Namespace for Android Virtualization Framework related features accessible by native code.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_VIRTUALIZATION_FRAMEWORK_NATIVE =
+ "virtualization_framework_native";
+
+ /**
* Namespace for Constrain Display APIs related features.
*
* @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ac520e8b3dec..84be74669f11 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11218,22 +11218,38 @@ public final class Settings {
"night_display_forced_auto_mode_available";
/**
- * If the NITZ_UPDATE_DIFF time is exceeded then an automatic adjustment
- * to SystemClock will be allowed even if NITZ_UPDATE_SPACING has not been
- * exceeded.
- * @hide
- */
+ * If UTC time between two NITZ signals is greater than this value then the second signal
+ * cannot be ignored.
+ *
+ * <p>This value is in milliseconds. It is used for telephony-based time and time zone
+ * detection.
+ * @hide
+ */
@Readable
public static final String NITZ_UPDATE_DIFF = "nitz_update_diff";
/**
- * The length of time in milli-seconds that automatic small adjustments to
- * SystemClock are ignored if NITZ_UPDATE_DIFF is not exceeded.
- * @hide
- */
+ * If the elapsed realtime between two NITZ signals is greater than this value then the
+ * second signal cannot be ignored.
+ *
+ * <p>This value is in milliseconds. It is used for telephony-based time and time zone
+ * detection.
+ * @hide
+ */
@Readable
public static final String NITZ_UPDATE_SPACING = "nitz_update_spacing";
+ /**
+ * If the device connects to a telephony network and was disconnected from a telephony
+ * network for less than this time, a previously received NITZ signal can be restored.
+ *
+ * <p>This value is in milliseconds. It is used for telephony-based time and time zone
+ * detection.
+ * @hide
+ */
+ public static final String NITZ_NETWORK_DISCONNECT_RETENTION =
+ "nitz_network_disconnect_retention";
+
/** Preferred NTP server. {@hide} */
@Readable
public static final String NTP_SERVER = "ntp_server";
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index f3a8b5d79ea0..9f3a847e12eb 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -5365,5 +5365,14 @@ public final class Telephony {
*/
public static final String COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS =
"d2d_sharing_contacts";
+
+ /**
+ * TelephonyProvider column name for NR Advanced calling
+ * Determines if the user has enabled VoNR settings for this subscription.
+ *
+ * @hide
+ */
+ public static final String COLUMN_NR_ADVANCED_CALLING_ENABLED =
+ "nr_advanced_calling_enabled";
}
}
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index d39b56ddabed..5b9d69c2f9ff 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -191,20 +191,6 @@ public class PhoneStateListener {
public static final int LISTEN_SIGNAL_STRENGTHS = 0x00000100;
/**
- * Listen 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 #onSignalStrengthsChanged
- *
- * @hide
- * @deprecated Use TelephonyManager#setSignalStrengthUpdateRequest
- * instead.
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
- public static final int LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH = 0x00000200;
-
- /**
* Listen for changes to observed cell info.
*
* Listening to this event requires the {@link Manifest.permission#READ_PHONE_STATE} and
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index bedad7344e9d..cb1cff9cda22 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -1041,10 +1041,6 @@ public class TelephonyRegistryManager {
eventList.add(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED);
}
- if ((eventMask & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
- eventList.add(TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED);
- }
-
if ((eventMask & PhoneStateListener.LISTEN_CELL_INFO) != 0) {
eventList.add(TelephonyCallback.EVENT_CELL_INFO_CHANGED);
}
diff --git a/core/java/android/util/BackupUtils.java b/core/java/android/util/BackupUtils.java
index 474cedaa0552..4fcb13c2bcf6 100644
--- a/core/java/android/util/BackupUtils.java
+++ b/core/java/android/util/BackupUtils.java
@@ -37,6 +37,10 @@ public class BackupUtils {
public BadVersionException(String message) {
super(message);
}
+
+ public BadVersionException(String message, Throwable throwable) {
+ super(message, throwable);
+ }
}
public static String readString(DataInputStream in) throws IOException {
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 12bcd8b0aa97..b5fe4f58dfb2 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -62,6 +62,10 @@ import java.net.UnknownHostException;
* another buffer allocation and copy, and even more pressure on the gc.
* That means that if your log message is filtered out, you might be doing
* significant work and incurring significant overhead.
+ *
+ * <p>When calling the log methods that take a Throwable parameter,
+ * if any of the throwables in the cause chain is an <code>UnknownHostException</code>,
+ * then the stack trace is not logged.
*/
public final class Log {
/** @hide */
@@ -341,6 +345,9 @@ public final class Log {
/**
* Handy function to get a loggable stack trace from a Throwable
+
+ * <p>If any of the throwables in the cause chain is an <code>UnknownHostException</code>,
+ * this returns an empty string.
* @param tr An exception to log
*/
@NonNull
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index cda9b233576c..ba6f4eb7e598 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -830,13 +830,45 @@ public class KeyEvent extends InputEvent implements Parcelable {
* consuming content. May be consumed by system to set account globally.
*/
public static final int KEYCODE_PROFILE_SWITCH = 288;
-
- /**
+ /** Key code constant: Video Application key #1. */
+ public static final int KEYCODE_VIDEO_APP_1 = 289;
+ /** Key code constant: Video Application key #2. */
+ public static final int KEYCODE_VIDEO_APP_2 = 290;
+ /** Key code constant: Video Application key #3. */
+ public static final int KEYCODE_VIDEO_APP_3 = 291;
+ /** Key code constant: Video Application key #4. */
+ public static final int KEYCODE_VIDEO_APP_4 = 292;
+ /** Key code constant: Video Application key #5. */
+ public static final int KEYCODE_VIDEO_APP_5 = 293;
+ /** Key code constant: Video Application key #6. */
+ public static final int KEYCODE_VIDEO_APP_6 = 294;
+ /** Key code constant: Video Application key #7. */
+ public static final int KEYCODE_VIDEO_APP_7 = 295;
+ /** Key code constant: Video Application key #8. */
+ public static final int KEYCODE_VIDEO_APP_8 = 296;
+ /** Key code constant: Featured Application key #1. */
+ public static final int KEYCODE_FEATURED_APP_1 = 297;
+ /** Key code constant: Featured Application key #2. */
+ public static final int KEYCODE_FEATURED_APP_2 = 298;
+ /** Key code constant: Featured Application key #3. */
+ public static final int KEYCODE_FEATURED_APP_3 = 299;
+ /** Key code constant: Featured Application key #4. */
+ public static final int KEYCODE_FEATURED_APP_4 = 300;
+ /** Key code constant: Demo Application key #1. */
+ public static final int KEYCODE_DEMO_APP_1 = 301;
+ /** Key code constant: Demo Application key #2. */
+ public static final int KEYCODE_DEMO_APP_2 = 302;
+ /** Key code constant: Demo Application key #3. */
+ public static final int KEYCODE_DEMO_APP_3 = 303;
+ /** Key code constant: Demo Application key #4. */
+ public static final int KEYCODE_DEMO_APP_4 = 304;
+
+ /**
* Integer value of the last KEYCODE. Increases as new keycodes are added to KeyEvent.
* @hide
*/
@TestApi
- public static final int LAST_KEYCODE = KEYCODE_PROFILE_SWITCH;
+ public static final int LAST_KEYCODE = KEYCODE_DEMO_APP_4;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 8143cf953f19..ffce4617eec6 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -157,6 +157,7 @@ public final class SurfaceControl implements Parcelable {
private static native boolean nativeGetAnimationFrameStats(WindowAnimationFrameStats outStats);
private static native long[] nativeGetPhysicalDisplayIds();
+ private static native long nativeGetPrimaryPhysicalDisplayId();
private static native IBinder nativeGetPhysicalDisplayToken(long physicalDisplayId);
private static native IBinder nativeCreateDisplay(String name, boolean secure);
private static native void nativeDestroyDisplay(IBinder displayToken);
@@ -2266,6 +2267,15 @@ public final class SurfaceControl implements Parcelable {
}
/**
+ * Exposed to identify the correct display to apply the primary display orientation. Avoid using
+ * for any other purpose.
+ * @hide
+ */
+ public static long getPrimaryPhysicalDisplayId() {
+ return nativeGetPrimaryPhysicalDisplayId();
+ }
+
+ /**
* @hide
*/
public static IBinder getPhysicalDisplayToken(long physicalDisplayId) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3550a31f9038..2257f6cd2159 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -8448,13 +8448,13 @@ public final class ViewRootImpl implements ViewParent,
MotionEvent me = (MotionEvent) event;
if (me.getAction() == MotionEvent.ACTION_CANCEL) {
EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Motion - Cancel",
- getTitle());
+ getTitle().toString());
}
} else if (event instanceof KeyEvent) {
KeyEvent ke = (KeyEvent) event;
if (ke.isCanceled()) {
EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Key - Cancel",
- getTitle());
+ getTitle().toString());
}
}
// Always enqueue the input event in order, regardless of its time stamp.
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 55beae0f7b3d..00f4eb83bdaa 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -127,17 +127,15 @@ import java.util.function.Consumer;
/**
* The interface that apps use to talk to the window manager.
- * </p><p>
- * Each window manager instance is bound to a particular {@link Display}.
- * To obtain a {@link WindowManager} for a different display, use
- * {@link Context#createDisplayContext} to obtain a {@link Context} for that
- * display, then use <code>Context.getSystemService(Context.WINDOW_SERVICE)</code>
- * to get the WindowManager.
- * </p><p>
- * The simplest way to show a window on another display is to create a
- * {@link Presentation}. The presentation will automatically obtain a
- * {@link WindowManager} and {@link Context} for that display.
- * </p>
+ * <p>
+ * Each window manager instance is bound to a {@link Display}. To obtain the
+ * <code>WindowManager</code> associated with a display,
+ * call {@link Context#createWindowContext(Display, int, Bundle)} to get the display's UI context,
+ * then call {@link Context#getSystemService(String)} or {@link Context#getSystemService(Class)} on
+ * the UI context.
+ * <p>
+ * The simplest way to show a window on a particular display is to create a {@link Presentation},
+ * which automatically obtains a <code>WindowManager</code> and context for the display.
*/
@SystemService(Context.WINDOW_SERVICE)
public interface WindowManager extends ViewManager {
diff --git a/core/java/com/android/internal/compat/OWNERS b/core/java/com/android/internal/compat/OWNERS
index cfd0a4b079ad..ee3086ab2fdb 100644
--- a/core/java/com/android/internal/compat/OWNERS
+++ b/core/java/com/android/internal/compat/OWNERS
@@ -1,6 +1 @@
-# Use this reviewer by default.
-platform-compat-eng+reviews@google.com
-
-andreionea@google.com
-mathewi@google.com
-satayev@google.com
+include tools/platform-compat:/OWNERS
diff --git a/core/java/com/android/internal/net/OWNERS b/core/java/com/android/internal/net/OWNERS
index 050cb5c2b44e..71f997bb57c5 100644
--- a/core/java/com/android/internal/net/OWNERS
+++ b/core/java/com/android/internal/net/OWNERS
@@ -1,9 +1,4 @@
set noparent
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
-codewiz@google.com
-ek@google.com
-jchalard@google.com
jsharkey@android.com
-lorenzo@google.com
-reminv@google.com
-satk@google.com
diff --git a/core/java/com/android/internal/os/ClassLoaderFactory.java b/core/java/com/android/internal/os/ClassLoaderFactory.java
index 8b0411de5477..8f5e97d40530 100644
--- a/core/java/com/android/internal/os/ClassLoaderFactory.java
+++ b/core/java/com/android/internal/os/ClassLoaderFactory.java
@@ -24,6 +24,7 @@ import dalvik.system.DelegateLastClassLoader;
import dalvik.system.DexClassLoader;
import dalvik.system.PathClassLoader;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -100,14 +101,25 @@ public class ClassLoaderFactory {
}
/**
- * Same as {@code createClassLoader} below, but passes a null list of shared
- * libraries.
+ * Same as {@code createClassLoader} below, but passes a null list of shared libraries. This
+ * method is used only to load platform classes (i.e. those in framework.jar or services.jar),
+ * and MUST NOT be used for loading untrusted classes, especially the app classes. For the
+ * latter case, use the below method which accepts list of shared libraries so that the classes
+ * don't have unlimited access to all shared libraries.
*/
public static ClassLoader createClassLoader(String dexPath,
String librarySearchPath, String libraryPermittedPath, ClassLoader parent,
int targetSdkVersion, boolean isNamespaceShared, String classLoaderName) {
+ // b/205164833: allow framework classes to have access to all public vendor libraries.
+ // This is because those classes are part of the platform and don't have an app manifest
+ // where required libraries can be specified using the <uses-native-library> tag.
+ // Note that this still does not give access to "private" vendor libraries.
+ List<String> nativeSharedLibraries = new ArrayList<>();
+ nativeSharedLibraries.add("ALL");
+
return createClassLoader(dexPath, librarySearchPath, libraryPermittedPath,
- parent, targetSdkVersion, isNamespaceShared, classLoaderName, null, null, null);
+ parent, targetSdkVersion, isNamespaceShared, classLoaderName, null,
+ nativeSharedLibraries, null);
}
/**
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 92d5a47a2ed0..6d4b8c5ea1ad 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -724,9 +724,6 @@ public final class Zygote {
DataOutputStream usapOutputStream = null;
ZygoteArguments args = null;
- // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool.
- blockSigTerm();
-
LocalSocket sessionSocket = null;
if (argBuffer == null) {
// Read arguments from usapPoolSocket instead.
@@ -742,6 +739,10 @@ public final class Zygote {
ZygoteCommandBuffer tmpArgBuffer = null;
try {
sessionSocket = usapPoolSocket.accept();
+ // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool.
+ // This is safe from a race condition because the pool is only flushed after
+ // the SystemServer changes its internal state to stop using the USAP pool.
+ blockSigTerm();
usapOutputStream =
new DataOutputStream(sessionSocket.getOutputStream());
@@ -759,9 +760,10 @@ public final class Zygote {
unblockSigTerm();
IoUtils.closeQuietly(sessionSocket);
IoUtils.closeQuietly(tmpArgBuffer);
- blockSigTerm();
}
} else {
+ // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool.
+ blockSigTerm();
try {
args = ZygoteArguments.getInstance(argBuffer);
} catch (Exception ex) {
diff --git a/core/java/com/android/internal/view/OWNERS b/core/java/com/android/internal/view/OWNERS
index eb2478f6550a..7a590d0ed079 100644
--- a/core/java/com/android/internal/view/OWNERS
+++ b/core/java/com/android/internal/view/OWNERS
@@ -15,7 +15,7 @@ per-file *Surface* = file:/services/core/java/com/android/server/wm/OWNERS
# WindowManager
per-file AppearanceRegion = file:/services/core/java/com/android/server/wm/OWNERS
-per-file BaseIWIndow.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file BaseIWindow.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file RotationPolicy.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file WindowManagerPolicyThread.java = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/com/android/server/NetworkManagementSocketTagger.java b/core/java/com/android/server/NetworkManagementSocketTagger.java
index 2959667e046f..26ff192521da 100644
--- a/core/java/com/android/server/NetworkManagementSocketTagger.java
+++ b/core/java/com/android/server/NetworkManagementSocketTagger.java
@@ -17,7 +17,6 @@
package com.android.server;
import android.os.StrictMode;
-import android.os.SystemProperties;
import android.util.Log;
import android.util.Slog;
@@ -33,13 +32,6 @@ public final class NetworkManagementSocketTagger extends SocketTagger {
private static final String TAG = "NetworkManagementSocketTagger";
private static final boolean LOGD = false;
- /**
- * {@link SystemProperties} key that indicates if {@code qtaguid} bandwidth
- * controls have been enabled.
- */
- // TODO: remove when always enabled, or once socket tagging silently fails.
- public static final String PROP_QTAGUID_ENABLED = "net.qtaguid_enabled";
-
private static ThreadLocal<SocketTags> threadSocketTags = new ThreadLocal<SocketTags>() {
@Override
protected SocketTags initialValue() {
@@ -88,13 +80,11 @@ public final class NetworkManagementSocketTagger extends SocketTagger {
private void tagSocketFd(FileDescriptor fd, int tag, int uid) {
if (tag == -1 && uid == -1) return;
- if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
- final int errno = native_tagSocketFd(fd, tag, uid);
- if (errno < 0) {
- Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", "
- + tag + ", " +
- + uid + ") failed with errno" + errno);
- }
+ final int errno = native_tagSocketFd(fd, tag, uid);
+ if (errno < 0) {
+ Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", "
+ + tag + ", "
+ + uid + ") failed with errno" + errno);
}
}
@@ -110,11 +100,9 @@ public final class NetworkManagementSocketTagger extends SocketTagger {
final SocketTags options = threadSocketTags.get();
if (options.statsTag == -1 && options.statsUid == -1) return;
- if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
- final int errno = native_untagSocketFd(fd);
- if (errno < 0) {
- Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno);
- }
+ final int errno = native_untagSocketFd(fd);
+ if (errno < 0) {
+ Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno);
}
}
@@ -124,21 +112,17 @@ public final class NetworkManagementSocketTagger extends SocketTagger {
}
public static void setKernelCounterSet(int uid, int counterSet) {
- if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
- final int errno = native_setCounterSet(counterSet, uid);
- if (errno < 0) {
- Log.w(TAG, "setKernelCountSet(" + uid + ", " + counterSet + ") failed with errno "
- + errno);
- }
+ final int errno = native_setCounterSet(counterSet, uid);
+ if (errno < 0) {
+ Log.w(TAG, "setKernelCountSet(" + uid + ", " + counterSet + ") failed with errno "
+ + errno);
}
}
public static void resetKernelUidStats(int uid) {
- if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
- int errno = native_deleteTagData(0, uid);
- if (errno < 0) {
- Slog.w(TAG, "problem clearing counters for uid " + uid + " : errno " + errno);
- }
+ int errno = native_deleteTagData(0, uid);
+ if (errno < 0) {
+ Slog.w(TAG, "problem clearing counters for uid " + uid + " : errno " + errno);
}
}
diff --git a/core/java/com/android/server/net/OWNERS b/core/java/com/android/server/net/OWNERS
index d3836d4c6c57..62c5737a2e8e 100644
--- a/core/java/com/android/server/net/OWNERS
+++ b/core/java/com/android/server/net/OWNERS
@@ -1,8 +1,2 @@
set noparent
-
-codewiz@google.com
-jchalard@google.com
-junyulai@google.com
-lorenzo@google.com
-reminv@google.com
-satk@google.com
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 937fa8101def..2cfec4b17f63 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -391,7 +391,6 @@ cc_library_headers {
name: "libandroid_runtime_vm_headers",
host_supported: true,
vendor_available: true,
- recovery_available: true,
// TODO(b/153609531): remove when libbinder is not native_bridge_supported
native_bridge_supported: true,
// Allow only modules from the following list to create threads that can be
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 97cac291630c..a13111143b0e 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -746,8 +746,9 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p
}
const bool checkJni = GetBoolProperty("dalvik.vm.checkjni", false);
- ALOGV("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
if (checkJni) {
+ ALOGD("CheckJNI is ON");
+
/* extended JNI checking */
addOption("-Xcheck:jni");
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 78787e52dbaa..65d073fc1467 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -69,6 +69,9 @@ per-file AndroidRuntime.cpp = calin@google.com, ngeoffray@google.com, oth@google
# Although marked "view" this is mostly graphics stuff
per-file android_view_* = file:/graphics/java/android/graphics/OWNERS
+# Verity
+per-file com_android_internal_security_Verity* = ebiggers@google.com, victorhsieh@google.com
+
# VINTF
per-file android_os_VintfObject* = file:platform/system/libvintf:/OWNERS
per-file android_os_VintfRuntimeInfo* = file:platform/system/libvintf:/OWNERS
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 4c2b114c724a..5e0d9b32380c 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -34,6 +34,7 @@
#include <vector>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <bionic/malloc.h>
#include <debuggerd/client.h>
#include <log/log.h>
@@ -859,7 +860,22 @@ static jlong android_os_Debug_getDmabufHeapPoolsSizeKb(JNIEnv* env, jobject claz
return poolsSizeKb;
}
+static bool halSupportsGpuPrivateMemory() {
+ int productApiLevel =
+ android::base::GetIntProperty("ro.product.first_api_level",
+ android::base::GetIntProperty("ro.build.version.sdk",
+ __ANDROID_API_FUTURE__));
+ int boardApiLevel =
+ android::base::GetIntProperty("ro.board.api_level",
+ android::base::GetIntProperty("ro.board.first_api_level",
+ __ANDROID_API_FUTURE__));
+
+ return std::min(productApiLevel, boardApiLevel) >= __ANDROID_API_S__;
+}
+
static jlong android_os_Debug_getGpuPrivateMemoryKb(JNIEnv* env, jobject clazz) {
+ static bool gpuPrivateMemorySupported = halSupportsGpuPrivateMemory();
+
struct memtrack_proc* p = memtrack_proc_new();
if (p == nullptr) {
LOG(ERROR) << "getGpuPrivateMemoryKb: Failed to create memtrack_proc";
@@ -876,6 +892,12 @@ static jlong android_os_Debug_getGpuPrivateMemoryKb(JNIEnv* env, jobject clazz)
ssize_t gpuPrivateMem = memtrack_proc_gl_pss(p);
memtrack_proc_destroy(p);
+
+ // Old HAL implementations may return 0 for GPU private memory if not supported
+ if (gpuPrivateMem == 0 && !gpuPrivateMemorySupported) {
+ return -1;
+ }
+
return gpuPrivateMem / 1024;
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 8d12df226ffe..e47718305b7c 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -889,6 +889,12 @@ static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
return array;
}
+static jlong nativeGetPrimaryPhysicalDisplayId(JNIEnv* env, jclass clazz) {
+ PhysicalDisplayId displayId;
+ SurfaceComposerClient::getPrimaryPhysicalDisplayId(&displayId);
+ return static_cast<jlong>(displayId.value);
+}
+
static jobject nativeGetPhysicalDisplayToken(JNIEnv* env, jclass clazz, jlong physicalDisplayId) {
sp<IBinder> token =
SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId(physicalDisplayId));
@@ -1879,6 +1885,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeReleaseFrameRateFlexibilityToken },
{"nativeGetPhysicalDisplayIds", "()[J",
(void*)nativeGetPhysicalDisplayIds },
+ {"nativeGetPrimaryPhysicalDisplayId", "()J",
+ (void*)nativeGetPrimaryPhysicalDisplayId },
{"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;",
(void*)nativeGetPhysicalDisplayToken },
{"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index be82879c8411..ef6fd7dd6829 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -36,6 +36,7 @@
#include <inttypes.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <linux/fs.h>
#include <memory>
@@ -253,6 +254,16 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr
return INSTALL_FAILED_CONTAINER_ERROR;
}
+ // If a filesystem like f2fs supports per-file compression, set the compression bit before data
+ // writes
+ unsigned int flags;
+ if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1) {
+ ALOGE("Failed to call FS_IOC_GETFLAGS on %s: %s\n", localTmpFileName, strerror(errno));
+ } else if ((flags & FS_COMPR_FL) == 0) {
+ flags |= FS_COMPR_FL;
+ ioctl(fd, FS_IOC_SETFLAGS, &flags);
+ }
+
if (!zipFile->uncompressEntry(zipEntry, fd)) {
ALOGE("Failed uncompressing %s to %s\n", fileName, localTmpFileName);
close(fd);
diff --git a/core/proto/android/app/OWNERS b/core/proto/android/app/OWNERS
index cc479e61b855..4d76aee9d722 100644
--- a/core/proto/android/app/OWNERS
+++ b/core/proto/android/app/OWNERS
@@ -1 +1,2 @@
-per-file location_time_zone_manager.proto, time_zone_detector.proto = nfuller@google.com, mingaleev@google.com
+per-file location_time_zone_manager.proto = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
+per-file time_zone_detector.proto = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index c3d159659622..ed3968ae9b78 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -672,18 +672,31 @@ message GlobalSettingsProto {
optional SettingProto new_contact_aggregator = 79 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto night_display_forced_auto_mode_available = 80 [ (android.privacy).dest = DEST_AUTOMATIC ];
- message NitzUpdate {
- option (android.msg_privacy).dest = DEST_EXPLICIT;
-
- // If the NITZ_UPDATE_DIFF time is exceeded then an automatic adjustment to
- // SystemClock will be allowed even if NITZ_UPDATE_SPACING has not been
- // exceeded.
- optional SettingProto diff = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
- // The length of time in milli-seconds that automatic small adjustments to
- // SystemClock are ignored if NITZ_UPDATE_DIFF is not exceeded.
- optional SettingProto spacing = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
- }
- optional NitzUpdate nitz_update = 81;
+ message Nitz {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ // If UTC time between two NITZ signals is greater than this value then the second signal
+ // cannot be ignored.
+ //
+ // This value is in milliseconds. It is used for telephony-based time and time zone
+ // detection.
+ optional SettingProto update_diff = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+ // If the elapsed realtime between two NITZ signals is greater than this value then the
+ // second signal cannot be ignored.
+ //
+ // This value is in milliseconds. It is used for telephony-based time and time zone
+ // detection.
+ optional SettingProto update_spacing = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+ // If the device connects to a telephony network and was disconnected from a telephony
+ // network for less than this time, a previously received NITZ signal can be restored.
+ //
+ // This value is in milliseconds. It is used for telephony-based time and time zone
+ // detection.
+ optional SettingProto network_disconnect_retention = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional Nitz nitz = 81;
message Notification {
option (android.msg_privacy).dest = DEST_EXPLICIT;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index fa1e9d4afcdf..a62ddd084aab 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -351,6 +351,7 @@ message ActivityRecordProto {
optional bool translucent = 30;
optional bool pip_auto_enter_enabled = 31;
optional bool in_size_compat_mode = 32;
+ optional float min_aspect_ratio = 33;
}
/* represents WindowToken */
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1418dbe0f849..1a38ea10a97d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -252,6 +252,11 @@
android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" />
<protected-broadcast
android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_CONF_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_GROUP_NODE_STATUS_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.action.LE_AUDIO_GROUP_STATUS_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.action.TETHERING_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED" />
@@ -1194,6 +1199,14 @@
android:description="@string/permdesc_readPhoneState"
android:protectionLevel="dangerous" />
+ <!-- Allows read only access to phone state with a non dangerous permission,
+ including the information like cellular network type, software version. -->
+ <permission android:name="android.permission.READ_BASIC_PHONE_STATE"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_readBasicPhoneState"
+ android:description="@string/permdesc_readBasicPhoneState"
+ android:protectionLevel="normal" />
+
<!-- Allows read access to the device's phone number(s). This is a subset of the capabilities
granted by {@link #READ_PHONE_STATE} but is exposed to instant applications.
<p>Protection level: dangerous-->
@@ -2394,7 +2407,7 @@
<permission android:name="android.permission.READ_ACTIVE_EMERGENCY_SESSION"
android:protectionLevel="signature" />
- <!-- Allows listen permission to always reported signal strength.
+ <!-- Allows listen permission to always reported system signal strength.
@hide Used internally. -->
<permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH"
android:protectionLevel="signature" />
@@ -6247,6 +6260,10 @@
android:permission="android.permission.BIND_JOB_SERVICE">
</service>
+ <service android:name="com.android.server.compos.IsolatedCompilationJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE">
+ </service>
+
<service android:name="com.android.server.PruneInstantAppsJobService"
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a5f505176d5d..dc92e10abf0d 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1984,6 +1984,22 @@
<enum name="KEYCODE_THUMBS_UP" value="286" />
<enum name="KEYCODE_THUMBS_DOWN" value="287" />
<enum name="KEYCODE_PROFILE_SWITCH" value="288" />
+ <enum name="KEYCODE_VIDEO_APP_1" value="289" />
+ <enum name="KEYCODE_VIDEO_APP_2" value="290" />
+ <enum name="KEYCODE_VIDEO_APP_3" value="291" />
+ <enum name="KEYCODE_VIDEO_APP_4" value="292" />
+ <enum name="KEYCODE_VIDEO_APP_5" value="293" />
+ <enum name="KEYCODE_VIDEO_APP_6" value="294" />
+ <enum name="KEYCODE_VIDEO_APP_7" value="295" />
+ <enum name="KEYCODE_VIDEO_APP_8" value="296" />
+ <enum name="KEYCODE_FEATURED_APP_1" value="297" />
+ <enum name="KEYCODE_FEATURED_APP_2" value="298" />
+ <enum name="KEYCODE_FEATURED_APP_3" value="299" />
+ <enum name="KEYCODE_FEATURED_APP_4" value="300" />
+ <enum name="KEYCODE_DEMO_APP_1" value="301" />
+ <enum name="KEYCODE_DEMO_APP_2" value="302" />
+ <enum name="KEYCODE_DEMO_APP_3" value="303" />
+ <enum name="KEYCODE_DEMO_APP_4" value="304" />
</attr>
<!-- ***************************************************************** -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index d052d70442c4..f4acfaa1baca 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -547,7 +547,7 @@
<attr name="allowTaskReparenting" format="boolean" />
<!-- Declare that this application may use cleartext traffic, such as HTTP rather than HTTPS;
- WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP without STARTTLS or TLS.
+ WebSockets rather than WebSockets Secure; XMPP, IMAP, SMTP without STARTTLS or TLS.
Defaults to true. If set to false {@code false}, the application declares that it does not
intend to use cleartext network traffic, in which case platform components (e.g. HTTP
stacks, {@code DownloadManager}, {@code MediaPlayer}) will refuse applications's requests
@@ -1762,7 +1762,7 @@
<!-- @deprecated replaced by setting appCategory attribute to "game" -->
<attr name="isGame" />
<!-- Declare that this application may use cleartext traffic, such as HTTP rather than
- HTTPS; WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP without STARTTLS or
+ HTTPS; WebSockets rather than WebSockets Secure; XMPP, IMAP, SMTP without STARTTLS or
TLS). Defaults to true. If set to false {@code false}, the application declares that it
does not intend to use cleartext network traffic, in which case platform components
(e.g. HTTP stacks, {@code DownloadManager}, {@code MediaPlayer}) will refuse
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7db2fe94d243..8496a478af97 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5054,4 +5054,7 @@
<!-- the number of the max cached processes in the system. -->
<integer name="config_customizedMaxCachedProcesses">32</integer>
+
+ <!-- Whether this device should support taking app snapshots on closure -->
+ <bool name="config_disableTaskSnapshots">false</bool>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a350d14d92ab..8eede56035c1 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -64,16 +64,74 @@
<!-- Displayed when a carrier does not support call forwarding queries when roaming. -->
<string name="mmiErrorWhileRoaming">Can not change call forwarding settings from your phone while you are roaming.</string>
- <!-- Displayed when a phone feature such as call barring was activated. -->
+ <!-- Displayed when a phone feature such as call forwarding, call waiting, or call barring was
+ activated.
+ Used to build messages of the form:
+ <X>
+ <Y>
+
+ Where <X> is the name of the service which was enabled. Can be one of:
+ {@link #BaMmi Call barring}, {@link #CfMmi Call forwarding},
+ {@link #PwdMmi Password change}, {@link #CwMmi Call waiting},
+ {@link #ClipMmi Incoming Caller ID}, {@link #ClirMmi Hide Outgoing Caller ID},
+ {@link #ColpMmi Connected Line ID}, {@link #ColrMmi Connected Line ID Restriction}.
+ And <Y> is {@link #serviceEnabled} (this string).
+ -->
<string name="serviceEnabled">Service was enabled.</string>
<!-- Displayed in front of the list of a set of service classes
- (voice, data, fax, etc.) that were enabled. -->
+ (voice, data, fax, etc.) that call waiting were enabled for.
+ Will be used with messages of the form:
+ <X>
+ <Y1>
+ ...
+ <Yn>
+ Where <X> is {@link #serviceEnabledFor} (this string) and <Y>..<Yn> can be:
+ {@link #serviceClassData}, {@link #serviceClassVoice}, {@link #serviceClassFAX},
+ {@link #serviceClassSMS}, {@link #serviceClassDataAsync}, {@link #serviceClassDataSync},
+ {@link #serviceClassPacket}, {@link #serviceClassPAD}.
+ -->
<string name="serviceEnabledFor">Service was enabled for:</string>
- <!-- Displayed when a phone feature such as call forwarding was deactivated. -->
+ <!-- Displayed when a phone feature such as call forwarding was deactivated.
+ Used to build messages of the form:
+ <X>
+ <Y>
+
+ Where <X> is the name of the service which was disabled. Can be one of:
+ {@link #BaMmi Call barring}, {@link #CfMmi Call forwarding},
+ {@link #PwdMmi Password change}, {@link #CwMmi Call waiting},
+ {@link #ClipMmi Incoming Caller ID}, {@link #ClirMmi Hide Outgoing Caller ID},
+ {@link #ColpMmi Connected Line ID}, {@link #ColrMmi Connected Line ID Restriction}.
+ And <Y> is {@link #serviceDisabled} (this string).
+ -->
<string name="serviceDisabled">Service has been disabled.</string>
- <!-- Displayed when a phone property such as a SIM password was registered. -->
+ <!-- Displayed when a phone property such as a SIM password was registered. Registration
+ entails setting up a service for use, where {@link #serviceEnabled} entails enabling a
+ previously registered service.
+ Used to build messages of the form:
+ <X>
+ <Y>
+
+ Where <X> is the name of the service which was registered. Can be one of:
+ {@link #BaMmi Call barring}, {@link #CfMmi Call forwarding},
+ {@link #PwdMmi Password change}, {@link #CwMmi Call waiting},
+ {@link #ClipMmi Incoming Caller ID}, {@link #ClirMmi Hide Outgoing Caller ID},
+ {@link #ColpMmi Connected Line ID}, {@link #ColrMmi Connected Line ID Restriction}.
+ And <Y> is {@link #serviceRegistered} (this string). -->
<string name="serviceRegistered">Registration was successful.</string>
- <!-- Displayed when a phone property such as a SIM password was erased. -->
+ <!-- Displayed when a phone property such as a SIM password was erased.
+ Erasure is the opposite of {@link #serviceRegistered} and entails removal of a service.
+
+ Used to build messages of the form:
+ <X>
+ <Y>
+
+ Where <X> is the name of the service which was registered. Can be one of:
+ {@link #BaMmi Call barring}, {@link #CfMmi Call forwarding},
+ {@link #PwdMmi Password change}, {@link #CwMmi Call waiting},
+ {@link #ClipMmi Incoming Caller ID}, {@link #ClirMmi Hide Outgoing Caller ID},
+ {@link #ColpMmi Connected Line ID}, {@link #ColrMmi Connected Line ID Restriction}.
+ And <Y> is {@link #serviceErased} (this string).
+ -->
<string name="serviceErased">Erasure was successful.</string>
<!-- Displayed when a SIM password was entered incorrectly. -->
<string name="passwordIncorrect">Incorrect password.</string>
@@ -107,23 +165,32 @@
[CHAR LIMIT=10] -->
<string name="meid">MEID</string>
- <!-- Displayed as the title for a success/failure report enabling/disabling caller ID. -->
+ <!-- Displayed as the title for a success/failure report enabling/disabling caller ID.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="ClipMmi">Incoming Caller ID</string>
- <!-- Displayed as the title for a success/failure report enabling/disabling caller ID. -->
+ <!-- Displayed as the title for a success/failure report enabling/disabling caller ID.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="ClirMmi">Hide Outgoing Caller ID</string>
- <!-- Displayed as the title for a success/failure report enabling/disabling connected line ID. -->
+ <!-- Displayed as the title for a success/failure report enabling/disabling connected line ID.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="ColpMmi">Connected Line ID</string>
- <!-- Displayed as the title for a success/failure report enabling/disabling connected line ID restriction. -->
+ <!-- Displayed as the title for a success/failure report enabling/disabling connected line ID restriction.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="ColrMmi">Connected Line ID Restriction</string>
- <!-- Displayed as the title for a success/failure report enabling/disabling call forwarding. -->
+ <!-- Displayed as the title for a success/failure report enabling/disabling call forwarding.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="CfMmi">Call forwarding</string>
- <!-- Displayed as the title for a success/failure report enabling/disabling call waiting. -->
+ <!-- Displayed as the title for a success/failure report enabling/disabling call waiting.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="CwMmi">Call waiting</string>
- <!-- Displayed as the title for a success/failure report enabling/disabling call barring. -->
+ <!-- Displayed as the title for a success/failure report enabling/disabling call barring.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="BaMmi">Call barring</string>
- <!-- Displayed as the title for a success/failure report changing the SIM password. -->
+ <!-- Displayed as the title for a success/failure report changing the SIM password.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="PwdMmi">Password change</string>
- <!-- Displayed as the title for a success/failure report changing the SIM PIN. -->
+ <!-- Displayed as the title for a success/failure report changing the SIM PIN.
+ See {@link #serviceEnabled}, {@link #serviceDisabled}. -->
<string name="PinMmi">PIN change</string>
<string name="CnipMmi">Calling number present</string>
<string name="CnirMmi">Calling number restricted</string>
@@ -198,21 +265,29 @@
<string name="peerTtyModeOff">Peer requested TTY Mode OFF</string>
<!-- Mappings between TS 27.007 +CFCC/+CLCK "service classes" and human-readable strings--> <skip />
- <!-- Example: Service was enabled for: Voice, Data -->
+ <!-- Example: Service was enabled for: Voice, Data
+ See {@link #serviceEnabledFor}.-->
<string name="serviceClassVoice">Voice</string>
- <!-- Example: Service was enabled for: Voice, Data -->
+ <!-- Example: Service was enabled for: Voice, Data.
+ See {@link #serviceEnabledFor}. -->
<string name="serviceClassData">Data</string>
- <!-- Example: Service was enabled for: Voice, FAX -->
+ <!-- Example: Service was enabled for: Voice, FAX
+ See {@link #serviceEnabledFor}. -->
<string name="serviceClassFAX">FAX</string>
- <!-- Example: Service was enabled for: Voice, SMS -->
+ <!-- Example: Service was enabled for: Voice, SMS
+ See {@link #serviceEnabledFor}. -->
<string name="serviceClassSMS">SMS</string>
- <!-- Meaning: asynchronous data. Example: Service was enabled for: Voice, Async -->
+ <!-- Meaning: asynchronous data. Example: Service was enabled for: Voice, Async
+ See {@link #serviceEnabledFor}. -->
<string name="serviceClassDataAsync">Async</string>
- <!-- Meaning: synchronous data. Example: Service was enabled for: Voice, Async -->
+ <!-- Meaning: synchronous data. Example: Service was enabled for: Voice, Async
+ See {@link #serviceEnabledFor}. -->
<string name="serviceClassDataSync">Sync</string>
- <!-- Meaning: packet data. Example: Service was enabled for: Voice, Packet -->
+ <!-- Meaning: packet data. Example: Service was enabled for: Voice, Packet
+ See {@link #serviceEnabledFor}. -->
<string name="serviceClassPacket">Packet</string>
- <!-- Meaning: unknown. Example: Service was enabled for: Voice, PAD -->
+ <!-- Meaning: unknown. Example: Service was enabled for: Voice, PAD
+ See {@link #serviceEnabledFor}. -->
<string name="serviceClassPAD">PAD</string>
<!-- CDMA Roaming Indicator Strings (non ERI)--> <skip />
@@ -1275,6 +1350,12 @@
phone number and device IDs, whether a call is active, and the remote number
connected by a call.</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=80]-->
+ <string name="permlab_readBasicPhoneState">read basic telephony status and identity </string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] -->
+ <string name="permdesc_readBasicPhoneState">Allows the app to access the basic telephony
+ features of the device.</string>
+
<!-- Title of an application permission. When granted the user is giving access to a third
party app to route its calls through the system. -->
<string name="permlab_manageOwnCalls">route calls through the system</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1c4452667541..d06dafe9b3e7 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4403,7 +4403,7 @@
<java-symbol type="string" name="view_and_control_notification_title" />
<java-symbol type="string" name="view_and_control_notification_content" />
<java-symbol type="array" name="config_accessibility_allowed_install_source" />
-
+
<!-- Translation -->
<java-symbol type="string" name="ui_translation_accessibility_translated_text" />
<java-symbol type="string" name="ui_translation_accessibility_translation_finished" />
@@ -4430,4 +4430,7 @@
<java-symbol type="array" name="config_sharedLibrariesLoadedAfterApp" />
<java-symbol type="integer" name="config_customizedMaxCachedProcesses" />
+
+ <java-symbol type="bool" name="config_disableTaskSnapshots" />
+
</resources>
diff --git a/core/tests/PlatformCompatFramework/OWNERS b/core/tests/PlatformCompatFramework/OWNERS
index cfd0a4b079ad..ee3086ab2fdb 100644
--- a/core/tests/PlatformCompatFramework/OWNERS
+++ b/core/tests/PlatformCompatFramework/OWNERS
@@ -1,6 +1 @@
-# Use this reviewer by default.
-platform-compat-eng+reviews@google.com
-
-andreionea@google.com
-mathewi@google.com
-satayev@google.com
+include tools/platform-compat:/OWNERS
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java
index 59b46656dd52..bd55426601fc 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java
@@ -17,7 +17,6 @@
package android.bluetooth;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
import junit.framework.TestCase;
@@ -34,7 +33,6 @@ public class BluetoothCodecConfigTest extends TestCase {
BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
- BluetoothCodecConfig.SOURCE_CODEC_TYPE_MAX,
BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID,
};
private static final int[] kCodecPriorityArray = new int[] {
@@ -168,20 +166,11 @@ public class BluetoothCodecConfigTest extends TestCase {
long codec_specific3 = selectCodecSpecific3(config_id);
long codec_specific4 = selectCodecSpecific4(config_id);
- BluetoothCodecConfig bcc = new BluetoothCodecConfig(codec_type, codec_priority,
+ BluetoothCodecConfig bcc = buildBluetoothCodecConfig(codec_type, codec_priority,
sample_rate, bits_per_sample,
channel_mode, codec_specific1,
codec_specific2, codec_specific3,
codec_specific4);
- if (sample_rate == BluetoothCodecConfig.SAMPLE_RATE_NONE) {
- assertFalse(bcc.isValid());
- } else if (bits_per_sample == BluetoothCodecConfig.BITS_PER_SAMPLE_NONE) {
- assertFalse(bcc.isValid());
- } else if (channel_mode == BluetoothCodecConfig.CHANNEL_MODE_NONE) {
- assertFalse(bcc.isValid());
- } else {
- assertTrue(bcc.isValid());
- }
if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC) {
assertTrue(bcc.isMandatoryCodec());
@@ -204,10 +193,6 @@ public class BluetoothCodecConfigTest extends TestCase {
if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC) {
assertEquals("LDAC", bcc.getCodecName());
}
- if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_MAX) {
- assertEquals("UNKNOWN CODEC(" + BluetoothCodecConfig.SOURCE_CODEC_TYPE_MAX + ")",
- bcc.getCodecName());
- }
if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
assertEquals("INVALID CODEC", bcc.getCodecName());
}
@@ -227,7 +212,7 @@ public class BluetoothCodecConfigTest extends TestCase {
@SmallTest
public void testBluetoothCodecConfig_equals() {
BluetoothCodecConfig bcc1 =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -235,7 +220,7 @@ public class BluetoothCodecConfigTest extends TestCase {
1000, 2000, 3000, 4000);
BluetoothCodecConfig bcc2_same =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -244,7 +229,7 @@ public class BluetoothCodecConfigTest extends TestCase {
assertTrue(bcc1.equals(bcc2_same));
BluetoothCodecConfig bcc3_codec_type =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -253,7 +238,7 @@ public class BluetoothCodecConfigTest extends TestCase {
assertFalse(bcc1.equals(bcc3_codec_type));
BluetoothCodecConfig bcc4_codec_priority =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -262,7 +247,7 @@ public class BluetoothCodecConfigTest extends TestCase {
assertFalse(bcc1.equals(bcc4_codec_priority));
BluetoothCodecConfig bcc5_sample_rate =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_48000,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -271,7 +256,7 @@ public class BluetoothCodecConfigTest extends TestCase {
assertFalse(bcc1.equals(bcc5_sample_rate));
BluetoothCodecConfig bcc6_bits_per_sample =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_24,
@@ -280,7 +265,7 @@ public class BluetoothCodecConfigTest extends TestCase {
assertFalse(bcc1.equals(bcc6_bits_per_sample));
BluetoothCodecConfig bcc7_channel_mode =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -289,7 +274,7 @@ public class BluetoothCodecConfigTest extends TestCase {
assertFalse(bcc1.equals(bcc7_channel_mode));
BluetoothCodecConfig bcc8_codec_specific1 =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -298,7 +283,7 @@ public class BluetoothCodecConfigTest extends TestCase {
assertFalse(bcc1.equals(bcc8_codec_specific1));
BluetoothCodecConfig bcc9_codec_specific2 =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -307,7 +292,7 @@ public class BluetoothCodecConfigTest extends TestCase {
assertFalse(bcc1.equals(bcc9_codec_specific2));
BluetoothCodecConfig bcc10_codec_specific3 =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -316,7 +301,7 @@ public class BluetoothCodecConfigTest extends TestCase {
assertFalse(bcc1.equals(bcc10_codec_specific3));
BluetoothCodecConfig bcc11_codec_specific4 =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -324,4 +309,21 @@ public class BluetoothCodecConfigTest extends TestCase {
1000, 2000, 3000, 4004);
assertFalse(bcc1.equals(bcc11_codec_specific4));
}
+
+ private BluetoothCodecConfig buildBluetoothCodecConfig(int sourceCodecType,
+ int codecPriority, int sampleRate, int bitsPerSample, int channelMode,
+ long codecSpecific1, long codecSpecific2, long codecSpecific3, long codecSpecific4) {
+ return new BluetoothCodecConfig.Builder()
+ .setCodecType(sourceCodecType)
+ .setCodecPriority(codecPriority)
+ .setSampleRate(sampleRate)
+ .setBitsPerSample(bitsPerSample)
+ .setChannelMode(channelMode)
+ .setCodecSpecific1(codecSpecific1)
+ .setCodecSpecific2(codecSpecific2)
+ .setCodecSpecific3(codecSpecific3)
+ .setCodecSpecific4(codecSpecific4)
+ .build();
+
+ }
}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java
index 83bf2ed19380..1cb2dcae865c 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java
@@ -17,13 +17,13 @@
package android.bluetooth;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-import java.util.Arrays;
-import java.util.Objects;
import junit.framework.TestCase;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
/**
* Unit test cases for {@link BluetoothCodecStatus}.
* <p>
@@ -34,7 +34,7 @@ public class BluetoothCodecStatusTest extends TestCase {
// Codec configs: A and B are same; C is different
private static final BluetoothCodecConfig config_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -42,7 +42,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig config_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -50,7 +50,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig config_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -59,7 +59,7 @@ public class BluetoothCodecStatusTest extends TestCase {
// Local capabilities: A and B are same; C is different
private static final BluetoothCodecConfig local_capability1_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -69,7 +69,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability1_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -79,7 +79,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability1_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -89,7 +89,7 @@ public class BluetoothCodecStatusTest extends TestCase {
private static final BluetoothCodecConfig local_capability2_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -99,7 +99,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability2_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -109,7 +109,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability2_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -118,7 +118,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability3_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -128,7 +128,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability3_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -138,7 +138,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability3_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -147,7 +147,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability4_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -157,7 +157,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability4_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -167,7 +167,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability4_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000,
@@ -176,7 +176,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability5_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000 |
@@ -190,7 +190,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability5_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000 |
@@ -204,7 +204,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig local_capability5_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000 |
@@ -219,7 +219,7 @@ public class BluetoothCodecStatusTest extends TestCase {
// Selectable capabilities: A and B are same; C is different
private static final BluetoothCodecConfig selectable_capability1_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -228,7 +228,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability1_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -237,7 +237,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability1_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -245,7 +245,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability2_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -254,7 +254,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability2_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -263,7 +263,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability2_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -271,7 +271,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability3_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -280,7 +280,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability3_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -289,7 +289,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability3_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_16,
@@ -297,7 +297,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability4_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_24,
@@ -306,7 +306,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability4_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_24,
@@ -315,7 +315,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability4_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100,
BluetoothCodecConfig.BITS_PER_SAMPLE_24,
@@ -323,7 +323,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability5_A =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000 |
@@ -337,7 +337,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability5_B =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000 |
@@ -351,7 +351,7 @@ public class BluetoothCodecStatusTest extends TestCase {
1000, 2000, 3000, 4000);
private static final BluetoothCodecConfig selectable_capability5_C =
- new BluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
+ buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
BluetoothCodecConfig.SAMPLE_RATE_44100 |
BluetoothCodecConfig.SAMPLE_RATE_48000 |
@@ -363,79 +363,87 @@ public class BluetoothCodecStatusTest extends TestCase {
BluetoothCodecConfig.CHANNEL_MODE_STEREO,
1000, 2000, 3000, 4000);
- private static final BluetoothCodecConfig[] local_capability_A = {
- local_capability1_A,
- local_capability2_A,
- local_capability3_A,
- local_capability4_A,
- local_capability5_A,
- };
-
- private static final BluetoothCodecConfig[] local_capability_B = {
- local_capability1_B,
- local_capability2_B,
- local_capability3_B,
- local_capability4_B,
- local_capability5_B,
- };
-
- private static final BluetoothCodecConfig[] local_capability_B_reordered = {
- local_capability5_B,
- local_capability4_B,
- local_capability2_B,
- local_capability3_B,
- local_capability1_B,
- };
-
- private static final BluetoothCodecConfig[] local_capability_C = {
- local_capability1_C,
- local_capability2_C,
- local_capability3_C,
- local_capability4_C,
- local_capability5_C,
- };
-
- private static final BluetoothCodecConfig[] selectable_capability_A = {
- selectable_capability1_A,
- selectable_capability2_A,
- selectable_capability3_A,
- selectable_capability4_A,
- selectable_capability5_A,
- };
-
- private static final BluetoothCodecConfig[] selectable_capability_B = {
- selectable_capability1_B,
- selectable_capability2_B,
- selectable_capability3_B,
- selectable_capability4_B,
- selectable_capability5_B,
- };
-
- private static final BluetoothCodecConfig[] selectable_capability_B_reordered = {
- selectable_capability5_B,
- selectable_capability4_B,
- selectable_capability2_B,
- selectable_capability3_B,
- selectable_capability1_B,
- };
-
- private static final BluetoothCodecConfig[] selectable_capability_C = {
- selectable_capability1_C,
- selectable_capability2_C,
- selectable_capability3_C,
- selectable_capability4_C,
- selectable_capability5_C,
- };
+ private static final List<BluetoothCodecConfig> LOCAL_CAPABILITY_A =
+ new ArrayList() {{
+ add(local_capability1_A);
+ add(local_capability2_A);
+ add(local_capability3_A);
+ add(local_capability4_A);
+ add(local_capability5_A);
+ }};
+
+ private static final List<BluetoothCodecConfig> LOCAL_CAPABILITY_B =
+ new ArrayList() {{
+ add(local_capability1_B);
+ add(local_capability2_B);
+ add(local_capability3_B);
+ add(local_capability4_B);
+ add(local_capability5_B);
+ }};
+
+ private static final List<BluetoothCodecConfig> LOCAL_CAPABILITY_B_REORDERED =
+ new ArrayList() {{
+ add(local_capability5_B);
+ add(local_capability4_B);
+ add(local_capability2_B);
+ add(local_capability3_B);
+ add(local_capability1_B);
+ }};
+
+ private static final List<BluetoothCodecConfig> LOCAL_CAPABILITY_C =
+ new ArrayList() {{
+ add(local_capability1_C);
+ add(local_capability2_C);
+ add(local_capability3_C);
+ add(local_capability4_C);
+ add(local_capability5_C);
+ }};
+
+ private static final List<BluetoothCodecConfig> SELECTABLE_CAPABILITY_A =
+ new ArrayList() {{
+ add(selectable_capability1_A);
+ add(selectable_capability2_A);
+ add(selectable_capability3_A);
+ add(selectable_capability4_A);
+ add(selectable_capability5_A);
+ }};
+
+ private static final List<BluetoothCodecConfig> SELECTABLE_CAPABILITY_B =
+ new ArrayList() {{
+ add(selectable_capability1_B);
+ add(selectable_capability2_B);
+ add(selectable_capability3_B);
+ add(selectable_capability4_B);
+ add(selectable_capability5_B);
+ }};
+
+ private static final List<BluetoothCodecConfig> SELECTABLE_CAPABILITY_B_REORDERED =
+ new ArrayList() {{
+ add(selectable_capability5_B);
+ add(selectable_capability4_B);
+ add(selectable_capability2_B);
+ add(selectable_capability3_B);
+ add(selectable_capability1_B);
+ }};
+
+ private static final List<BluetoothCodecConfig> SELECTABLE_CAPABILITY_C =
+ new ArrayList() {{
+ add(selectable_capability1_C);
+ add(selectable_capability2_C);
+ add(selectable_capability3_C);
+ add(selectable_capability4_C);
+ add(selectable_capability5_C);
+ }};
private static final BluetoothCodecStatus bcs_A =
- new BluetoothCodecStatus(config_A, local_capability_A, selectable_capability_A);
+ new BluetoothCodecStatus(config_A, LOCAL_CAPABILITY_A, SELECTABLE_CAPABILITY_A);
private static final BluetoothCodecStatus bcs_B =
- new BluetoothCodecStatus(config_B, local_capability_B, selectable_capability_B);
+ new BluetoothCodecStatus(config_B, LOCAL_CAPABILITY_B, SELECTABLE_CAPABILITY_B);
private static final BluetoothCodecStatus bcs_B_reordered =
- new BluetoothCodecStatus(config_B, local_capability_B_reordered,
- selectable_capability_B_reordered);
+ new BluetoothCodecStatus(config_B, LOCAL_CAPABILITY_B_REORDERED,
+ SELECTABLE_CAPABILITY_B_REORDERED);
private static final BluetoothCodecStatus bcs_C =
- new BluetoothCodecStatus(config_C, local_capability_C, selectable_capability_C);
+ new BluetoothCodecStatus(config_C, LOCAL_CAPABILITY_C, SELECTABLE_CAPABILITY_C);
@SmallTest
public void testBluetoothCodecStatus_get_methods() {
@@ -444,16 +452,16 @@ public class BluetoothCodecStatusTest extends TestCase {
assertTrue(Objects.equals(bcs_A.getCodecConfig(), config_B));
assertFalse(Objects.equals(bcs_A.getCodecConfig(), config_C));
- assertTrue(Arrays.equals(bcs_A.getCodecsLocalCapabilities(), local_capability_A));
- assertTrue(Arrays.equals(bcs_A.getCodecsLocalCapabilities(), local_capability_B));
- assertFalse(Arrays.equals(bcs_A.getCodecsLocalCapabilities(), local_capability_C));
+ assertTrue(bcs_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_A));
+ assertTrue(bcs_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_B));
+ assertFalse(bcs_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_C));
- assertTrue(Arrays.equals(bcs_A.getCodecsSelectableCapabilities(),
- selectable_capability_A));
- assertTrue(Arrays.equals(bcs_A.getCodecsSelectableCapabilities(),
- selectable_capability_B));
- assertFalse(Arrays.equals(bcs_A.getCodecsSelectableCapabilities(),
- selectable_capability_C));
+ assertTrue(bcs_A.getCodecsSelectableCapabilities()
+ .equals(SELECTABLE_CAPABILITY_A));
+ assertTrue(bcs_A.getCodecsSelectableCapabilities()
+ .equals(SELECTABLE_CAPABILITY_B));
+ assertFalse(bcs_A.getCodecsSelectableCapabilities()
+ .equals(SELECTABLE_CAPABILITY_C));
}
@SmallTest
@@ -465,4 +473,21 @@ public class BluetoothCodecStatusTest extends TestCase {
assertFalse(bcs_A.equals(bcs_C));
assertFalse(bcs_C.equals(bcs_A));
}
+
+ private static BluetoothCodecConfig buildBluetoothCodecConfig(int sourceCodecType,
+ int codecPriority, int sampleRate, int bitsPerSample, int channelMode,
+ long codecSpecific1, long codecSpecific2, long codecSpecific3, long codecSpecific4) {
+ return new BluetoothCodecConfig.Builder()
+ .setCodecType(sourceCodecType)
+ .setCodecPriority(codecPriority)
+ .setSampleRate(sampleRate)
+ .setBitsPerSample(bitsPerSample)
+ .setChannelMode(channelMode)
+ .setCodecSpecific1(codecSpecific1)
+ .setCodecSpecific2(codecSpecific2)
+ .setCodecSpecific3(codecSpecific3)
+ .setCodecSpecific4(codecSpecific4)
+ .build();
+
+ }
}
diff --git a/core/tests/coretests/OWNERS b/core/tests/coretests/OWNERS
new file mode 100644
index 000000000000..0fb0c3021486
--- /dev/null
+++ b/core/tests/coretests/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/services/core/java/com/android/server/am/OWNERS
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index cf072b488efc..1c7659ec0bec 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -225,6 +225,8 @@ applications that come with the platform
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
<permission name="android.permission.USE_RESERVED_DISK"/>
+ <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+ <permission name="android.permission.LOG_COMPAT_CHANGE" />
</privapp-permissions>
<privapp-permissions package="com.android.providers.downloads">
@@ -501,6 +503,8 @@ applications that come with the platform
<permission name="android.permission.UPDATE_DEVICE_STATS" />
<!-- Permission required for GTS test - PendingSystemUpdateTest -->
<permission name="android.permission.NOTIFY_PENDING_SYSTEM_UPDATE" />
+ <!-- Permission required for ATS test - CarDevicePolicyManagerTest -->
+ <permission name="android.permission.LOCK_DEVICE" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index b67988ee9646..c94b3d5ce6b2 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -499,6 +499,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-1556507536": {
+ "message": "Passing transform hint %d for window %s%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"-1554521902": {
"message": "showInsets(ime) was requested by different window: %s ",
"level": "WARN",
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index c3b1cd74d29b..b61ae1259cf5 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -1075,6 +1076,53 @@ public class HardwareRenderer {
ProcessInitializer.sInstance.setContext(context);
}
+ /**
+ * Returns true if HardwareRender will produce output.
+ *
+ * This value is global to the process and affects all uses of HardwareRenderer,
+ * including
+ * those created by the system such as those used by the View tree when using hardware
+ * accelerated rendering.
+ *
+ * Default is true in all production environments, but may be false in testing-focused
+ * emulators or if {@link #setDrawingEnabled(boolean)} is used.
+ *
+ * Backported from android T.
+ *
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public static boolean isDrawingEnabled() {
+ return nIsDrawingEnabled();
+ }
+
+ /**
+ * Toggles whether or not HardwareRenderer will produce drawing output globally in the current
+ * process.
+ *
+ * This applies to all HardwareRenderer instances, including those created by the platform such
+ * as those used by the system for hardware accelerated View rendering.
+ *
+ * The capability to disable drawing output is intended for test environments, primarily
+ * headless ones. By setting this to false, tests that launch activities or interact with Views
+ * can be quicker with less RAM usage by skipping the final step of View drawing. All View
+ * lifecycle events will occur as normal, only the final step of rendering on the GPU to the
+ * display will be skipped.
+ *
+ * This can be toggled on and off at will, so screenshot tests can also run in this same
+ * environment by toggling drawing back on and forcing a frame to be drawn such as by calling
+ * view#invalidate(). Once drawn and the screenshot captured, this can then be turned back off.
+ *
+ * Backported from android T.
+ *
+ * @hide
+ */
+ // TODO: Add link to androidx's Screenshot library for help with this
+ @UnsupportedAppUsage
+ public static void setDrawingEnabled(boolean drawingEnabled) {
+ nSetDrawingEnabled(drawingEnabled);
+ }
+
private static final class DestroyContextRunnable implements Runnable {
private final long mNativeInstance;
@@ -1393,4 +1441,8 @@ public class HardwareRenderer {
private static native void nInitDisplayInfo(int width, int height, float refreshRate,
int wideColorDataspace, long appVsyncOffsetNanos, long presentationDeadlineNanos);
+
+ private static native void nSetDrawingEnabled(boolean drawingEnabled);
+
+ private static native boolean nIsDrawingEnabled();
}
diff --git a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
index 850c55166edc..6fa1a694eb67 100644
--- a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
+++ b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
@@ -89,7 +89,7 @@ abstract class KeyStoreCryptoOperationUtils {
// specific sensor (the one that hasn't changed), and 2) currently the only
// signal to developers is the UserNotAuthenticatedException, which doesn't
// indicate a specific sensor.
- boolean canUnlockViaBiometrics = true;
+ boolean canUnlockViaBiometrics = biometricSids.length > 0;
for (long sid : biometricSids) {
if (!keySids.contains(sid)) {
canUnlockViaBiometrics = false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
index e6d088e6537d..2adf8ce8525f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
@@ -272,8 +272,10 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou
final String innerPrefix = prefix + " ";
final String childPrefix = innerPrefix + " ";
pw.println(prefix + this);
- pw.println(innerPrefix + "Root taskId=" + getRootTaskId()
- + " winMode=" + mRootTaskInfo.getWindowingMode());
+ if (mRootTaskInfo != null) {
+ pw.println(innerPrefix + "Root taskId=" + mRootTaskInfo.taskId
+ + " winMode=" + mRootTaskInfo.getWindowingMode());
+ }
if (mTaskInfo1 != null) {
pw.println(innerPrefix + "1 taskId=" + mTaskInfo1.taskId
+ " winMode=" + mTaskInfo1.getWindowingMode());
diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS
index d80699de8a2d..f49e80ae16b1 100644
--- a/libs/WindowManager/Shell/tests/OWNERS
+++ b/libs/WindowManager/Shell/tests/OWNERS
@@ -1,3 +1,4 @@
# Bug component: 909476
# includes OWNERS from parent directories
natanieljr@google.com
+pablogamito@google.com
diff --git a/libs/androidfw/OWNERS b/libs/androidfw/OWNERS
index 610fd80fe73c..17f5164cf417 100644
--- a/libs/androidfw/OWNERS
+++ b/libs/androidfw/OWNERS
@@ -1,6 +1,6 @@
set noparent
toddke@google.com
-rtmitchell@google.com
+zyy@google.com
patb@google.com
per-file CursorWindow.cpp=omakoto@google.com
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index b8fa55a18dac..c804418e8380 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -88,6 +88,8 @@ bool Properties::enableWebViewOverlays = false;
StretchEffectBehavior Properties::stretchEffectBehavior = StretchEffectBehavior::ShaderHWUI;
+DrawingEnabled Properties::drawingEnabled = DrawingEnabled::NotInitialized;
+
bool Properties::load() {
bool prevDebugLayersUpdates = debugLayersUpdates;
bool prevDebugOverdraw = debugOverdraw;
@@ -141,6 +143,9 @@ bool Properties::load() {
enableWebViewOverlays = base::GetBoolProperty(PROPERTY_WEBVIEW_OVERLAYS_ENABLED, false);
+ // call isDrawingEnabled to force loading of the property
+ isDrawingEnabled();
+
return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw);
}
@@ -210,5 +215,19 @@ void Properties::overrideRenderPipelineType(RenderPipelineType type, bool inUnit
sRenderPipelineType = type;
}
+void Properties::setDrawingEnabled(bool newDrawingEnabled) {
+ drawingEnabled = newDrawingEnabled ? DrawingEnabled::On : DrawingEnabled::Off;
+ enableRTAnimations = newDrawingEnabled;
+}
+
+bool Properties::isDrawingEnabled() {
+ if (drawingEnabled == DrawingEnabled::NotInitialized) {
+ bool drawingEnabledProp = base::GetBoolProperty(PROPERTY_DRAWING_ENABLED, true);
+ drawingEnabled = drawingEnabledProp ? DrawingEnabled::On : DrawingEnabled::Off;
+ enableRTAnimations = drawingEnabledProp;
+ }
+ return drawingEnabled == DrawingEnabled::On;
+}
+
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 7df6e2c92247..7f9782bf8d20 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -187,6 +187,12 @@ enum DebugLevel {
*/
#define PROPERTY_WEBVIEW_OVERLAYS_ENABLED "debug.hwui.webview_overlays_enabled"
+/**
+ * Property for globally GL drawing state. Can be overridden per process with
+ * setDrawingEnabled.
+ */
+#define PROPERTY_DRAWING_ENABLED "debug.hwui.drawing_enabled"
+
///////////////////////////////////////////////////////////////////////////////
// Misc
///////////////////////////////////////////////////////////////////////////////
@@ -208,6 +214,8 @@ enum class StretchEffectBehavior {
UniformScale // Uniform scale stretch everywhere
};
+enum class DrawingEnabled { NotInitialized, On, Off };
+
/**
* Renderthread-only singleton which manages several static rendering properties. Most of these
* are driven by system properties which are queried once at initialization, and again if init()
@@ -301,6 +309,11 @@ public:
stretchEffectBehavior = behavior;
}
+ // Represents if drawing is enabled. Should only be Off in headless testing environments
+ static DrawingEnabled drawingEnabled;
+ static bool isDrawingEnabled();
+ static void setDrawingEnabled(bool enable);
+
private:
static StretchEffectBehavior stretchEffectBehavior;
static ProfileType sProfileType;
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index 54367b8334cb..9e56584ed582 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -817,6 +817,14 @@ static void android_view_ThreadedRenderer_initDisplayInfo(JNIEnv*, jclass, jint
DeviceInfo::setPresentationDeadlineNanos(presentationDeadlineNanos);
}
+static void android_view_ThreadedRenderer_setDrawingEnabled(JNIEnv*, jclass, jboolean enabled) {
+ Properties::setDrawingEnabled(enabled);
+}
+
+static jboolean android_view_ThreadedRenderer_isDrawingEnabled(JNIEnv*, jclass) {
+ return Properties::isDrawingEnabled();
+}
+
// ----------------------------------------------------------------------------
// HardwareRendererObserver
// ----------------------------------------------------------------------------
@@ -953,6 +961,9 @@ static const JNINativeMethod gMethods[] = {
{"preload", "()V", (void*)android_view_ThreadedRenderer_preload},
{"isWebViewOverlaysEnabled", "()Z",
(void*)android_view_ThreadedRenderer_isWebViewOverlaysEnabled},
+ {"nSetDrawingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDrawingEnabled},
+ {"nIsDrawingEnabled", "()Z", (void*)android_view_ThreadedRenderer_isDrawingEnabled},
+
};
static JavaVM* mJvm = nullptr;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 2f3a509831d1..bb0b1352c360 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -256,7 +256,7 @@ void CanvasContext::setStopped(bool stopped) {
}
void CanvasContext::allocateBuffers() {
- if (mNativeSurface) {
+ if (mNativeSurface && Properties::isDrawingEnabled()) {
ANativeWindow_tryAllocateBuffers(mNativeSurface->getNativeWindow());
}
}
@@ -480,7 +480,8 @@ nsecs_t CanvasContext::draw() {
SkRect dirty;
mDamageAccumulator.finish(&dirty);
- if (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw()) {
+ if (!Properties::isDrawingEnabled() ||
+ (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw())) {
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
if (auto grContext = getGrContext()) {
// Submit to ensure that any texture uploads complete and Skia can
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 6dbfcc349d50..2fed4686f16e 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -90,9 +90,17 @@ public:
* and false otherwise (e.g. cache limits have been exceeded).
*/
bool pinImages(std::vector<SkImage*>& mutableImages) {
+ if (!Properties::isDrawingEnabled()) {
+ return true;
+ }
return mRenderPipeline->pinImages(mutableImages);
}
- bool pinImages(LsaVector<sk_sp<Bitmap>>& images) { return mRenderPipeline->pinImages(images); }
+ bool pinImages(LsaVector<sk_sp<Bitmap>>& images) {
+ if (!Properties::isDrawingEnabled()) {
+ return true;
+ }
+ return mRenderPipeline->pinImages(images);
+ }
/**
* Unpin any image that had be previously pinned to the GPU cache
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index ed8cdb941792..c7f56961e498 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -32,7 +32,6 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothCodecConfig;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -3255,6 +3254,54 @@ public class AudioManager {
}
/**
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ public void setHfpEnabled(boolean enable) {
+ AudioSystem.setParameters("hfp_enable=" + enable);
+ }
+
+ /**
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ public void setHfpVolume(int volume) {
+ AudioSystem.setParameters("hfp_volume=" + volume);
+ }
+
+ /**
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ public void setHfpSamplingRate(int rate) {
+ AudioSystem.setParameters("hfp_set_sampling_rate=" + rate);
+ }
+
+ /**
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ public void setBluetoothHeadsetProperties(@NonNull String name, boolean hasNrecEnabled,
+ boolean hasWbsEnabled) {
+ AudioSystem.setParameters("bt_headset_name=" + name
+ + ";bt_headset_nrec=" + (hasNrecEnabled ? "on" : "off")
+ + ";bt_wbs=" + (hasWbsEnabled ? "on" : "off"));
+ }
+
+ /**
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ public void setA2dpSuspended(boolean enable) {
+ AudioSystem.setParameters("A2dpSuspended=" + enable);
+ }
+
+ /**
* Gets a variable number of parameter values from audio hardware.
*
* @param keys list of parameters
@@ -5748,112 +5795,25 @@ public class AudioManager {
}
}
- /**
- * Indicate Hearing Aid connection state change and eventually suppress
- * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
- * This operation is asynchronous but its execution will still be sequentially scheduled
- * relative to calls to {@link #setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- * * BluetoothDevice, int, int, boolean, int)} and
- * and {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}.
- * @param device Bluetooth device connected/disconnected
- * @param state new connection state (BluetoothProfile.STATE_xxx)
- * @param musicDevice Default get system volume for the connecting device.
- * (either {@link android.bluetooth.BluetoothProfile.hearingaid} or
- * {@link android.bluetooth.BluetoothProfile.HEARING_AID})
- * @param suppressNoisyIntent if true the
- * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
- * {@hide}
- */
- public void setBluetoothHearingAidDeviceConnectionState(
- BluetoothDevice device, int state, boolean suppressNoisyIntent,
- int musicDevice) {
- final IAudioService service = getService();
- try {
- service.setBluetoothHearingAidDeviceConnectionState(device,
- state, suppressNoisyIntent, musicDevice);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Indicate Le Audio output device connection state change and eventually suppress
- * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
- * @param device Bluetooth device connected/disconnected
- * @param state new connection state (BluetoothProfile.STATE_xxx)
- * @param suppressNoisyIntent if true the
- * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
- * {@hide}
- */
- public void setBluetoothLeAudioOutDeviceConnectionState(BluetoothDevice device, int state,
- boolean suppressNoisyIntent) {
- final IAudioService service = getService();
- try {
- service.setBluetoothLeAudioOutDeviceConnectionState(device, state, suppressNoisyIntent);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
/**
- * Indicate Le Audio input connection state change.
- * @param device Bluetooth device connected/disconnected
- * @param state new connection state (BluetoothProfile.STATE_xxx)
- * {@hide}
- */
- public void setBluetoothLeAudioInDeviceConnectionState(BluetoothDevice device, int state) {
- final IAudioService service = getService();
- try {
- service.setBluetoothLeAudioInDeviceConnectionState(device, state);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Indicate A2DP source or sink connection state change and eventually suppress
- * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
- * This operation is asynchronous but its execution will still be sequentially scheduled
- * relative to calls to {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice,
- * int, boolean, int)} and
- * {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}.
- * @param device Bluetooth device connected/disconnected
- * @param state new connection state, {@link BluetoothProfile#STATE_CONNECTED}
- * or {@link BluetoothProfile#STATE_DISCONNECTED}
- * @param profile profile for the A2DP device
- * @param a2dpVolume New volume for the connecting device. Does nothing if disconnecting.
- * (either {@link android.bluetooth.BluetoothProfile.A2DP} or
- * {@link android.bluetooth.BluetoothProfile.A2DP_SINK})
- * @param suppressNoisyIntent if true the
- * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
- * {@hide}
- */
- public void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- BluetoothDevice device, int state,
- int profile, boolean suppressNoisyIntent, int a2dpVolume) {
- final IAudioService service = getService();
- try {
- service.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device,
- state, profile, suppressNoisyIntent, a2dpVolume);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Indicate A2DP device configuration has changed.
- * This operation is asynchronous but its execution will still be sequentially scheduled
- * relative to calls to
- * {@link #setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice, int, int,
- * boolean, int)} and
- * {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice, int, boolean, int)}
- * @param device Bluetooth device whose configuration has changed.
+ * Indicate Bluetooth profile connection state change.
+ * Configuration changes for A2DP are indicated by having the same <code>newDevice</code> and
+ * <code>previousDevice</code>
+ * This operation is asynchronous.
+ *
+ * @param newDevice Bluetooth device connected or null if there is no new devices
+ * @param previousDevice Bluetooth device disconnected or null if there is no disconnected
+ * devices
+ * @param info contain all info related to the device. {@link BtProfileConnectionInfo}
* {@hide}
*/
- public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device) {
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice,
+ @Nullable BluetoothDevice previousDevice, @NonNull BtProfileConnectionInfo info) {
final IAudioService service = getService();
try {
- service.handleBluetoothA2dpDeviceConfigChange(device);
+ service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/media/java/android/media/BtProfileConnectionInfo.aidl b/media/java/android/media/BtProfileConnectionInfo.aidl
new file mode 100644
index 000000000000..047f06be0964
--- /dev/null
+++ b/media/java/android/media/BtProfileConnectionInfo.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.media;
+
+parcelable BtProfileConnectionInfo;
+
diff --git a/media/java/android/media/BtProfileConnectionInfo.java b/media/java/android/media/BtProfileConnectionInfo.java
new file mode 100644
index 000000000000..19ea2de6a434
--- /dev/null
+++ b/media/java/android/media/BtProfileConnectionInfo.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 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.media;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.bluetooth.BluetoothProfile;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Contains information about Bluetooth profile connection state changed
+ * {@hide}
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class BtProfileConnectionInfo implements Parcelable {
+ /** @hide */
+ @IntDef({
+ BluetoothProfile.A2DP,
+ BluetoothProfile.A2DP_SINK, // Can only be set by BtHelper
+ BluetoothProfile.HEADSET, // Can only be set by BtHelper
+ BluetoothProfile.HEARING_AID,
+ BluetoothProfile.LE_AUDIO,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface BtProfile {}
+
+ private final @BtProfile int mProfile;
+ private final boolean mSupprNoisy;
+ private final int mVolume;
+ private final boolean mIsLeOutput;
+
+ private BtProfileConnectionInfo(@BtProfile int profile, boolean suppressNoisyIntent, int volume,
+ boolean isLeOutput) {
+ mProfile = profile;
+ mSupprNoisy = suppressNoisyIntent;
+ mVolume = volume;
+ mIsLeOutput = isLeOutput;
+ }
+
+ /**
+ * Constructor used by BtHelper when a profile is connected
+ * {@hide}
+ */
+ public BtProfileConnectionInfo(@BtProfile int profile) {
+ this(profile, false, -1, false);
+ }
+
+ public static final @NonNull Parcelable.Creator<BtProfileConnectionInfo> CREATOR =
+ new Parcelable.Creator<BtProfileConnectionInfo>() {
+ @Override
+ public BtProfileConnectionInfo createFromParcel(Parcel source) {
+ return new BtProfileConnectionInfo(source.readInt(), source.readBoolean(),
+ source.readInt(), source.readBoolean());
+ }
+
+ @Override
+ public BtProfileConnectionInfo[] newArray(int size) {
+ return new BtProfileConnectionInfo[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, @WriteFlags int flags) {
+ dest.writeInt(mProfile);
+ dest.writeBoolean(mSupprNoisy);
+ dest.writeInt(mVolume);
+ dest.writeBoolean(mIsLeOutput);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Constructor for A2dp info
+ *
+ * @param suppressNoisyIntent if true the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY}
+ * intent will not be sent.
+ *
+ * @param volume of device -1 to ignore value
+ */
+ public static @NonNull BtProfileConnectionInfo a2dpInfo(boolean suppressNoisyIntent,
+ int volume) {
+ return new BtProfileConnectionInfo(BluetoothProfile.A2DP, suppressNoisyIntent, volume,
+ false);
+ }
+
+ /**
+ * Constructor for hearing aid info
+ *
+ * @param suppressNoisyIntent if true the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY}
+ * intent will not be sent.
+ */
+ public static @NonNull BtProfileConnectionInfo hearingAidInfo(boolean suppressNoisyIntent) {
+ return new BtProfileConnectionInfo(BluetoothProfile.HEARING_AID, suppressNoisyIntent, -1,
+ false);
+ }
+
+ /**
+ * constructor for le audio info
+ *
+ * @param suppressNoisyIntent if true the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY}
+ * intent will not be sent.
+ *
+ * @param isLeOutput if true mean the device is an output device, if false it's an input device
+ */
+ public static @NonNull BtProfileConnectionInfo leAudio(boolean suppressNoisyIntent,
+ boolean isLeOutput) {
+ return new BtProfileConnectionInfo(BluetoothProfile.LE_AUDIO, suppressNoisyIntent, -1,
+ isLeOutput);
+ }
+
+ /**
+ * @return The profile connection
+ */
+ public @BtProfile int getProfile() {
+ return mProfile;
+ }
+
+ /**
+ * @return {@code true} if {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be
+ * sent
+ */
+ public boolean getSuppressNoisyIntent() {
+ return mSupprNoisy;
+ }
+
+ /**
+ * Only for {@link BluetoothProfile.A2DP} profile
+ * @return the volume of the connection or -1 if the value is ignored
+ */
+ public int getVolume() {
+ return mVolume;
+ }
+
+ /**
+ * Only for {@link BluetoothProfile.LE_AUDIO} profile
+ * @return {@code true} is the LE device is an output device, {@code false} if it's an input
+ * device
+ */
+ public boolean getIsLeOutput() {
+ return mIsLeOutput;
+ }
+}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index dd44fdf1e8c4..5ff56f9c680d 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -24,6 +24,7 @@ import android.media.AudioFocusInfo;
import android.media.AudioPlaybackConfiguration;
import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo;
+import android.media.BtProfileConnectionInfo;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioModeDispatcher;
import android.media.IAudioRoutesObserver;
@@ -207,8 +208,6 @@ interface IAudioService {
void setWiredDeviceConnectionState(int type, int state, String address, String name,
String caller);
- void handleBluetoothA2dpDeviceConfigChange(in BluetoothDevice device);
-
@UnsupportedAppUsage
AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);
@@ -268,16 +267,8 @@ interface IAudioService {
oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio);
- void setBluetoothHearingAidDeviceConnectionState(in BluetoothDevice device,
- int state, boolean suppressNoisyIntent, int musicDevice);
-
- void setBluetoothLeAudioOutDeviceConnectionState(in BluetoothDevice device, int state,
- boolean suppressNoisyIntent);
-
- void setBluetoothLeAudioInDeviceConnectionState(in BluetoothDevice device, int state);
-
- void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device,
- int state, int profile, boolean suppressNoisyIntent, int a2dpVolume);
+ void handleBluetoothActiveDeviceChanged(in BluetoothDevice newDevice,
+ in BluetoothDevice previousDevice, in BtProfileConnectionInfo info);
oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult,
in IAudioPolicyCallback pcb);
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 1616c03112a8..54e19db8e7e9 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -163,6 +163,14 @@ public abstract class Image implements AutoCloseable {
* {@link android.graphics.BitmapFactory#decodeByteArray BitmapFactory#decodeByteArray}.
* </td>
* </tr>
+ * <tr>
+ * <td>{@link android.graphics.ImageFormat#YCBCR_P010 YCBCR_P010}</td>
+ * <td>1</td>
+ * <td>P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane
+ * followed by a Wx(H/2) CbCr plane. Each sample is represented by a 16-bit
+ * little-endian value, with the lower 6 bits set to zero.
+ * </td>
+ * </tr>
* </table>
*
* @see android.graphics.ImageFormat
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 8b9153621165..72dd2bd43eb6 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -60,10 +60,10 @@ import java.util.concurrent.locks.ReentrantLock;
with {@link MediaExtractor}, {@link MediaSync}, {@link MediaMuxer}, {@link MediaCrypto},
{@link MediaDrm}, {@link Image}, {@link Surface}, and {@link AudioTrack}.)
<p>
- <center><object style="width: 540px; height: 205px;" type="image/svg+xml"
- data="../../../images/media/mediacodec_buffers.svg"><img
- src="../../../images/media/mediacodec_buffers.png" style="width: 540px; height: 205px"
- alt="MediaCodec buffer flow diagram"></object></center>
+ <center>
+ <img src="../../../images/media/mediacodec_buffers.svg" style="width: 540px; height: 205px"
+ alt="MediaCodec buffer flow diagram">
+ </center>
<p>
In broad terms, a codec processes input data to generate output data. It processes data
asynchronously and uses a set of input and output buffers. At a simplistic level, you request
@@ -268,10 +268,10 @@ import java.util.concurrent.locks.ReentrantLock;
Uninitialized, Configured and Error, whereas the Executing state conceptually progresses through
three sub-states: Flushed, Running and End-of-Stream.
<p>
- <center><object style="width: 516px; height: 353px;" type="image/svg+xml"
- data="../../../images/media/mediacodec_states.svg"><img
- src="../../../images/media/mediacodec_states.png" style="width: 519px; height: 356px"
- alt="MediaCodec state diagram"></object></center>
+ <center>
+ <img src="../../../images/media/mediacodec_states.svg" style="width: 519px; height: 356px"
+ alt="MediaCodec state diagram">
+ </center>
<p>
When you create a codec using one of the factory methods, the codec is in the Uninitialized
state. First, you need to configure it via {@link #configure configure(&hellip;)}, which brings
@@ -513,10 +513,10 @@ import java.util.concurrent.locks.ReentrantLock;
Similarly, upon an initial call to {@code start} the codec will move directly to the Running
sub-state and start passing available input buffers via the callback.
<p>
- <center><object style="width: 516px; height: 353px;" type="image/svg+xml"
- data="../../../images/media/mediacodec_async_states.svg"><img
- src="../../../images/media/mediacodec_async_states.png" style="width: 516px; height: 353px"
- alt="MediaCodec state diagram for asynchronous operation"></object></center>
+ <center>
+ <img src="../../../images/media/mediacodec_async_states.svg" style="width: 516px; height: 353px"
+ alt="MediaCodec state diagram for asynchronous operation">
+ </center>
<p>
MediaCodec is typically used like this in asynchronous mode:
<pre class=prettyprint>
@@ -5107,7 +5107,6 @@ final public class MediaCodec {
public MediaImage(
@NonNull ByteBuffer buffer, @NonNull ByteBuffer info, boolean readOnly,
long timestamp, int xOffset, int yOffset, @Nullable Rect cropRect) {
- mFormat = ImageFormat.YUV_420_888;
mTimestamp = timestamp;
mIsImageValid = true;
mIsReadOnly = buffer.isReadOnly();
@@ -5120,6 +5119,11 @@ final public class MediaCodec {
mBufferContext = 0;
+ int cbPlaneOffset = -1;
+ int crPlaneOffset = -1;
+ int planeOffsetInc = -1;
+ int pixelStride = -1;
+
// read media-info. See MediaImage2
if (info.remaining() == 104) {
int type = info.getInt();
@@ -5137,14 +5141,27 @@ final public class MediaCodec {
"unsupported size: " + mWidth + "x" + mHeight);
}
int bitDepth = info.getInt();
- if (bitDepth != 8) {
+ if (bitDepth != 8 && bitDepth != 10) {
throw new UnsupportedOperationException("unsupported bit depth: " + bitDepth);
}
int bitDepthAllocated = info.getInt();
- if (bitDepthAllocated != 8) {
+ if (bitDepthAllocated != 8 && bitDepthAllocated != 16) {
throw new UnsupportedOperationException(
"unsupported allocated bit depth: " + bitDepthAllocated);
}
+ if (bitDepth == 8 && bitDepthAllocated == 8) {
+ mFormat = ImageFormat.YUV_420_888;
+ planeOffsetInc = 1;
+ pixelStride = 2;
+ } else if (bitDepth == 10 && bitDepthAllocated == 16) {
+ mFormat = ImageFormat.YCBCR_P010;
+ planeOffsetInc = 2;
+ pixelStride = 4;
+ } else {
+ throw new UnsupportedOperationException("couldn't infer ImageFormat"
+ + " bitDepth: " + bitDepth + " bitDepthAllocated: " + bitDepthAllocated);
+ }
+
mPlanes = new MediaPlane[numPlanes];
for (int ix = 0; ix < numPlanes; ix++) {
int planeOffset = info.getInt();
@@ -5166,12 +5183,31 @@ final public class MediaCodec {
buffer.limit(buffer.position() + Utils.divUp(bitDepth, 8)
+ (mHeight / vert - 1) * rowInc + (mWidth / horiz - 1) * colInc);
mPlanes[ix] = new MediaPlane(buffer.slice(), rowInc, colInc);
+ if ((mFormat == ImageFormat.YUV_420_888 || mFormat == ImageFormat.YCBCR_P010)
+ && ix == 1) {
+ cbPlaneOffset = planeOffset;
+ } else if ((mFormat == ImageFormat.YUV_420_888
+ || mFormat == ImageFormat.YCBCR_P010) && ix == 2) {
+ crPlaneOffset = planeOffset;
+ }
}
} else {
throw new UnsupportedOperationException(
"unsupported info length: " + info.remaining());
}
+ // Validate chroma semiplanerness.
+ if (mFormat == ImageFormat.YCBCR_P010) {
+ if (crPlaneOffset != cbPlaneOffset + planeOffsetInc) {
+ throw new UnsupportedOperationException("Invalid plane offsets"
+ + " cbPlaneOffset: " + cbPlaneOffset + " crPlaneOffset: " + crPlaneOffset);
+ }
+ if (mPlanes[1].getPixelStride() != pixelStride
+ || mPlanes[2].getPixelStride() != pixelStride) {
+ throw new UnsupportedOperationException("Invalid pixelStride");
+ }
+ }
+
if (cropRect == null) {
cropRect = new Rect(0, 0, mWidth, mHeight);
}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 374cc7592faf..3c152fb68c0a 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -426,6 +426,12 @@ public final class MediaCodecInfo {
/** @deprecated Use {@link #COLOR_Format32bitABGR8888}. */
public static final int COLOR_Format24BitABGR6666 = 43;
+ /** @hide
+ * P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane
+ * followed by a Wx(H/2) CbCr plane. Each sample is represented by a 16-bit
+ * little-endian value, with the lower 6 bits set to zero. */
+ public static final int COLOR_FormatYUVP010 = 54;
+
/** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
// COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference.
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 86ed50bacb63..72ee00f03774 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -102,6 +102,13 @@ public abstract class PlayerBase {
mState = AudioPlaybackConfiguration.PLAYER_STATE_IDLE;
};
+ /** @hide */
+ public int getPlayerIId() {
+ synchronized (mLock) {
+ return mPlayerIId;
+ }
+ }
+
/**
* Call from derived class when instantiation / initialization is successful
*/
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 2636ab227646..8dcdc989ec8f 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -953,7 +953,7 @@ android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_t
Parcel* parcel = parcelForJavaObject(env, jAttributionSource);
android::content::AttributionSourceState attributionSource;
attributionSource.readFromParcel(parcel);
- sp<MediaPlayer> mp = new MediaPlayer(attributionSource);
+ sp<MediaPlayer> mp = sp<MediaPlayer>::make(attributionSource);
if (mp == NULL) {
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
return;
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index ecd9cc1cd098..39b560b393a9 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -65,6 +65,7 @@ bool isPossiblyYUV(PixelFormat format) {
case HAL_PIXEL_FORMAT_Y8:
case HAL_PIXEL_FORMAT_Y16:
case HAL_PIXEL_FORMAT_RAW16:
+ case HAL_PIXEL_FORMAT_RAW12:
case HAL_PIXEL_FORMAT_RAW10:
case HAL_PIXEL_FORMAT_RAW_OPAQUE:
case HAL_PIXEL_FORMAT_BLOB:
diff --git a/media/native/midi/amidi.cpp b/media/native/midi/amidi.cpp
index 923377c8180e..f90796e415c0 100644
--- a/media/native/midi/amidi.cpp
+++ b/media/native/midi/amidi.cpp
@@ -325,8 +325,8 @@ public:
}
uint8_t readBuffer[AMIDI_PACKET_SIZE];
- ssize_t readCount = read(mPort->ufd, readBuffer, sizeof(readBuffer));
- if (readCount == EINTR || readCount < 1) {
+ ssize_t readCount = TEMP_FAILURE_RETRY(read(mPort->ufd, readBuffer, sizeof(readBuffer)));
+ if (readCount < 1) {
return AMEDIA_ERROR_UNKNOWN;
}
@@ -407,7 +407,8 @@ ssize_t AMIDI_API AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPo
ssize_t numTransferBytes =
AMIDI_makeSendBuffer(writeBuffer, data + numSent, blockSize, timestamp);
- ssize_t numWritten = write(((AMIDI_Port*)inputPort)->ufd, writeBuffer, numTransferBytes);
+ ssize_t numWritten = TEMP_FAILURE_RETRY(write(((AMIDI_Port*)inputPort)->ufd, writeBuffer,
+ numTransferBytes));
if (numWritten < 0) {
break; // error so bail out.
}
@@ -430,7 +431,8 @@ media_status_t AMIDI_API AMidiInputPort_sendFlush(const AMidiInputPort *inputPor
uint8_t opCode = AMIDI_OPCODE_FLUSH;
ssize_t numTransferBytes = 1;
- ssize_t numWritten = write(((AMIDI_Port*)inputPort)->ufd, &opCode, numTransferBytes);
+ ssize_t numWritten = TEMP_FAILURE_RETRY(write(((AMIDI_Port*)inputPort)->ufd, &opCode,
+ numTransferBytes));
if (numWritten < numTransferBytes) {
ALOGE("AMidiInputPort_flush Couldn't write MIDI flush. requested:%zd, written:%zd",
diff --git a/mms/OWNERS b/mms/OWNERS
index 7f05a2a24d6e..f56845ed80c7 100644
--- a/mms/OWNERS
+++ b/mms/OWNERS
@@ -3,16 +3,15 @@ set noparent
tgunn@google.com
breadley@google.com
rgreenwalt@google.com
-amitmahajan@google.com
fionaxu@google.com
jackyu@google.com
jminjie@google.com
satk@google.com
shuoq@google.com
-nazaninb@google.com
sarahchin@google.com
xiaotonj@google.com
huiwang@google.com
jayachandranc@google.com
chinmayd@google.com
amruthr@google.com
+sasindran@google.com
diff --git a/omapi/aidl/Android.bp b/omapi/aidl/Android.bp
new file mode 100644
index 000000000000..2b81200f0079
--- /dev/null
+++ b/omapi/aidl/Android.bp
@@ -0,0 +1,35 @@
+// 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.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+ name: "android.se.omapi",
+ vendor_available: true,
+ srcs: ["android/se/omapi/*.aidl"],
+ stability: "vintf",
+ backend: {
+ java: {
+ sdk_version: "module_current",
+ },
+ rust: {
+ enabled: true,
+ },
+ ndk: {
+ separate_platform_variant: false,
+ },
+ },
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementChannel.aidl b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementChannel.aidl
new file mode 100644
index 000000000000..725013a35cde
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementChannel.aidl
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementChannel {
+ void close();
+ boolean isClosed();
+ boolean isBasicChannel();
+ byte[] getSelectResponse();
+ byte[] transmit(in byte[] command);
+ boolean selectNext();
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementListener.aidl b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementListener.aidl
new file mode 100644
index 000000000000..77e1c53f47ac
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementListener.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementListener {
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementReader.aidl b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementReader.aidl
new file mode 100644
index 000000000000..2b10c473c902
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementReader.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementReader {
+ boolean isSecureElementPresent();
+ android.se.omapi.ISecureElementSession openSession();
+ void closeSessions();
+ boolean reset();
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementService.aidl b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementService.aidl
new file mode 100644
index 000000000000..0c8e431d18a1
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementService.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *//*
+ * Copyright (c) 2015-2017, The Linux Foundation.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementService {
+ String[] getReaders();
+ android.se.omapi.ISecureElementReader getReader(in String reader);
+ boolean[] isNfcEventAllowed(in String reader, in byte[] aid, in String[] packageNames, in int userId);
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementSession.aidl b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementSession.aidl
new file mode 100644
index 000000000000..06287c551f5c
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/current/android/se/omapi/ISecureElementSession.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *//*
+ * Copyright (c) 2015-2017, The Linux Foundation.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementSession {
+ byte[] getAtr();
+ void close();
+ void closeChannels();
+ boolean isClosed();
+ android.se.omapi.ISecureElementChannel openBasicChannel(in byte[] aid, in byte p2, in android.se.omapi.ISecureElementListener listener);
+ android.se.omapi.ISecureElementChannel openLogicalChannel(in byte[] aid, in byte p2, in android.se.omapi.ISecureElementListener listener);
+}
diff --git a/core/java/android/se/omapi/ISecureElementChannel.aidl b/omapi/aidl/android/se/omapi/ISecureElementChannel.aidl
index 4ae57ab829cb..bbd3c148caaf 100644
--- a/core/java/android/se/omapi/ISecureElementChannel.aidl
+++ b/omapi/aidl/android/se/omapi/ISecureElementChannel.aidl
@@ -22,6 +22,7 @@ package android.se.omapi;
import android.se.omapi.ISecureElementSession;
/** @hide */
+@VintfStability
interface ISecureElementChannel {
/**
@@ -58,6 +59,9 @@ interface ISecureElementChannel {
* Transmits the specified command APDU and returns the response APDU.
* MANAGE channel commands are not supported.
* Selection of applets is not supported in logical channels.
+ *
+ * @param command Command APDU, its structure is defined in ISO/IEC 7816-4
+ * in Standard byte format
*/
byte[] transmit(in byte[] command);
diff --git a/core/java/android/se/omapi/ISecureElementListener.aidl b/omapi/aidl/android/se/omapi/ISecureElementListener.aidl
index e9dd18181c56..479dcd7d5acf 100644
--- a/core/java/android/se/omapi/ISecureElementListener.aidl
+++ b/omapi/aidl/android/se/omapi/ISecureElementListener.aidl
@@ -23,5 +23,6 @@ package android.se.omapi;
* Interface to receive call-backs when the service is connected.
* @hide
*/
+@VintfStability
interface ISecureElementListener {
}
diff --git a/core/java/android/se/omapi/ISecureElementReader.aidl b/omapi/aidl/android/se/omapi/ISecureElementReader.aidl
index 41244ab058e0..a6979face61f 100644
--- a/core/java/android/se/omapi/ISecureElementReader.aidl
+++ b/omapi/aidl/android/se/omapi/ISecureElementReader.aidl
@@ -22,6 +22,7 @@ package android.se.omapi;
import android.se.omapi.ISecureElementSession;
/** @hide */
+@VintfStability
interface ISecureElementReader {
/**
@@ -34,7 +35,7 @@ interface ISecureElementReader {
* Connects to a secure element in this reader. <br>
* This method prepares (initialises) the Secure Element for communication
* before the Session object is returned (e.g. powers the Secure Element by
- * ICC ON if its not already on). There might be multiple sessions opened at
+ * ICC ON if it is not already on). There might be multiple sessions opened at
* the same time on the same reader. The system ensures the interleaving of
* APDUs between the respective sessions.
*
diff --git a/core/java/android/se/omapi/ISecureElementService.aidl b/omapi/aidl/android/se/omapi/ISecureElementService.aidl
index 4fa799e78757..13707ec22b5c 100644
--- a/core/java/android/se/omapi/ISecureElementService.aidl
+++ b/omapi/aidl/android/se/omapi/ISecureElementService.aidl
@@ -28,23 +28,31 @@ import android.se.omapi.ISecureElementReader;
* SecureElement service interface.
* @hide
*/
+@VintfStability
interface ISecureElementService {
/**
* Returns the friendly names of available Secure Element readers.
+ * <ul>
+ * <li>If the reader is a SIM reader, then its name must be "SIM[Slot]".</li>
+ * <li>If the reader is a SD or micro SD reader, then its name must be "SD[Slot]"</li>
+ * <li>If the reader is a embedded SE reader, then its name must be "eSE[Slot]"</li>
+ * </ul>
+ * Slot is a decimal number without leading zeros. The Numbering must start with 1
+ * (e.g. SIM1, SIM2, ... or SD1, SD2, ... or eSE1, eSE2, ...).
*/
String[] getReaders();
/**
* Returns SecureElement Service reader object to the given name.
*/
- ISecureElementReader getReader(String reader);
+ ISecureElementReader getReader(in String reader);
/**
* Checks if the application defined by the package name is allowed to
* receive NFC transaction events for the defined AID.
*/
- boolean[] isNFCEventAllowed(String reader, in byte[] aid,
- in String[] packageNames);
+ boolean[] isNfcEventAllowed(in String reader, in byte[] aid,
+ in String[] packageNames, in int userId);
}
diff --git a/core/java/android/se/omapi/ISecureElementSession.aidl b/omapi/aidl/android/se/omapi/ISecureElementSession.aidl
index 8ea599f2e866..129ecc4ddaa3 100644
--- a/core/java/android/se/omapi/ISecureElementSession.aidl
+++ b/omapi/aidl/android/se/omapi/ISecureElementSession.aidl
@@ -27,6 +27,7 @@ import android.se.omapi.ISecureElementReader;
import android.se.omapi.ISecureElementListener;
/** @hide */
+@VintfStability
interface ISecureElementSession {
/**
@@ -45,7 +46,6 @@ interface ISecureElementSession {
*/
void closeChannels();
-
/**
* Tells if this session is closed.
*
@@ -59,15 +59,19 @@ interface ISecureElementSession {
* applet if aid != null.
* Logical channels cannot be opened with this connection.
* Use interface method openLogicalChannel() to open a logical channel.
+ * Listener is passed to secure element service and used to monitor whether
+ * the client application that uses OMAPI is still alive or not.
*/
ISecureElementChannel openBasicChannel(in byte[] aid, in byte p2,
- ISecureElementListener listener);
+ in ISecureElementListener listener);
/**
* Opens a connection using the next free logical channel of the card in the
* specified reader. Selects the specified applet.
* Selection of other applets with this connection is not supported.
+ * Listener is passed to secure element service and used to monitor whether
+ * the client application that uses OMAPI is still alive or not.
*/
ISecureElementChannel openLogicalChannel(in byte[] aid, in byte p2,
- ISecureElementListener listener);
+ in ISecureElementListener listener);
}
diff --git a/omapi/aidl/vts/functional/AccessControlApp/Android.bp b/omapi/aidl/vts/functional/AccessControlApp/Android.bp
new file mode 100644
index 000000000000..f03c3f6eb647
--- /dev/null
+++ b/omapi/aidl/vts/functional/AccessControlApp/Android.bp
@@ -0,0 +1,54 @@
+//
+// 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+ name: "VtsHalOmapiSeAccessControlTestCases",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "VtsHalOmapiSeAccessControlTestCases.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libnativehelper",
+ "libutils",
+ "libbinder_ndk",
+ ],
+ static_libs: [
+ "VtsHalHidlTargetTestBase",
+ "android.se.omapi-V1-ndk",
+ ],
+ cflags: [
+ "-O0",
+ "-g",
+ "-Wall",
+ "-Werror",
+ ],
+ require_root: true,
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/omapi/aidl/vts/functional/AccessControlApp/VtsHalOmapiSeAccessControlTestCases.cpp b/omapi/aidl/vts/functional/AccessControlApp/VtsHalOmapiSeAccessControlTestCases.cpp
new file mode 100644
index 000000000000..9ea65431417a
--- /dev/null
+++ b/omapi/aidl/vts/functional/AccessControlApp/VtsHalOmapiSeAccessControlTestCases.cpp
@@ -0,0 +1,428 @@
+/*
+ * 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.
+ */
+
+#include <aidl/android/se/omapi/BnSecureElementListener.h>
+#include <aidl/android/se/omapi/ISecureElementChannel.h>
+#include <aidl/android/se/omapi/ISecureElementListener.h>
+#include <aidl/android/se/omapi/ISecureElementReader.h>
+#include <aidl/android/se/omapi/ISecureElementService.h>
+#include <aidl/android/se/omapi/ISecureElementSession.h>
+
+#include <VtsCoreUtil.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+#include <cutils/properties.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <utils/String16.h>
+
+using namespace std;
+using namespace ::testing;
+using namespace android;
+
+int main(int argc, char** argv) {
+ InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ return status;
+}
+
+namespace {
+
+class OMAPISEAccessControlTest : public TestWithParam<std::string> {
+ protected:
+
+ class SEListener : public ::aidl::android::se::omapi::BnSecureElementListener {};
+
+ /**
+ * Verifies TLV data
+ *
+ * @return true if the data is tlv formatted, false otherwise
+ */
+ bool verifyBerTlvData(std::vector<uint8_t> tlv) {
+ if (tlv.size() == 0) {
+ LOG(ERROR) << "Invalid tlv, null";
+ return false;
+ }
+ int i = 0;
+ if ((tlv[i++] & 0x1F) == 0x1F) {
+ // extra byte for TAG field
+ i++;
+ }
+
+ int len = tlv[i++] & 0xFF;
+ if (len > 127) {
+ // more than 1 byte for length
+ int bytesLength = len - 128;
+ len = 0;
+ for (int j = bytesLength; j > 0; j--) {
+ len += (len << 8) + (tlv[i++] & 0xFF);
+ }
+ }
+ // Additional 2 bytes for the SW
+ return (tlv.size() == (i + len + 2));
+ }
+
+ void testSelectableAid(
+ std::vector<std::vector<uint8_t>> authorizedAids) {
+ for (auto aid : authorizedAids) {
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+ auto seListener = ndk::SharedRefBase::make<SEListener>();
+
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ std::vector<uint8_t> selectResponse = {};
+ ASSERT_NE(reader, nullptr) << "reader is null";
+
+ bool status = false;
+ auto res = reader->isSecureElementPresent(&status);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_TRUE(status);
+
+ res = reader->openSession(&session);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_NE(session, nullptr) << "Could not open session";
+
+ res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_NE(channel, nullptr) << "Could not open channel";
+
+ res = channel->getSelectResponse(&selectResponse);
+ ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
+ ASSERT_GE(selectResponse.size(), 2);
+
+ if (channel != nullptr) channel->close();
+ if (session != nullptr) session->close();
+
+ ASSERT_EQ((selectResponse[selectResponse.size() - 1] & 0xFF), (0x00));
+ ASSERT_EQ((selectResponse[selectResponse.size() - 2] & 0xFF), (0x90));
+ ASSERT_TRUE(
+ verifyBerTlvData(selectResponse)) << "Select Response is not complete";
+ }
+ }
+ }
+ }
+
+ void testUnauthorisedAid(
+ std::vector<std::vector<uint8_t>> unAuthorizedAids) {
+ for (auto aid : unAuthorizedAids) {
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+ auto seListener = ndk::SharedRefBase::make<SEListener>();
+
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ ASSERT_NE(reader, nullptr) << "reader is null";
+
+ bool status = false;
+ auto res = reader->isSecureElementPresent(&status);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_TRUE(status);
+
+ res = reader->openSession(&session);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_NE(session, nullptr) << "Could not open session";
+
+ res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
+
+ if (channel != nullptr) channel->close();
+ if (session != nullptr) session->close();
+
+ if (!res.isOk()) {
+ ASSERT_EQ(res.getExceptionCode(), EX_SECURITY);
+ ASSERT_FALSE(res.isOk()) << "expected failed status for this test";
+ }
+ }
+ }
+ }
+ }
+
+ void testTransmitAPDU(
+ std::vector<uint8_t> aid,
+ std::vector<std::vector<uint8_t>> apdus) {
+ for (auto apdu : apdus) {
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+ auto seListener = ndk::SharedRefBase::make<SEListener>();
+
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ ASSERT_NE(reader, nullptr) << "reader is null";
+ bool status = false;
+ std::vector<uint8_t> selectResponse = {};
+ std::vector<uint8_t> transmitResponse = {};
+ auto res = reader->isSecureElementPresent(&status);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_TRUE(status);
+
+ res = reader->openSession(&session);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_NE(session, nullptr) << "Could not open session";
+
+ res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_NE(channel, nullptr) << "Could not open channel";
+
+ res = channel->getSelectResponse(&selectResponse);
+ ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
+ ASSERT_GE(selectResponse.size(), 2);
+ ASSERT_EQ((selectResponse[selectResponse.size() - 1] & 0xFF), (0x00));
+ ASSERT_EQ((selectResponse[selectResponse.size() - 2] & 0xFF), (0x90));
+ ASSERT_TRUE(
+ verifyBerTlvData(selectResponse)) << "Select Response is not complete";
+
+ res = channel->transmit(apdu, &transmitResponse);
+ LOG(INFO) << "STATUS OF TRNSMIT: " << res.getExceptionCode()
+ << " Message: " << res.getMessage();
+ if (channel != nullptr) channel->close();
+ if (session != nullptr) session->close();
+ ASSERT_TRUE(res.isOk()) << "failed to transmit";
+ }
+ }
+ }
+ }
+
+ void testUnauthorisedAPDU(
+ std::vector<uint8_t> aid,
+ std::vector<std::vector<uint8_t>> apdus) {
+ for (auto apdu : apdus) {
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+ auto seListener = ndk::SharedRefBase::make<SEListener>();
+
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ ASSERT_NE(reader, nullptr) << "reader is null";
+ bool status = false;
+ std::vector<uint8_t> selectResponse = {};
+ std::vector<uint8_t> transmitResponse = {};
+ auto res = reader->isSecureElementPresent(&status);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_TRUE(status);
+
+ res = reader->openSession(&session);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_NE(session, nullptr) << "Could not open session";
+
+ res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_NE(channel, nullptr) << "Could not open channel";
+
+ res = channel->getSelectResponse(&selectResponse);
+ ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
+ ASSERT_GE(selectResponse.size(), 2);
+ ASSERT_EQ((selectResponse[selectResponse.size() - 1] & 0xFF), (0x00));
+ ASSERT_EQ((selectResponse[selectResponse.size() - 2] & 0xFF), (0x90));
+ ASSERT_TRUE(
+ verifyBerTlvData(selectResponse)) << "Select Response is not complete";
+
+ res = channel->transmit(apdu, &transmitResponse);
+ LOG(INFO) << "STATUS OF TRNSMIT: " << res.getExceptionCode()
+ << " Message: " << res.getMessage();
+
+ if (channel != nullptr) channel->close();
+ if (session != nullptr) session->close();
+ if (!res.isOk()) {
+ ASSERT_EQ(res.getExceptionCode(), EX_SECURITY);
+ ASSERT_FALSE(res.isOk()) << "expected failed status for this test";
+ }
+ }
+ }
+ }
+ }
+
+ bool supportOMAPIReaders() {
+ return (deviceSupportsFeature(FEATURE_SE_OMAPI_ESE.c_str()));
+ }
+
+ void getFirstApiLevel(int32_t* outApiLevel) {
+ int32_t firstApiLevel = property_get_int32(FEATURE_SE_API_LEVEL.c_str(), -1);
+ if (firstApiLevel < 0) {
+ firstApiLevel = property_get_int32(FEATURE_SE_SDK_VERSION.c_str(), -1);
+ }
+ ASSERT_GT(firstApiLevel, 0); // first_api_level must exist
+ *outApiLevel = firstApiLevel;
+ return;
+ }
+
+ bool supportsHardware() {
+ bool lowRamDevice = property_get_bool(FEATURE_SE_LOW_RAM.c_str(), true);
+ return !lowRamDevice || deviceSupportsFeature(FEATURE_SE_HARDWARE_WATCH.c_str()) ||
+ deviceSupportsFeature(FEATURE_SE_OMAPI_SERVICE.c_str()); // android.se.omapi
+ }
+
+ void SetUp() override {
+ ASSERT_TRUE(supportsHardware());
+ int32_t apiLevel;
+ getFirstApiLevel(&apiLevel);
+ ASSERT_TRUE(apiLevel > 27);
+ ASSERT_TRUE(supportOMAPIReaders());
+ LOG(INFO) << "get OMAPI service with name:" << GetParam();
+ ::ndk::SpAIBinder ks2Binder(AServiceManager_getService(GetParam().c_str()));
+ mOmapiSeService = aidl::android::se::omapi::ISecureElementService::fromBinder(ks2Binder);
+ ASSERT_TRUE(mOmapiSeService);
+
+ std::vector<std::string> readers = {};
+
+ if (mOmapiSeService != NULL) {
+ auto status = mOmapiSeService->getReaders(&readers);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+ for (auto readerName : readers) {
+ // Filter eSE readers only
+ if (readerName.find(ESE_READER_PREFIX, 0) != std::string::npos) {
+ std::shared_ptr<::aidl::android::se::omapi::ISecureElementReader> reader;
+ status = mOmapiSeService->getReader(readerName, &reader);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+ mVSReaders[readerName] = reader;
+ }
+ }
+ }
+ }
+
+ void TearDown() override {
+ if (mOmapiSeService != nullptr) {
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ reader->closeSessions();
+ }
+ }
+ }
+ }
+
+ static inline std::string const ESE_READER_PREFIX = "eSE";
+ static inline std::string const FEATURE_SE_OMAPI_ESE = "android.hardware.se.omapi.ese";
+ static inline std::string const FEATURE_SE_LOW_RAM = "ro.config.low_ram";
+ static inline std::string const FEATURE_SE_HARDWARE_WATCH = "android.hardware.type.watch";
+ static inline std::string const FEATURE_SE_OMAPI_SERVICE = "com.android.se";
+ static inline std::string const FEATURE_SE_SDK_VERSION = "ro.build.version.sdk";
+ static inline std::string const FEATURE_SE_API_LEVEL = "ro.product.first_api_level";
+
+ std::vector<uint8_t> AID_40 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x40};
+ std::vector<uint8_t> AID_41 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x41};
+ std::vector<uint8_t> AID_42 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x42};
+ std::vector<uint8_t> AID_43 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x43};
+ std::vector<uint8_t> AID_44 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x44};
+ std::vector<uint8_t> AID_45 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x45};
+ std::vector<uint8_t> AID_46 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x46};
+ std::vector<uint8_t> AID_47 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x47};
+ std::vector<uint8_t> AID_48 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x48};
+ std::vector<uint8_t> AID_49 = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x49};
+ std::vector<uint8_t> AID_4A = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4A};
+ std::vector<uint8_t> AID_4B = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4B};
+ std::vector<uint8_t> AID_4C = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4C};
+ std::vector<uint8_t> AID_4D = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4D};
+ std::vector<uint8_t> AID_4E = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4E};
+ std::vector<uint8_t> AID_4F = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x4F};
+
+ std::vector<std::vector<uint8_t>> AUTHORIZED_AID = {AID_40, AID_41, AID_42, AID_44, AID_45,
+ AID_47, AID_48, AID_49, AID_4A, AID_4B,
+ AID_4C, AID_4D, AID_4E, AID_4F};
+ std::vector<std::vector<uint8_t>> UNAUTHORIZED_AID = {AID_43, AID_46};
+
+ /* Authorized APDU for AID_40 */
+ std::vector<std::vector<uint8_t>> AUTHORIZED_APDU_AID_40 = {
+ {0x00, 0x06, 0x00, 0x00},
+ {0xA0, 0x06, 0x00, 0x00},
+ };
+ /* Unauthorized APDU for AID_40 */
+ std::vector<std::vector<uint8_t>> UNAUTHORIZED_APDU_AID_40 = {
+ {0x00, 0x08, 0x00, 0x00, 0x00},
+ {0x80, 0x06, 0x00, 0x00},
+ {0xA0, 0x08, 0x00, 0x00, 0x00},
+ {0x94, 0x06, 0x00, 0x00, 0x00},
+ };
+
+ /* Authorized APDU for AID_41 */
+ std::vector<std::vector<uint8_t>> AUTHORIZED_APDU_AID_41 = {
+ {0x94, 0x06, 0x00, 0x00},
+ {0x94, 0x08, 0x00, 0x00, 0x00},
+ {0x94, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
+ {0x94, 0x0A, 0x00, 0x00, 0x01, 0xAA}};
+ /* Unauthorized APDU for AID_41 */
+ std::vector<std::vector<uint8_t>> UNAUTHORIZED_APDU_AID_41 = {
+ {0x00, 0x06, 0x00, 0x00},
+ {0x80, 0x06, 0x00, 0x00},
+ {0xA0, 0x06, 0x00, 0x00},
+ {0x00, 0x08, 0x00, 0x00, 0x00},
+ {0x00, 0x0A, 0x00, 0x00, 0x01, 0xAA},
+ {0x80, 0x0A, 0x00, 0x00, 0x01, 0xAA},
+ {0xA0, 0x0A, 0x00, 0x00, 0x01, 0xAA},
+ {0x80, 0x08, 0x00, 0x00, 0x00},
+ {0xA0, 0x08, 0x00, 0x00, 0x00},
+ {0x00, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
+ {0x80, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
+ {0xA0, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
+ };
+
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementService> mOmapiSeService;
+
+ std::map<std::string, std::shared_ptr<aidl::android::se::omapi::ISecureElementReader>>
+ mVSReaders = {};
+};
+
+TEST_P(OMAPISEAccessControlTest, TestAuthorizedAID) {
+ testSelectableAid(AUTHORIZED_AID);
+}
+
+TEST_P(OMAPISEAccessControlTest, TestUnauthorizedAID) {
+ testUnauthorisedAid(UNAUTHORIZED_AID);
+}
+
+TEST_P(OMAPISEAccessControlTest, TestAuthorizedAPDUAID40) {
+ testTransmitAPDU(AID_40, AUTHORIZED_APDU_AID_40);
+}
+
+TEST_P(OMAPISEAccessControlTest, TestUnauthorisedAPDUAID40) {
+ testUnauthorisedAPDU(AID_40, UNAUTHORIZED_APDU_AID_40);
+}
+
+TEST_P(OMAPISEAccessControlTest, TestAuthorizedAPDUAID41) {
+ testTransmitAPDU(AID_41, AUTHORIZED_APDU_AID_41);
+}
+
+TEST_P(OMAPISEAccessControlTest, TestUnauthorisedAPDUAID41) {
+ testUnauthorisedAPDU(AID_41, UNAUTHORIZED_APDU_AID_41);
+}
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, OMAPISEAccessControlTest,
+ testing::ValuesIn(::android::getAidlHalInstanceNames(
+ aidl::android::se::omapi::ISecureElementService::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OMAPISEAccessControlTest);
+
+} // namespace
diff --git a/omapi/aidl/vts/functional/omapi/Android.bp b/omapi/aidl/vts/functional/omapi/Android.bp
new file mode 100644
index 000000000000..c3ab8d13920c
--- /dev/null
+++ b/omapi/aidl/vts/functional/omapi/Android.bp
@@ -0,0 +1,54 @@
+//
+// 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+ name: "VtsHalOmapiSeServiceV1_TargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "VtsHalOmapiSeServiceV1_TargetTest.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libnativehelper",
+ "libutils",
+ "libbinder_ndk",
+ ],
+ static_libs: [
+ "VtsHalHidlTargetTestBase",
+ "android.se.omapi-V1-ndk",
+ ],
+ cflags: [
+ "-O0",
+ "-g",
+ "-Wall",
+ "-Werror",
+ ],
+ require_root: true,
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/omapi/aidl/vts/functional/omapi/VtsHalOmapiSeServiceV1_TargetTest.cpp b/omapi/aidl/vts/functional/omapi/VtsHalOmapiSeServiceV1_TargetTest.cpp
new file mode 100644
index 000000000000..319cb7e70884
--- /dev/null
+++ b/omapi/aidl/vts/functional/omapi/VtsHalOmapiSeServiceV1_TargetTest.cpp
@@ -0,0 +1,609 @@
+/*
+ * 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.
+ */
+
+#include <aidl/android/se/omapi/BnSecureElementListener.h>
+#include <aidl/android/se/omapi/ISecureElementChannel.h>
+#include <aidl/android/se/omapi/ISecureElementListener.h>
+#include <aidl/android/se/omapi/ISecureElementReader.h>
+#include <aidl/android/se/omapi/ISecureElementService.h>
+#include <aidl/android/se/omapi/ISecureElementSession.h>
+
+#include <VtsCoreUtil.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+#include <cutils/properties.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <utils/String16.h>
+
+using namespace std;
+using namespace ::testing;
+using namespace android;
+
+int main(int argc, char** argv) {
+ InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ return status;
+}
+
+namespace {
+
+class OMAPISEServiceHalTest : public TestWithParam<std::string> {
+ protected:
+ class SEListener : public ::aidl::android::se::omapi::BnSecureElementListener {};
+
+ void testSelectableAid(
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementReader> reader,
+ std::vector<uint8_t> aid, std::vector<uint8_t>& selectResponse) {
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+ auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
+
+ ASSERT_NE(reader, nullptr) << "reader is null";
+
+ bool status = false;
+ auto res = reader->isSecureElementPresent(&status);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_TRUE(status);
+
+ res = reader->openSession(&session);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_NE(session, nullptr) << "Could not open session";
+
+ res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_NE(channel, nullptr) << "Could not open channel";
+
+ res = channel->getSelectResponse(&selectResponse);
+ ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
+ ASSERT_GE(selectResponse.size(), 2);
+
+ if (channel != nullptr) channel->close();
+ if (session != nullptr) session->close();
+
+ ASSERT_EQ((selectResponse[selectResponse.size() - 1] & 0xFF), (0x00));
+ ASSERT_EQ((selectResponse[selectResponse.size() - 2] & 0xFF), (0x90));
+ }
+
+ void testNonSelectableAid(
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementReader> reader,
+ std::vector<uint8_t> aid) {
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+ auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
+
+ ASSERT_NE(reader, nullptr) << "reader is null";
+
+ bool status = false;
+ auto res = reader->isSecureElementPresent(&status);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_TRUE(status);
+
+ res = reader->openSession(&session);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_NE(session, nullptr) << "Could not open session";
+
+ res = session->openLogicalChannel(aid, 0x00, seListener, &channel);
+ if (channel != nullptr) channel->close();
+ if (session != nullptr) session->close();
+
+ LOG(ERROR) << res.getMessage();
+ ASSERT_FALSE(res.isOk()) << "expected to fail to open channel for this test";
+ }
+
+ /**
+ * Verifies TLV data
+ *
+ * @return true if the data is tlv formatted, false otherwise
+ */
+ bool verifyBerTlvData(std::vector<uint8_t> tlv) {
+ if (tlv.size() == 0) {
+ LOG(ERROR) << "Invalid tlv, null";
+ return false;
+ }
+ int i = 0;
+ if ((tlv[i++] & 0x1F) == 0x1F) {
+ // extra byte for TAG field
+ i++;
+ }
+
+ int len = tlv[i++] & 0xFF;
+ if (len > 127) {
+ // more than 1 byte for length
+ int bytesLength = len - 128;
+ len = 0;
+ for (int j = bytesLength; j > 0; j--) {
+ len += (len << 8) + (tlv[i++] & 0xFF);
+ }
+ }
+ // Additional 2 bytes for the SW
+ return (tlv.size() == (i + len + 2));
+ }
+
+ void internalTransmitApdu(
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementReader> reader,
+ std::vector<uint8_t> apdu, std::vector<uint8_t>& transmitResponse) {
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+ auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
+ std::vector<uint8_t> selectResponse = {};
+
+ ASSERT_NE(reader, nullptr) << "reader is null";
+
+ bool status = false;
+ auto res = reader->isSecureElementPresent(&status);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_TRUE(status);
+
+ res = reader->openSession(&session);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_NE(session, nullptr) << "Could not open session";
+
+ res = session->openLogicalChannel(SELECTABLE_AID, 0x00, seListener, &channel);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_NE(channel, nullptr) << "Could not open channel";
+
+ res = channel->getSelectResponse(&selectResponse);
+ ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
+ ASSERT_GE(selectResponse.size(), 2);
+
+ res = channel->transmit(apdu, &transmitResponse);
+ if (channel != nullptr) channel->close();
+ if (session != nullptr) session->close();
+ LOG(INFO) << "STATUS OF TRNSMIT: " << res.getExceptionCode()
+ << " Message: " << res.getMessage();
+ ASSERT_TRUE(res.isOk()) << "failed to transmit";
+ }
+
+ bool supportOMAPIReaders() {
+ return (deviceSupportsFeature(FEATURE_SE_OMAPI_ESE.c_str()));
+ }
+
+ void SetUp() override {
+ LOG(INFO) << "get OMAPI service with name:" << GetParam();
+ ::ndk::SpAIBinder ks2Binder(AServiceManager_getService(GetParam().c_str()));
+ mOmapiSeService = aidl::android::se::omapi::ISecureElementService::fromBinder(ks2Binder);
+ ASSERT_TRUE(mOmapiSeService);
+
+ std::vector<std::string> readers = {};
+
+ if (omapiSecureService() != NULL) {
+ auto status = omapiSecureService()->getReaders(&readers);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+ for (auto readerName : readers) {
+ // Filter eSE readers only
+ if (readerName.find(ESE_READER_PREFIX, 0) != std::string::npos) {
+ std::shared_ptr<::aidl::android::se::omapi::ISecureElementReader> reader;
+ status = omapiSecureService()->getReader(readerName, &reader);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+ mVSReaders[readerName] = reader;
+ }
+ }
+ }
+ }
+
+ void TearDown() override {
+ if (mOmapiSeService != nullptr) {
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ reader->closeSessions();
+ }
+ }
+ }
+ }
+
+ bool isDebuggableBuild() {
+ char value[PROPERTY_VALUE_MAX] = {0};
+ property_get("ro.system.build.type", value, "");
+ if (strcmp(value, "userdebug") == 0) {
+ return true;
+ }
+ if (strcmp(value, "eng") == 0) {
+ return true;
+ }
+ return false;
+ }
+
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementService> omapiSecureService() {
+ return mOmapiSeService;
+ }
+
+ static inline std::string const ESE_READER_PREFIX = "eSE";
+ static inline std::string const FEATURE_SE_OMAPI_ESE = "android.hardware.se.omapi.ese";
+
+ std::vector<uint8_t> SELECTABLE_AID = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x31};
+ std::vector<uint8_t> LONG_SELECT_RESPONSE_AID = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41,
+ 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64,
+ 0x43, 0x54, 0x53, 0x32};
+ std::vector<uint8_t> NON_SELECTABLE_AID = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
+ 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0xFF};
+
+ std::vector<std::vector<uint8_t>> ILLEGAL_COMMANDS_TRANSMIT = {
+ {0x00, 0x70, 0x00, 0x00},
+ {0x00, 0x70, 0x80, 0x00},
+ {0x00, 0xA4, 0x04, 0x04, 0x10, 0x4A, 0x53, 0x52, 0x31, 0x37, 0x37,
+ 0x54, 0x65, 0x73, 0x74, 0x65, 0x72, 0x20, 0x31, 0x2E, 0x30}};
+
+ /* OMAPI APDU Test case 1 and 3 */
+ std::vector<std::vector<uint8_t>> NO_DATA_APDU = {{0x00, 0x06, 0x00, 0x00},
+ {0x80, 0x06, 0x00, 0x00},
+ {0xA0, 0x06, 0x00, 0x00},
+ {0x94, 0x06, 0x00, 0x00},
+ {0x00, 0x0A, 0x00, 0x00, 0x01, 0xAA},
+ {0x80, 0x0A, 0x00, 0x00, 0x01, 0xAA},
+ {0xA0, 0x0A, 0x00, 0x00, 0x01, 0xAA},
+ {0x94, 0x0A, 0x00, 0x00, 0x01, 0xAA}};
+
+ /* OMAPI APDU Test case 2 and 4 */
+ std::vector<std::vector<uint8_t>> DATA_APDU = {{0x00, 0x08, 0x00, 0x00, 0x00},
+ {0x80, 0x08, 0x00, 0x00, 0x00},
+ {0xA0, 0x08, 0x00, 0x00, 0x00},
+ {0x94, 0x08, 0x00, 0x00, 0x00},
+ {0x00, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
+ {0x80, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
+ {0xA0, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00},
+ {0x94, 0x0C, 0x00, 0x00, 0x01, 0xAA, 0x00}};
+
+ /* Case 2 APDU command expects the P2 received in the SELECT command as 1-byte outgoing data */
+ std::vector<uint8_t> CHECK_SELECT_P2_APDU = {0x00, 0xF4, 0x00, 0x00, 0x00};
+
+ /* OMAPI APDU Test case 1 and 3 */
+ std::vector<std::vector<uint8_t>> SW_62xx_NO_DATA_APDU = {{0x00, 0xF3, 0x00, 0x06},
+ {0x00, 0xF3, 0x00, 0x0A, 0x01, 0xAA}};
+
+ /* OMAPI APDU Test case 2 and 4 */
+ std::vector<uint8_t> SW_62xx_DATA_APDU = {0x00, 0xF3, 0x00, 0x08, 0x00};
+ std::vector<uint8_t> SW_62xx_VALIDATE_DATA_APDU = {0x00, 0xF3, 0x00, 0x0C, 0x01, 0xAA, 0x00};
+ std::vector<std::vector<uint8_t>> SW_62xx = {
+ {0x62, 0x00}, {0x62, 0x81}, {0x62, 0x82}, {0x62, 0x83}, {0x62, 0x85}, {0x62, 0xF1},
+ {0x62, 0xF2}, {0x63, 0xF1}, {0x63, 0xF2}, {0x63, 0xC2}, {0x62, 0x02}, {0x62, 0x80},
+ {0x62, 0x84}, {0x62, 0x86}, {0x63, 0x00}, {0x63, 0x81}};
+
+ std::vector<std::vector<uint8_t>> SEGMENTED_RESP_APDU = {
+ // Get response Case2 61FF+61XX with answer length (P1P2) of 0x0800, 2048 bytes
+ {0x00, 0xC2, 0x08, 0x00, 0x00},
+ // Get response Case4 61FF+61XX with answer length (P1P2) of 0x0800, 2048 bytes
+ {0x00, 0xC4, 0x08, 0x00, 0x02, 0x12, 0x34, 0x00},
+ // Get response Case2 6100+61XX with answer length (P1P2) of 0x0800, 2048 bytes
+ {0x00, 0xC6, 0x08, 0x00, 0x00},
+ // Get response Case4 6100+61XX with answer length (P1P2) of 0x0800, 2048 bytes
+ {0x00, 0xC8, 0x08, 0x00, 0x02, 0x12, 0x34, 0x00},
+ // Test device buffer capacity 7FFF data
+ {0x00, 0xC2, 0x7F, 0xFF, 0x00},
+ // Get response 6CFF+61XX with answer length (P1P2) of 0x0800, 2048 bytes
+ {0x00, 0xCF, 0x08, 0x00, 0x00},
+ // Get response with another CLA with answer length (P1P2) of 0x0800, 2048 bytes
+ {0x94, 0xC2, 0x08, 0x00, 0x00}};
+ long SERVICE_CONNECTION_TIME_OUT = 3000;
+
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementService> mOmapiSeService;
+
+ std::map<std::string, std::shared_ptr<aidl::android::se::omapi::ISecureElementReader>>
+ mVSReaders = {};
+};
+
+/** Tests getReaders API */
+TEST_P(OMAPISEServiceHalTest, TestGetReaders) {
+ std::vector<std::shared_ptr<aidl::android::se::omapi::ISecureElementReader>> eseReaders =
+ {};
+
+ for (const auto& [name, reader] : mVSReaders) {
+ bool status = false;
+ LOG(INFO) << "Name of the reader: " << name;
+
+ if (reader) {
+ auto res = reader->isSecureElementPresent(&status);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ }
+ ASSERT_TRUE(status);
+
+ if (name.find(ESE_READER_PREFIX) == std::string::npos) {
+ LOG(ERROR) << "Incorrect Reader name";
+ FAIL();
+ }
+
+ if (name.find(ESE_READER_PREFIX, 0) != std::string::npos) {
+ eseReaders.push_back(reader);
+ } else {
+ LOG(INFO) << "Reader not supported: " << name;
+ FAIL();
+ }
+ }
+
+ if (deviceSupportsFeature(FEATURE_SE_OMAPI_ESE.c_str())) {
+ ASSERT_GE(eseReaders.size(), 1);
+ } else {
+ ASSERT_TRUE(eseReaders.size() == 0);
+ }
+}
+
+/** Tests OpenBasicChannel API when aid is null */
+TEST_P(OMAPISEServiceHalTest, TestOpenBasicChannelNullAid) {
+ ASSERT_TRUE(supportOMAPIReaders() == true);
+ std::vector<uint8_t> aid = {};
+ auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
+
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+ bool result = false;
+
+ auto status = reader->openSession(&session);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+ if (!session) {
+ LOG(ERROR) << "Could not open session";
+ FAIL();
+ }
+
+ status = session->openBasicChannel(aid, 0x00, seListener, &channel);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+ if (channel != nullptr) channel->close();
+ if (session != nullptr) session->close();
+
+ if (channel != nullptr) {
+ status = channel->isBasicChannel(&result);
+ ASSERT_TRUE(status.isOk()) << "Basic Channel cannot be opened";
+ }
+ }
+ }
+}
+
+/** Tests OpenBasicChannel API when aid is provided */
+TEST_P(OMAPISEServiceHalTest, TestOpenBasicChannelNonNullAid) {
+ ASSERT_TRUE(supportOMAPIReaders() == true);
+ auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
+
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+ bool result = false;
+
+ auto status = reader->openSession(&session);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+ if (!session) {
+ LOG(ERROR) << "Could not open session";
+ FAIL();
+ }
+
+ status = session->openBasicChannel(SELECTABLE_AID, 0x00, seListener, &channel);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+ if (channel != nullptr) channel->close();
+ if (session != nullptr) session->close();
+
+ if (channel != nullptr) {
+ status = channel->isBasicChannel(&result);
+ ASSERT_TRUE(status.isOk()) << "Basic Channel cannot be opened";
+ }
+ }
+ }
+}
+
+/** Tests Select API */
+TEST_P(OMAPISEServiceHalTest, TestSelectableAid) {
+ ASSERT_TRUE(supportOMAPIReaders() == true);
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ std::vector<uint8_t> selectResponse = {};
+ testSelectableAid(reader, SELECTABLE_AID, selectResponse);
+ }
+ }
+}
+
+/** Tests Select API */
+TEST_P(OMAPISEServiceHalTest, TestLongSelectResponse) {
+ ASSERT_TRUE(supportOMAPIReaders() == true);
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ std::vector<uint8_t> selectResponse = {};
+ testSelectableAid(reader, LONG_SELECT_RESPONSE_AID, selectResponse);
+ ASSERT_TRUE(verifyBerTlvData(selectResponse)) << "Select Response is not complete";
+ }
+ }
+}
+
+/** Test to fail open channel with wrong aid */
+TEST_P(OMAPISEServiceHalTest, TestWrongAid) {
+ ASSERT_TRUE(supportOMAPIReaders() == true);
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ testNonSelectableAid(reader, NON_SELECTABLE_AID);
+ }
+ }
+}
+
+/** Tests with invalid cmds in Transmit */
+TEST_P(OMAPISEServiceHalTest, TestSecurityExceptionInTransmit) {
+ ASSERT_TRUE(supportOMAPIReaders() == true);
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+ auto seListener = ndk::SharedRefBase::make<::OMAPISEServiceHalTest::SEListener>();
+ std::vector<uint8_t> selectResponse = {};
+
+ ASSERT_NE(reader, nullptr) << "reader is null";
+
+ bool status = false;
+ auto res = reader->isSecureElementPresent(&status);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_TRUE(status);
+
+ res = reader->openSession(&session);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_NE(session, nullptr) << "Could not open session";
+
+ res = session->openLogicalChannel(SELECTABLE_AID, 0x00, seListener, &channel);
+ ASSERT_TRUE(res.isOk()) << res.getMessage();
+ ASSERT_NE(channel, nullptr) << "Could not open channel";
+
+ res = channel->getSelectResponse(&selectResponse);
+ ASSERT_TRUE(res.isOk()) << "failed to get Select Response";
+ ASSERT_GE(selectResponse.size(), 2);
+
+ ASSERT_EQ((selectResponse[selectResponse.size() - 1] & 0xFF), (0x00));
+ ASSERT_EQ((selectResponse[selectResponse.size() - 2] & 0xFF), (0x90));
+
+ for (auto cmd : ILLEGAL_COMMANDS_TRANSMIT) {
+ std::vector<uint8_t> response = {};
+ res = channel->transmit(cmd, &response);
+ ASSERT_EQ(res.getExceptionCode(), EX_SECURITY);
+ ASSERT_FALSE(res.isOk()) << "expected failed status for this test";
+ }
+ if (channel != nullptr) channel->close();
+ if (session != nullptr) session->close();
+ }
+ }
+}
+
+/**
+ * Tests Transmit API for all readers.
+ *
+ * Checks the return status and verifies the size of the
+ * response.
+ */
+TEST_P(OMAPISEServiceHalTest, TestTransmitApdu) {
+ ASSERT_TRUE(supportOMAPIReaders() == true);
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ for (auto apdu : NO_DATA_APDU) {
+ std::vector<uint8_t> response = {};
+ internalTransmitApdu(reader, apdu, response);
+ ASSERT_GE(response.size(), 2);
+ ASSERT_EQ((response[response.size() - 1] & 0xFF), (0x00));
+ ASSERT_EQ((response[response.size() - 2] & 0xFF), (0x90));
+ }
+
+ for (auto apdu : DATA_APDU) {
+ std::vector<uint8_t> response = {};
+ internalTransmitApdu(reader, apdu, response);
+ /* 256 byte data and 2 bytes of status word */
+ ASSERT_GE(response.size(), 258);
+ ASSERT_EQ((response[response.size() - 1] & 0xFF), (0x00));
+ ASSERT_EQ((response[response.size() - 2] & 0xFF), (0x90));
+ }
+ }
+ }
+}
+
+/**
+ * Tests if underlying implementations returns the correct Status Word
+ *
+ * TO verify that :
+ * - the device does not modify the APDU sent to the Secure Element
+ * - the warning code is properly received by the application layer as SW answer
+ * - the verify that the application layer can fetch the additionnal data (when present)
+ */
+TEST_P(OMAPISEServiceHalTest, testStatusWordTransmit) {
+ ASSERT_TRUE(supportOMAPIReaders() == true);
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ for (auto apdu : SW_62xx_NO_DATA_APDU) {
+ for (uint8_t i = 0x00; i < SW_62xx.size(); i++) {
+ apdu[2] = i + 1;
+ std::vector<uint8_t> response = {};
+ internalTransmitApdu(reader, apdu, response);
+ std::vector<uint8_t> SW = SW_62xx[i];
+ ASSERT_GE(response.size(), 2);
+ ASSERT_EQ(response[response.size() - 1], SW[1]);
+ ASSERT_EQ(response[response.size() - 2], SW[0]);
+ }
+ }
+
+ for (uint8_t i = 0x00; i < SW_62xx.size(); i++) {
+ std::vector<uint8_t> apdu = SW_62xx_DATA_APDU;
+ apdu[2] = i + 1;
+ std::vector<uint8_t> response = {};
+ internalTransmitApdu(reader, apdu, response);
+ std::vector<uint8_t> SW = SW_62xx[i];
+ ASSERT_GE(response.size(), 3);
+ ASSERT_EQ(response[response.size() - 1], SW[1]);
+ ASSERT_EQ(response[response.size() - 2], SW[0]);
+ }
+
+ for (uint8_t i = 0x00; i < SW_62xx.size(); i++) {
+ std::vector<uint8_t> apdu = SW_62xx_VALIDATE_DATA_APDU;
+ apdu[2] = i + 1;
+ std::vector<uint8_t> response = {};
+ internalTransmitApdu(reader, apdu, response);
+ ASSERT_GE(response.size(), apdu.size() + 2);
+ std::vector<uint8_t> responseSubstring((response.begin() + 0),
+ (response.begin() + apdu.size()));
+ // We should not care about which channel number is actually assigned.
+ responseSubstring[0] = apdu[0];
+ ASSERT_TRUE((responseSubstring == apdu));
+ std::vector<uint8_t> SW = SW_62xx[i];
+ ASSERT_EQ(response[response.size() - 1], SW[1]);
+ ASSERT_EQ(response[response.size() - 2], SW[0]);
+ }
+ }
+ }
+}
+
+/** Test if the responses are segmented by the underlying implementation */
+TEST_P(OMAPISEServiceHalTest, TestSegmentedResponseTransmit) {
+ ASSERT_TRUE(supportOMAPIReaders() == true);
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ for (auto apdu : SEGMENTED_RESP_APDU) {
+ std::vector<uint8_t> response = {};
+ internalTransmitApdu(reader, apdu, response);
+ int expectedLength = (0x00 << 24) | (0x00 << 16) | (apdu[2] << 8) | apdu[3];
+ ASSERT_EQ(response.size(), (expectedLength + 2));
+ ASSERT_EQ((response[response.size() - 1] & 0xFF), (0x00));
+ ASSERT_EQ((response[response.size() - 2] & 0xFF), (0x90));
+ ASSERT_EQ((response[response.size() - 3] & 0xFF), (0xFF));
+ }
+ }
+ }
+}
+
+/**
+ * Tests the P2 value of the select command.
+ *
+ * Verifies that the default P2 value (0x00) is not modified by the underlying implementation.
+ */
+TEST_P(OMAPISEServiceHalTest, TestP2Value) {
+ ASSERT_TRUE(supportOMAPIReaders() == true);
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ std::vector<uint8_t> response = {};
+ internalTransmitApdu(reader, CHECK_SELECT_P2_APDU, response);
+ ASSERT_GE(response.size(), 3);
+ ASSERT_EQ((response[response.size() - 1] & 0xFF), (0x00));
+ ASSERT_EQ((response[response.size() - 2] & 0xFF), (0x90));
+ ASSERT_EQ((response[response.size() - 3] & 0xFF), (0x00));
+ }
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, OMAPISEServiceHalTest,
+ testing::ValuesIn(::android::getAidlHalInstanceNames(
+ aidl::android::se::omapi::ISecureElementService::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OMAPISEServiceHalTest);
+
+} // namespace
diff --git a/omapi/java/Android.bp b/omapi/java/Android.bp
new file mode 100644
index 000000000000..8d38da048d9b
--- /dev/null
+++ b/omapi/java/Android.bp
@@ -0,0 +1,17 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+ name: "framework-omapi-sources",
+ srcs: [
+ "**/*.java",
+ "**/*.aidl",
+ ],
+ visibility: ["//frameworks/base"],
+}
diff --git a/core/java/android/se/OWNERS b/omapi/java/android/se/OWNERS
index 5682fd3281f4..5682fd3281f4 100644
--- a/core/java/android/se/OWNERS
+++ b/omapi/java/android/se/OWNERS
diff --git a/core/java/android/se/omapi/Channel.java b/omapi/java/android/se/omapi/Channel.java
index 90ce11ae0313..90ce11ae0313 100644
--- a/core/java/android/se/omapi/Channel.java
+++ b/omapi/java/android/se/omapi/Channel.java
diff --git a/core/java/android/se/omapi/OWNERS b/omapi/java/android/se/omapi/OWNERS
index 5682fd3281f4..5682fd3281f4 100644
--- a/core/java/android/se/omapi/OWNERS
+++ b/omapi/java/android/se/omapi/OWNERS
diff --git a/core/java/android/se/omapi/Reader.java b/omapi/java/android/se/omapi/Reader.java
index 90c934d189fa..3c2135d9bc9d 100644
--- a/core/java/android/se/omapi/Reader.java
+++ b/omapi/java/android/se/omapi/Reader.java
@@ -170,7 +170,9 @@ public final class Reader {
try {
closeSessions();
return mReader.reset();
- } catch (RemoteException ignore) {return false;}
+ } catch (RemoteException ignore) {
+ return false;
+ }
}
}
}
diff --git a/core/java/android/se/omapi/SEService.java b/omapi/java/android/se/omapi/SEService.java
index 333af91ac872..f42ca364b6d9 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/omapi/java/android/se/omapi/SEService.java
@@ -230,20 +230,20 @@ public final class SEService {
* is not exist.
* @return A Reader object for this uicc slot.
*/
- public @NonNull Reader getUiccReader(int slotNumber) {
- if (slotNumber < 1) {
- throw new IllegalArgumentException("slotNumber should be larger than 0");
- }
- loadReaders();
+ public @NonNull Reader getUiccReader(int slotNumber) {
+ if (slotNumber < 1) {
+ throw new IllegalArgumentException("slotNumber should be larger than 0");
+ }
+ loadReaders();
- String readerName = UICC_TERMINAL + slotNumber;
- Reader reader = mReaders.get(readerName);
+ String readerName = UICC_TERMINAL + slotNumber;
+ Reader reader = mReaders.get(readerName);
- if (reader == null) {
+ if (reader == null) {
throw new IllegalArgumentException("Reader:" + readerName + " doesn't exist");
- }
+ }
- return reader;
+ return reader;
}
/**
diff --git a/core/java/android/se/omapi/Session.java b/omapi/java/android/se/omapi/Session.java
index d5f8c82bf47e..d5f8c82bf47e 100644
--- a/core/java/android/se/omapi/Session.java
+++ b/omapi/java/android/se/omapi/Session.java
diff --git a/packages/CarrierDefaultApp/OWNERS b/packages/CarrierDefaultApp/OWNERS
index 0d23f053499c..b9de5a3919f5 100644
--- a/packages/CarrierDefaultApp/OWNERS
+++ b/packages/CarrierDefaultApp/OWNERS
@@ -2,17 +2,16 @@ set noparent
tgunn@google.com
breadley@google.com
rgreenwalt@google.com
-amitmahajan@google.com
fionaxu@google.com
jackyu@google.com
jminjie@google.com
satk@google.com
shuoq@google.com
-nazaninb@google.com
sarahchin@google.com
xiaotonj@google.com
huiwang@google.com
jayachandranc@google.com
chinmayd@google.com
amruthr@google.com
+sasindran@google.com
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index c1a0a9a92cc2..b4cafd8548f4 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -93,9 +93,9 @@ public class CompanionDeviceActivity extends Activity {
final DeviceFilterPair selectedDevice = getService().mDevicesFound.get(0);
setTitle(Html.fromHtml(getString(
R.string.confirmation_title,
- getCallingAppName(),
- profileName,
- selectedDevice.getDisplayName()), 0));
+ Html.escapeHtml(getCallingAppName()),
+ Html.escapeHtml(selectedDevice.getDisplayName())), 0));
+
mPairButton = findViewById(R.id.button_pair);
mPairButton.setOnClickListener(v -> onDeviceConfirmed(getService().mSelectedDevice));
getService().mSelectedDevice = selectedDevice;
@@ -108,8 +108,8 @@ public class CompanionDeviceActivity extends Activity {
mPairButton = findViewById(R.id.button_pair);
mPairButton.setVisibility(View.GONE);
setTitle(Html.fromHtml(getString(R.string.chooser_title,
- profileName,
- getCallingAppName()), 0));
+ Html.escapeHtml(profileName),
+ Html.escapeHtml(getCallingAppName())), 0));
mDeviceListView = findViewById(R.id.device_list);
mDevicesAdapter = new DevicesAdapter();
mDeviceListView.setAdapter(mDevicesAdapter);
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 801b490406cc..a3eb0eccad9d 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -251,7 +251,7 @@ public class ExternalStorageProvider extends FileSystemProvider {
if (volume.getType() == VolumeInfo.TYPE_PUBLIC) {
root.flags |= Root.FLAG_HAS_SETTINGS;
}
- if (volume.isVisibleForRead(userId)) {
+ if (volume.isVisibleForUser(userId)) {
root.visiblePath = volume.getPathForUser(userId);
} else {
root.visiblePath = null;
diff --git a/packages/Nsd/OWNERS b/packages/Nsd/OWNERS
new file mode 100644
index 000000000000..4862377852ac
--- /dev/null
+++ b/packages/Nsd/OWNERS
@@ -0,0 +1 @@
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking \ No newline at end of file
diff --git a/packages/Nsd/framework/Android.bp b/packages/Nsd/framework/Android.bp
new file mode 100644
index 000000000000..2363a9f8d4a3
--- /dev/null
+++ b/packages/Nsd/framework/Android.bp
@@ -0,0 +1,54 @@
+//
+// 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 {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+filegroup {
+ name: "framework-connectivity-nsd-internal-sources",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.aidl",
+ ],
+ path: "src",
+ visibility: [
+ "//visibility:private",
+ ],
+}
+
+filegroup {
+ name: "framework-connectivity-nsd-aidl-export-sources",
+ srcs: [
+ "aidl-export/**/*.aidl",
+ ],
+ path: "aidl-export",
+ visibility: [
+ "//visibility:private",
+ ],
+}
+
+filegroup {
+ name: "framework-connectivity-nsd-sources",
+ srcs: [
+ ":framework-connectivity-nsd-internal-sources",
+ ":framework-connectivity-nsd-aidl-export-sources",
+ ],
+ visibility: [
+ "//frameworks/base",
+ ],
+}
diff --git a/packages/Nsd/framework/aidl-export/android/net/nsd/NsdServiceInfo.aidl b/packages/Nsd/framework/aidl-export/android/net/nsd/NsdServiceInfo.aidl
new file mode 100644
index 000000000000..657bdd1e8706
--- /dev/null
+++ b/packages/Nsd/framework/aidl-export/android/net/nsd/NsdServiceInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.nsd;
+
+@JavaOnlyStableParcelable parcelable NsdServiceInfo; \ No newline at end of file
diff --git a/core/java/android/net/nsd/INsdManager.aidl b/packages/Nsd/framework/src/android/net/nsd/INsdManager.aidl
index e9e8935a19b2..89e9cdbd4445 100644
--- a/core/java/android/net/nsd/INsdManager.aidl
+++ b/packages/Nsd/framework/src/android/net/nsd/INsdManager.aidl
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2012, The Android Open Source Project
+ * 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.
@@ -16,16 +16,15 @@
package android.net.nsd;
+import android.net.nsd.INsdManagerCallback;
+import android.net.nsd.INsdServiceConnector;
import android.os.Messenger;
/**
- * Interface that NsdService implements
+ * Interface that NsdService implements to connect NsdManager clients.
*
* {@hide}
*/
-interface INsdManager
-{
- @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
- Messenger getMessenger();
- void setEnabled(boolean enable);
+interface INsdManager {
+ INsdServiceConnector connect(INsdManagerCallback cb);
}
diff --git a/packages/Nsd/framework/src/android/net/nsd/INsdManagerCallback.aidl b/packages/Nsd/framework/src/android/net/nsd/INsdManagerCallback.aidl
new file mode 100644
index 000000000000..1a262ec0e9dd
--- /dev/null
+++ b/packages/Nsd/framework/src/android/net/nsd/INsdManagerCallback.aidl
@@ -0,0 +1,39 @@
+/**
+ * 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.nsd;
+
+import android.os.Messenger;
+import android.net.nsd.NsdServiceInfo;
+
+/**
+ * Callbacks from NsdService to NsdManager
+ * @hide
+ */
+oneway interface INsdManagerCallback {
+ void onDiscoverServicesStarted(int listenerKey, in NsdServiceInfo info);
+ void onDiscoverServicesFailed(int listenerKey, int error);
+ void onServiceFound(int listenerKey, in NsdServiceInfo info);
+ void onServiceLost(int listenerKey, in NsdServiceInfo info);
+ void onStopDiscoveryFailed(int listenerKey, int error);
+ void onStopDiscoverySucceeded(int listenerKey);
+ void onRegisterServiceFailed(int listenerKey, int error);
+ void onRegisterServiceSucceeded(int listenerKey, in NsdServiceInfo info);
+ void onUnregisterServiceFailed(int listenerKey, int error);
+ void onUnregisterServiceSucceeded(int listenerKey);
+ void onResolveServiceFailed(int listenerKey, int error);
+ void onResolveServiceSucceeded(int listenerKey, in NsdServiceInfo info);
+}
diff --git a/packages/Nsd/framework/src/android/net/nsd/INsdServiceConnector.aidl b/packages/Nsd/framework/src/android/net/nsd/INsdServiceConnector.aidl
new file mode 100644
index 000000000000..b06ae55b150e
--- /dev/null
+++ b/packages/Nsd/framework/src/android/net/nsd/INsdServiceConnector.aidl
@@ -0,0 +1,35 @@
+/**
+ * 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.nsd;
+
+import android.net.nsd.INsdManagerCallback;
+import android.net.nsd.NsdServiceInfo;
+import android.os.Messenger;
+
+/**
+ * Interface that NsdService implements for each NsdManager client.
+ *
+ * {@hide}
+ */
+interface INsdServiceConnector {
+ void registerService(int listenerKey, in NsdServiceInfo serviceInfo);
+ void unregisterService(int listenerKey);
+ void discoverServices(int listenerKey, in NsdServiceInfo serviceInfo);
+ void stopDiscovery(int listenerKey);
+ void resolveService(int listenerKey, in NsdServiceInfo serviceInfo);
+ void startDaemon();
+} \ No newline at end of file
diff --git a/core/java/android/net/nsd/NsdManager.java b/packages/Nsd/framework/src/android/net/nsd/NsdManager.java
index ae8d0101947d..6c597e26e042 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/packages/Nsd/framework/src/android/net/nsd/NsdManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * 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.
@@ -31,17 +31,13 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
-import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
-import java.util.concurrent.CountDownLatch;
-
/**
* The Network Service Discovery Manager class provides the API to discover services
* on a network. As an example, if device A and device B are connected over a Wi-Fi
@@ -234,6 +230,11 @@ public final class NsdManager {
/** @hide */
public static final int NATIVE_DAEMON_EVENT = BASE + 26;
+ /** @hide */
+ public static final int REGISTER_CLIENT = BASE + 27;
+ /** @hide */
+ public static final int UNREGISTER_CLIENT = BASE + 28;
+
/** Dns based service discovery protocol */
public static final int PROTOCOL_DNS_SD = 0x0001;
@@ -274,7 +275,7 @@ public final class NsdManager {
private static final int FIRST_LISTENER_KEY = 1;
- private final INsdManager mService;
+ private final INsdServiceConnector mService;
private final Context mContext;
private int mListenerKey = FIRST_LISTENER_KEY;
@@ -282,9 +283,7 @@ public final class NsdManager {
private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<>();
private final Object mMapLock = new Object();
- private final AsyncChannel mAsyncChannel = new AsyncChannel();
- private ServiceHandler mHandler;
- private final CountDownLatch mConnected = new CountDownLatch(1);
+ private final ServiceHandler mHandler;
/**
* Create a new Nsd instance. Applications use
@@ -295,18 +294,108 @@ public final class NsdManager {
* is a system private class.
*/
public NsdManager(Context context, INsdManager service) {
- mService = service;
mContext = context;
- init();
+
+ HandlerThread t = new HandlerThread("NsdManager");
+ t.start();
+ mHandler = new ServiceHandler(t.getLooper());
+
+ try {
+ mService = service.connect(new NsdCallbackImpl(mHandler));
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed to connect to NsdService");
+ }
+
+ // Only proactively start the daemon if the target SDK < S, otherwise the internal service
+ // would automatically start/stop the native daemon as needed.
+ if (!CompatChanges.isChangeEnabled(RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)) {
+ try {
+ mService.startDaemon();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to proactively start daemon");
+ // Continue: the daemon can still be started on-demand later
+ }
+ }
}
- /**
- * @hide
- */
- @VisibleForTesting
- public void disconnect() {
- mAsyncChannel.disconnect();
- mHandler.getLooper().quitSafely();
+ private static class NsdCallbackImpl extends INsdManagerCallback.Stub {
+ private final Handler mServHandler;
+
+ NsdCallbackImpl(Handler serviceHandler) {
+ mServHandler = serviceHandler;
+ }
+
+ private void sendInfo(int message, int listenerKey, NsdServiceInfo info) {
+ mServHandler.sendMessage(mServHandler.obtainMessage(message, 0, listenerKey, info));
+ }
+
+ private void sendError(int message, int listenerKey, int error) {
+ mServHandler.sendMessage(mServHandler.obtainMessage(message, error, listenerKey));
+ }
+
+ private void sendNoArg(int message, int listenerKey) {
+ mServHandler.sendMessage(mServHandler.obtainMessage(message, 0, listenerKey));
+ }
+
+ @Override
+ public void onDiscoverServicesStarted(int listenerKey, NsdServiceInfo info) {
+ sendInfo(DISCOVER_SERVICES_STARTED, listenerKey, info);
+ }
+
+ @Override
+ public void onDiscoverServicesFailed(int listenerKey, int error) {
+ sendError(DISCOVER_SERVICES_FAILED, listenerKey, error);
+ }
+
+ @Override
+ public void onServiceFound(int listenerKey, NsdServiceInfo info) {
+ sendInfo(SERVICE_FOUND, listenerKey, info);
+ }
+
+ @Override
+ public void onServiceLost(int listenerKey, NsdServiceInfo info) {
+ sendInfo(SERVICE_LOST, listenerKey, info);
+ }
+
+ @Override
+ public void onStopDiscoveryFailed(int listenerKey, int error) {
+ sendError(STOP_DISCOVERY_FAILED, listenerKey, error);
+ }
+
+ @Override
+ public void onStopDiscoverySucceeded(int listenerKey) {
+ sendNoArg(STOP_DISCOVERY_SUCCEEDED, listenerKey);
+ }
+
+ @Override
+ public void onRegisterServiceFailed(int listenerKey, int error) {
+ sendError(REGISTER_SERVICE_FAILED, listenerKey, error);
+ }
+
+ @Override
+ public void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info) {
+ sendInfo(REGISTER_SERVICE_SUCCEEDED, listenerKey, info);
+ }
+
+ @Override
+ public void onUnregisterServiceFailed(int listenerKey, int error) {
+ sendError(UNREGISTER_SERVICE_FAILED, listenerKey, error);
+ }
+
+ @Override
+ public void onUnregisterServiceSucceeded(int listenerKey) {
+ sendNoArg(UNREGISTER_SERVICE_SUCCEEDED, listenerKey);
+ }
+
+ @Override
+ public void onResolveServiceFailed(int listenerKey, int error) {
+ sendError(RESOLVE_SERVICE_FAILED, listenerKey, error);
+ }
+
+ @Override
+ public void onResolveServiceSucceeded(int listenerKey, NsdServiceInfo info) {
+ sendInfo(RESOLVE_SERVICE_SUCCEEDED, listenerKey, info);
+ }
}
/**
@@ -376,19 +465,6 @@ public final class NsdManager {
public void handleMessage(Message message) {
final int what = message.what;
final int key = message.arg2;
- switch (what) {
- case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
- mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
- return;
- case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
- mConnected.countDown();
- return;
- case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
- Log.e(TAG, "Channel lost");
- return;
- default:
- break;
- }
final Object listener;
final NsdServiceInfo ns;
synchronized (mMapLock) {
@@ -504,36 +580,6 @@ public final class NsdManager {
}
/**
- * Initialize AsyncChannel
- */
- private void init() {
- final Messenger messenger = getMessenger();
- if (messenger == null) {
- fatal("Failed to obtain service Messenger");
- }
- HandlerThread t = new HandlerThread("NsdManager");
- t.start();
- mHandler = new ServiceHandler(t.getLooper());
- mAsyncChannel.connect(mContext, mHandler, messenger);
- try {
- mConnected.await();
- } catch (InterruptedException e) {
- fatal("Interrupted wait at init");
- }
- if (CompatChanges.isChangeEnabled(RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)) {
- return;
- }
- // Only proactively start the daemon if the target SDK < S, otherwise the internal service
- // would automatically start/stop the native daemon as needed.
- mAsyncChannel.sendMessage(DAEMON_STARTUP);
- }
-
- private static void fatal(String msg) {
- Log.e(TAG, msg);
- throw new RuntimeException(msg);
- }
-
- /**
* Register a service to be discovered by other services.
*
* <p> The function call immediately returns after sending a request to register service
@@ -556,7 +602,11 @@ public final class NsdManager {
checkServiceInfo(serviceInfo);
checkProtocol(protocolType);
int key = putListener(listener, serviceInfo);
- mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, key, serviceInfo);
+ try {
+ mService.registerService(key, serviceInfo);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
}
/**
@@ -574,7 +624,11 @@ public final class NsdManager {
*/
public void unregisterService(RegistrationListener listener) {
int id = getListenerKey(listener);
- mAsyncChannel.sendMessage(UNREGISTER_SERVICE, 0, id);
+ try {
+ mService.unregisterService(id);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
}
/**
@@ -613,7 +667,11 @@ public final class NsdManager {
s.setServiceType(serviceType);
int key = putListener(listener, s);
- mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, key, s);
+ try {
+ mService.discoverServices(key, s);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
}
/**
@@ -634,7 +692,11 @@ public final class NsdManager {
*/
public void stopServiceDiscovery(DiscoveryListener listener) {
int id = getListenerKey(listener);
- mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, id);
+ try {
+ mService.stopDiscovery(id);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
}
/**
@@ -649,29 +711,10 @@ public final class NsdManager {
public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) {
checkServiceInfo(serviceInfo);
int key = putListener(listener, serviceInfo);
- mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, key, serviceInfo);
- }
-
- /** Internal use only @hide */
- public void setEnabled(boolean enabled) {
- try {
- mService.setEnabled(enabled);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Get a reference to NsdService handler. This is used to establish
- * an AsyncChannel communication with the service
- *
- * @return Messenger pointing to the NsdService handler
- */
- private Messenger getMessenger() {
try {
- return mService.getMessenger();
+ mService.resolveService(key, serviceInfo);
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ e.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/packages/Nsd/framework/src/android/net/nsd/NsdServiceInfo.java
index 0946499f164f..0946499f164f 100644
--- a/core/java/android/net/nsd/NsdServiceInfo.java
+++ b/packages/Nsd/framework/src/android/net/nsd/NsdServiceInfo.java
diff --git a/packages/Nsd/service/Android.bp b/packages/Nsd/service/Android.bp
new file mode 100644
index 000000000000..529f58d130ed
--- /dev/null
+++ b/packages/Nsd/service/Android.bp
@@ -0,0 +1,31 @@
+//
+// 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 {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+filegroup {
+ name: "services.connectivity-nsd-sources",
+ srcs: [
+ "src/**/*.java",
+ ],
+ path: "src",
+ visibility: [
+ "//frameworks/base/services/core",
+ ],
+}
diff --git a/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java b/packages/Nsd/service/src/com/android/server/INativeDaemonConnectorCallbacks.java
index 0cf9dcde012d..0cf9dcde012d 100644
--- a/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java
+++ b/packages/Nsd/service/src/com/android/server/INativeDaemonConnectorCallbacks.java
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java
index eac767f7355c..ec8d7798e17e 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java
@@ -20,18 +20,15 @@ import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Build;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.util.LocalLog;
-import android.util.Slog;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
-import com.android.server.power.ShutdownThread;
-import com.google.android.collect.Lists;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -40,19 +37,19 @@ import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.LinkedList;
+import java.util.Objects;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.LinkedList;
-import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Generic connector class for interfacing with a native daemon which uses the
* {@code libsysutils} FrameworkListener protocol.
*/
-final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor {
+final class NativeDaemonConnector implements Runnable, Handler.Callback {
private final static boolean VDBG = false;
private final String TAG;
@@ -85,13 +82,6 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) {
- this(callbacks, socket, responseQueueSize, logTag, maxLogSize, wl,
- FgThread.get().getLooper());
- }
-
- NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
- int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl,
- Looper looper) {
mCallbacks = callbacks;
mSocket = socket;
mResponseQueue = new ResponseQueue(responseQueueSize);
@@ -99,15 +89,17 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
if (mWakeLock != null) {
mWakeLock.setReferenceCounted(true);
}
- mLooper = looper;
mSequenceNumber = new AtomicInteger(0);
TAG = logTag != null ? logTag : "NativeDaemonConnector";
mLocalLog = new LocalLog(maxLogSize);
+ final HandlerThread thread = new HandlerThread(TAG);
+ thread.start();
+ mLooper = thread.getLooper();
}
/**
* Enable Set debugging mode, which causes messages to also be written to both
- * {@link Slog} in addition to internal log.
+ * {@link Log} in addition to internal log.
*/
public void setDebug(boolean debug) {
mDebug = debug;
@@ -126,7 +118,9 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
* calls while holding a lock on the given object.
*/
public void setWarnIfHeld(Object warnIfHeld) {
- Preconditions.checkState(mWarnIfHeld == null);
+ if (mWarnIfHeld != null) {
+ throw new IllegalStateException("warnIfHeld is already set.");
+ }
mWarnIfHeld = Objects.requireNonNull(warnIfHeld);
}
@@ -135,23 +129,15 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
mCallbackHandler = new Handler(mLooper, this);
while (true) {
- if (isShuttingDown()) break;
try {
listenToSocket();
} catch (Exception e) {
loge("Error in NativeDaemonConnector: " + e);
- if (isShuttingDown()) break;
SystemClock.sleep(5000);
}
}
}
- private static boolean isShuttingDown() {
- String shutdownAct = SystemProperties.get(
- ShutdownThread.SHUTDOWN_ACTION_PROPERTY, "");
- return shutdownAct != null && shutdownAct.length() > 0;
- }
-
@Override
public boolean handleMessage(Message msg) {
final String event = (String) msg.obj;
@@ -183,7 +169,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
// In order to ensure that unprivileged apps aren't able to impersonate native daemons on
// production devices, even if said native daemons ill-advisedly pick a socket name that
// starts with __test__, only allow this on debug builds.
- if (mSocket.startsWith("__test__") && Build.IS_DEBUGGABLE) {
+ if (mSocket.startsWith("__test__") && Build.isDebuggable()) {
return new LocalSocketAddress(mSocket);
} else {
return new LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED);
@@ -375,7 +361,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
try {
latch.await();
} catch (InterruptedException e) {
- Slog.wtf(TAG, "Interrupted while waiting for unsolicited response handling", e);
+ Log.wtf(TAG, "Interrupted while waiting for unsolicited response handling", e);
}
}
@@ -462,13 +448,13 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args)
throws NativeDaemonConnectorException {
if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
- Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
+ Log.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
+ Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
}
final long startTime = SystemClock.elapsedRealtime();
- final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();
+ final ArrayList<NativeDaemonEvent> events = new ArrayList<>();
final StringBuilder rawBuilder = new StringBuilder();
final StringBuilder logBuilder = new StringBuilder();
@@ -571,7 +557,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
*/
public static class Command {
private String mCmd;
- private ArrayList<Object> mArguments = Lists.newArrayList();
+ private ArrayList<Object> mArguments = new ArrayList<>();
public Command(String cmd, Object... args) {
mCmd = cmd;
@@ -586,11 +572,6 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
}
}
- /** {@inheritDoc} */
- public void monitor() {
- synchronized (mDaemonLock) { }
- }
-
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mLocalLog.dump(fd, pw, args);
pw.println();
@@ -598,12 +579,12 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
}
private void log(String logstring) {
- if (mDebug) Slog.d(TAG, logstring);
+ if (mDebug) Log.d(TAG, logstring);
mLocalLog.log(logstring);
}
private void loge(String logstring) {
- Slog.e(TAG, logstring);
+ Log.e(TAG, logstring);
mLocalLog.log(logstring);
}
@@ -659,12 +640,12 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
if (found == null) {
// didn't find it - make sure our queue isn't too big before adding
while (mPendingCmds.size() >= mMaxCount) {
- Slog.e("NativeDaemonConnector.ResponseQueue",
+ Log.e("NativeDaemonConnector.ResponseQueue",
"more buffered than allowed: " + mPendingCmds.size() +
" >= " + mMaxCount);
// let any waiter timeout waiting for this
PendingCmd pendingCmd = mPendingCmds.remove();
- Slog.e("NativeDaemonConnector.ResponseQueue",
+ Log.e("NativeDaemonConnector.ResponseQueue",
"Removing request: " + pendingCmd.logCmd + " (" +
pendingCmd.cmdNum + ")");
}
@@ -706,7 +687,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
result = found.responses.poll(timeoutMs, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {}
if (result == null) {
- Slog.e("NativeDaemonConnector.ResponseQueue", "Timeout waiting for response");
+ Log.e("NativeDaemonConnector.ResponseQueue", "Timeout waiting for response");
}
return result;
}
diff --git a/services/core/java/com/android/server/NativeDaemonConnectorException.java b/packages/Nsd/service/src/com/android/server/NativeDaemonConnectorException.java
index 4d8881c68324..4d8881c68324 100644
--- a/services/core/java/com/android/server/NativeDaemonConnectorException.java
+++ b/packages/Nsd/service/src/com/android/server/NativeDaemonConnectorException.java
diff --git a/services/core/java/com/android/server/NativeDaemonEvent.java b/packages/Nsd/service/src/com/android/server/NativeDaemonEvent.java
index e6feda3dad22..568369434629 100644
--- a/services/core/java/com/android/server/NativeDaemonEvent.java
+++ b/packages/Nsd/service/src/com/android/server/NativeDaemonEvent.java
@@ -16,8 +16,7 @@
package com.android.server;
-import android.util.Slog;
-import com.google.android.collect.Lists;
+import android.util.Log;
import java.io.FileDescriptor;
import java.util.ArrayList;
@@ -179,7 +178,7 @@ public class NativeDaemonEvent {
* {@link #getMessage()} for any events matching the requested code.
*/
public static String[] filterMessageList(NativeDaemonEvent[] events, int matchCode) {
- final ArrayList<String> result = Lists.newArrayList();
+ final ArrayList<String> result = new ArrayList<>();
for (NativeDaemonEvent event : events) {
if (event.getCode() == matchCode) {
result.add(event.getMessage());
@@ -212,7 +211,7 @@ public class NativeDaemonEvent {
int wordEnd = -1;
boolean quoted = false;
- if (DEBUG_ROUTINE) Slog.e(LOGTAG, "parsing '" + rawEvent + "'");
+ if (DEBUG_ROUTINE) Log.e(LOGTAG, "parsing '" + rawEvent + "'");
if (rawEvent.charAt(current) == '\"') {
quoted = true;
current++;
@@ -240,14 +239,14 @@ public class NativeDaemonEvent {
word = word.replace("\\\\", "\\");
word = word.replace("\\\"", "\"");
- if (DEBUG_ROUTINE) Slog.e(LOGTAG, "found '" + word + "'");
+ if (DEBUG_ROUTINE) Log.e(LOGTAG, "found '" + word + "'");
parsed.add(word);
// find the beginning of the next word - either of these options
int nextSpace = rawEvent.indexOf(' ', current);
int nextQuote = rawEvent.indexOf(" \"", current);
if (DEBUG_ROUTINE) {
- Slog.e(LOGTAG, "nextSpace=" + nextSpace + ", nextQuote=" + nextQuote);
+ Log.e(LOGTAG, "nextSpace=" + nextSpace + ", nextQuote=" + nextQuote);
}
if (nextQuote > -1 && nextQuote <= nextSpace) {
quoted = true;
@@ -259,8 +258,8 @@ public class NativeDaemonEvent {
}
} // else we just start the next word after the current and read til the end
if (DEBUG_ROUTINE) {
- Slog.e(LOGTAG, "next loop - current=" + current +
- ", length=" + length + ", quoted=" + quoted);
+ Log.e(LOGTAG, "next loop - current=" + current
+ + ", length=" + length + ", quoted=" + quoted);
}
}
return parsed.toArray(new String[parsed.size()]);
diff --git a/services/core/java/com/android/server/NativeDaemonTimeoutException.java b/packages/Nsd/service/src/com/android/server/NativeDaemonTimeoutException.java
index 658f7d6264eb..658f7d6264eb 100644
--- a/services/core/java/com/android/server/NativeDaemonTimeoutException.java
+++ b/packages/Nsd/service/src/com/android/server/NativeDaemonTimeoutException.java
diff --git a/services/core/java/com/android/server/NsdService.java b/packages/Nsd/service/src/com/android/server/NsdService.java
index c9608a55170e..497107dbf989 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/packages/Nsd/service/src/com/android/server/NsdService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -16,29 +16,27 @@
package com.android.server;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.database.ContentObserver;
-import android.net.NetworkStack;
-import android.net.Uri;
+import android.content.pm.PackageManager;
import android.net.nsd.INsdManager;
+import android.net.nsd.INsdManagerCallback;
+import android.net.nsd.INsdServiceConnector;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.Message;
-import android.os.Messenger;
+import android.os.RemoteException;
import android.os.UserHandle;
-import android.provider.Settings;
import android.util.Base64;
-import android.util.Slog;
+import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.DumpUtils;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.net.module.util.DnsSdTxtRecord;
@@ -64,7 +62,6 @@ public class NsdService extends INsdManager.Stub {
private static final long CLEANUP_DELAY_MS = 10000;
private final Context mContext;
- private final NsdSettings mNsdSettings;
private final NsdStateMachine mNsdStateMachine;
private final DaemonConnection mDaemon;
private final NativeCallbackReceiver mDaemonCallback;
@@ -72,12 +69,11 @@ public class NsdService extends INsdManager.Stub {
/**
* Clients receiving asynchronous messages
*/
- private final HashMap<Messenger, ClientInfo> mClients = new HashMap<>();
+ private final HashMap<NsdServiceConnector, ClientInfo> mClients = new HashMap<>();
/* A map from unique id to client info */
private final SparseArray<ClientInfo> mIdToClientInfoMap= new SparseArray<>();
- private final AsyncChannel mReplyChannel = new AsyncChannel();
private final long mCleanupDelayMs;
private static final int INVALID_ID = 0;
@@ -120,94 +116,79 @@ public class NsdService extends INsdManager.Stub {
this.removeMessages(NsdManager.DAEMON_CLEANUP);
}
- /**
- * Observes the NSD on/off setting, and takes action when changed.
- */
- private void registerForNsdSetting() {
- final ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
- @Override
- public void onChange(boolean selfChange) {
- notifyEnabled(isNsdEnabled());
- }
- };
-
- final Uri uri = Settings.Global.getUriFor(Settings.Global.NSD_ON);
- mNsdSettings.registerContentObserver(uri, contentObserver);
- }
-
NsdStateMachine(String name, Handler handler) {
super(name, handler);
addState(mDefaultState);
addState(mDisabledState, mDefaultState);
addState(mEnabledState, mDefaultState);
- State initialState = isNsdEnabled() ? mEnabledState : mDisabledState;
+ State initialState = mEnabledState;
setInitialState(initialState);
setLogRecSize(25);
- registerForNsdSetting();
}
class DefaultState extends State {
@Override
public boolean processMessage(Message msg) {
- ClientInfo cInfo = null;
+ final ClientInfo cInfo;
+ final int clientId = msg.arg2;
switch (msg.what) {
- case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
- if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- AsyncChannel c = (AsyncChannel) msg.obj;
- if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
- c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
- cInfo = new ClientInfo(c, msg.replyTo);
- mClients.put(msg.replyTo, cInfo);
- } else {
- Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
+ case NsdManager.REGISTER_CLIENT:
+ final Pair<NsdServiceConnector, INsdManagerCallback> arg =
+ (Pair<NsdServiceConnector, INsdManagerCallback>) msg.obj;
+ final INsdManagerCallback cb = arg.second;
+ try {
+ cb.asBinder().linkToDeath(arg.first, 0);
+ cInfo = new ClientInfo(cb);
+ mClients.put(arg.first, cInfo);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Client " + clientId + " has already died");
}
break;
- case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
- switch (msg.arg1) {
- case AsyncChannel.STATUS_SEND_UNSUCCESSFUL:
- Slog.e(TAG, "Send failed, client connection lost");
- break;
- case AsyncChannel.STATUS_REMOTE_DISCONNECTION:
- if (DBG) Slog.d(TAG, "Client disconnected");
- break;
- default:
- if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
- break;
- }
-
- cInfo = mClients.get(msg.replyTo);
+ case NsdManager.UNREGISTER_CLIENT:
+ final NsdServiceConnector connector = (NsdServiceConnector) msg.obj;
+ cInfo = mClients.remove(connector);
if (cInfo != null) {
cInfo.expungeAllRequests();
- mClients.remove(msg.replyTo);
if (cInfo.isLegacy()) {
mLegacyClientCount -= 1;
}
}
maybeScheduleStop();
break;
- case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
- AsyncChannel ac = new AsyncChannel();
- ac.connect(mContext, getHandler(), msg.replyTo);
- break;
case NsdManager.DISCOVER_SERVICES:
- replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR);
+ cInfo = getClientInfoForReply(msg);
+ if (cInfo != null) {
+ cInfo.onDiscoverServicesFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
+ }
break;
case NsdManager.STOP_DISCOVERY:
- replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR);
+ cInfo = getClientInfoForReply(msg);
+ if (cInfo != null) {
+ cInfo.onStopDiscoveryFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
+ }
break;
case NsdManager.REGISTER_SERVICE:
- replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR);
+ cInfo = getClientInfoForReply(msg);
+ if (cInfo != null) {
+ cInfo.onRegisterServiceFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
+ }
break;
case NsdManager.UNREGISTER_SERVICE:
- replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR);
+ cInfo = getClientInfoForReply(msg);
+ if (cInfo != null) {
+ cInfo.onUnregisterServiceFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
+ }
break;
case NsdManager.RESOLVE_SERVICE:
- replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR);
+ cInfo = getClientInfoForReply(msg);
+ if (cInfo != null) {
+ cInfo.onResolveServiceFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
+ }
break;
case NsdManager.DAEMON_CLEANUP:
mDaemon.maybeStop();
@@ -215,7 +196,7 @@ public class NsdService extends INsdManager.Stub {
// This event should be only sent by the legacy (target SDK < S) clients.
// Mark the sending client as legacy.
case NsdManager.DAEMON_STARTUP:
- cInfo = mClients.get(msg.replyTo);
+ cInfo = getClientInfoForReply(msg);
if (cInfo != null) {
cancelStop();
cInfo.setLegacy();
@@ -225,11 +206,16 @@ public class NsdService extends INsdManager.Stub {
break;
case NsdManager.NATIVE_DAEMON_EVENT:
default:
- Slog.e(TAG, "Unhandled " + msg);
+ Log.e(TAG, "Unhandled " + msg);
return NOT_HANDLED;
}
return HANDLED;
}
+
+ private ClientInfo getClientInfoForReply(Message msg) {
+ final ListenerArgs args = (ListenerArgs) msg.obj;
+ return mClients.get(args.connector);
+ }
}
class DisabledState extends State {
@@ -266,7 +252,7 @@ public class NsdService extends INsdManager.Stub {
private boolean requestLimitReached(ClientInfo clientInfo) {
if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) {
- if (DBG) Slog.d(TAG, "Exceeded max outstanding requests " + clientInfo);
+ if (DBG) Log.d(TAG, "Exceeded max outstanding requests " + clientInfo);
return true;
}
return false;
@@ -289,122 +275,119 @@ public class NsdService extends INsdManager.Stub {
@Override
public boolean processMessage(Message msg) {
- ClientInfo clientInfo;
- NsdServiceInfo servInfo;
- int id;
+ final ClientInfo clientInfo;
+ final int id;
+ final int clientId = msg.arg2;
+ final ListenerArgs args;
switch (msg.what) {
- case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
- return NOT_HANDLED;
- case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
- return NOT_HANDLED;
case NsdManager.DISABLE:
//TODO: cleanup clients
transitionTo(mDisabledState);
break;
case NsdManager.DISCOVER_SERVICES:
- if (DBG) Slog.d(TAG, "Discover services");
- servInfo = (NsdServiceInfo) msg.obj;
- clientInfo = mClients.get(msg.replyTo);
+ if (DBG) Log.d(TAG, "Discover services");
+ args = (ListenerArgs) msg.obj;
+ clientInfo = mClients.get(args.connector);
if (requestLimitReached(clientInfo)) {
- replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
- NsdManager.FAILURE_MAX_LIMIT);
+ clientInfo.onDiscoverServicesFailed(
+ clientId, NsdManager.FAILURE_MAX_LIMIT);
break;
}
maybeStartDaemon();
id = getUniqueId();
- if (discoverServices(id, servInfo.getServiceType())) {
+ if (discoverServices(id, args.serviceInfo.getServiceType())) {
if (DBG) {
- Slog.d(TAG, "Discover " + msg.arg2 + " " + id +
- servInfo.getServiceType());
+ Log.d(TAG, "Discover " + msg.arg2 + " " + id
+ + args.serviceInfo.getServiceType());
}
- storeRequestMap(msg.arg2, id, clientInfo, msg.what);
- replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo);
+ storeRequestMap(clientId, id, clientInfo, msg.what);
+ clientInfo.onDiscoverServicesStarted(clientId, args.serviceInfo);
} else {
stopServiceDiscovery(id);
- replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
+ clientInfo.onDiscoverServicesFailed(clientId,
NsdManager.FAILURE_INTERNAL_ERROR);
}
break;
case NsdManager.STOP_DISCOVERY:
- if (DBG) Slog.d(TAG, "Stop service discovery");
- clientInfo = mClients.get(msg.replyTo);
+ if (DBG) Log.d(TAG, "Stop service discovery");
+ args = (ListenerArgs) msg.obj;
+ clientInfo = mClients.get(args.connector);
try {
- id = clientInfo.mClientIds.get(msg.arg2);
+ id = clientInfo.mClientIds.get(clientId);
} catch (NullPointerException e) {
- replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR);
+ clientInfo.onStopDiscoveryFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
break;
}
- removeRequestMap(msg.arg2, id, clientInfo);
+ removeRequestMap(clientId, id, clientInfo);
if (stopServiceDiscovery(id)) {
- replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED);
+ clientInfo.onStopDiscoverySucceeded(clientId);
} else {
- replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR);
+ clientInfo.onStopDiscoveryFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
}
break;
case NsdManager.REGISTER_SERVICE:
- if (DBG) Slog.d(TAG, "Register service");
- clientInfo = mClients.get(msg.replyTo);
+ if (DBG) Log.d(TAG, "Register service");
+ args = (ListenerArgs) msg.obj;
+ clientInfo = mClients.get(args.connector);
if (requestLimitReached(clientInfo)) {
- replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
- NsdManager.FAILURE_MAX_LIMIT);
+ clientInfo.onRegisterServiceFailed(
+ clientId, NsdManager.FAILURE_MAX_LIMIT);
break;
}
maybeStartDaemon();
id = getUniqueId();
- if (registerService(id, (NsdServiceInfo) msg.obj)) {
- if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id);
- storeRequestMap(msg.arg2, id, clientInfo, msg.what);
+ if (registerService(id, args.serviceInfo)) {
+ if (DBG) Log.d(TAG, "Register " + clientId + " " + id);
+ storeRequestMap(clientId, id, clientInfo, msg.what);
// Return success after mDns reports success
} else {
unregisterService(id);
- replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR);
+ clientInfo.onRegisterServiceFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
}
break;
case NsdManager.UNREGISTER_SERVICE:
- if (DBG) Slog.d(TAG, "unregister service");
- clientInfo = mClients.get(msg.replyTo);
- try {
- id = clientInfo.mClientIds.get(msg.arg2);
- } catch (NullPointerException e) {
- replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR);
+ if (DBG) Log.d(TAG, "unregister service");
+ args = (ListenerArgs) msg.obj;
+ clientInfo = mClients.get(args.connector);
+ if (clientInfo == null) {
+ Log.e(TAG, "Unknown connector in unregistration");
break;
}
- removeRequestMap(msg.arg2, id, clientInfo);
+ id = clientInfo.mClientIds.get(clientId);
+ removeRequestMap(clientId, id, clientInfo);
if (unregisterService(id)) {
- replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED);
+ clientInfo.onUnregisterServiceSucceeded(clientId);
} else {
- replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR);
+ clientInfo.onUnregisterServiceFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
}
break;
case NsdManager.RESOLVE_SERVICE:
- if (DBG) Slog.d(TAG, "Resolve service");
- servInfo = (NsdServiceInfo) msg.obj;
- clientInfo = mClients.get(msg.replyTo);
-
+ if (DBG) Log.d(TAG, "Resolve service");
+ args = (ListenerArgs) msg.obj;
+ clientInfo = mClients.get(args.connector);
if (clientInfo.mResolvedService != null) {
- replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
- NsdManager.FAILURE_ALREADY_ACTIVE);
+ clientInfo.onResolveServiceFailed(
+ clientId, NsdManager.FAILURE_ALREADY_ACTIVE);
break;
}
maybeStartDaemon();
id = getUniqueId();
- if (resolveService(id, servInfo)) {
+ if (resolveService(id, args.serviceInfo)) {
clientInfo.mResolvedService = new NsdServiceInfo();
- storeRequestMap(msg.arg2, id, clientInfo, msg.what);
+ storeRequestMap(clientId, id, clientInfo, msg.what);
} else {
- replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR);
+ clientInfo.onResolveServiceFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
}
break;
case NsdManager.NATIVE_DAEMON_EVENT:
@@ -425,7 +408,7 @@ public class NsdService extends INsdManager.Stub {
ClientInfo clientInfo = mIdToClientInfoMap.get(id);
if (clientInfo == null) {
String name = NativeResponseCode.nameOf(code);
- Slog.e(TAG, String.format("id %d for %s has no client mapping", id, name));
+ Log.e(TAG, String.format("id %d for %s has no client mapping", id, name));
return false;
}
@@ -436,43 +419,40 @@ public class NsdService extends INsdManager.Stub {
// SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
// and we may get in this situation.
String name = NativeResponseCode.nameOf(code);
- Slog.d(TAG, String.format(
+ Log.d(TAG, String.format(
"Notification %s for listener id %d that is no longer active",
name, id));
return false;
}
if (DBG) {
String name = NativeResponseCode.nameOf(code);
- Slog.d(TAG, String.format("Native daemon message %s: %s", name, raw));
+ Log.d(TAG, String.format("Native daemon message %s: %s", name, raw));
}
switch (code) {
case NativeResponseCode.SERVICE_FOUND:
/* NNN uniqueId serviceName regType domain */
servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
- clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
- clientId, servInfo);
+ clientInfo.onServiceFound(clientId, servInfo);
break;
case NativeResponseCode.SERVICE_LOST:
/* NNN uniqueId serviceName regType domain */
servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
- clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
- clientId, servInfo);
+ clientInfo.onServiceLost(clientId, servInfo);
break;
case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
/* NNN uniqueId errorCode */
- clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+ clientInfo.onDiscoverServicesFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
break;
case NativeResponseCode.SERVICE_REGISTERED:
/* NNN regId serviceName regType */
servInfo = new NsdServiceInfo(cooked[2], null);
- clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
- id, clientId, servInfo);
+ clientInfo.onRegisterServiceSucceeded(clientId, servInfo);
break;
case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
/* NNN regId errorCode */
- clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+ clientInfo.onRegisterServiceFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
break;
case NativeResponseCode.SERVICE_UPDATED:
/* NNN regId */
@@ -490,7 +470,7 @@ public class NsdService extends INsdManager.Stub {
++index;
}
if (index >= cooked[2].length()) {
- Slog.e(TAG, "Invalid service found " + raw);
+ Log.e(TAG, "Invalid service found " + raw);
break;
}
String name = cooked[2].substring(0, index);
@@ -511,8 +491,8 @@ public class NsdService extends INsdManager.Stub {
if (getAddrInfo(id2, cooked[3])) {
storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE);
} else {
- clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+ clientInfo.onResolveServiceFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
clientInfo.mResolvedService = null;
}
break;
@@ -521,26 +501,26 @@ public class NsdService extends INsdManager.Stub {
stopResolveService(id);
removeRequestMap(clientId, id, clientInfo);
clientInfo.mResolvedService = null;
- clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+ clientInfo.onResolveServiceFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
break;
case NativeResponseCode.SERVICE_GET_ADDR_FAILED:
/* NNN resolveId errorCode */
stopGetAddrInfo(id);
removeRequestMap(clientId, id, clientInfo);
clientInfo.mResolvedService = null;
- clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+ clientInfo.onResolveServiceFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
break;
case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
/* NNN resolveId hostname ttl addr */
try {
clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
- clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
- 0, clientId, clientInfo.mResolvedService);
+ clientInfo.onResolveServiceSucceeded(
+ clientId, clientInfo.mResolvedService);
} catch (java.net.UnknownHostException e) {
- clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
- NsdManager.FAILURE_INTERNAL_ERROR, clientId);
+ clientInfo.onResolveServiceFailed(
+ clientId, NsdManager.FAILURE_INTERNAL_ERROR);
}
stopGetAddrInfo(id);
removeRequestMap(clientId, id, clientInfo);
@@ -560,13 +540,13 @@ public class NsdService extends INsdManager.Stub {
char c = s.charAt(i);
if (c == '\\') {
if (++i >= s.length()) {
- Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
+ Log.e(TAG, "Unexpected end of escape sequence in: " + s);
break;
}
c = s.charAt(i);
if (c != '.' && c != '\\') {
if (i + 2 >= s.length()) {
- Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
+ Log.e(TAG, "Unexpected end of escape sequence in: " + s);
break;
}
c = (char) ((c-'0') * 100 + (s.charAt(i+1)-'0') * 10 + (s.charAt(i+2)-'0'));
@@ -579,11 +559,9 @@ public class NsdService extends INsdManager.Stub {
}
@VisibleForTesting
- NsdService(Context ctx, NsdSettings settings, Handler handler,
- DaemonConnectionSupplier fn, long cleanupDelayMs) {
+ NsdService(Context ctx, Handler handler, DaemonConnectionSupplier fn, long cleanupDelayMs) {
mCleanupDelayMs = cleanupDelayMs;
mContext = ctx;
- mNsdSettings = settings;
mNsdStateMachine = new NsdStateMachine(TAG, handler);
mNsdStateMachine.start();
mDaemonCallback = new NativeCallbackReceiver();
@@ -591,29 +569,80 @@ public class NsdService extends INsdManager.Stub {
}
public static NsdService create(Context context) throws InterruptedException {
- NsdSettings settings = NsdSettings.makeDefault(context);
HandlerThread thread = new HandlerThread(TAG);
thread.start();
Handler handler = new Handler(thread.getLooper());
- NsdService service = new NsdService(context, settings, handler,
- DaemonConnection::new, CLEANUP_DELAY_MS);
+ NsdService service =
+ new NsdService(context, handler, DaemonConnection::new, CLEANUP_DELAY_MS);
service.mDaemonCallback.awaitConnection();
return service;
}
- public Messenger getMessenger() {
+ @Override
+ public INsdServiceConnector connect(INsdManagerCallback cb) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService");
- return new Messenger(mNsdStateMachine.getHandler());
+ final INsdServiceConnector connector = new NsdServiceConnector();
+ mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
+ NsdManager.REGISTER_CLIENT, new Pair<>(connector, cb)));
+ return connector;
}
- public void setEnabled(boolean isEnabled) {
- NetworkStack.checkNetworkStackPermission(mContext);
- mNsdSettings.putEnabledStatus(isEnabled);
- notifyEnabled(isEnabled);
+ private static class ListenerArgs {
+ public final NsdServiceConnector connector;
+ public final NsdServiceInfo serviceInfo;
+ ListenerArgs(NsdServiceConnector connector, NsdServiceInfo serviceInfo) {
+ this.connector = connector;
+ this.serviceInfo = serviceInfo;
+ }
}
- private void notifyEnabled(boolean isEnabled) {
- mNsdStateMachine.sendMessage(isEnabled ? NsdManager.ENABLE : NsdManager.DISABLE);
+ private class NsdServiceConnector extends INsdServiceConnector.Stub
+ implements IBinder.DeathRecipient {
+ @Override
+ public void registerService(int listenerKey, NsdServiceInfo serviceInfo) {
+ mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
+ NsdManager.REGISTER_SERVICE, 0, listenerKey,
+ new ListenerArgs(this, serviceInfo)));
+ }
+
+ @Override
+ public void unregisterService(int listenerKey) {
+ mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
+ NsdManager.UNREGISTER_SERVICE, 0, listenerKey,
+ new ListenerArgs(this, null)));
+ }
+
+ @Override
+ public void discoverServices(int listenerKey, NsdServiceInfo serviceInfo) {
+ mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
+ NsdManager.DISCOVER_SERVICES, 0, listenerKey,
+ new ListenerArgs(this, serviceInfo)));
+ }
+
+ @Override
+ public void stopDiscovery(int listenerKey) {
+ mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
+ NsdManager.STOP_DISCOVERY, 0, listenerKey, new ListenerArgs(this, null)));
+ }
+
+ @Override
+ public void resolveService(int listenerKey, NsdServiceInfo serviceInfo) {
+ mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
+ NsdManager.RESOLVE_SERVICE, 0, listenerKey,
+ new ListenerArgs(this, serviceInfo)));
+ }
+
+ @Override
+ public void startDaemon() {
+ mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
+ NsdManager.DAEMON_STARTUP, new ListenerArgs(this, null)));
+ }
+
+ @Override
+ public void binderDied() {
+ mNsdStateMachine.sendMessage(
+ mNsdStateMachine.obtainMessage(NsdManager.UNREGISTER_CLIENT, this));
+ }
}
private void sendNsdStateChangeBroadcast(boolean isEnabled) {
@@ -624,14 +653,6 @@ public class NsdService extends INsdManager.Stub {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- private boolean isNsdEnabled() {
- boolean ret = mNsdSettings.isEnabled();
- if (DBG) {
- Slog.d(TAG, "Network service discovery is " + (ret ? "enabled" : "disabled"));
- }
- return ret;
- }
-
private int getUniqueId() {
if (++mUniqueId == INVALID_ID) return ++mUniqueId;
return mUniqueId;
@@ -737,12 +758,12 @@ public class NsdService extends INsdManager.Stub {
*/
public boolean execute(Object... args) {
if (DBG) {
- Slog.d(TAG, "mdnssd " + Arrays.toString(args));
+ Log.d(TAG, "mdnssd " + Arrays.toString(args));
}
try {
mNativeConnector.execute("mdnssd", args);
} catch (NativeDaemonConnectorException e) {
- Slog.e(TAG, "Failed to execute mdnssd " + Arrays.toString(args), e);
+ Log.e(TAG, "Failed to execute mdnssd " + Arrays.toString(args), e);
return false;
}
return true;
@@ -773,7 +794,7 @@ public class NsdService extends INsdManager.Stub {
private boolean registerService(int regId, NsdServiceInfo service) {
if (DBG) {
- Slog.d(TAG, "registerService: " + regId + " " + service);
+ Log.d(TAG, "registerService: " + regId + " " + service);
}
String name = service.getServiceName();
String type = service.getServiceType();
@@ -822,7 +843,12 @@ public class NsdService extends INsdManager.Stub {
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump " + TAG
+ + " due to missing android.permission.DUMP permission");
+ return;
+ }
for (ClientInfo client : mClients.values()) {
pw.println("Client Info");
@@ -832,43 +858,11 @@ public class NsdService extends INsdManager.Stub {
mNsdStateMachine.dump(fd, pw, args);
}
- /* arg2 on the source message has an id that needs to be retained in replies
- * see NsdManager for details */
- private Message obtainMessage(Message srcMsg) {
- Message msg = Message.obtain();
- msg.arg2 = srcMsg.arg2;
- return msg;
- }
-
- private void replyToMessage(Message msg, int what) {
- if (msg.replyTo == null) return;
- Message dstMsg = obtainMessage(msg);
- dstMsg.what = what;
- mReplyChannel.replyToMessage(msg, dstMsg);
- }
-
- private void replyToMessage(Message msg, int what, int arg1) {
- if (msg.replyTo == null) return;
- Message dstMsg = obtainMessage(msg);
- dstMsg.what = what;
- dstMsg.arg1 = arg1;
- mReplyChannel.replyToMessage(msg, dstMsg);
- }
-
- private void replyToMessage(Message msg, int what, Object obj) {
- if (msg.replyTo == null) return;
- Message dstMsg = obtainMessage(msg);
- dstMsg.what = what;
- dstMsg.obj = obj;
- mReplyChannel.replyToMessage(msg, dstMsg);
- }
-
/* Information tracked per client */
private class ClientInfo {
private static final int MAX_LIMIT = 10;
- private final AsyncChannel mChannel;
- private final Messenger mMessenger;
+ private final INsdManagerCallback mCb;
/* Remembers a resolved service until getaddrinfo completes */
private NsdServiceInfo mResolvedService;
@@ -881,17 +875,14 @@ public class NsdService extends INsdManager.Stub {
// The target SDK of this client < Build.VERSION_CODES.S
private boolean mIsLegacy = false;
- private ClientInfo(AsyncChannel c, Messenger m) {
- mChannel = c;
- mMessenger = m;
- if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m);
+ private ClientInfo(INsdManagerCallback cb) {
+ mCb = cb;
+ if (DBG) Log.d(TAG, "New client");
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append("mChannel ").append(mChannel).append("\n");
- sb.append("mMessenger ").append(mMessenger).append("\n");
sb.append("mResolvedService ").append(mResolvedService).append("\n");
sb.append("mIsLegacy ").append(mIsLegacy).append("\n");
for(int i = 0; i< mClientIds.size(); i++) {
@@ -920,8 +911,10 @@ public class NsdService extends INsdManager.Stub {
clientId = mClientIds.keyAt(i);
globalId = mClientIds.valueAt(i);
mIdToClientInfoMap.remove(globalId);
- if (DBG) Slog.d(TAG, "Terminating client-ID " + clientId +
- " global-ID " + globalId + " type " + mClientRequests.get(clientId));
+ if (DBG) {
+ Log.d(TAG, "Terminating client-ID " + clientId
+ + " global-ID " + globalId + " type " + mClientRequests.get(clientId));
+ }
switch (mClientRequests.get(clientId)) {
case NsdManager.DISCOVER_SERVICES:
stopServiceDiscovery(globalId);
@@ -949,36 +942,101 @@ public class NsdService extends INsdManager.Stub {
}
return mClientIds.keyAt(idx);
}
- }
- /**
- * Interface which encapsulates dependencies of NsdService that are hard to mock, hard to
- * override, or have side effects on global state in unit tests.
- */
- @VisibleForTesting
- public interface NsdSettings {
- boolean isEnabled();
- void putEnabledStatus(boolean isEnabled);
- void registerContentObserver(Uri uri, ContentObserver observer);
-
- static NsdSettings makeDefault(Context context) {
- final ContentResolver resolver = context.getContentResolver();
- return new NsdSettings() {
- @Override
- public boolean isEnabled() {
- return Settings.Global.getInt(resolver, Settings.Global.NSD_ON, 1) == 1;
- }
+ void onDiscoverServicesStarted(int listenerKey, NsdServiceInfo info) {
+ try {
+ mCb.onDiscoverServicesStarted(listenerKey, info);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling onDiscoverServicesStarted", e);
+ }
+ }
- @Override
- public void putEnabledStatus(boolean isEnabled) {
- Settings.Global.putInt(resolver, Settings.Global.NSD_ON, isEnabled ? 1 : 0);
- }
+ void onDiscoverServicesFailed(int listenerKey, int error) {
+ try {
+ mCb.onDiscoverServicesFailed(listenerKey, error);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling onDiscoverServicesFailed", e);
+ }
+ }
- @Override
- public void registerContentObserver(Uri uri, ContentObserver observer) {
- resolver.registerContentObserver(uri, false, observer);
- }
- };
+ void onServiceFound(int listenerKey, NsdServiceInfo info) {
+ try {
+ mCb.onServiceFound(listenerKey, info);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling onServiceFound(", e);
+ }
+ }
+
+ void onServiceLost(int listenerKey, NsdServiceInfo info) {
+ try {
+ mCb.onServiceLost(listenerKey, info);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling onServiceLost(", e);
+ }
+ }
+
+ void onStopDiscoveryFailed(int listenerKey, int error) {
+ try {
+ mCb.onStopDiscoveryFailed(listenerKey, error);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling onStopDiscoveryFailed", e);
+ }
+ }
+
+ void onStopDiscoverySucceeded(int listenerKey) {
+ try {
+ mCb.onStopDiscoverySucceeded(listenerKey);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling onStopDiscoverySucceeded", e);
+ }
+ }
+
+ void onRegisterServiceFailed(int listenerKey, int error) {
+ try {
+ mCb.onRegisterServiceFailed(listenerKey, error);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling onRegisterServiceFailed", e);
+ }
+ }
+
+ void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info) {
+ try {
+ mCb.onRegisterServiceSucceeded(listenerKey, info);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling onRegisterServiceSucceeded", e);
+ }
+ }
+
+ void onUnregisterServiceFailed(int listenerKey, int error) {
+ try {
+ mCb.onUnregisterServiceFailed(listenerKey, error);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling onUnregisterServiceFailed", e);
+ }
+ }
+
+ void onUnregisterServiceSucceeded(int listenerKey) {
+ try {
+ mCb.onUnregisterServiceSucceeded(listenerKey);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling onUnregisterServiceSucceeded", e);
+ }
+ }
+
+ void onResolveServiceFailed(int listenerKey, int error) {
+ try {
+ mCb.onResolveServiceFailed(listenerKey, error);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling onResolveServiceFailed", e);
+ }
+ }
+
+ void onResolveServiceSucceeded(int listenerKey, NsdServiceInfo info) {
+ try {
+ mCb.onResolveServiceSucceeded(listenerKey, info);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling onResolveServiceSucceeded", e);
+ }
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java b/packages/Nsd/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java
index e2253a2151b0..e2253a2151b0 100644
--- a/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java
+++ b/packages/Nsd/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java
diff --git a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
index 7ff9cedab5f7..b2c82c6fb846 100644
--- a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
+++ b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
@@ -30,11 +30,8 @@ static bool writeAllBytes(const int fd, void* buffer, const size_t byteCount) {
char* writeBuffer = static_cast<char*>(buffer);
size_t remainingBytes = byteCount;
while (remainingBytes > 0) {
- ssize_t writtenByteCount = write(fd, writeBuffer, remainingBytes);
+ ssize_t writtenByteCount = TEMP_FAILURE_RETRY(write(fd, writeBuffer, remainingBytes));
if (writtenByteCount == -1) {
- if (errno == EINTR) {
- continue;
- }
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"Error writing to buffer: %d", errno);
return false;
@@ -49,19 +46,17 @@ static bool readAllBytes(const int fd, void* buffer, const size_t byteCount) {
char* readBuffer = static_cast<char*>(buffer);
size_t remainingBytes = byteCount;
while (remainingBytes > 0) {
- ssize_t readByteCount = read(fd, readBuffer, remainingBytes);
-
- remainingBytes -= readByteCount;
- readBuffer += readByteCount;
-
+ ssize_t readByteCount = TEMP_FAILURE_RETRY(read(fd, readBuffer, remainingBytes));
if (readByteCount == -1) {
- if (errno == EINTR) {
- continue;
- }
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"Error reading from buffer: %d", errno);
return false;
- } else if (readByteCount == 0 && remainingBytes > 0) {
+ }
+
+ remainingBytes -= readByteCount;
+ readBuffer += readByteCount;
+
+ if (readByteCount == 0 && remainingBytes > 0) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
"File closed before all bytes were read. %zu/%zu remaining", remainingBytes,
byteCount);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 3c7856048860..99e3160fcbe3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -28,13 +28,16 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
+import android.os.Build;
import android.os.ParcelUuid;
import android.util.Log;
+import androidx.annotation.RequiresApi;
+
import com.android.settingslib.R;
import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
public class A2dpProfile implements LocalBluetoothProfile {
@@ -226,6 +229,10 @@ public class A2dpProfile implements LocalBluetoothProfile {
return support == BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED;
}
+ /**
+ * @return whether high quality audio is enabled or not
+ */
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
public boolean isHighQualityAudioEnabled(BluetoothDevice device) {
BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice();
if (bluetoothDevice == null) {
@@ -271,6 +278,13 @@ public class A2dpProfile implements LocalBluetoothProfile {
}
}
+ /**
+ * Gets the label associated with the codec of a Bluetooth device.
+ *
+ * @param device to get codec label from
+ * @return the label associated with the device codec
+ */
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
public String getHighQualityAudioOptionLabel(BluetoothDevice device) {
BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice();
int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec;
@@ -280,18 +294,18 @@ public class A2dpProfile implements LocalBluetoothProfile {
}
// We want to get the highest priority codec, since that's the one that will be used with
// this device, and see if it is high-quality (ie non-mandatory).
- BluetoothCodecConfig[] selectable = null;
+ List<BluetoothCodecConfig> selectable = null;
if (mService.getCodecStatus(device) != null) {
selectable = mService.getCodecStatus(device).getCodecsSelectableCapabilities();
// To get the highest priority, we sort in reverse.
- Arrays.sort(selectable,
+ Collections.sort(selectable,
(a, b) -> {
return b.getCodecPriority() - a.getCodecPriority();
});
}
- final BluetoothCodecConfig codecConfig = (selectable == null || selectable.length < 1)
- ? null : selectable[0];
+ final BluetoothCodecConfig codecConfig = (selectable == null || selectable.size() < 1)
+ ? null : selectable.get(0);
final int codecType = (codecConfig == null || codecConfig.isMandatoryCodec())
? BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID : codecConfig.getCodecType();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 58d2185ea9e9..389892ed15e4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -160,10 +160,12 @@ public class BluetoothEventManager {
private void registerIntentReceiver(BroadcastReceiver receiver, IntentFilter filter) {
if (mUserHandle == null) {
// If userHandle has not been provided, simply call registerReceiver.
- mContext.registerReceiver(receiver, filter, null, mReceiverHandler);
+ mContext.registerReceiver(receiver, filter, null, mReceiverHandler,
+ Context.RECEIVER_EXPORTED);
} else {
// userHandle was explicitly specified, so need to call multi-user aware API.
- mContext.registerReceiverAsUser(receiver, mUserHandle, filter, null, mReceiverHandler);
+ mContext.registerReceiverAsUser(receiver, mUserHandle, filter, null, mReceiverHandler,
+ Context.RECEIVER_EXPORTED);
}
}
@@ -305,7 +307,8 @@ public class BluetoothEventManager {
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
if (cachedDevice == null) {
cachedDevice = mDeviceManager.addDevice(device);
- Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice");
+ Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice "
+ + cachedDevice.getDevice().getAnonymizedAddress());
} else if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
&& !cachedDevice.getDevice().isConnected()) {
// Dispatch device add callback to show bonded but
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 021ba2247e67..ddee433d3997 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -21,7 +21,6 @@ import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHearingAid;
-import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
@@ -191,7 +190,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
void onProfileStateChanged(LocalBluetoothProfile profile, int newProfileState) {
if (BluetoothUtils.D) {
Log.d(TAG, "onProfileStateChanged: profile " + profile + ", device "
- + mDevice.getAlias() + ", newProfileState " + newProfileState);
+ + mDevice.getAnonymizedAddress() + ", newProfileState " + newProfileState);
}
if (mLocalAdapter.getState() == BluetoothAdapter.STATE_TURNING_OFF)
{
@@ -741,7 +740,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
}
if (BluetoothUtils.D) {
- Log.d(TAG, "updating profiles for " + mDevice.getAlias());
+ Log.d(TAG, "updating profiles for " + mDevice.getAnonymizedAddress());
BluetoothClass bluetoothClass = mDevice.getBluetoothClass();
if (bluetoothClass != null) Log.v(TAG, "Class: " + bluetoothClass.toString());
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
index 9afdd43ce73c..f167721f94bf 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
@@ -43,6 +43,9 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
+import java.util.Arrays;
+import java.util.List;
+
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothAdapter.class})
public class A2dpProfileTest {
@@ -179,7 +182,7 @@ public class A2dpProfileTest {
BluetoothProfile.STATE_CONNECTED);
BluetoothCodecStatus status = mock(BluetoothCodecStatus.class);
BluetoothCodecConfig config = mock(BluetoothCodecConfig.class);
- BluetoothCodecConfig[] configs = {config};
+ List<BluetoothCodecConfig> configs = Arrays.asList(config);
when(mBluetoothA2dp.getCodecStatus(mDevice)).thenReturn(status);
when(status.getCodecsSelectableCapabilities()).thenReturn(configs);
@@ -194,7 +197,7 @@ public class A2dpProfileTest {
BluetoothProfile.STATE_CONNECTED);
BluetoothCodecStatus status = mock(BluetoothCodecStatus.class);
BluetoothCodecConfig config = mock(BluetoothCodecConfig.class);
- BluetoothCodecConfig[] configs = {config};
+ List<BluetoothCodecConfig> configs = Arrays.asList(config);
when(mBluetoothA2dp.getCodecStatus(mDevice)).thenReturn(status);
when(status.getCodecsSelectableCapabilities()).thenReturn(configs);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java
index 5252c6c82754..52d243a14e2f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java
@@ -20,9 +20,8 @@ import static com.google.common.truth.Truth.assertThat;
import static org.robolectric.shadow.api.Shadow.extract;
-import android.net.ConnectivityManager;
import android.os.UserManager;
-import android.util.SparseBooleanArray;
+import android.telephony.TelephonyManager;
import org.junit.Before;
import org.junit.Test;
@@ -35,7 +34,7 @@ import org.robolectric.annotation.Implements;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {SimStatusImeiInfoPreferenceControllerTest.ShadowUserManager.class,
- SimStatusImeiInfoPreferenceControllerTest.ShadowConnectivityManager.class})
+ SimStatusImeiInfoPreferenceControllerTest.ShadowTelephonyManager.class})
public class SimStatusImeiInfoPreferenceControllerTest {
private AbstractSimStatusImeiInfoPreferenceController mController;
@@ -56,9 +55,9 @@ public class SimStatusImeiInfoPreferenceControllerTest {
ShadowUserManager userManager =
extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
userManager.setIsAdminUser(true);
- ShadowConnectivityManager connectivityManager =
- extract(RuntimeEnvironment.application.getSystemService(ConnectivityManager.class));
- connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, true);
+ ShadowTelephonyManager telephonyManager =
+ extract(RuntimeEnvironment.application.getSystemService(TelephonyManager.class));
+ telephonyManager.setDataCapable(true);
assertThat(mController.isAvailable()).isTrue();
}
@@ -68,9 +67,9 @@ public class SimStatusImeiInfoPreferenceControllerTest {
ShadowUserManager userManager =
extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
userManager.setIsAdminUser(true);
- ShadowConnectivityManager connectivityManager =
- extract(RuntimeEnvironment.application.getSystemService(ConnectivityManager.class));
- connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, false);
+ ShadowTelephonyManager telephonyManager =
+ extract(RuntimeEnvironment.application.getSystemService(TelephonyManager.class));
+ telephonyManager.setDataCapable(false);
assertThat(mController.isAvailable()).isFalse();
}
@@ -99,19 +98,17 @@ public class SimStatusImeiInfoPreferenceControllerTest {
}
}
- @Implements(ConnectivityManager.class)
- public static class ShadowConnectivityManager
- extends org.robolectric.shadows.ShadowConnectivityManager {
-
- private final SparseBooleanArray mSupportedNetworkTypes = new SparseBooleanArray();
-
- private void setNetworkSupported(int networkType, boolean supported) {
- mSupportedNetworkTypes.put(networkType, supported);
+ @Implements(TelephonyManager.class)
+ public static class ShadowTelephonyManager
+ extends org.robolectric.shadows.ShadowTelephonyManager {
+ private boolean mDataCapable = false;
+ private void setDataCapable(boolean capable) {
+ mDataCapable = capable;
}
@Implementation
- public boolean isNetworkSupported(int networkType) {
- return mSupportedNetworkTypes.get(networkType);
+ public boolean isDataCapable() {
+ return mDataCapable;
}
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 9cd7083a2a11..c30c742fd9d9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -98,6 +98,10 @@ public class SettingsBackupAgent extends BackupAgentHelper {
private static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config";
private static final String KEY_DEVICE_SPECIFIC_CONFIG = "device_specific_config";
private static final String KEY_SIM_SPECIFIC_SETTINGS = "sim_specific_settings";
+ // Restoring sim-specific data backed up from newer Android version to Android 12 was causing a
+ // fatal crash. Creating a backup with a different key will prevent Android 12 versions from
+ // restoring this data.
+ private static final String KEY_SIM_SPECIFIC_SETTINGS_2 = "sim_specific_settings_2";
// Versioning of the state file. Increment this version
// number any time the set of state items is altered.
@@ -253,7 +257,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
deviceSpecificInformation, data);
stateChecksums[STATE_SIM_SPECIFIC_SETTINGS] =
writeIfChanged(stateChecksums[STATE_SIM_SPECIFIC_SETTINGS],
- KEY_SIM_SPECIFIC_SETTINGS, simSpecificSettingsData, data);
+ KEY_SIM_SPECIFIC_SETTINGS_2, simSpecificSettingsData, data);
writeNewChecksums(stateChecksums, newState);
}
@@ -395,6 +399,9 @@ public class SettingsBackupAgent extends BackupAgentHelper {
break;
case KEY_SIM_SPECIFIC_SETTINGS:
+ // Intentional fall through so that sim-specific backups from Android 12 will
+ // also be restored on newer Android versions.
+ case KEY_SIM_SPECIFIC_SETTINGS_2:
byte[] restoredSimSpecificSettings = new byte[size];
data.readEntityData(restoredSimSpecificSettings, 0, size);
restoreSimSpecificSettings(restoredSimSpecificSettings);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 073b4d00653d..6c6b0e8a5076 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1085,14 +1085,17 @@ class SettingsProtoDumpUtil {
Settings.Global.NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE,
GlobalSettingsProto.NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE);
- final long nitzUpdateToken = p.start(GlobalSettingsProto.NITZ_UPDATE);
+ final long nitzToken = p.start(GlobalSettingsProto.NITZ);
dumpSetting(s, p,
Settings.Global.NITZ_UPDATE_DIFF,
- GlobalSettingsProto.NitzUpdate.DIFF);
+ GlobalSettingsProto.Nitz.UPDATE_DIFF);
dumpSetting(s, p,
Settings.Global.NITZ_UPDATE_SPACING,
- GlobalSettingsProto.NitzUpdate.SPACING);
- p.end(nitzUpdateToken);
+ GlobalSettingsProto.Nitz.UPDATE_SPACING);
+ dumpSetting(s, p,
+ Settings.Global.NITZ_NETWORK_DISCONNECT_RETENTION,
+ GlobalSettingsProto.Nitz.NETWORK_DISCONNECT_RETENTION);
+ p.end(nitzToken);
final long notificationToken = p.start(GlobalSettingsProto.NOTIFICATION);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 3297937e3e75..773b0682233f 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -388,6 +388,7 @@ public class SettingsBackupTest {
Settings.Global.NETWORK_WATCHLIST_ENABLED,
Settings.Global.NEW_CONTACT_AGGREGATOR,
Settings.Global.NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE,
+ Settings.Global.NITZ_NETWORK_DISCONNECT_RETENTION,
Settings.Global.NITZ_UPDATE_DIFF,
Settings.Global.NITZ_UPDATE_SPACING,
Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 54fb6475197a..87d50f29061f 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -575,6 +575,12 @@
<uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
<uses-permission android:name="android.permission.DEBUG_VIRTUAL_MACHINE" />
+ <!-- Permission required for CTS test - SettingsMultiPaneDeepLinkTest -->
+ <uses-permission android:name="android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK" />
+
+ <!-- Permission required for ATS test - CarDevicePolicyManagerTest -->
+ <uses-permission android:name="android.permission.LOCK_DEVICE" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
@@ -641,6 +647,15 @@
</intent-filter>
</receiver>
+ <receiver
+ android:name=".ProfcollectUploadReceiver"
+ android:exported="true"
+ android:permission="android.permission.TRIGGER_SHELL_PROFCOLLECT_UPLOAD" >
+ <intent-filter>
+ <action android:name="com.android.shell.action.PROFCOLLECT_UPLOAD" />
+ </intent-filter>
+ </receiver>
+
<service
android:name=".BugreportProgressService"
android:exported="false"/>
diff --git a/packages/Shell/res/xml/file_provider_paths.xml b/packages/Shell/res/xml/file_provider_paths.xml
index 225c7571e7e2..85d7dd372294 100644
--- a/packages/Shell/res/xml/file_provider_paths.xml
+++ b/packages/Shell/res/xml/file_provider_paths.xml
@@ -1,3 +1,4 @@
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="bugreports" path="bugreports/" />
+ <root-path name="profcollect" path="/data/misc/profcollectd/report/" />
</paths>
diff --git a/packages/Shell/src/com/android/shell/ProfcollectUploadReceiver.java b/packages/Shell/src/com/android/shell/ProfcollectUploadReceiver.java
new file mode 100644
index 000000000000..d2da724796cb
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/ProfcollectUploadReceiver.java
@@ -0,0 +1,98 @@
+/*
+ * 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.shell;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.util.Log;
+
+import androidx.core.content.FileProvider;
+
+import com.android.internal.R;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * A proxy service that relays report upload requests to the uploader app, while translating
+ * the path to the report to a content URI owned by this service.
+ */
+public final class ProfcollectUploadReceiver extends BroadcastReceiver {
+ private static final String AUTHORITY = "com.android.shell";
+ private static final String PROFCOLLECT_DATA_ROOT = "/data/misc/profcollectd/report/";
+
+ private static final String LOG_TAG = "ProfcollectUploadReceiver";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.i(LOG_TAG, "Received upload intent");
+
+ String uploaderPkg = getUploaderPackageName(context);
+ String uploaderAction = getUploaderActionName(context);
+
+ try {
+ ApplicationInfo info = context.getPackageManager().getApplicationInfo(uploaderPkg,
+ 0);
+ if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ Log.e(LOG_TAG, "The profcollect uploader app " + uploaderPkg
+ + " must be a system application");
+ return;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOG_TAG, "Cannot find profcollect uploader app " + uploaderPkg);
+ return;
+ }
+
+ String filename = intent.getStringExtra("filename");
+ File reportFile = new File(PROFCOLLECT_DATA_ROOT + filename);
+ Uri reportUri = FileProvider.getUriForFile(context, AUTHORITY, reportFile);
+ Intent uploadIntent =
+ new Intent(uploaderAction)
+ .setPackage(uploaderPkg)
+ .putExtra("EXTRA_DESTINATION", "PROFCOLLECT")
+ .putExtra("EXTRA_PACKAGE_NAME", context.getPackageName())
+ .setData(reportUri)
+ .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+
+ List<ResolveInfo> receivers =
+ context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0);
+ if (receivers == null || receivers.isEmpty()) {
+ Log.e(LOG_TAG, "No one to receive upload intent, abort upload.");
+ return;
+ }
+
+ context.grantUriPermission(uploaderPkg, reportUri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ context.sendBroadcast(uploadIntent);
+ }
+
+ private String getUploaderPackageName(Context context) {
+ return context.getResources().getString(
+ R.string.config_defaultProfcollectReportUploaderApp);
+ }
+
+ private String getUploaderActionName(Context context) {
+ return context.getResources().getString(
+ R.string.config_defaultProfcollectReportUploaderAction);
+ }
+}
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 1cf14f2362de..e1da74466b55 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -11,6 +11,7 @@ asc@google.com
awickham@google.com
beverlyt@google.com
brockman@google.com
+brycelee@google.com
ccassidy@google.com
cinek@google.com
cwren@google.com
@@ -22,6 +23,7 @@ hwwang@google.com
hyunyoungs@google.com
jaggies@google.com
jamesoleary@google.com
+jbolinger@google.com
jdemeulenaere@google.com
jeffdq@google.com
jjaggi@google.com
@@ -70,4 +72,4 @@ zakcohen@google.com
hseog@google.com
#Android TV
-rgl@google.com \ No newline at end of file
+rgl@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java
index 376368fbf9d4..d80d9cc9d62d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java
@@ -21,12 +21,19 @@ import android.annotation.Nullable;
import android.content.Context;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.util.AttributeSet;
+import android.util.Log;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
/**
* Manages the layout for under-display fingerprint sensors (UDFPS). Ensures that UI elements
* do not overlap with
*/
public class AuthBiometricUdfpsView extends AuthBiometricFingerprintView {
+ private static final String TAG = "AuthBiometricUdfpsView";
+
@Nullable private UdfpsDialogMeasureAdapter mMeasureAdapter;
public AuthBiometricUdfpsView(Context context) {
@@ -51,4 +58,23 @@ public class AuthBiometricUdfpsView extends AuthBiometricFingerprintView {
? mMeasureAdapter.onMeasureInternal(width, height, layoutParams)
: layoutParams;
}
+
+ @Override
+ void onLayoutInternal() {
+ super.onLayoutInternal();
+
+ // Move the UDFPS icon and indicator text if necessary. This probably only needs to happen
+ // for devices where the UDFPS sensor is too low.
+ // TODO(b/201510778): Update this logic to support cases where the sensor or text overlap
+ // the button bar area.
+ final int bottomSpacerHeight = mMeasureAdapter.getBottomSpacerHeight();
+ Log.w(TAG, "bottomSpacerHeight: " + bottomSpacerHeight);
+ if (bottomSpacerHeight < 0) {
+ FrameLayout iconFrame = findViewById(R.id.biometric_icon_frame);
+ iconFrame.setTranslationY(-bottomSpacerHeight);
+
+ TextView indicator = findViewById(R.id.indicator);
+ indicator.setTranslationY(-bottomSpacerHeight);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
index 7ccfb865cd5a..6185e59b17d8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
@@ -45,6 +45,7 @@ public class UdfpsDialogMeasureAdapter {
@NonNull private final FingerprintSensorPropertiesInternal mSensorProps;
@Nullable private WindowManager mWindowManager;
+ private int mBottomSpacerHeight;
public UdfpsDialogMeasureAdapter(
@NonNull ViewGroup view, @NonNull FingerprintSensorPropertiesInternal sensorProps) {
@@ -74,6 +75,16 @@ public class UdfpsDialogMeasureAdapter {
}
}
+ /**
+ * @return the actual (and possibly negative) bottom spacer height. If negative, this indicates
+ * that the UDFPS sensor is too low. Our current xml and custom measurement logic is very hard
+ * too cleanly support this case. So, let's have the onLayout code translate the sensor location
+ * instead.
+ */
+ int getBottomSpacerHeight() {
+ return mBottomSpacerHeight;
+ }
+
@NonNull
private AuthDialog.LayoutParams onMeasureInternalPortrait(int width, int height) {
// Get the height of the everything below the icon. Currently, that's the indicator and
@@ -86,7 +97,7 @@ public class UdfpsDialogMeasureAdapter {
final int dialogMargin = getDialogMarginPx();
final int displayHeight = getWindowBounds().height();
final Insets navbarInsets = getNavbarInsets();
- final int bottomSpacerHeight = calculateBottomSpacerHeightForPortrait(
+ mBottomSpacerHeight = calculateBottomSpacerHeightForPortrait(
mSensorProps, displayHeight, textIndicatorHeight, buttonBarHeight,
dialogMargin, navbarInsets.bottom);
@@ -122,9 +133,10 @@ public class UdfpsDialogMeasureAdapter {
MeasureSpec.EXACTLY));
} else if (child.getId() == R.id.space_below_icon) {
// Set the spacer height so the fingerprint icon is on the physical sensor area
+ final int clampedSpacerHeight = Math.max(mBottomSpacerHeight, 0);
child.measure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(bottomSpacerHeight, MeasureSpec.EXACTLY));
+ MeasureSpec.makeMeasureSpec(clampedSpacerHeight, MeasureSpec.EXACTLY));
} else {
child.measure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index 15f77ffc08fd..8a213ec502e4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -239,18 +239,20 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin
if (mGhbmView != null && surface == null) {
Log.e(TAG, "doIlluminate | surface must be non-null for GHBM");
}
- mHbmProvider.enableHbm(mHbmType, surface, () -> {
- if (mGhbmView != null) {
- mGhbmView.drawIlluminationDot(mSensorRect);
- }
- if (onIlluminatedRunnable != null) {
- // No framework API can reliably tell when a frame reaches the panel. A timeout
- // is the safest solution.
- postDelayed(onIlluminatedRunnable, mOnIlluminatedDelayMs);
- } else {
- Log.w(TAG, "doIlluminate | onIlluminatedRunnable is null");
- }
- });
+ if (mHbmProvider != null) {
+ mHbmProvider.enableHbm(mHbmType, surface, () -> {
+ if (mGhbmView != null) {
+ mGhbmView.drawIlluminationDot(mSensorRect);
+ }
+ if (onIlluminatedRunnable != null) {
+ // No framework API can reliably tell when a frame reaches the panel. A timeout
+ // is the safest solution.
+ postDelayed(onIlluminatedRunnable, mOnIlluminatedDelayMs);
+ } else {
+ Log.w(TAG, "doIlluminate | onIlluminatedRunnable is null");
+ }
+ });
+ }
}
@Override
@@ -263,6 +265,8 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin
mGhbmView.setGhbmIlluminationListener(null);
mGhbmView.setVisibility(View.INVISIBLE);
}
- mHbmProvider.disableHbm(null /* onHbmDisabled */);
+ if (mHbmProvider != null) {
+ mHbmProvider.disableHbm(null /* onHbmDisabled */);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 89786ee880ad..a617850ef0ae 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -139,7 +139,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
+ " with ducking", e);
}
player.start();
- if (DEBUG) { Log.d(mTag, "player.start"); }
+ if (DEBUG) { Log.d(mTag, "player.start piid:" + player.getPlayerIId()); }
} catch (Exception e) {
if (player != null) {
player.release();
@@ -155,7 +155,13 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
mPlayer = player;
}
if (mp != null) {
- if (DEBUG) { Log.d(mTag, "mPlayer.release"); }
+ if (DEBUG) {
+ Log.d(mTag, "mPlayer.pause+release piid:" + player.getPlayerIId());
+ }
+ mp.pause();
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ie) { }
mp.release();
}
this.notify();
@@ -244,6 +250,10 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
try {
mp.stop();
} catch (Exception e) { }
+ if (DEBUG) {
+ Log.i(mTag, "About to release MediaPlayer piid:"
+ + mp.getPlayerIId() + " due to notif cancelled");
+ }
mp.release();
synchronized(mQueueAudioFocusLock) {
if (mAudioManagerWithAudioFocus != null) {
@@ -284,7 +294,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
public void onCompletion(MediaPlayer mp) {
synchronized(mQueueAudioFocusLock) {
if (mAudioManagerWithAudioFocus != null) {
- if (DEBUG) Log.d(mTag, "onCompletion() abandonning AudioFocus");
+ if (DEBUG) Log.d(mTag, "onCompletion() abandoning AudioFocus");
mAudioManagerWithAudioFocus.abandonAudioFocus(null);
mAudioManagerWithAudioFocus = null;
} else {
@@ -310,6 +320,10 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
}
}
if (mp != null) {
+ if (DEBUG) {
+ Log.i("NotificationPlayer", "About to release MediaPlayer piid:"
+ + mp.getPlayerIId() + " due to onCompletion");
+ }
mp.release();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 541ee2c4fe8f..4a75810f86db 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -51,6 +51,7 @@ import com.android.systemui.qs.external.TileServices;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -95,6 +96,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
private final UiEventLogger mUiEventLogger;
private final InstanceIdSequence mInstanceIdSequence;
private final CustomTileStatePersister mCustomTileStatePersister;
+ private final FeatureFlags mFeatureFlags;
private final List<Callback> mCallbacks = new ArrayList<>();
private AutoTileManager mAutoTiles;
@@ -122,7 +124,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
UiEventLogger uiEventLogger,
UserTracker userTracker,
SecureSettings secureSettings,
- CustomTileStatePersister customTileStatePersister
+ CustomTileStatePersister customTileStatePersister,
+ FeatureFlags featureFlags
) {
mIconController = iconController;
mContext = context;
@@ -144,6 +147,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
mUserTracker = userTracker;
mSecureSettings = secureSettings;
mCustomTileStatePersister = customTileStatePersister;
+ mFeatureFlags = featureFlags;
mainHandler.post(() -> {
// This is technically a hack to avoid circular dependency of
@@ -265,7 +269,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
if (newValue == null && UserManager.isDeviceInDemoMode(mContext)) {
newValue = mContext.getResources().getString(R.string.quick_settings_tiles_retail_mode);
}
- final List<String> tileSpecs = loadTileSpecs(mContext, newValue);
+ final List<String> tileSpecs = loadTileSpecs(mContext, newValue, mFeatureFlags);
int currentUser = mUserTracker.getUserId();
if (currentUser != mCurrentUser) {
mUserContext = mUserTracker.getUserContext();
@@ -334,7 +338,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
if (newTiles.isEmpty() && !tileSpecs.isEmpty()) {
// If we didn't manage to create any tiles, set it to empty (default)
Log.d(TAG, "No valid tiles on tuning changed. Setting to default.");
- changeTiles(currentSpecs, loadTileSpecs(mContext, ""));
+ changeTiles(currentSpecs, loadTileSpecs(mContext, "", mFeatureFlags));
} else {
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onTilesChanged();
@@ -389,7 +393,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
private void changeTileSpecs(Predicate<List<String>> changeFunction) {
final String setting = mSecureSettings.getStringForUser(TILES_SETTING, mCurrentUser);
- final List<String> tileSpecs = loadTileSpecs(mContext, setting);
+ final List<String> tileSpecs = loadTileSpecs(mContext, setting, mFeatureFlags);
if (changeFunction.test(tileSpecs)) {
saveTilesToSettings(tileSpecs);
}
@@ -478,7 +482,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
throw new RuntimeException("Default factory didn't create view for " + tile.getTileSpec());
}
- protected static List<String> loadTileSpecs(Context context, String tileList) {
+ protected static List<String> loadTileSpecs(
+ Context context, String tileList, FeatureFlags featureFlags) {
final Resources res = context.getResources();
if (TextUtils.isEmpty(tileList)) {
@@ -511,6 +516,21 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
}
}
}
+ if (featureFlags.isProviderModelSettingEnabled()) {
+ if (!tiles.contains("internet")) {
+ if (tiles.contains("wifi")) {
+ // Replace the WiFi with Internet, and remove the Cell
+ tiles.set(tiles.indexOf("wifi"), "internet");
+ tiles.remove("cell");
+ } else if (tiles.contains("cell")) {
+ // Replace the Cell with Internet
+ tiles.set(tiles.indexOf("cell"), "internet");
+ }
+ } else {
+ tiles.remove("wifi");
+ tiles.remove("cell");
+ }
+ }
return tiles;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 3c2f35b954ea..f2832b3d45ff 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -41,6 +41,7 @@ import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.util.leak.GarbageMonitor;
import java.util.ArrayList;
@@ -62,6 +63,7 @@ public class TileQueryHelper {
private final Executor mBgExecutor;
private final Context mContext;
private final UserTracker mUserTracker;
+ private final FeatureFlags mFeatureFlags;
private TileStateListener mListener;
private boolean mFinished;
@@ -71,12 +73,14 @@ public class TileQueryHelper {
Context context,
UserTracker userTracker,
@Main Executor mainExecutor,
- @Background Executor bgExecutor
+ @Background Executor bgExecutor,
+ FeatureFlags featureFlags
) {
mContext = context;
mMainExecutor = mainExecutor;
mBgExecutor = bgExecutor;
mUserTracker = userTracker;
+ mFeatureFlags = featureFlags;
}
public void setListener(TileStateListener listener) {
@@ -117,6 +121,10 @@ public class TileQueryHelper {
}
final ArrayList<QSTile> tilesToAdd = new ArrayList<>();
+ if (mFeatureFlags.isProviderModelSettingEnabled()) {
+ possibleTiles.remove("cell");
+ possibleTiles.remove("wifi");
+ }
for (String spec : possibleTiles) {
// Only add current and stock tiles that can be created from QSFactoryImpl.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
index 86c90c7bcb2e..9eb95c409009 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.notification.row;
-import android.annotation.ColorInt;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -28,15 +27,12 @@ import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.ViewState;
public class FooterView extends StackScrollerDecorView {
- private final int mClearAllTopPadding;
private FooterViewButton mDismissButton;
private FooterViewButton mManageButton;
private boolean mShowHistory;
public FooterView(Context context, AttributeSet attrs) {
super(context, attrs);
- mClearAllTopPadding = context.getResources().getDimensionPixelSize(
- R.dimen.clear_all_padding_top);
}
@Override
@@ -55,11 +51,6 @@ public class FooterView extends StackScrollerDecorView {
mManageButton = findViewById(R.id.manage_text);
}
- public void setTextColor(@ColorInt int color) {
- mManageButton.setTextColor(color);
- mDismissButton.setTextColor(color);
- }
-
public void setManageButtonClickListener(OnClickListener listener) {
mManageButton.setOnClickListener(listener);
}
@@ -95,21 +86,25 @@ public class FooterView extends StackScrollerDecorView {
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- int textColor = getResources().getColor(R.color.notif_pill_text);
- Resources.Theme theme = getContext().getTheme();
- mDismissButton.setBackground(
- getResources().getDrawable(R.drawable.notif_footer_btn_background, theme));
- mDismissButton.setTextColor(textColor);
- mManageButton.setBackground(
- getResources().getDrawable(R.drawable.notif_footer_btn_background, theme));
- mManageButton = findViewById(R.id.manage_text);
+ updateColors();
mDismissButton.setText(R.string.clear_all_notifications_text);
- mManageButton.setTextColor(textColor);
mDismissButton.setContentDescription(
mContext.getString(R.string.accessibility_clear_all));
showHistory(mShowHistory);
}
+ /**
+ * Update the text and background colors for the current color palette and night mode setting.
+ */
+ public void updateColors() {
+ Resources.Theme theme = mContext.getTheme();
+ int textColor = getResources().getColor(R.color.notif_pill_text, theme);
+ mDismissButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background));
+ mDismissButton.setTextColor(textColor);
+ mManageButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background));
+ mManageButton.setTextColor(textColor);
+ }
+
@Override
public ExpandableViewState createExpandableViewState() {
return new FooterViewState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 289c32f17b31..0660daab3720 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -4231,7 +4231,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
final @ColorInt int textColor =
Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
mSectionsManager.setHeaderForegroundColor(textColor);
- mFooterView.setTextColor(textColor);
+ mFooterView.updateColors();
mEmptyShadeView.setTextColor(textColor);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 3ee3e55c749a..7f89b2629a6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -139,7 +139,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
() -> mock(AutoTileManager.class), mock(DumpManager.class),
mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)),
mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class),
- mock(SecureSettings.class), mock(CustomTileStatePersister.class));
+ mock(SecureSettings.class), mock(CustomTileStatePersister.class), mFeatureFlags);
qs.setHost(host);
qs.setListening(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index 9e97f801be3e..4cbad5f15c5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -63,6 +63,7 @@ import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -124,6 +125,8 @@ public class QSTileHostTest extends SysuiTestCase {
private SecureSettings mSecureSettings;
@Mock
private CustomTileStatePersister mCustomTileStatePersister;
+ @Mock
+ private FeatureFlags mFeatureFlags;
private Handler mHandler;
private TestableLooper mLooper;
@@ -137,9 +140,9 @@ public class QSTileHostTest extends SysuiTestCase {
mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler,
mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager,
mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker,
- mSecureSettings, mCustomTileStatePersister);
+ mSecureSettings, mCustomTileStatePersister, mFeatureFlags);
setUpTileFactory();
-
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(false);
when(mSecureSettings.getStringForUser(eq(QSTileHost.TILES_SETTING), anyInt()))
.thenReturn("");
}
@@ -169,13 +172,13 @@ public class QSTileHostTest extends SysuiTestCase {
@Test
public void testLoadTileSpecs_emptySetting() {
- List<String> tiles = QSTileHost.loadTileSpecs(mContext, "");
+ List<String> tiles = QSTileHost.loadTileSpecs(mContext, "", mFeatureFlags);
assertFalse(tiles.isEmpty());
}
@Test
public void testLoadTileSpecs_nullSetting() {
- List<String> tiles = QSTileHost.loadTileSpecs(mContext, null);
+ List<String> tiles = QSTileHost.loadTileSpecs(mContext, null, mFeatureFlags);
assertFalse(tiles.isEmpty());
}
@@ -189,6 +192,55 @@ public class QSTileHostTest extends SysuiTestCase {
}
@Test
+ public void testRemoveWifiAndCellularWithoutInternet() {
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true);
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2");
+
+ assertEquals("internet", mQSTileHost.mTileSpecs.get(0));
+ assertEquals("spec1", mQSTileHost.mTileSpecs.get(1));
+ assertEquals("spec2", mQSTileHost.mTileSpecs.get(2));
+ }
+
+ @Test
+ public void testRemoveWifiAndCellularWithInternet() {
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true);
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2, internet");
+
+ assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
+ assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
+ assertEquals("internet", mQSTileHost.mTileSpecs.get(2));
+ }
+
+ @Test
+ public void testRemoveWifiWithoutInternet() {
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true);
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, wifi, spec2");
+
+ assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
+ assertEquals("internet", mQSTileHost.mTileSpecs.get(1));
+ assertEquals("spec2", mQSTileHost.mTileSpecs.get(2));
+ }
+
+ @Test
+ public void testRemoveCellWithInternet() {
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true);
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, spec2, cell, internet");
+
+ assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
+ assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
+ assertEquals("internet", mQSTileHost.mTileSpecs.get(2));
+ }
+
+ @Test
+ public void testNoWifiNoCellularNoInternet() {
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true);
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2");
+
+ assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
+ assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
+ }
+
+ @Test
public void testSpecWithInvalidDoesNotUseDefault() {
mContext.getOrCreateTestableResources()
.addOverride(R.string.quick_settings_tiles, "spec1,spec2");
@@ -321,7 +373,7 @@ public class QSTileHostTest extends SysuiTestCase {
@Test
public void testLoadTileSpec_repeated() {
- List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2");
+ List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2", mFeatureFlags);
assertEquals(2, specs.size());
assertEquals("spec1", specs.get(0));
@@ -332,7 +384,7 @@ public class QSTileHostTest extends SysuiTestCase {
public void testLoadTileSpec_repeatedInDefault() {
mContext.getOrCreateTestableResources()
.addOverride(R.string.quick_settings_tiles_default, "spec1,spec1");
- List<String> specs = QSTileHost.loadTileSpecs(mContext, "default");
+ List<String> specs = QSTileHost.loadTileSpecs(mContext, "default", mFeatureFlags);
// Remove spurious tiles, like dbg:mem
specs.removeIf(spec -> !"spec1".equals(spec));
@@ -343,7 +395,7 @@ public class QSTileHostTest extends SysuiTestCase {
public void testLoadTileSpec_repeatedDefaultAndSetting() {
mContext.getOrCreateTestableResources()
.addOverride(R.string.quick_settings_tiles_default, "spec1");
- List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1");
+ List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1", mFeatureFlags);
// Remove spurious tiles, like dbg:mem
specs.removeIf(spec -> !"spec1".equals(spec));
@@ -371,11 +423,12 @@ public class QSTileHostTest extends SysuiTestCase {
Provider<AutoTileManager> autoTiles, DumpManager dumpManager,
BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger,
UiEventLogger uiEventLogger, UserTracker userTracker,
- SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister) {
+ SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister,
+ FeatureFlags featureFlags) {
super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager,
tunerService, autoTiles, dumpManager, broadcastDispatcher,
Optional.of(statusBar), qsLogger, uiEventLogger, userTracker, secureSettings,
- customTileStatePersister);
+ customTileStatePersister, featureFlags);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index 4efcc5c3fc73..c5b67091d197 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -58,6 +58,7 @@ import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -108,6 +109,8 @@ public class TileQueryHelperTest extends SysuiTestCase {
private PackageManager mPackageManager;
@Mock
private UserTracker mUserTracker;
+ @Mock
+ private FeatureFlags mFeatureFlags;
@Captor
private ArgumentCaptor<List<TileQueryHelper.TileInfo>> mCaptor;
@@ -133,12 +136,12 @@ public class TileQueryHelperTest extends SysuiTestCase {
}
}
).when(mQSTileHost).createTile(anyString());
-
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(false);
FakeSystemClock clock = new FakeSystemClock();
mMainExecutor = new FakeExecutor(clock);
mBgExecutor = new FakeExecutor(clock);
mTileQueryHelper = new TileQueryHelper(
- mContext, mUserTracker, mMainExecutor, mBgExecutor);
+ mContext, mUserTracker, mMainExecutor, mBgExecutor, mFeatureFlags);
mTileQueryHelper.setListener(mListener);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 2b1840462291..01fa222896d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -48,6 +48,7 @@ import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -98,6 +99,8 @@ public class TileServicesTest extends SysuiTestCase {
private UserTracker mUserTracker;
@Mock
private SecureSettings mSecureSettings;
+ @Mock
+ private FeatureFlags mFeatureFlags;
@Before
public void setUp() throws Exception {
@@ -119,7 +122,8 @@ public class TileServicesTest extends SysuiTestCase {
mUiEventLogger,
mUserTracker,
mSecureSettings,
- mock(CustomTileStatePersister.class));
+ mock(CustomTileStatePersister.class),
+ mFeatureFlags);
mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher,
mUserTracker);
}
diff --git a/rs/jni/Android.bp b/rs/jni/Android.bp
new file mode 100644
index 000000000000..9a6fa8e8e423
--- /dev/null
+++ b/rs/jni/Android.bp
@@ -0,0 +1,54 @@
+//
+// 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 {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+cc_library_shared {
+ name: "librs_jni",
+
+ srcs: ["android_renderscript_RenderScript.cpp"],
+
+ shared_libs: [
+ "libandroid",
+ "libandroid_runtime",
+ "libandroidfw",
+ "libRS",
+ "libcutils",
+ "libhwui",
+ "liblog",
+ "libutils",
+ "libui",
+ "libgui",
+ "libjnigraphics",
+ ],
+
+ header_libs: [
+ "jni_headers",
+ "libbase_headers",
+ ],
+
+ include_dirs: ["frameworks/rs"],
+
+ cflags: [
+ "-Wno-unused-parameter",
+ "-Wunused",
+ "-Wunreachable-code",
+ "-Wno-deprecated-declarations",
+ ],
+}
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
deleted file mode 100644
index 0caba421dca8..000000000000
--- a/rs/jni/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- android_renderscript_RenderScript.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libandroid \
- libandroid_runtime \
- libandroidfw \
- libRS \
- libcutils \
- libhwui \
- liblog \
- libutils \
- libui \
- libgui \
- libjnigraphics
-
-LOCAL_HEADER_LIBRARIES := \
- jni_headers \
- libbase_headers
-
-LOCAL_C_INCLUDES += \
- frameworks/rs
-
-LOCAL_CFLAGS += -Wno-unused-parameter
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -Wno-deprecated-declarations
-
-LOCAL_MODULE:= librs_jni
-LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS:= notice
-LOCAL_NOTICE_FILE:= $(LOCAL_PATH)/../../NOTICE
-LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := libRS
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/services/Android.bp b/services/Android.bp
index cc0fd98c7060..e11b0442377e 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -23,6 +23,36 @@ java_defaults {
},
}
+// Opt-in config for optimizing and shrinking the services target using R8.
+// Enabled via `export SYSTEM_OPTIMIZE_JAVA=true`, or explicitly in Make via the
+// `SOONG_CONFIG_ANDROID_SYSTEM_OPTIMIZE_JAVA` variable.
+// TODO(b/196084106): Enable optimizations by default after stabilizing and
+// building out retrace infrastructure.
+soong_config_module_type {
+ name: "system_optimized_java_defaults",
+ module_type: "java_defaults",
+ config_namespace: "ANDROID",
+ bool_variables: ["SYSTEM_OPTIMIZE_JAVA"],
+ properties: ["optimize"],
+}
+
+system_optimized_java_defaults {
+ name: "services_java_defaults",
+ soong_config_variables: {
+ SYSTEM_OPTIMIZE_JAVA: {
+ optimize: {
+ enabled: true,
+ optimize: true,
+ shrink: true,
+ proguard_flags_files: ["proguard.flags"],
+ },
+ // Note: Optimizations are disabled by default if unspecified in
+ // the java_library rule.
+ conditions_default: {},
+ },
+ },
+}
+
filegroup {
name: "services-main-sources",
srcs: [
@@ -81,6 +111,7 @@ java_library {
// ============================================================
java_library {
name: "services",
+ defaults: ["services_java_defaults"],
installable: true,
dex_preopt: {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 7d75b738d818..0aa50bd1fe93 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -407,7 +407,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
@Override
public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
synchronized (mLock) {
- if (mSecurityPolicy.canPerformGestures(this)) {
+ if (mServiceInterface != null && mSecurityPolicy.canPerformGestures(this)) {
MotionEventInjector motionEventInjector =
mSystemSupport.getMotionEventInjectorForDisplayLocked(displayId);
if (motionEventInjector != null
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 55b982b40611..d65969c11357 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -111,6 +111,7 @@ java_library_static {
"java/com/android/server/am/EventLogTags.logtags",
"java/com/android/server/wm/EventLogTags.logtags",
"java/com/android/server/policy/EventLogTags.logtags",
+ ":services.connectivity-nsd-sources",
],
libs: [
@@ -138,9 +139,11 @@ java_library_static {
"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",
- "android.hardware.health-V2.1-java",
+ "android.hardware.health-V1.0-java", // HIDL
+ "android.hardware.health-V2.0-java", // HIDL
+ "android.hardware.health-V2.1-java", // HIDL
+ "android.hardware.health-V1-java", // AIDL
+ "android.hardware.health-translate-java",
"android.hardware.light-V1-java",
"android.hardware.tv.cec-V1.1-java",
"android.hardware.weaver-V1.0-java",
@@ -149,7 +152,7 @@ java_library_static {
"android.hardware.biometrics.fingerprint-V2.3-java",
"android.hardware.biometrics.fingerprint-V1-java",
"android.hardware.oemlock-V1.0-java",
- "android.hardware.configstore-V1.0-java",
+ "android.hardware.configstore-V1.1-java",
"android.hardware.contexthub-V1.0-java",
"android.hardware.rebootescrow-V1-java",
"android.hardware.soundtrigger-V2.3-java",
diff --git a/services/core/java/com/android/server/AppFuseMountException.java b/services/core/java/com/android/server/AppFuseMountException.java
new file mode 100644
index 000000000000..9a9379e4a1c7
--- /dev/null
+++ b/services/core/java/com/android/server/AppFuseMountException.java
@@ -0,0 +1,41 @@
+/*
+ * 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;
+
+import android.os.Parcel;
+
+/**
+ * An exception that indicates there was an error with a
+ * app fuse mount operation.
+ */
+public class AppFuseMountException extends Exception {
+ public AppFuseMountException(String detailMessage) {
+ super(detailMessage);
+ }
+
+ public AppFuseMountException(String detailMessage, Throwable throwable) {
+ super(detailMessage, throwable);
+ }
+
+ /**
+ * Rethrow as a {@link RuntimeException} subclass that is handled by
+ * {@link Parcel#writeException(Exception)}.
+ */
+ public IllegalArgumentException rethrowAsParcelableException() {
+ throw new IllegalStateException(getMessage(), this);
+ }
+}
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 0146aa82a217..844ac86e8eb5 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -17,6 +17,7 @@
package com.android.server;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import static com.android.server.health.Utils.copyV1Battery;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -25,14 +26,8 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
-import android.hardware.health.V1_0.HealthInfo;
-import android.hardware.health.V2_0.IHealth;
-import android.hardware.health.V2_0.Result;
+import android.hardware.health.HealthInfo;
import android.hardware.health.V2_1.BatteryCapacityLevel;
-import android.hardware.health.V2_1.Constants;
-import android.hardware.health.V2_1.IHealthInfoCallback;
-import android.hidl.manager.V1_0.IServiceManager;
-import android.hidl.manager.V1_0.IServiceNotification;
import android.metrics.LogMaker;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
@@ -44,7 +39,6 @@ import android.os.Bundle;
import android.os.DropBoxManager;
import android.os.FileUtils;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBatteryPropertiesRegistrar;
import android.os.IBinder;
import android.os.OsProtoEnums;
@@ -62,15 +56,14 @@ import android.provider.Settings;
import android.service.battery.BatteryServiceDumpProto;
import android.sysprop.PowerProperties;
import android.util.EventLog;
-import android.util.MutableInt;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.DumpUtils;
import com.android.server.am.BatteryStatsService;
+import com.android.server.health.HealthServiceWrapper;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight;
@@ -82,8 +75,6 @@ import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.NoSuchElementException;
-import java.util.Objects;
-import java.util.concurrent.atomic.AtomicReference;
/**
* <p>BatteryService monitors the charging status, and charge level of the device
@@ -147,7 +138,6 @@ public final class BatteryService extends SystemService {
private HealthInfo mHealthInfo;
private final HealthInfo mLastHealthInfo = new HealthInfo();
- private android.hardware.health.V2_1.HealthInfo mHealthInfo2p1;
private boolean mBatteryLevelCritical;
private int mLastBatteryStatus;
private int mLastBatteryHealth;
@@ -191,7 +181,6 @@ public final class BatteryService extends SystemService {
private ActivityManagerInternal mActivityManagerInternal;
private HealthServiceWrapper mHealthServiceWrapper;
- private HealthHalCallback mHealthHalCallback;
private BatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
private ArrayDeque<Bundle> mBatteryLevelsEventQueue;
private long mLastBatteryLevelChangedSentMs;
@@ -274,13 +263,9 @@ public final class BatteryService extends SystemService {
private void registerHealthCallback() {
traceBegin("HealthInitWrapper");
- mHealthServiceWrapper = new HealthServiceWrapper();
- mHealthHalCallback = new HealthHalCallback();
// IHealth is lazily retrieved.
try {
- mHealthServiceWrapper.init(mHealthHalCallback,
- new HealthServiceWrapper.IServiceManagerSupplier() {},
- new HealthServiceWrapper.IHealthSupplier() {});
+ mHealthServiceWrapper = HealthServiceWrapper.create(this::update);
} catch (RemoteException ex) {
Slog.e(TAG, "health: cannot register callback. (RemoteException)");
throw ex.rethrowFromSystemServer();
@@ -368,8 +353,8 @@ public final class BatteryService extends SystemService {
}
private boolean shouldShutdownLocked() {
- if (mHealthInfo2p1.batteryCapacityLevel != BatteryCapacityLevel.UNSUPPORTED) {
- return (mHealthInfo2p1.batteryCapacityLevel == BatteryCapacityLevel.CRITICAL);
+ if (mHealthInfo.batteryCapacityLevel != BatteryCapacityLevel.UNSUPPORTED) {
+ return (mHealthInfo.batteryCapacityLevel == BatteryCapacityLevel.CRITICAL);
}
if (mHealthInfo.batteryLevel > 0) {
return false;
@@ -411,7 +396,7 @@ public final class BatteryService extends SystemService {
// shut down gracefully if temperature is too high (> 68.0C by default)
// wait until the system has booted before attempting to display the
// shutdown dialog.
- if (mHealthInfo.batteryTemperature > mShutdownBatteryTemperature) {
+ if (mHealthInfo.batteryTemperatureTenthsCelsius > mShutdownBatteryTemperature) {
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -428,51 +413,28 @@ public final class BatteryService extends SystemService {
}
}
- private void update(android.hardware.health.V2_1.HealthInfo info) {
+ private void update(android.hardware.health.HealthInfo info) {
traceBegin("HealthInfoUpdate");
- Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryChargeCounter",
- info.legacy.legacy.batteryChargeCounter);
- Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryCurrent",
- info.legacy.legacy.batteryCurrent);
- Trace.traceCounter(Trace.TRACE_TAG_POWER, "PlugType",
- plugType(info.legacy.legacy));
- Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryStatus",
- info.legacy.legacy.batteryStatus);
+ Trace.traceCounter(
+ Trace.TRACE_TAG_POWER, "BatteryChargeCounter", info.batteryChargeCounterUah);
+ Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryCurrent", info.batteryCurrentMicroamps);
+ Trace.traceCounter(Trace.TRACE_TAG_POWER, "PlugType", plugType(info));
+ Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryStatus", info.batteryStatus);
synchronized (mLock) {
if (!mUpdatesStopped) {
- mHealthInfo = info.legacy.legacy;
- mHealthInfo2p1 = info;
+ mHealthInfo = info;
// Process the new values.
processValuesLocked(false);
mLock.notifyAll(); // for any waiters on new info
} else {
- copy(mLastHealthInfo, info.legacy.legacy);
+ copyV1Battery(mLastHealthInfo, info);
}
}
traceEnd();
}
- private static void copy(HealthInfo dst, HealthInfo src) {
- dst.chargerAcOnline = src.chargerAcOnline;
- dst.chargerUsbOnline = src.chargerUsbOnline;
- dst.chargerWirelessOnline = src.chargerWirelessOnline;
- dst.maxChargingCurrent = src.maxChargingCurrent;
- dst.maxChargingVoltage = src.maxChargingVoltage;
- dst.batteryStatus = src.batteryStatus;
- dst.batteryHealth = src.batteryHealth;
- dst.batteryPresent = src.batteryPresent;
- dst.batteryLevel = src.batteryLevel;
- dst.batteryVoltage = src.batteryVoltage;
- dst.batteryTemperature = src.batteryTemperature;
- dst.batteryCurrent = src.batteryCurrent;
- dst.batteryCycleCount = src.batteryCycleCount;
- dst.batteryFullCharge = src.batteryFullCharge;
- dst.batteryChargeCounter = src.batteryChargeCounter;
- dst.batteryTechnology = src.batteryTechnology;
- }
-
private static int plugType(HealthInfo healthInfo) {
if (healthInfo.chargerAcOnline) {
return BatteryManager.BATTERY_PLUGGED_AC;
@@ -503,11 +465,16 @@ public final class BatteryService extends SystemService {
// Let the battery stats keep track of the current level.
try {
- mBatteryStats.setBatteryState(mHealthInfo.batteryStatus, mHealthInfo.batteryHealth,
- mPlugType, mHealthInfo.batteryLevel, mHealthInfo.batteryTemperature,
- mHealthInfo.batteryVoltage, mHealthInfo.batteryChargeCounter,
- mHealthInfo.batteryFullCharge,
- mHealthInfo2p1.batteryChargeTimeToFullNowSeconds);
+ mBatteryStats.setBatteryState(
+ mHealthInfo.batteryStatus,
+ mHealthInfo.batteryHealth,
+ mPlugType,
+ mHealthInfo.batteryLevel,
+ mHealthInfo.batteryTemperatureTenthsCelsius,
+ mHealthInfo.batteryVoltageMillivolts,
+ mHealthInfo.batteryChargeCounterUah,
+ mHealthInfo.batteryFullChargeUah,
+ mHealthInfo.batteryChargeTimeToFullNowSeconds);
} catch (RemoteException e) {
// Should never happen.
}
@@ -515,17 +482,18 @@ public final class BatteryService extends SystemService {
shutdownIfNoPowerLocked();
shutdownIfOverTempLocked();
- if (force || (mHealthInfo.batteryStatus != mLastBatteryStatus ||
- mHealthInfo.batteryHealth != mLastBatteryHealth ||
- mHealthInfo.batteryPresent != mLastBatteryPresent ||
- mHealthInfo.batteryLevel != mLastBatteryLevel ||
- mPlugType != mLastPlugType ||
- mHealthInfo.batteryVoltage != mLastBatteryVoltage ||
- mHealthInfo.batteryTemperature != mLastBatteryTemperature ||
- mHealthInfo.maxChargingCurrent != mLastMaxChargingCurrent ||
- mHealthInfo.maxChargingVoltage != mLastMaxChargingVoltage ||
- mHealthInfo.batteryChargeCounter != mLastChargeCounter ||
- mInvalidCharger != mLastInvalidCharger)) {
+ if (force
+ || (mHealthInfo.batteryStatus != mLastBatteryStatus
+ || mHealthInfo.batteryHealth != mLastBatteryHealth
+ || mHealthInfo.batteryPresent != mLastBatteryPresent
+ || mHealthInfo.batteryLevel != mLastBatteryLevel
+ || mPlugType != mLastPlugType
+ || mHealthInfo.batteryVoltageMillivolts != mLastBatteryVoltage
+ || mHealthInfo.batteryTemperatureTenthsCelsius != mLastBatteryTemperature
+ || mHealthInfo.maxChargingCurrentMicroamps != mLastMaxChargingCurrent
+ || mHealthInfo.maxChargingVoltageMicrovolts != mLastMaxChargingVoltage
+ || mHealthInfo.batteryChargeCounterUah != mLastChargeCounter
+ || mInvalidCharger != mLastInvalidCharger)) {
if (mPlugType != mLastPlugType) {
if (mLastPlugType == BATTERY_PLUGGED_NONE) {
@@ -582,8 +550,11 @@ public final class BatteryService extends SystemService {
if (mHealthInfo.batteryLevel != mLastBatteryLevel) {
// Don't do this just from voltage or temperature changes, that is
// too noisy.
- EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
- mHealthInfo.batteryLevel, mHealthInfo.batteryVoltage, mHealthInfo.batteryTemperature);
+ EventLog.writeEvent(
+ EventLogTags.BATTERY_LEVEL,
+ mHealthInfo.batteryLevel,
+ mHealthInfo.batteryVoltageMillivolts,
+ mHealthInfo.batteryTemperatureTenthsCelsius);
}
if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
mPlugType == BATTERY_PLUGGED_NONE) {
@@ -689,11 +660,11 @@ public final class BatteryService extends SystemService {
mLastBatteryPresent = mHealthInfo.batteryPresent;
mLastBatteryLevel = mHealthInfo.batteryLevel;
mLastPlugType = mPlugType;
- mLastBatteryVoltage = mHealthInfo.batteryVoltage;
- mLastBatteryTemperature = mHealthInfo.batteryTemperature;
- mLastMaxChargingCurrent = mHealthInfo.maxChargingCurrent;
- mLastMaxChargingVoltage = mHealthInfo.maxChargingVoltage;
- mLastChargeCounter = mHealthInfo.batteryChargeCounter;
+ mLastBatteryVoltage = mHealthInfo.batteryVoltageMillivolts;
+ mLastBatteryTemperature = mHealthInfo.batteryTemperatureTenthsCelsius;
+ mLastMaxChargingCurrent = mHealthInfo.maxChargingCurrentMicroamps;
+ mLastMaxChargingVoltage = mHealthInfo.maxChargingVoltageMicrovolts;
+ mLastChargeCounter = mHealthInfo.batteryChargeCounterUah;
mLastBatteryLevelCritical = mBatteryLevelCritical;
mLastInvalidCharger = mInvalidCharger;
}
@@ -716,13 +687,17 @@ public final class BatteryService extends SystemService {
intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);
- intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltage);
- intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperature);
+ intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltageMillivolts);
+ intent.putExtra(
+ BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperatureTenthsCelsius);
intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mHealthInfo.batteryTechnology);
intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
- intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrent);
- intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mHealthInfo.maxChargingVoltage);
- intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounter);
+ intent.putExtra(
+ BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrentMicroamps);
+ intent.putExtra(
+ BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE,
+ mHealthInfo.maxChargingVoltageMicrovolts);
+ intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah);
if (DEBUG) {
Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. scale:" + BATTERY_SCALE
+ ", info:" + mHealthInfo.toString());
@@ -742,9 +717,9 @@ public final class BatteryService extends SystemService {
event.putBoolean(BatteryManager.EXTRA_BATTERY_LOW, mSentLowBatteryBroadcast);
event.putInt(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
event.putInt(BatteryManager.EXTRA_PLUGGED, mPlugType);
- event.putInt(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltage);
- event.putInt(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperature);
- event.putInt(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounter);
+ event.putInt(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltageMillivolts);
+ event.putInt(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperatureTenthsCelsius);
+ event.putInt(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah);
event.putLong(BatteryManager.EXTRA_EVENT_TIMESTAMP, now);
boolean queueWasEmpty = mBatteryLevelsEventQueue.isEmpty();
@@ -936,7 +911,7 @@ public final class BatteryService extends SystemService {
}
try {
if (!mUpdatesStopped) {
- copy(mLastHealthInfo, mHealthInfo);
+ copyV1Battery(mLastHealthInfo, mHealthInfo);
}
boolean update = true;
switch (key) {
@@ -959,10 +934,10 @@ public final class BatteryService extends SystemService {
mHealthInfo.batteryLevel = Integer.parseInt(value);
break;
case "counter":
- mHealthInfo.batteryChargeCounter = Integer.parseInt(value);
+ mHealthInfo.batteryChargeCounterUah = Integer.parseInt(value);
break;
case "temp":
- mHealthInfo.batteryTemperature = Integer.parseInt(value);
+ mHealthInfo.batteryTemperatureTenthsCelsius = Integer.parseInt(value);
break;
case "invalid":
mInvalidCharger = Integer.parseInt(value);
@@ -1006,7 +981,7 @@ public final class BatteryService extends SystemService {
private void setChargerAcOnline(boolean online, boolean forceUpdate) {
if (!mUpdatesStopped) {
- copy(mLastHealthInfo, mHealthInfo);
+ copyV1Battery(mLastHealthInfo, mHealthInfo);
}
mHealthInfo.chargerAcOnline = online;
mUpdatesStopped = true;
@@ -1015,7 +990,7 @@ public final class BatteryService extends SystemService {
private void setBatteryLevel(int level, boolean forceUpdate) {
if (!mUpdatesStopped) {
- copy(mLastHealthInfo, mHealthInfo);
+ copyV1Battery(mLastHealthInfo, mHealthInfo);
}
mHealthInfo.batteryLevel = level;
mUpdatesStopped = true;
@@ -1024,7 +999,7 @@ public final class BatteryService extends SystemService {
private void unplugBattery(boolean forceUpdate, PrintWriter pw) {
if (!mUpdatesStopped) {
- copy(mLastHealthInfo, mHealthInfo);
+ copyV1Battery(mLastHealthInfo, mHealthInfo);
}
mHealthInfo.chargerAcOnline = false;
mHealthInfo.chargerUsbOnline = false;
@@ -1036,7 +1011,7 @@ public final class BatteryService extends SystemService {
private void resetBattery(boolean forceUpdate, @Nullable PrintWriter pw) {
if (mUpdatesStopped) {
mUpdatesStopped = false;
- copy(mHealthInfo, mLastHealthInfo);
+ copyV1Battery(mHealthInfo, mLastHealthInfo);
Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate, pw));
}
if (mBatteryInputSuspended) {
@@ -1071,16 +1046,16 @@ public final class BatteryService extends SystemService {
pw.println(" AC powered: " + mHealthInfo.chargerAcOnline);
pw.println(" USB powered: " + mHealthInfo.chargerUsbOnline);
pw.println(" Wireless powered: " + mHealthInfo.chargerWirelessOnline);
- pw.println(" Max charging current: " + mHealthInfo.maxChargingCurrent);
- pw.println(" Max charging voltage: " + mHealthInfo.maxChargingVoltage);
- pw.println(" Charge counter: " + mHealthInfo.batteryChargeCounter);
+ pw.println(" Max charging current: " + mHealthInfo.maxChargingCurrentMicroamps);
+ pw.println(" Max charging voltage: " + mHealthInfo.maxChargingVoltageMicrovolts);
+ pw.println(" Charge counter: " + mHealthInfo.batteryChargeCounterUah);
pw.println(" status: " + mHealthInfo.batteryStatus);
pw.println(" health: " + mHealthInfo.batteryHealth);
pw.println(" present: " + mHealthInfo.batteryPresent);
pw.println(" level: " + mHealthInfo.batteryLevel);
pw.println(" scale: " + BATTERY_SCALE);
- pw.println(" voltage: " + mHealthInfo.batteryVoltage);
- pw.println(" temperature: " + mHealthInfo.batteryTemperature);
+ pw.println(" voltage: " + mHealthInfo.batteryVoltageMillivolts);
+ pw.println(" temperature: " + mHealthInfo.batteryTemperatureTenthsCelsius);
pw.println(" technology: " + mHealthInfo.batteryTechnology);
} else {
Shell shell = new Shell();
@@ -1103,16 +1078,23 @@ public final class BatteryService extends SystemService {
batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_WIRELESS;
}
proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue);
- proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrent);
- proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mHealthInfo.maxChargingVoltage);
- proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.batteryChargeCounter);
+ proto.write(
+ BatteryServiceDumpProto.MAX_CHARGING_CURRENT,
+ mHealthInfo.maxChargingCurrentMicroamps);
+ proto.write(
+ BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE,
+ mHealthInfo.maxChargingVoltageMicrovolts);
+ proto.write(
+ BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah);
proto.write(BatteryServiceDumpProto.STATUS, mHealthInfo.batteryStatus);
proto.write(BatteryServiceDumpProto.HEALTH, mHealthInfo.batteryHealth);
proto.write(BatteryServiceDumpProto.IS_PRESENT, mHealthInfo.batteryPresent);
proto.write(BatteryServiceDumpProto.LEVEL, mHealthInfo.batteryLevel);
proto.write(BatteryServiceDumpProto.SCALE, BATTERY_SCALE);
- proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.batteryVoltage);
- proto.write(BatteryServiceDumpProto.TEMPERATURE, mHealthInfo.batteryTemperature);
+ proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.batteryVoltageMillivolts);
+ proto.write(
+ BatteryServiceDumpProto.TEMPERATURE,
+ mHealthInfo.batteryTemperatureTenthsCelsius);
proto.write(BatteryServiceDumpProto.TECHNOLOGY, mHealthInfo.batteryTechnology);
}
proto.flush();
@@ -1184,64 +1166,6 @@ public final class BatteryService extends SystemService {
}
}
- private final class HealthHalCallback extends IHealthInfoCallback.Stub
- implements HealthServiceWrapper.Callback {
- @Override public void healthInfoChanged(android.hardware.health.V2_0.HealthInfo props) {
- android.hardware.health.V2_1.HealthInfo propsLatest =
- new android.hardware.health.V2_1.HealthInfo();
- propsLatest.legacy = props;
-
- propsLatest.batteryCapacityLevel = BatteryCapacityLevel.UNSUPPORTED;
- propsLatest.batteryChargeTimeToFullNowSeconds =
- Constants.BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED;
-
- BatteryService.this.update(propsLatest);
- }
-
- @Override public void healthInfoChanged_2_1(android.hardware.health.V2_1.HealthInfo props) {
- BatteryService.this.update(props);
- }
-
- // on new service registered
- @Override public void onRegistration(IHealth oldService, IHealth newService,
- String instance) {
- if (newService == null) return;
-
- traceBegin("HealthUnregisterCallback");
- try {
- if (oldService != null) {
- int r = oldService.unregisterCallback(this);
- if (r != Result.SUCCESS) {
- Slog.w(TAG, "health: cannot unregister previous callback: " +
- Result.toString(r));
- }
- }
- } catch (RemoteException ex) {
- Slog.w(TAG, "health: cannot unregister previous callback (transaction error): "
- + ex.getMessage());
- } finally {
- traceEnd();
- }
-
- traceBegin("HealthRegisterCallback");
- try {
- int r = newService.registerCallback(this);
- if (r != Result.SUCCESS) {
- Slog.w(TAG, "health: cannot register callback: " + Result.toString(r));
- return;
- }
- // registerCallback does NOT guarantee that update is called
- // immediately, so request a manual update here.
- newService.update();
- } catch (RemoteException ex) {
- Slog.e(TAG, "health: cannot register callback (transaction error): "
- + ex.getMessage());
- } finally {
- traceEnd();
- }
- }
- }
-
private final class BinderService extends Binder {
@Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
@@ -1265,71 +1189,11 @@ public final class BatteryService extends SystemService {
private final class BatteryPropertiesRegistrar extends IBatteryPropertiesRegistrar.Stub {
@Override
public int getProperty(int id, final BatteryProperty prop) throws RemoteException {
- traceBegin("HealthGetProperty");
- try {
- IHealth service = mHealthServiceWrapper.getLastService();
- if (service == null) throw new RemoteException("no health service");
- final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED);
- switch(id) {
- case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
- service.getChargeCounter((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
- service.getCurrentNow((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:
- service.getCurrentAverage((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_CAPACITY:
- service.getCapacity((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_STATUS:
- service.getChargeStatus((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
- service.getEnergyCounter((int result, long value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- }
- return outResult.value;
- } finally {
- traceEnd();
- }
+ return mHealthServiceWrapper.getProperty(id, prop);
}
@Override
public void scheduleUpdate() throws RemoteException {
- mHealthServiceWrapper.getHandlerThread().getThreadHandler().post(() -> {
- traceBegin("HealthScheduleUpdate");
- try {
- IHealth service = mHealthServiceWrapper.getLastService();
- if (service == null) {
- Slog.e(TAG, "no health service");
- return;
- }
- service.update();
- } catch (RemoteException ex) {
- Slog.e(TAG, "Cannot call update on health HAL", ex);
- } finally {
- traceEnd();
- }
- });
+ mHealthServiceWrapper.scheduleUpdate();
}
}
@@ -1358,14 +1222,14 @@ public final class BatteryService extends SystemService {
@Override
public int getBatteryChargeCounter() {
synchronized (mLock) {
- return mHealthInfo.batteryChargeCounter;
+ return mHealthInfo.batteryChargeCounterUah;
}
}
@Override
public int getBatteryFullCharge() {
synchronized (mLock) {
- return mHealthInfo.batteryFullCharge;
+ return mHealthInfo.batteryFullChargeUah;
}
}
@@ -1418,184 +1282,4 @@ public final class BatteryService extends SystemService {
BatteryService.this.suspendBatteryInput();
}
}
-
- /**
- * HealthServiceWrapper wraps the internal IHealth service and refreshes the service when
- * necessary.
- *
- * On new registration of IHealth service, {@link #onRegistration onRegistration} is called and
- * the internal service is refreshed.
- * On death of an existing IHealth service, the internal service is NOT cleared to avoid
- * race condition between death notification and new service notification. Hence,
- * a caller must check for transaction errors when calling into the service.
- *
- * @hide Should only be used internally.
- */
- public static final class HealthServiceWrapper {
- private static final String TAG = "HealthServiceWrapper";
- public static final String INSTANCE_VENDOR = "default";
-
- private final IServiceNotification mNotification = new Notification();
- private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceHwbinder");
- // These variables are fixed after init.
- private Callback mCallback;
- private IHealthSupplier mHealthSupplier;
- private String mInstanceName;
-
- // Last IHealth service received.
- private final AtomicReference<IHealth> mLastService = new AtomicReference<>();
-
- /**
- * init should be called after constructor. For testing purposes, init is not called by
- * constructor.
- */
- public HealthServiceWrapper() {
- }
-
- public IHealth getLastService() {
- return mLastService.get();
- }
-
- /**
- * See {@link #init(Callback, IServiceManagerSupplier, IHealthSupplier)}
- */
- public void init() throws RemoteException, NoSuchElementException {
- init(/* callback= */null, new HealthServiceWrapper.IServiceManagerSupplier() {},
- new HealthServiceWrapper.IHealthSupplier() {});
- }
-
- /**
- * Start monitoring registration of new IHealth services. Only instance
- * {@link #INSTANCE_VENDOR} and in device / framework manifest are used. This function should
- * only be called once.
- *
- * mCallback.onRegistration() is called synchronously (aka in init thread) before
- * this method returns if callback is not null.
- *
- * @throws RemoteException transaction error when talking to IServiceManager
- * @throws NoSuchElementException if one of the following cases:
- * - No service manager;
- * - {@link #INSTANCE_VENDOR} is not in manifests (i.e. not
- * available on this device), or none of these instances are available to current
- * process.
- * @throws NullPointerException when supplier is null
- */
- void init(@Nullable Callback callback,
- IServiceManagerSupplier managerSupplier,
- IHealthSupplier healthSupplier)
- throws RemoteException, NoSuchElementException, NullPointerException {
- if (managerSupplier == null || healthSupplier == null) {
- throw new NullPointerException();
- }
- IServiceManager manager;
-
- mHealthSupplier = healthSupplier;
-
- // Initialize mLastService and call callback for the first time (in init thread)
- IHealth newService = null;
- traceBegin("HealthInitGetService_" + INSTANCE_VENDOR);
- try {
- newService = healthSupplier.get(INSTANCE_VENDOR);
- } catch (NoSuchElementException ex) {
- /* ignored, handled below */
- } finally {
- traceEnd();
- }
- if (newService != null) {
- mInstanceName = INSTANCE_VENDOR;
- mLastService.set(newService);
- }
-
- if (mInstanceName == null || newService == null) {
- throw new NoSuchElementException(String.format(
- "IHealth service instance %s isn't available. Perhaps no permission?",
- INSTANCE_VENDOR));
- }
-
- if (callback != null) {
- mCallback = callback;
- mCallback.onRegistration(null, newService, mInstanceName);
- }
-
- // Register for future service registrations
- traceBegin("HealthInitRegisterNotification");
- mHandlerThread.start();
- try {
- managerSupplier.get().registerForNotifications(
- IHealth.kInterfaceName, mInstanceName, mNotification);
- } finally {
- traceEnd();
- }
- Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + mInstanceName);
- }
-
- @VisibleForTesting
- HandlerThread getHandlerThread() {
- return mHandlerThread;
- }
-
- interface Callback {
- /**
- * This function is invoked asynchronously when a new and related IServiceNotification
- * is received.
- * @param service the recently retrieved service from IServiceManager.
- * Can be a dead service before service notification of a new service is delivered.
- * Implementation must handle cases for {@link RemoteException}s when calling
- * into service.
- * @param instance instance name.
- */
- void onRegistration(IHealth oldService, IHealth newService, String instance);
- }
-
- /**
- * Supplier of services.
- * Must not return null; throw {@link NoSuchElementException} if a service is not available.
- */
- interface IServiceManagerSupplier {
- default IServiceManager get() throws NoSuchElementException, RemoteException {
- return IServiceManager.getService();
- }
- }
- /**
- * Supplier of services.
- * Must not return null; throw {@link NoSuchElementException} if a service is not available.
- */
- interface IHealthSupplier {
- default IHealth get(String name) throws NoSuchElementException, RemoteException {
- return IHealth.getService(name, true /* retry */);
- }
- }
-
- private class Notification extends IServiceNotification.Stub {
- @Override
- public final void onRegistration(String interfaceName, String instanceName,
- boolean preexisting) {
- if (!IHealth.kInterfaceName.equals(interfaceName)) return;
- if (!mInstanceName.equals(instanceName)) return;
-
- // This runnable only runs on mHandlerThread and ordering is ensured, hence
- // no locking is needed inside the runnable.
- mHandlerThread.getThreadHandler().post(new Runnable() {
- @Override
- public void run() {
- try {
- IHealth newService = mHealthSupplier.get(mInstanceName);
- IHealth oldService = mLastService.getAndSet(newService);
-
- // preexisting may be inaccurate (race). Check for equality here.
- if (Objects.equals(newService, oldService)) return;
-
- Slog.i(TAG, "health: new instance registered " + mInstanceName);
- // #init() may be called with null callback. Skip null callbacks.
- if (mCallback == null) return;
- mCallback.onRegistration(oldService, newService, mInstanceName);
- } catch (NoSuchElementException | RemoteException ex) {
- Slog.e(TAG, "health: Cannot get instance '" + mInstanceName
- + "': " + ex.getMessage() + ". Perhaps no permission?");
- }
- }
- });
- }
- }
- }
}
diff --git a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
index 197321f1cb6a..263ff189a288 100644
--- a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
+++ b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
@@ -35,6 +35,7 @@ import com.android.internal.annotations.VisibleForTesting;
* when Bluetooth is on and Bluetooth is in one of the following situations:
* 1. Bluetooth A2DP is connected.
* 2. Bluetooth Hearing Aid profile is connected.
+ * 3. Bluetooth LE Audio is connected
*/
class BluetoothAirplaneModeListener {
private static final String TAG = "BluetoothAirplaneModeListener";
@@ -132,7 +133,7 @@ class BluetoothAirplaneModeListener {
return false;
}
if (!mAirplaneHelper.isBluetoothOn() || !mAirplaneHelper.isAirplaneModeOn()
- || !mAirplaneHelper.isA2dpOrHearingAidConnected()) {
+ || !mAirplaneHelper.isMediaProfileConnected()) {
return false;
}
return true;
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index f62935ab1b13..8860a8164109 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -35,6 +35,7 @@ import android.app.BroadcastOptions;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProtoEnums;
import android.bluetooth.IBluetooth;
@@ -456,12 +457,13 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
}
} else if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(action)
- || BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
+ || BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(action)
+ || BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED.equals(action)) {
final int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
BluetoothProfile.STATE_CONNECTED);
if (mHandler.hasMessages(MESSAGE_INIT_FLAGS_CHANGED)
&& state == BluetoothProfile.STATE_DISCONNECTED
- && !mBluetoothModeChangeHelper.isA2dpOrHearingAidConnected()) {
+ && !mBluetoothModeChangeHelper.isMediaProfileConnected()) {
Slog.i(TAG, "Device disconnected, reactivating pending flag changes");
onInitFlagsChanged();
}
@@ -2291,7 +2293,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
Slog.d(TAG, "MESSAGE_INIT_FLAGS_CHANGED");
}
mHandler.removeMessages(MESSAGE_INIT_FLAGS_CHANGED);
- if (mBluetoothModeChangeHelper.isA2dpOrHearingAidConnected()) {
+ if (mBluetoothModeChangeHelper.isMediaProfileConnected()) {
Slog.i(TAG, "Delaying MESSAGE_INIT_FLAGS_CHANGED by "
+ DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS
+ " ms due to existing connections");
diff --git a/services/core/java/com/android/server/BluetoothModeChangeHelper.java b/services/core/java/com/android/server/BluetoothModeChangeHelper.java
index 3642e4dccf34..e5854c968207 100644
--- a/services/core/java/com/android/server/BluetoothModeChangeHelper.java
+++ b/services/core/java/com/android/server/BluetoothModeChangeHelper.java
@@ -20,6 +20,7 @@ import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile.ServiceListener;
import android.content.Context;
@@ -37,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting;
public class BluetoothModeChangeHelper {
private volatile BluetoothA2dp mA2dp;
private volatile BluetoothHearingAid mHearingAid;
+ private volatile BluetoothLeAudio mLeAudio;
private final BluetoothAdapter mAdapter;
private final Context mContext;
@@ -47,6 +49,7 @@ public class BluetoothModeChangeHelper {
mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.A2DP);
mAdapter.getProfileProxy(mContext, mProfileServiceListener,
BluetoothProfile.HEARING_AID);
+ mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.LE_AUDIO);
}
private final ServiceListener mProfileServiceListener = new ServiceListener() {
@@ -60,6 +63,9 @@ public class BluetoothModeChangeHelper {
case BluetoothProfile.HEARING_AID:
mHearingAid = (BluetoothHearingAid) proxy;
break;
+ case BluetoothProfile.LE_AUDIO:
+ mLeAudio = (BluetoothLeAudio) proxy;
+ break;
default:
break;
}
@@ -75,6 +81,9 @@ public class BluetoothModeChangeHelper {
case BluetoothProfile.HEARING_AID:
mHearingAid = null;
break;
+ case BluetoothProfile.LE_AUDIO:
+ mLeAudio = null;
+ break;
default:
break;
}
@@ -82,8 +91,8 @@ public class BluetoothModeChangeHelper {
};
@VisibleForTesting
- public boolean isA2dpOrHearingAidConnected() {
- return isA2dpConnected() || isHearingAidConnected();
+ public boolean isMediaProfileConnected() {
+ return isA2dpConnected() || isHearingAidConnected() || isLeAudioConnected();
}
@VisibleForTesting
@@ -142,4 +151,12 @@ public class BluetoothModeChangeHelper {
}
return hearingAid.getConnectedDevices().size() > 0;
}
+
+ private boolean isLeAudioConnected() {
+ final BluetoothLeAudio leAudio = mLeAudio;
+ if (leAudio == null) {
+ return false;
+ }
+ return leAudio.getConnectedDevices().size() > 0;
+ }
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index c7e906876526..a2c2dbd407a5 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -39,8 +39,6 @@ import static android.net.NetworkStats.STATS_PER_UID;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.TrafficStats.UID_TETHERING;
-import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
-
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.content.Context;
@@ -72,7 +70,6 @@ import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.os.StrictMode;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.os.Trace;
import android.text.TextUtils;
import android.util.Log;
@@ -446,9 +443,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
// push any existing quota or UID rules
synchronized (mQuotaLock) {
- // Netd unconditionally enable bandwidth control
- SystemProperties.set(PROP_QTAGUID_ENABLED, "1");
-
mStrictEnabled = true;
setDataSaverModeEnabled(mDataSaverMode);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 69c29269b7a9..32f6496af151 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1230,7 +1230,7 @@ class StorageManagerService extends IStorageManager.Stub
}
for (int i = 0; i < mVolumes.size(); i++) {
final VolumeInfo vol = mVolumes.valueAt(i);
- if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) {
+ if (vol.isVisibleForUser(userId) && vol.isMountedReadable()) {
final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
@@ -1558,13 +1558,13 @@ class StorageManagerService extends IStorageManager.Stub
&& VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
Slog.v(TAG, "Found primary storage at " + vol);
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
- vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE;
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
} else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
Slog.v(TAG, "Found primary storage at " + vol);
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
- vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE;
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
}
@@ -1574,13 +1574,13 @@ class StorageManagerService extends IStorageManager.Stub
&& vol.disk.isDefaultPrimary()) {
Slog.v(TAG, "Found primary storage at " + vol);
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
- vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE;
}
// Adoptable public disks are visible to apps, since they meet
// public API requirement of being in a stable location.
if (vol.disk.isAdoptable()) {
- vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE;
}
vol.mountUserId = mCurrentUserId;
@@ -1591,7 +1591,9 @@ class StorageManagerService extends IStorageManager.Stub
} else if (vol.type == VolumeInfo.TYPE_STUB) {
if (vol.disk.isStubVisible()) {
- vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE;
+ } else {
+ vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_READ;
}
vol.mountUserId = mCurrentUserId;
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
@@ -1738,7 +1740,7 @@ class StorageManagerService extends IStorageManager.Stub
// started after this point will trigger additional
// user-specific broadcasts.
for (int userId : mSystemUnlockedUsers) {
- if (vol.isVisibleForRead(userId)) {
+ if (vol.isVisibleForUser(userId)) {
final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
false);
mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
@@ -3560,24 +3562,24 @@ class StorageManagerService extends IStorageManager.Stub
}
@Override
- public ParcelFileDescriptor open() throws NativeDaemonConnectorException {
+ public ParcelFileDescriptor open() throws AppFuseMountException {
try {
final FileDescriptor fd = mVold.mountAppFuse(uid, mountId);
mMounted = true;
return new ParcelFileDescriptor(fd);
} catch (Exception e) {
- throw new NativeDaemonConnectorException("Failed to mount", e);
+ throw new AppFuseMountException("Failed to mount", e);
}
}
@Override
public ParcelFileDescriptor openFile(int mountId, int fileId, int flags)
- throws NativeDaemonConnectorException {
+ throws AppFuseMountException {
try {
return new ParcelFileDescriptor(
mVold.openAppFuseFile(uid, mountId, fileId, flags));
} catch (Exception e) {
- throw new NativeDaemonConnectorException("Failed to open", e);
+ throw new AppFuseMountException("Failed to open", e);
}
}
@@ -3617,7 +3619,7 @@ class StorageManagerService extends IStorageManager.Stub
// It seems the thread of mAppFuseBridge has already been terminated.
mAppFuseBridge = null;
}
- } catch (NativeDaemonConnectorException e) {
+ } catch (AppFuseMountException e) {
throw e.rethrowAsParcelableException();
}
}
@@ -3766,7 +3768,7 @@ class StorageManagerService extends IStorageManager.Stub
if (forWrite) {
match = vol.isVisibleForWrite(userId);
} else {
- match = vol.isVisibleForRead(userId)
+ match = vol.isVisibleForUser(userId)
|| (includeInvisible && vol.getPath() != null);
}
if (!match) continue;
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 43bd9e773070..5ed6c86bdc18 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -47,6 +47,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.telecom.TelecomManager;
+import android.telephony.AccessNetworkConstants;
import android.telephony.Annotation;
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SrvccState;
@@ -1164,17 +1165,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
remove(r.binder);
}
}
- if (events.contains(
- TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
- updateReportSignalStrengthDecision(r.subId);
- try {
- if (mSignalStrength[r.phoneId] != null) {
- r.callback.onSignalStrengthsChanged(mSignalStrength[r.phoneId]);
- }
- } catch (RemoteException ex) {
- remove(r.binder);
- }
- }
if (validateEventAndUserLocked(
r, TelephonyCallback.EVENT_CELL_INFO_CHANGED)) {
try {
@@ -1353,27 +1343,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- private void updateReportSignalStrengthDecision(int subscriptionId) {
- synchronized (mRecords) {
- TelephonyManager telephonyManager = (TelephonyManager) mContext
- .getSystemService(Context.TELEPHONY_SERVICE);
- for (Record r : mRecords) {
- // If any of the system clients wants to always listen to signal strength,
- // we need to set it on.
- if (r.matchTelephonyCallbackEvent(
- TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
- telephonyManager.createForSubscriptionId(subscriptionId)
- .setAlwaysReportSignalStrength(true);
- return;
- }
- }
- // If none of the system clients wants to always listen to signal strength,
- // we need to set it off.
- telephonyManager.createForSubscriptionId(subscriptionId)
- .setAlwaysReportSignalStrength(false);
- }
- }
-
private String getCallIncomingNumber(Record record, int phoneId) {
// Only reveal the incoming number if the record has read call log permission.
return record.canReadCallLog() ? mCallIncomingNumber[phoneId] : "";
@@ -1457,14 +1426,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
mRecords.remove(i);
-
- // Every time a client that is registrating to always receive the signal
- // strength is removed from registry records, we need to check if
- // the signal strength decision needs to update on its slot.
- if (r.matchTelephonyCallbackEvent(
- TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
- updateReportSignalStrengthDecision(r.subId);
- }
return;
}
}
@@ -1696,10 +1657,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
log("notifySignalStrengthForPhoneId: r=" + r + " subId=" + subId
+ " phoneId=" + phoneId + " ss=" + signalStrength);
}
- if ((r.matchTelephonyCallbackEvent(
+ if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED)
- || r.matchTelephonyCallbackEvent(
- TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))
&& idMatch(r, subId, phoneId)) {
try {
if (DBG) {
@@ -2002,42 +1961,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
ApnSetting apnSetting = preciseState.getApnSetting();
- int apnTypes = apnSetting.getApnTypeBitmask();
- int state = preciseState.getState();
- int networkType = preciseState.getNetworkType();
-
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
- // We only call the callback when the change is for default APN type.
- if ((ApnSetting.TYPE_DEFAULT & apnTypes) != 0
- && (mDataConnectionState[phoneId] != state
- || mDataConnectionNetworkType[phoneId] != networkType)) {
- String str = "onDataConnectionStateChanged("
- + TelephonyUtils.dataStateToString(state)
- + ", " + getNetworkTypeName(networkType)
- + ") subId=" + subId + ", phoneId=" + phoneId;
- log(str);
- mLocalLog.log(str);
- for (Record r : mRecords) {
- if (r.matchTelephonyCallbackEvent(
- TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED)
- && idMatch(r, subId, phoneId)) {
- try {
- if (DBG) {
- log("Notify data connection state changed on sub: " + subId);
- }
- r.callback.onDataConnectionStateChanged(state, networkType);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
- }
- }
- }
- handleRemoveListLocked();
-
- mDataConnectionState[phoneId] = state;
- mDataConnectionNetworkType[phoneId] = networkType;
- }
-
Pair<Integer, ApnSetting> key = Pair.create(preciseState.getTransportType(),
preciseState.getApnSetting());
PreciseDataConnectionState oldState = mPreciseDataConnectionStates.get(phoneId)
@@ -2069,6 +1994,73 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (preciseState.getState() != TelephonyManager.DATA_DISCONNECTED) {
mPreciseDataConnectionStates.get(phoneId).put(key, preciseState);
}
+
+ // Note that below is just the workaround for reporting the correct data connection
+ // state. The actual fix should be put in the new data stack in T.
+ // TODO: Remove the code below in T.
+
+ // Collect all possible candidate data connection state for internet. Key is the
+ // data connection state, value is the precise data connection state.
+ Map<Integer, PreciseDataConnectionState> internetConnections = new ArrayMap<>();
+ if (preciseState.getState() == TelephonyManager.DATA_DISCONNECTED
+ && preciseState.getApnSetting().getApnTypes()
+ .contains(ApnSetting.TYPE_DEFAULT)) {
+ internetConnections.put(TelephonyManager.DATA_DISCONNECTED, preciseState);
+ }
+ for (Map.Entry<Pair<Integer, ApnSetting>, PreciseDataConnectionState> entry :
+ mPreciseDataConnectionStates.get(phoneId).entrySet()) {
+ if (entry.getKey().first == AccessNetworkConstants.TRANSPORT_TYPE_WWAN
+ && entry.getKey().second.getApnTypes()
+ .contains(ApnSetting.TYPE_DEFAULT)) {
+ internetConnections.put(entry.getValue().getState(), entry.getValue());
+ }
+ }
+
+ // If any internet data is in connected state, then report connected, then check
+ // suspended, connecting, disconnecting, and disconnected. The order is very
+ // important.
+ int[] statesInPriority = new int[]{TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.DATA_SUSPENDED, TelephonyManager.DATA_CONNECTING,
+ TelephonyManager.DATA_DISCONNECTING,
+ TelephonyManager.DATA_DISCONNECTED};
+ int state = TelephonyManager.DATA_DISCONNECTED;
+ int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ for (int s : statesInPriority) {
+ if (internetConnections.containsKey(s)) {
+ state = s;
+ networkType = internetConnections.get(s).getNetworkType();
+ break;
+ }
+ }
+
+ if (mDataConnectionState[phoneId] != state
+ || mDataConnectionNetworkType[phoneId] != networkType) {
+ String str = "onDataConnectionStateChanged("
+ + TelephonyUtils.dataStateToString(state)
+ + ", " + TelephonyManager.getNetworkTypeName(networkType)
+ + ") subId=" + subId + ", phoneId=" + phoneId;
+ log(str);
+ mLocalLog.log(str);
+ for (Record r : mRecords) {
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED)
+ && idMatch(r, subId, phoneId)) {
+ try {
+ if (DBG) {
+ log("Notify data connection state changed on sub: " + subId);
+ }
+ r.callback.onDataConnectionStateChanged(state, networkType);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+
+ mDataConnectionState[phoneId] = state;
+ mDataConnectionNetworkType[phoneId] = networkType;
+
+ handleRemoveListLocked();
+ }
}
}
}
@@ -3119,11 +3111,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null);
}
- if ((events.contains(TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH, null);
- }
-
if (isPrivilegedPhoneStatePermissionRequired(events)) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
@@ -3284,9 +3271,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED)
- || events.contains(
- TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED)) {
try {
if (mSignalStrength[phoneId] != null) {
SignalStrength signalStrength = mSignalStrength[phoneId];
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index b068f86ff0ab..0c990ecfc827 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -141,7 +141,7 @@ import java.util.concurrent.TimeUnit;
* | or its properties
* v |
* +-----------------------------------------------------------------------+
- * | UnderlyingNetworkTracker |
+ * | UnderlyingNetworkController |
* | |
* | Manages lifecycle of underlying physical networks, filing requests to |
* | bring them up, and releasing them as they become no longer necessary |
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 731f7fec466c..ab2147dff853 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -1834,6 +1834,11 @@ public class AccountManagerService
+ ", skipping since the account already exists");
return false;
}
+ if (accounts.accountsDb.findAllDeAccounts().size() > 100) {
+ Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
+ + ", skipping since more than 50 accounts on device exist");
+ return false;
+ }
long accountId = accounts.accountsDb.insertCeAccount(account, password);
if (accountId < 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 3ccacd84a9f3..c5ac3907ecfe 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -94,6 +94,8 @@ public class SettingsToPropertiesMapper {
DeviceConfig.NAMESPACE_STATSD_NATIVE,
DeviceConfig.NAMESPACE_STATSD_NATIVE_BOOT,
DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ DeviceConfig.NAMESPACE_TETHERING,
+ DeviceConfig.NAMESPACE_VIRTUALIZATION_FRAMEWORK_NATIVE,
DeviceConfig.NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT,
};
diff --git a/services/core/java/com/android/server/app/OWNERS b/services/core/java/com/android/server/app/OWNERS
new file mode 100644
index 000000000000..aaebbfa8e253
--- /dev/null
+++ b/services/core/java/com/android/server/app/OWNERS
@@ -0,0 +1 @@
+per-file GameManager* = file:/GAME_MANAGER_OWNERS
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index c383f5120407..0b2311bc563a 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -17,12 +17,9 @@ package com.android.server.audio;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothLeAudio;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -32,6 +29,7 @@ import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.AudioRoutesInfo;
import android.media.AudioSystem;
+import android.media.BtProfileConnectionInfo;
import android.media.IAudioRoutesObserver;
import android.media.ICapturePresetDevicesRoleDispatcher;
import android.media.ICommunicationDeviceDispatcher;
@@ -516,29 +514,82 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
};
- /*package*/ static final class BtDeviceConnectionInfo {
+ /*package*/ static final class BtDeviceChangedData {
+ final @Nullable BluetoothDevice mNewDevice;
+ final @Nullable BluetoothDevice mPreviousDevice;
+ final @NonNull BtProfileConnectionInfo mInfo;
+ final @NonNull String mEventSource;
+
+ BtDeviceChangedData(@Nullable BluetoothDevice newDevice,
+ @Nullable BluetoothDevice previousDevice,
+ @NonNull BtProfileConnectionInfo info, @NonNull String eventSource) {
+ mNewDevice = newDevice;
+ mPreviousDevice = previousDevice;
+ mInfo = info;
+ mEventSource = eventSource;
+ }
+
+ @Override
+ public String toString() {
+ return "BtDeviceChangedData profile=" + BluetoothProfile.getProfileName(
+ mInfo.getProfile())
+ + ", switch device: [" + mPreviousDevice + "] -> [" + mNewDevice + "]";
+ }
+ }
+
+ /*package*/ static final class BtDeviceInfo {
final @NonNull BluetoothDevice mDevice;
final @AudioService.BtProfileConnectionState int mState;
- final int mProfile;
+ final @AudioService.BtProfile int mProfile;
final boolean mSupprNoisy;
final int mVolume;
+ final boolean mIsLeOutput;
+ final @NonNull String mEventSource;
+ final @AudioSystem.AudioFormatNativeEnumForBtCodec int mCodec;
+ final int mAudioSystemDevice;
+ final int mMusicDevice;
- BtDeviceConnectionInfo(@NonNull BluetoothDevice device,
- @AudioService.BtProfileConnectionState int state,
- int profile, boolean suppressNoisyIntent, int vol) {
+ BtDeviceInfo(@NonNull BtDeviceChangedData d, @NonNull BluetoothDevice device, int state,
+ int audioDevice, @AudioSystem.AudioFormatNativeEnumForBtCodec int codec) {
mDevice = device;
mState = state;
+ mProfile = d.mInfo.getProfile();
+ mSupprNoisy = d.mInfo.getSuppressNoisyIntent();
+ mVolume = d.mInfo.getVolume();
+ mIsLeOutput = d.mInfo.getIsLeOutput();
+ mEventSource = d.mEventSource;
+ mAudioSystemDevice = audioDevice;
+ mMusicDevice = AudioSystem.DEVICE_NONE;
+ mCodec = codec;
+ }
+
+ // constructor used by AudioDeviceBroker to search similar message
+ BtDeviceInfo(@NonNull BluetoothDevice device, int profile) {
+ mDevice = device;
mProfile = profile;
- mSupprNoisy = suppressNoisyIntent;
- mVolume = vol;
- }
-
- BtDeviceConnectionInfo(@NonNull BtDeviceConnectionInfo info) {
- mDevice = info.mDevice;
- mState = info.mState;
- mProfile = info.mProfile;
- mSupprNoisy = info.mSupprNoisy;
- mVolume = info.mVolume;
+ mEventSource = "";
+ mMusicDevice = AudioSystem.DEVICE_NONE;
+ mCodec = AudioSystem.AUDIO_FORMAT_DEFAULT;
+ mAudioSystemDevice = 0;
+ mState = 0;
+ mSupprNoisy = false;
+ mVolume = -1;
+ mIsLeOutput = false;
+ }
+
+ // constructor used by AudioDeviceInventory when config change failed
+ BtDeviceInfo(@NonNull BluetoothDevice device, int profile, int state, int musicDevice,
+ int audioSystemDevice) {
+ mDevice = device;
+ mProfile = profile;
+ mEventSource = "";
+ mMusicDevice = musicDevice;
+ mCodec = AudioSystem.AUDIO_FORMAT_DEFAULT;
+ mAudioSystemDevice = audioSystemDevice;
+ mState = state;
+ mSupprNoisy = false;
+ mVolume = -1;
+ mIsLeOutput = false;
}
// redefine equality op so we can match messages intended for this device
@@ -550,16 +601,52 @@ import java.util.concurrent.atomic.AtomicBoolean;
if (this == o) {
return true;
}
- if (o instanceof BtDeviceConnectionInfo) {
- return mDevice.equals(((BtDeviceConnectionInfo) o).mDevice);
+ if (o instanceof BtDeviceInfo) {
+ return mProfile == ((BtDeviceInfo) o).mProfile
+ && mDevice.equals(((BtDeviceInfo) o).mDevice);
}
return false;
}
+ }
- @Override
- public String toString() {
- return "BtDeviceConnectionInfo dev=" + mDevice.toString();
+ BtDeviceInfo createBtDeviceInfo(@NonNull BtDeviceChangedData d, @NonNull BluetoothDevice device,
+ int state) {
+ int audioDevice;
+ int codec = AudioSystem.AUDIO_FORMAT_DEFAULT;
+ switch (d.mInfo.getProfile()) {
+ case BluetoothProfile.A2DP_SINK:
+ audioDevice = AudioSystem.DEVICE_IN_BLUETOOTH_A2DP;
+ break;
+ case BluetoothProfile.A2DP:
+ audioDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
+ synchronized (mDeviceStateLock) {
+ codec = mBtHelper.getA2dpCodec(device);
+ }
+ break;
+ case BluetoothProfile.HEARING_AID:
+ audioDevice = AudioSystem.DEVICE_OUT_HEARING_AID;
+ break;
+ case BluetoothProfile.LE_AUDIO:
+ if (d.mInfo.getIsLeOutput()) {
+ audioDevice = AudioSystem.DEVICE_OUT_BLE_HEADSET;
+ } else {
+ audioDevice = AudioSystem.DEVICE_IN_BLE_HEADSET;
+ }
+ break;
+ default: throw new IllegalArgumentException("Invalid profile " + d.mInfo.getProfile());
}
+ return new BtDeviceInfo(d, device, state, audioDevice, codec);
+ }
+
+ private void btMediaMetricRecord(@NonNull BluetoothDevice device, String state,
+ @NonNull BtDeviceChangedData data) {
+ final String name = TextUtils.emptyIfNull(device.getName());
+ new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
+ + "queueOnBluetoothActiveDeviceChanged")
+ .set(MediaMetrics.Property.STATE, state)
+ .set(MediaMetrics.Property.STATUS, data.mInfo.getProfile())
+ .set(MediaMetrics.Property.NAME, name)
+ .record();
}
/**
@@ -567,116 +654,37 @@ import java.util.concurrent.atomic.AtomicBoolean;
* not just a simple message post
* @param info struct with the (dis)connection information
*/
- /*package*/ void queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- @NonNull BtDeviceConnectionInfo info) {
- final String name = TextUtils.emptyIfNull(info.mDevice.getName());
- new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
- + "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent")
- .set(MediaMetrics.Property.STATE, info.mState == BluetoothProfile.STATE_CONNECTED
- ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
- .set(MediaMetrics.Property.INDEX, info.mVolume)
- .set(MediaMetrics.Property.NAME, name)
- .record();
-
- // operations of removing and posting messages related to A2DP device state change must be
- // mutually exclusive
- synchronized (mDeviceStateLock) {
- // when receiving a request to change the connection state of a device, this last
- // request is the source of truth, so cancel all previous requests that are already in
- // the handler
- removeScheduledA2dpEvents(info.mDevice);
-
- sendLMsgNoDelay(
- info.mState == BluetoothProfile.STATE_CONNECTED
- ? MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION
- : MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION,
- SENDMSG_QUEUE, info);
- }
- }
-
- /** remove all previously scheduled connection and state change events for the given device */
- @GuardedBy("mDeviceStateLock")
- private void removeScheduledA2dpEvents(@NonNull BluetoothDevice device) {
- mBrokerHandler.removeEqualMessages(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, device);
-
- final BtDeviceConnectionInfo connectionInfoToRemove = new BtDeviceConnectionInfo(device,
- // the next parameters of the constructor will be ignored when finding the message
- // to remove as the equality of the message's object is tested on the device itself
- // (see BtDeviceConnectionInfo.equals() method override)
- BluetoothProfile.STATE_CONNECTED, 0, false, -1);
- mBrokerHandler.removeEqualMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION,
- connectionInfoToRemove);
- mBrokerHandler.removeEqualMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION,
- connectionInfoToRemove);
-
- final BtHelper.BluetoothA2dpDeviceInfo devInfoToRemove =
- new BtHelper.BluetoothA2dpDeviceInfo(device);
- mBrokerHandler.removeEqualMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED,
- devInfoToRemove);
- mBrokerHandler.removeEqualMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED,
- devInfoToRemove);
- mBrokerHandler.removeEqualMessages(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE,
- devInfoToRemove);
- }
-
- private static final class HearingAidDeviceConnectionInfo {
- final @NonNull BluetoothDevice mDevice;
- final @AudioService.BtProfileConnectionState int mState;
- final boolean mSupprNoisy;
- final int mMusicDevice;
- final @NonNull String mEventSource;
-
- HearingAidDeviceConnectionInfo(@NonNull BluetoothDevice device,
- @AudioService.BtProfileConnectionState int state,
- boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) {
- mDevice = device;
- mState = state;
- mSupprNoisy = suppressNoisyIntent;
- mMusicDevice = musicDevice;
- mEventSource = eventSource;
- }
- }
-
- /*package*/ void postBluetoothHearingAidDeviceConnectionState(
- @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
- boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) {
- final HearingAidDeviceConnectionInfo info = new HearingAidDeviceConnectionInfo(
- device, state, suppressNoisyIntent, musicDevice, eventSource);
- sendLMsgNoDelay(MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
- }
-
- private static final class LeAudioDeviceConnectionInfo {
- final @NonNull BluetoothDevice mDevice;
- final @AudioService.BtProfileConnectionState int mState;
- final boolean mSupprNoisy;
- final @NonNull String mEventSource;
-
- LeAudioDeviceConnectionInfo(@NonNull BluetoothDevice device,
- @AudioService.BtProfileConnectionState int state,
- boolean suppressNoisyIntent, @NonNull String eventSource) {
- mDevice = device;
- mState = state;
- mSupprNoisy = suppressNoisyIntent;
- mEventSource = eventSource;
+ /*package*/ void queueOnBluetoothActiveDeviceChanged(@NonNull BtDeviceChangedData data) {
+ if (data.mInfo.getProfile() == BluetoothProfile.A2DP && data.mPreviousDevice != null
+ && data.mPreviousDevice.equals(data.mNewDevice)) {
+ final String name = TextUtils.emptyIfNull(data.mNewDevice.getName());
+ new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
+ + "queueOnBluetoothActiveDeviceChanged_update")
+ .set(MediaMetrics.Property.NAME, name)
+ .set(MediaMetrics.Property.STATUS, data.mInfo.getProfile())
+ .record();
+ synchronized (mDeviceStateLock) {
+ postBluetoothA2dpDeviceConfigChange(data.mNewDevice);
+ }
+ } else {
+ synchronized (mDeviceStateLock) {
+ if (data.mPreviousDevice != null) {
+ btMediaMetricRecord(data.mPreviousDevice, MediaMetrics.Value.DISCONNECTED,
+ data);
+ sendLMsgNoDelay(MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT, SENDMSG_QUEUE,
+ createBtDeviceInfo(data, data.mPreviousDevice,
+ BluetoothProfile.STATE_DISCONNECTED));
+ }
+ if (data.mNewDevice != null) {
+ btMediaMetricRecord(data.mNewDevice, MediaMetrics.Value.CONNECTED, data);
+ sendLMsgNoDelay(MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT, SENDMSG_QUEUE,
+ createBtDeviceInfo(data, data.mNewDevice,
+ BluetoothProfile.STATE_CONNECTED));
+ }
+ }
}
}
- /*package*/ void postBluetoothLeAudioOutDeviceConnectionState(
- @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
- boolean suppressNoisyIntent, @NonNull String eventSource) {
- final LeAudioDeviceConnectionInfo info = new LeAudioDeviceConnectionInfo(
- device, state, suppressNoisyIntent, eventSource);
- sendLMsgNoDelay(MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
- }
-
- /*package*/ void postBluetoothLeAudioInDeviceConnectionState(
- @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
- @NonNull String eventSource) {
- final LeAudioDeviceConnectionInfo info = new LeAudioDeviceConnectionInfo(
- device, state, false, eventSource);
- sendLMsgNoDelay(MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
- }
-
/**
* Current Bluetooth SCO audio active state indicated by BtHelper via setBluetoothScoOn().
*/
@@ -926,19 +934,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
@GuardedBy("mDeviceStateLock")
- /*package*/ void postA2dpSinkConnection(@AudioService.BtProfileConnectionState int state,
- @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
- sendILMsg(state == BluetoothA2dp.STATE_CONNECTED
- ? MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED
- : MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED,
- SENDMSG_QUEUE,
- state, btDeviceInfo, delay);
- }
-
- /*package*/ void postA2dpSourceConnection(@AudioService.BtProfileConnectionState int state,
- @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
- sendILMsg(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE,
- state, btDeviceInfo, delay);
+ /*package*/ void postBluetoothActiveDevice(BtDeviceInfo info, int delay) {
+ sendLMsg(MSG_L_SET_BT_ACTIVE_DEVICE, SENDMSG_QUEUE, info, delay);
}
/*package*/ void postSetWiredDeviceConnectionState(
@@ -946,72 +943,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
sendLMsg(MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE, SENDMSG_QUEUE, connectionState, delay);
}
- /*package*/ void postSetHearingAidConnectionState(
- @AudioService.BtProfileConnectionState int state,
- @NonNull BluetoothDevice device, int delay) {
- sendILMsg(MSG_IL_SET_HEARING_AID_CONNECTION_STATE, SENDMSG_QUEUE,
- state,
- device,
- delay);
- }
-
- /*package*/ void postSetLeAudioOutConnectionState(
- @AudioService.BtProfileConnectionState int state,
- @NonNull BluetoothDevice device, int delay) {
- sendILMsg(MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE, SENDMSG_QUEUE,
- state,
- device,
- delay);
- }
-
- /*package*/ void postSetLeAudioInConnectionState(
- @AudioService.BtProfileConnectionState int state,
- @NonNull BluetoothDevice device) {
- sendILMsgNoDelay(MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE, SENDMSG_QUEUE,
- state,
- device);
- }
-
- /*package*/ void postDisconnectA2dp() {
- sendMsgNoDelay(MSG_DISCONNECT_A2DP, SENDMSG_QUEUE);
- }
-
- /*package*/ void postDisconnectA2dpSink() {
- sendMsgNoDelay(MSG_DISCONNECT_A2DP_SINK, SENDMSG_QUEUE);
- }
-
- /*package*/ void postDisconnectHearingAid() {
- sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE);
- }
-
- /*package*/ void postDisconnectLeAudio() {
- sendMsgNoDelay(MSG_DISCONNECT_BT_LE_AUDIO, SENDMSG_QUEUE);
- }
-
- /*package*/ void postDisconnectHeadset() {
- sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE);
- }
-
- /*package*/ void postBtA2dpProfileConnected(BluetoothA2dp a2dpProfile) {
- sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP, SENDMSG_QUEUE, a2dpProfile);
- }
-
- /*package*/ void postBtA2dpSinkProfileConnected(BluetoothProfile profile) {
- sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK, SENDMSG_QUEUE, profile);
- }
-
- /*package*/ void postBtHeasetProfileConnected(BluetoothHeadset headsetProfile) {
- sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET, SENDMSG_QUEUE, headsetProfile);
- }
-
- /*package*/ void postBtHearingAidProfileConnected(BluetoothHearingAid hearingAidProfile) {
- sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID, SENDMSG_QUEUE,
- hearingAidProfile);
+ /*package*/ void postBtProfileDisconnected(int profile) {
+ sendIMsgNoDelay(MSG_I_BT_SERVICE_DISCONNECTED_PROFILE, SENDMSG_QUEUE, profile);
}
- /*package*/ void postBtLeAudioProfileConnected(BluetoothLeAudio leAudioProfile) {
- sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO, SENDMSG_QUEUE,
- leAudioProfile);
+ /*package*/ void postBtProfileConnected(int profile, BluetoothProfile proxy) {
+ sendILMsgNoDelay(MSG_IL_BT_SERVICE_CONNECTED_PROFILE, SENDMSG_QUEUE, profile, proxy);
}
/*package*/ void postCommunicationRouteClientDied(CommunicationRouteClient client) {
@@ -1069,13 +1006,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
}
- /*package*/ void postSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state,
- @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
- final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
- sendILMsgNoDelay(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE, state,
- btDeviceInfo);
- }
-
/*package*/ void handleFailureToConnectToBtHeadsetService(int delay) {
sendMsg(MSG_BT_HEADSET_CNCT_FAILED, SENDMSG_REPLACE, delay);
}
@@ -1088,19 +1018,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
sendMsgNoDelay(fromA2dp ? MSG_REPORT_NEW_ROUTES_A2DP : MSG_REPORT_NEW_ROUTES, SENDMSG_NOOP);
}
- /*package*/ void postA2dpActiveDeviceChange(
- @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
- sendLMsgNoDelay(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE, SENDMSG_QUEUE, btDeviceInfo);
- }
-
// must be called synchronized on mConnectedDevices
- /*package*/ boolean hasScheduledA2dpSinkConnectionState(BluetoothDevice btDevice) {
- final BtHelper.BluetoothA2dpDeviceInfo devInfoToCheck =
- new BtHelper.BluetoothA2dpDeviceInfo(btDevice);
- return (mBrokerHandler.hasEqualMessages(
- MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, devInfoToCheck)
- || mBrokerHandler.hasEqualMessages(
- MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, devInfoToCheck));
+ /*package*/ boolean hasScheduledA2dpConnection(BluetoothDevice btDevice) {
+ final BtDeviceInfo devInfoToCheck = new BtDeviceInfo(btDevice, BluetoothProfile.A2DP);
+ return mBrokerHandler.hasEqualMessages(MSG_L_SET_BT_ACTIVE_DEVICE, devInfoToCheck);
}
/*package*/ void setA2dpTimeout(String address, int a2dpCodec, int delayMs) {
@@ -1124,12 +1045,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
}
- /*package*/ int getA2dpCodec(@NonNull BluetoothDevice device) {
- synchronized (mDeviceStateLock) {
- return mBtHelper.getA2dpCodec(device);
- }
- }
-
/*package*/ void broadcastStickyIntentToCurrentProfileGroup(Intent intent) {
mSystemServer.broadcastStickyIntentToCurrentProfileGroup(intent);
}
@@ -1285,39 +1200,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
mDeviceInventory.onReportNewRoutes();
}
break;
- case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
- case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
- synchronized (mDeviceStateLock) {
- mDeviceInventory.onSetA2dpSinkConnectionState(
- (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
- }
- break;
- case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
- synchronized (mDeviceStateLock) {
- mDeviceInventory.onSetA2dpSourceConnectionState(
- (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
- }
- break;
- case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
+ case MSG_L_SET_BT_ACTIVE_DEVICE:
synchronized (mDeviceStateLock) {
- mDeviceInventory.onSetHearingAidConnectionState(
- (BluetoothDevice) msg.obj, msg.arg1,
+ mDeviceInventory.onSetBtActiveDevice((BtDeviceInfo) msg.obj,
mAudioService.getBluetoothContextualVolumeStream());
}
- break;
- case MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE:
- synchronized (mDeviceStateLock) {
- mDeviceInventory.onSetLeAudioOutConnectionState(
- (BluetoothDevice) msg.obj, msg.arg1,
- mAudioService.getBluetoothContextualVolumeStream());
- }
- break;
- case MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE:
- synchronized (mDeviceStateLock) {
- mDeviceInventory.onSetLeAudioInConnectionState(
- (BluetoothDevice) msg.obj, msg.arg1);
- }
- break;
case MSG_BT_HEADSET_CNCT_FAILED:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
@@ -1332,14 +1219,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
break;
case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
- final int a2dpCodec;
final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
synchronized (mDeviceStateLock) {
- a2dpCodec = mBtHelper.getA2dpCodec(btDevice);
- // TODO: name of method being called on AudioDeviceInventory is currently
- // misleading (config change vs active device change), to be
- // reconciliated once the BT side has been updated.
- mDeviceInventory.onBluetoothA2dpActiveDeviceChange(
+ final int a2dpCodec = mBtHelper.getA2dpCodec(btDevice);
+ mDeviceInventory.onBluetoothA2dpDeviceConfigChange(
new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec),
BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
}
@@ -1392,96 +1275,47 @@ import java.util.concurrent.atomic.AtomicBoolean;
mDeviceInventory.onToggleHdmi();
}
break;
- case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
- synchronized (mDeviceStateLock) {
- mDeviceInventory.onBluetoothA2dpActiveDeviceChange(
- (BtHelper.BluetoothA2dpDeviceInfo) msg.obj,
- BtHelper.EVENT_ACTIVE_DEVICE_CHANGE);
- }
- break;
- case MSG_DISCONNECT_A2DP:
- synchronized (mDeviceStateLock) {
- mDeviceInventory.disconnectA2dp();
- }
- break;
- case MSG_DISCONNECT_A2DP_SINK:
- synchronized (mDeviceStateLock) {
- mDeviceInventory.disconnectA2dpSink();
- }
- break;
- case MSG_DISCONNECT_BT_HEARING_AID:
- synchronized (mDeviceStateLock) {
- mDeviceInventory.disconnectHearingAid();
- }
- break;
- case MSG_DISCONNECT_BT_HEADSET:
- synchronized (mSetModeLock) {
+ case MSG_I_BT_SERVICE_DISCONNECTED_PROFILE:
+ if (msg.arg1 != BluetoothProfile.HEADSET) {
synchronized (mDeviceStateLock) {
- mBtHelper.disconnectHeadset();
+ mDeviceInventory.onBtProfileDisconnected(msg.arg1);
+ }
+ } else {
+ synchronized (mSetModeLock) {
+ synchronized (mDeviceStateLock) {
+ mBtHelper.disconnectHeadset();
+ }
}
}
break;
- case MSG_DISCONNECT_BT_LE_AUDIO:
- synchronized(mDeviceStateLock) {
- mDeviceInventory.disconnectLeAudio();
- }
- break;
- case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP:
- synchronized (mDeviceStateLock) {
- mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj);
- }
- break;
- case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK:
- synchronized (mDeviceStateLock) {
- mBtHelper.onA2dpSinkProfileConnected((BluetoothProfile) msg.obj);
- }
- break;
- case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID:
- synchronized (mDeviceStateLock) {
- mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj);
- }
- break;
-
- case MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO:
- synchronized(mDeviceStateLock) {
- mBtHelper.onLeAudioProfileConnected((BluetoothLeAudio) msg.obj);
- }
- break;
- case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET:
- synchronized (mSetModeLock) {
+ case MSG_IL_BT_SERVICE_CONNECTED_PROFILE:
+ if (msg.arg1 != BluetoothProfile.HEADSET) {
synchronized (mDeviceStateLock) {
- mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj);
+ mBtHelper.onBtProfileConnected(msg.arg1, (BluetoothProfile) msg.obj);
+ }
+ } else {
+ synchronized (mSetModeLock) {
+ synchronized (mDeviceStateLock) {
+ mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj);
+ }
}
}
break;
- case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION:
- case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: {
- final BtDeviceConnectionInfo info = (BtDeviceConnectionInfo) msg.obj;
+ case MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT: {
+ final BtDeviceInfo info = (BtDeviceInfo) msg.obj;
+ if (info.mDevice == null) break;
AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
- "msg: setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent "
+ "msg: onBluetoothActiveDeviceChange "
+ " state=" + info.mState
// only querying address as this is the only readily available
// field on the device
+ " addr=" + info.mDevice.getAddress()
- + " prof=" + info.mProfile + " supprNoisy=" + info.mSupprNoisy
- + " vol=" + info.mVolume)).printLog(TAG));
- synchronized (mDeviceStateLock) {
- mDeviceInventory.setBluetoothA2dpDeviceConnectionState(
- info.mDevice, info.mState, info.mProfile, info.mSupprNoisy,
- AudioSystem.DEVICE_NONE, info.mVolume);
- }
- } break;
- case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: {
- final HearingAidDeviceConnectionInfo info =
- (HearingAidDeviceConnectionInfo) msg.obj;
- AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
- "msg: setHearingAidDeviceConnectionState state=" + info.mState
- + " addr=" + info.mDevice.getAddress()
+ + " prof=" + info.mProfile
+ " supprNoisy=" + info.mSupprNoisy
- + " src=" + info.mEventSource)).printLog(TAG));
+ + " src=" + info.mEventSource
+ )).printLog(TAG));
synchronized (mDeviceStateLock) {
- mDeviceInventory.setBluetoothHearingAidDeviceConnectionState(
- info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice);
+ mDeviceInventory.setBluetoothActiveDevice(info);
}
} break;
case MSG_IL_SAVE_PREF_DEVICES_FOR_STRATEGY: {
@@ -1524,31 +1358,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
final int capturePreset = msg.arg1;
mDeviceInventory.onSaveClearPreferredDevicesForCapturePreset(capturePreset);
} break;
- case MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT: {
- final LeAudioDeviceConnectionInfo info =
- (LeAudioDeviceConnectionInfo) msg.obj;
- AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
- "setLeAudioDeviceOutConnectionState state=" + info.mState
- + " addr=" + info.mDevice.getAddress()
- + " supprNoisy=" + info.mSupprNoisy
- + " src=" + info.mEventSource)).printLog(TAG));
- synchronized (mDeviceStateLock) {
- mDeviceInventory.setBluetoothLeAudioOutDeviceConnectionState(
- info.mDevice, info.mState, info.mSupprNoisy);
- }
- } break;
- case MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT: {
- final LeAudioDeviceConnectionInfo info =
- (LeAudioDeviceConnectionInfo) msg.obj;
- AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
- "setLeAudioDeviceInConnectionState state=" + info.mState
- + " addr=" + info.mDevice.getAddress()
- + " src=" + info.mEventSource)).printLog(TAG));
- synchronized (mDeviceStateLock) {
- mDeviceInventory.setBluetoothLeAudioInDeviceConnectionState(info.mDevice,
- info.mState);
- }
- } break;
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
@@ -1579,8 +1388,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
private static final int MSG_IIL_SET_FORCE_USE = 4;
private static final int MSG_IIL_SET_FORCE_BT_A2DP_USE = 5;
private static final int MSG_TOGGLE_HDMI = 6;
- private static final int MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE = 7;
- private static final int MSG_IL_SET_HEARING_AID_CONNECTION_STATE = 8;
+ private static final int MSG_L_SET_BT_ACTIVE_DEVICE = 7;
private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
private static final int MSG_IL_BTA2DP_TIMEOUT = 10;
@@ -1593,25 +1401,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15;
private static final int MSG_I_SET_MODE_OWNER_PID = 16;
- // process active A2DP device change, obj is BtHelper.BluetoothA2dpDeviceInfo
- private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18;
-
- private static final int MSG_DISCONNECT_A2DP = 19;
- private static final int MSG_DISCONNECT_A2DP_SINK = 20;
- private static final int MSG_DISCONNECT_BT_HEARING_AID = 21;
- private static final int MSG_DISCONNECT_BT_HEADSET = 22;
- private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP = 23;
- private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK = 24;
- private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID = 25;
- private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET = 26;
-
- // process change of state, obj is BtHelper.BluetoothA2dpDeviceInfo
- private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED = 27;
- private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED = 28;
+ private static final int MSG_I_BT_SERVICE_DISCONNECTED_PROFILE = 22;
+ private static final int MSG_IL_BT_SERVICE_CONNECTED_PROFILE = 23;
// process external command to (dis)connect an A2DP device, obj is BtDeviceConnectionInfo
- private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION = 29;
- private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION = 30;
+ private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT = 29;
// process external command to (dis)connect a hearing aid device
private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 31;
@@ -1630,33 +1424,21 @@ import java.util.concurrent.atomic.AtomicBoolean;
private static final int MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY = 40;
private static final int MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY = 41;
- private static final int MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE = 42;
- private static final int MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE = 43;
- private static final int MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT = 44;
- private static final int MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT = 45;
+ private static final int MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT = 45;
+ //
// process set volume for Le Audio, obj is BleVolumeInfo
private static final int MSG_II_SET_LE_AUDIO_OUT_VOLUME = 46;
- private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO = 47;
- private static final int MSG_DISCONNECT_BT_LE_AUDIO = 48;
-
private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) {
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
- case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
- case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
- case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
- case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
+ case MSG_L_SET_BT_ACTIVE_DEVICE:
case MSG_IL_BTA2DP_TIMEOUT:
case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
case MSG_TOGGLE_HDMI:
- case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
- case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION:
- case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION:
+ case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT:
case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
case MSG_CHECK_MUTE_MUSIC:
- case MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT:
- case MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT:
return true;
default:
return false;
@@ -1739,14 +1521,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
long time = SystemClock.uptimeMillis() + delay;
switch (msg) {
- case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
- case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
- case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
- case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
+ case MSG_L_SET_BT_ACTIVE_DEVICE:
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
case MSG_IL_BTA2DP_TIMEOUT:
case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
- case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
if (sLastDeviceConnectMsgTime >= time) {
// add a little delay to make sure messages are ordered as expected
time = sLastDeviceConnectMsgTime + 30;
@@ -1765,14 +1543,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
private static final Set<Integer> MESSAGES_MUTE_MUSIC;
static {
MESSAGES_MUTE_MUSIC = new HashSet<>();
- MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED);
- MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED);
- MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE);
+ MESSAGES_MUTE_MUSIC.add(MSG_L_SET_BT_ACTIVE_DEVICE);
MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONFIG_CHANGE);
- MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE);
- MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION);
- MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION);
- MESSAGES_MUTE_MUSIC.add(MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT);
+ MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT);
MESSAGES_MUTE_MUSIC.add(MSG_IIL_SET_FORCE_BT_A2DP_USE);
MESSAGES_MUTE_MUSIC.add(MSG_REPORT_NEW_ROUTES_A2DP);
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 6c3c736aeb93..0a114b924063 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -16,11 +16,8 @@
package com.android.server.audio;
import android.annotation.NonNull;
-import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHearingAid;
-import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
import android.media.AudioDeviceAttributes;
@@ -286,186 +283,102 @@ public class AudioDeviceInventory {
}
}
- // only public for mocking/spying
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
- @VisibleForTesting
- public void onSetA2dpSinkConnectionState(@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo,
- @AudioService.BtProfileConnectionState int state) {
- final BluetoothDevice btDevice = btInfo.getBtDevice();
- int a2dpVolume = btInfo.getVolume();
- if (AudioService.DEBUG_DEVICES) {
- Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice + " state="
- + state + " vol=" + a2dpVolume);
- }
- String address = btDevice.getAddress();
- if (address == null) {
- address = "";
- }
- if (!BluetoothAdapter.checkBluetoothAddress(address)) {
- address = "";
- }
-
- final @AudioSystem.AudioFormatNativeEnumForBtCodec int a2dpCodec = btInfo.getCodec();
-
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "A2DP sink connected: device addr=" + address + " state=" + state
- + " codec=" + AudioSystem.audioFormatToString(a2dpCodec)
- + " vol=" + a2dpVolume));
-
- new MediaMetrics.Item(mMetricsId + "a2dp")
- .set(MediaMetrics.Property.ADDRESS, address)
- .set(MediaMetrics.Property.ENCODING, AudioSystem.audioFormatToString(a2dpCodec))
- .set(MediaMetrics.Property.EVENT, "onSetA2dpSinkConnectionState")
- .set(MediaMetrics.Property.INDEX, a2dpVolume)
- .set(MediaMetrics.Property.STATE,
- state == BluetoothProfile.STATE_CONNECTED
- ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
- .record();
-
- synchronized (mDevicesLock) {
- final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- btDevice.getAddress());
- final DeviceInfo di = mConnectedDevices.get(key);
- boolean isConnected = di != null;
-
- if (isConnected) {
- if (state == BluetoothProfile.STATE_CONNECTED) {
- // device is already connected, but we are receiving a connection again,
- // it could be for a codec change
- if (a2dpCodec != di.mDeviceCodecFormat) {
- mDeviceBroker.postBluetoothA2dpDeviceConfigChange(btDevice);
- }
- } else {
- makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat);
- }
- } else if (state == BluetoothProfile.STATE_CONNECTED) {
- // device is not already connected
- if (a2dpVolume != -1) {
- mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
- // convert index to internal representation in VolumeStreamState
- a2dpVolume * 10,
- AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "onSetA2dpSinkConnectionState");
- }
- makeA2dpDeviceAvailable(address, BtHelper.getName(btDevice),
- "onSetA2dpSinkConnectionState", a2dpCodec);
- }
- }
- }
-
- /*package*/ void onSetA2dpSourceConnectionState(
- @NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int state) {
- final BluetoothDevice btDevice = btInfo.getBtDevice();
+ void onSetBtActiveDevice(@NonNull AudioDeviceBroker.BtDeviceInfo btInfo, int streamType) {
if (AudioService.DEBUG_DEVICES) {
- Log.d(TAG, "onSetA2dpSourceConnectionState btDevice=" + btDevice + " state="
- + state);
+ Log.d(TAG, "onSetBtActiveDevice"
+ + " btDevice=" + btInfo.mDevice
+ + " profile=" + BluetoothProfile.getProfileName(btInfo.mProfile)
+ + " state=" + BluetoothProfile.getConnectionStateName(btInfo.mState));
}
- String address = btDevice.getAddress();
+ String address = btInfo.mDevice.getAddress();
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
address = "";
}
- synchronized (mDevicesLock) {
- final String key = DeviceInfo.makeDeviceListKey(
- AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
- final DeviceInfo di = mConnectedDevices.get(key);
- boolean isConnected = di != null;
-
- new MediaMetrics.Item(mMetricsId + "onSetA2dpSourceConnectionState")
- .set(MediaMetrics.Property.ADDRESS, address)
- .set(MediaMetrics.Property.DEVICE,
- AudioSystem.getDeviceName(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP))
- .set(MediaMetrics.Property.STATE,
- state == BluetoothProfile.STATE_CONNECTED
- ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
- .record();
-
- if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
- makeA2dpSrcUnavailable(address);
- } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
- makeA2dpSrcAvailable(address);
- }
- }
- }
-
- /*package*/ void onSetHearingAidConnectionState(BluetoothDevice btDevice,
- @AudioService.BtProfileConnectionState int state, int streamType) {
- String address = btDevice.getAddress();
- if (!BluetoothAdapter.checkBluetoothAddress(address)) {
- address = "";
- }
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "onSetHearingAidConnectionState addr=" + address));
+ AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent("BT connected:"
+ + " addr=" + address
+ + " profile=" + btInfo.mProfile
+ + " state=" + btInfo.mState
+ + " codec=" + AudioSystem.audioFormatToString(btInfo.mCodec)));
- new MediaMetrics.Item(mMetricsId + "onSetHearingAidConnectionState")
- .set(MediaMetrics.Property.ADDRESS, address)
+ new MediaMetrics.Item(mMetricsId + "onSetBtActiveDevice")
+ .set(MediaMetrics.Property.STATUS, btInfo.mProfile)
.set(MediaMetrics.Property.DEVICE,
- AudioSystem.getDeviceName(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP))
- .set(MediaMetrics.Property.STATE,
- state == BluetoothProfile.STATE_CONNECTED
- ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
+ AudioSystem.getDeviceName(btInfo.mAudioSystemDevice))
+ .set(MediaMetrics.Property.ADDRESS, address)
+ .set(MediaMetrics.Property.ENCODING,
+ AudioSystem.audioFormatToString(btInfo.mCodec))
+ .set(MediaMetrics.Property.EVENT, "onSetBtActiveDevice")
.set(MediaMetrics.Property.STREAM_TYPE,
AudioSystem.streamToString(streamType))
+ .set(MediaMetrics.Property.STATE,
+ btInfo.mState == BluetoothProfile.STATE_CONNECTED
+ ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
.record();
synchronized (mDevicesLock) {
- final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID,
- btDevice.getAddress());
+ final String key = DeviceInfo.makeDeviceListKey(btInfo.mAudioSystemDevice, address);
final DeviceInfo di = mConnectedDevices.get(key);
- boolean isConnected = di != null;
- if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
- makeHearingAidDeviceUnavailable(address);
- } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
- makeHearingAidDeviceAvailable(address, BtHelper.getName(btDevice), streamType,
- "onSetHearingAidConnectionState");
- }
- }
- }
+ final boolean isConnected = di != null;
- /*package*/ void onSetLeAudioConnectionState(BluetoothDevice btDevice,
- @AudioService.BtProfileConnectionState int state, int streamType, int device) {
- String address = btDevice.getAddress();
- if (!BluetoothAdapter.checkBluetoothAddress(address)) {
- address = "";
- }
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "onSetLeAudioConnectionState addr=" + address));
+ final boolean switchToUnavailable = isConnected
+ && btInfo.mState != BluetoothProfile.STATE_CONNECTED;
+ final boolean switchToAvailable = !isConnected
+ && btInfo.mState == BluetoothProfile.STATE_CONNECTED;
- synchronized (mDevicesLock) {
- DeviceInfo di = null;
- boolean isConnected = false;
-
- String key = DeviceInfo.makeDeviceListKey(device, btDevice.getAddress());
- di = mConnectedDevices.get(key);
- isConnected = di != null;
-
- if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
- makeLeAudioDeviceUnavailable(address, device);
- } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
- makeLeAudioDeviceAvailable(address, BtHelper.getName(btDevice), streamType,
- device, "onSetLeAudioConnectionState");
+ switch (btInfo.mProfile) {
+ case BluetoothProfile.A2DP_SINK:
+ if (switchToUnavailable) {
+ makeA2dpSrcUnavailable(address);
+ } else if (switchToAvailable) {
+ makeA2dpSrcAvailable(address);
+ }
+ break;
+ case BluetoothProfile.A2DP:
+ if (switchToUnavailable) {
+ makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat);
+ } else if (switchToAvailable) {
+ // device is not already connected
+ if (btInfo.mVolume != -1) {
+ mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
+ // convert index to internal representation in VolumeStreamState
+ btInfo.mVolume * 10, btInfo.mAudioSystemDevice,
+ "onSetBtActiveDevice");
+ }
+ makeA2dpDeviceAvailable(address, BtHelper.getName(btInfo.mDevice),
+ "onSetBtActiveDevice", btInfo.mCodec);
+ }
+ break;
+ case BluetoothProfile.HEARING_AID:
+ if (switchToUnavailable) {
+ makeHearingAidDeviceUnavailable(address);
+ } else if (switchToAvailable) {
+ makeHearingAidDeviceAvailable(address, BtHelper.getName(btInfo.mDevice),
+ streamType, "onSetBtActiveDevice");
+ }
+ break;
+ case BluetoothProfile.LE_AUDIO:
+ if (switchToUnavailable) {
+ makeLeAudioDeviceUnavailable(address, btInfo.mAudioSystemDevice);
+ } else if (switchToAvailable) {
+ makeLeAudioDeviceAvailable(address, BtHelper.getName(btInfo.mDevice),
+ streamType, btInfo.mAudioSystemDevice, "onSetBtActiveDevice");
+ }
+ break;
+ default: throw new IllegalArgumentException("Invalid profile "
+ + BluetoothProfile.getProfileName(btInfo.mProfile));
}
}
}
- /*package*/ void onSetLeAudioOutConnectionState(BluetoothDevice btDevice,
- @AudioService.BtProfileConnectionState int state, int streamType) {
- // TODO: b/198610537 clarify DEVICE_OUT_BLE_HEADSET vs DEVICE_OUT_BLE_SPEAKER criteria
- onSetLeAudioConnectionState(btDevice, state, streamType,
- AudioSystem.DEVICE_OUT_BLE_HEADSET);
- }
-
- /*package*/ void onSetLeAudioInConnectionState(BluetoothDevice btDevice,
- @AudioService.BtProfileConnectionState int state) {
- onSetLeAudioConnectionState(btDevice, state, AudioSystem.STREAM_DEFAULT,
- AudioSystem.DEVICE_IN_BLE_HEADSET);
- }
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
- /*package*/ void onBluetoothA2dpActiveDeviceChange(
+ /*package*/ void onBluetoothA2dpDeviceConfigChange(
@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int event) {
MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId
- + "onBluetoothA2dpActiveDeviceChange")
+ + "onBluetoothA2dpDeviceConfigChange")
.set(MediaMetrics.Property.EVENT, BtHelper.a2dpDeviceEventToString(event));
final BluetoothDevice btDevice = btInfo.getBtDevice();
@@ -474,7 +387,7 @@ public class AudioDeviceInventory {
return;
}
if (AudioService.DEBUG_DEVICES) {
- Log.d(TAG, "onBluetoothA2dpActiveDeviceChange btDevice=" + btDevice);
+ Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
}
int a2dpVolume = btInfo.getVolume();
@AudioSystem.AudioFormatNativeEnumForBtCodec final int a2dpCodec = btInfo.getCodec();
@@ -484,11 +397,11 @@ public class AudioDeviceInventory {
address = "";
}
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "onBluetoothA2dpActiveDeviceChange addr=" + address
+ "onBluetoothA2dpDeviceConfigChange addr=" + address
+ " event=" + BtHelper.a2dpDeviceEventToString(event)));
synchronized (mDevicesLock) {
- if (mDeviceBroker.hasScheduledA2dpSinkConnectionState(btDevice)) {
+ if (mDeviceBroker.hasScheduledA2dpConnection(btDevice)) {
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
"A2dp config change ignored (scheduled connection change)")
.printLog(TAG));
@@ -500,7 +413,7 @@ public class AudioDeviceInventory {
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
final DeviceInfo di = mConnectedDevices.get(key);
if (di == null) {
- Log.e(TAG, "invalid null DeviceInfo in onBluetoothA2dpActiveDeviceChange");
+ Log.e(TAG, "invalid null DeviceInfo in onBluetoothA2dpDeviceConfigChange");
mmi.set(MediaMetrics.Property.EARLY_RETURN, "null DeviceInfo").record();
return;
}
@@ -518,7 +431,7 @@ public class AudioDeviceInventory {
// convert index to internal representation in VolumeStreamState
a2dpVolume * 10,
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- "onBluetoothA2dpActiveDeviceChange");
+ "onBluetoothA2dpDeviceConfigChange");
}
} else if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) {
if (di.mDeviceCodecFormat != a2dpCodec) {
@@ -539,10 +452,9 @@ public class AudioDeviceInventory {
int musicDevice = mDeviceBroker.getDeviceForStream(AudioSystem.STREAM_MUSIC);
// force A2DP device disconnection in case of error so that AudioService state is
// consistent with audio policy manager state
- setBluetoothA2dpDeviceConnectionState(
- btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP,
- false /* suppressNoisyIntent */, musicDevice,
- -1 /* a2dpVolume */);
+ setBluetoothActiveDevice(new AudioDeviceBroker.BtDeviceInfo(btDevice,
+ BluetoothProfile.A2DP, BluetoothProfile.STATE_DISCONNECTED,
+ musicDevice, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
} else {
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
"APM handleDeviceConfigChange success for A2DP device addr=" + address
@@ -828,7 +740,7 @@ public class AudioDeviceInventory {
}
- /*package*/ void disconnectA2dp() {
+ private void disconnectA2dp() {
synchronized (mDevicesLock) {
final ArraySet<String> toRemove = new ArraySet<>();
// Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
@@ -850,7 +762,7 @@ public class AudioDeviceInventory {
}
}
- /*package*/ void disconnectA2dpSink() {
+ private void disconnectA2dpSink() {
synchronized (mDevicesLock) {
final ArraySet<String> toRemove = new ArraySet<>();
// Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
@@ -865,7 +777,7 @@ public class AudioDeviceInventory {
}
}
- /*package*/ void disconnectHearingAid() {
+ private void disconnectHearingAid() {
synchronized (mDevicesLock) {
final ArraySet<String> toRemove = new ArraySet<>();
// Disconnect ALL DEVICE_OUT_HEARING_AID devices
@@ -887,6 +799,28 @@ public class AudioDeviceInventory {
}
}
+ /*package*/ synchronized void onBtProfileDisconnected(int profile) {
+ switch (profile) {
+ case BluetoothProfile.A2DP:
+ disconnectA2dp();
+ break;
+ case BluetoothProfile.A2DP_SINK:
+ disconnectA2dpSink();
+ break;
+ case BluetoothProfile.HEARING_AID:
+ disconnectHearingAid();
+ break;
+ case BluetoothProfile.LE_AUDIO:
+ disconnectLeAudio();
+ break;
+ default:
+ // Not a valid profile to disconnect
+ Log.e(TAG, "onBtProfileDisconnected: Not a valid profile to disconnect "
+ + BluetoothProfile.getProfileName(profile));
+ break;
+ }
+ }
+
/*package*/ void disconnectLeAudio() {
synchronized (mDevicesLock) {
final ArraySet<String> toRemove = new ArraySet<>();
@@ -934,46 +868,39 @@ public class AudioDeviceInventory {
// only public for mocking/spying
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
@VisibleForTesting
- public void setBluetoothA2dpDeviceConnectionState(
- @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
- int profile, boolean suppressNoisyIntent, int musicDevice, int a2dpVolume) {
+ public int setBluetoothActiveDevice(@NonNull AudioDeviceBroker.BtDeviceInfo info) {
int delay;
- if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
- throw new IllegalArgumentException("invalid profile " + profile);
- }
synchronized (mDevicesLock) {
- if (profile == BluetoothProfile.A2DP && !suppressNoisyIntent) {
+ if (!info.mSupprNoisy
+ && ((info.mProfile == BluetoothProfile.LE_AUDIO && info.mIsLeOutput)
+ || info.mProfile == BluetoothProfile.HEARING_AID
+ || info.mProfile == BluetoothProfile.A2DP)) {
@AudioService.ConnectionState int asState =
- (state == BluetoothA2dp.STATE_CONNECTED)
+ (info.mState == BluetoothProfile.STATE_CONNECTED)
? AudioService.CONNECTION_STATE_CONNECTED
: AudioService.CONNECTION_STATE_DISCONNECTED;
- delay = checkSendBecomingNoisyIntentInt(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- asState, musicDevice);
+ delay = checkSendBecomingNoisyIntentInt(info.mAudioSystemDevice, asState,
+ info.mMusicDevice);
} else {
delay = 0;
}
- final int a2dpCodec = mDeviceBroker.getA2dpCodec(device);
-
if (AudioService.DEBUG_DEVICES) {
- Log.i(TAG, "setBluetoothA2dpDeviceConnectionState device: " + device
- + " state: " + state + " delay(ms): " + delay
- + " codec:" + Integer.toHexString(a2dpCodec)
- + " suppressNoisyIntent: " + suppressNoisyIntent);
+ Log.i(TAG, "setBluetoothActiveDevice device: " + info.mDevice
+ + " profile: " + BluetoothProfile.getProfileName(info.mProfile)
+ + " state: " + BluetoothProfile.getConnectionStateName(info.mState)
+ + " delay(ms): " + delay
+ + " codec:" + Integer.toHexString(info.mCodec)
+ + " suppressNoisyIntent: " + info.mSupprNoisy);
}
-
- final BtHelper.BluetoothA2dpDeviceInfo a2dpDeviceInfo =
- new BtHelper.BluetoothA2dpDeviceInfo(device, a2dpVolume, a2dpCodec);
- if (profile == BluetoothProfile.A2DP) {
- mDeviceBroker.postA2dpSinkConnection(state,
- a2dpDeviceInfo,
- delay);
- } else { //profile == BluetoothProfile.A2DP_SINK
- mDeviceBroker.postA2dpSourceConnection(state,
- a2dpDeviceInfo,
- delay);
+ mDeviceBroker.postBluetoothActiveDevice(info, delay);
+ if (info.mProfile == BluetoothProfile.HEARING_AID
+ && info.mState == BluetoothProfile.STATE_CONNECTED) {
+ mDeviceBroker.setForceUse_Async(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE,
+ "HEARING_AID set to CONNECTED");
}
}
+ return delay;
}
/*package*/ int setWiredDeviceConnectionState(int type, @AudioService.ConnectionState int state,
@@ -987,50 +914,6 @@ public class AudioDeviceInventory {
}
}
- /*package*/ int setBluetoothHearingAidDeviceConnectionState(
- @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
- boolean suppressNoisyIntent, int musicDevice) {
- int delay;
- synchronized (mDevicesLock) {
- if (!suppressNoisyIntent) {
- int intState = (state == BluetoothHearingAid.STATE_CONNECTED) ? 1 : 0;
- delay = checkSendBecomingNoisyIntentInt(AudioSystem.DEVICE_OUT_HEARING_AID,
- intState, musicDevice);
- } else {
- delay = 0;
- }
- mDeviceBroker.postSetHearingAidConnectionState(state, device, delay);
- if (state == BluetoothHearingAid.STATE_CONNECTED) {
- mDeviceBroker.setForceUse_Async(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE,
- "HEARING_AID set to CONNECTED");
- }
- return delay;
- }
- }
-
- /*package*/ int setBluetoothLeAudioOutDeviceConnectionState(
- @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
- boolean suppressNoisyIntent) {
- synchronized (mDevicesLock) {
- /* Active device become null and it's previous device is not connected anymore */
- int delay = 0;
- if (!suppressNoisyIntent) {
- int intState = (state == BluetoothLeAudio.STATE_CONNECTED) ? 1 : 0;
- delay = checkSendBecomingNoisyIntentInt(AudioSystem.DEVICE_OUT_BLE_HEADSET,
- intState, AudioSystem.DEVICE_NONE);
- }
- mDeviceBroker.postSetLeAudioOutConnectionState(state, device, delay);
- return delay;
- }
- }
-
- /*package*/ void setBluetoothLeAudioInDeviceConnectionState(
- @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state) {
- synchronized (mDevicesLock) {
- mDeviceBroker.postSetLeAudioInConnectionState(state, device);
- }
- }
-
//-------------------------------------------------------------------
// Internal utilities
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d75f21c4ef85..51784bbce2e0 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -83,6 +83,7 @@ import android.media.AudioPlaybackConfiguration;
import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo;
import android.media.AudioSystem;
+import android.media.BtProfileConnectionInfo;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioModeDispatcher;
import android.media.IAudioRoutesObserver;
@@ -309,8 +310,8 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_UPDATE_A11Y_SERVICE_UIDS = 35;
private static final int MSG_UPDATE_AUDIO_MODE = 36;
private static final int MSG_RECORDING_CONFIG_CHANGE = 37;
- private static final int MSG_SET_A2DP_DEV_CONNECTION_STATE = 38;
- private static final int MSG_A2DP_DEV_CONFIG_CHANGE = 39;
+ private static final int MSG_BT_DEV_CHANGED = 38;
+
private static final int MSG_DISPATCH_AUDIO_MODE = 40;
// start of messages handled under wakelock
@@ -6266,77 +6267,44 @@ public class AudioService extends IAudioService.Stub
public @interface BtProfileConnectionState {}
/**
- * See AudioManager.setBluetoothHearingAidDeviceConnectionState()
- */
- public void setBluetoothHearingAidDeviceConnectionState(
- @NonNull BluetoothDevice device, @BtProfileConnectionState int state,
- boolean suppressNoisyIntent, int musicDevice)
- {
- if (device == null) {
- throw new IllegalArgumentException("Illegal null device");
- }
- if (state != BluetoothProfile.STATE_CONNECTED
- && state != BluetoothProfile.STATE_DISCONNECTED) {
- throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
- + " (dis)connection, got " + state);
- }
- mDeviceBroker.postBluetoothHearingAidDeviceConnectionState(
- device, state, suppressNoisyIntent, musicDevice, "AudioService");
- }
-
- private void setBluetoothLeAudioDeviceConnectionState(@NonNull BluetoothDevice device,
- @BtProfileConnectionState int state) {
- if (device == null) {
- throw new IllegalArgumentException("Illegal null device");
- }
- if (state != BluetoothProfile.STATE_CONNECTED
- && state != BluetoothProfile.STATE_DISCONNECTED) {
- throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
- + " (dis)connection, got " + state);
- }
- }
-
- /**
- * See AudioManager.setBluetoothLeAudioOutDeviceConnectionState()
+ * @hide
+ * The profiles that can be used with AudioService.handleBluetoothActiveDeviceChanged()
*/
- public void setBluetoothLeAudioOutDeviceConnectionState(
- @NonNull BluetoothDevice device, @BtProfileConnectionState int state,
- boolean suppressNoisyIntent) {
- setBluetoothLeAudioDeviceConnectionState(device, state);
- mDeviceBroker.postBluetoothLeAudioOutDeviceConnectionState(device, state,
- suppressNoisyIntent, "AudioService");
- }
+ @IntDef({
+ BluetoothProfile.HEARING_AID,
+ BluetoothProfile.A2DP,
+ BluetoothProfile.A2DP_SINK,
+ BluetoothProfile.LE_AUDIO,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface BtProfile {}
- /**
- * See AudioManager.setBluetoothLeAudioInDeviceConnectionState()
- */
- public void setBluetoothLeAudioInDeviceConnectionState(
- @NonNull BluetoothDevice device, @BtProfileConnectionState int state) {
- setBluetoothLeAudioDeviceConnectionState(device, state);
- mDeviceBroker.postBluetoothLeAudioInDeviceConnectionState(device, state, "AudioService");
- }
/**
- * See AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent()
+ * See AudioManager.handleBluetoothActiveDeviceChanged(...)
*/
- public void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- @NonNull BluetoothDevice device, @BtProfileConnectionState int state,
- int profile, boolean suppressNoisyIntent, int a2dpVolume) {
- if (device == null) {
- throw new IllegalArgumentException("Illegal null device");
+ public void handleBluetoothActiveDeviceChanged(BluetoothDevice newDevice,
+ BluetoothDevice previousDevice, @NonNull BtProfileConnectionInfo info) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BLUETOOTH_STACK)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Bluetooth is the only caller allowed");
}
- if (state != BluetoothProfile.STATE_CONNECTED
- && state != BluetoothProfile.STATE_DISCONNECTED) {
- throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
- + " (dis)connection, got " + state);
+ if (info == null) {
+ throw new IllegalArgumentException("Illegal null BtProfileConnectionInfo for device "
+ + previousDevice + " -> " + newDevice);
}
-
- AudioDeviceBroker.BtDeviceConnectionInfo info =
- new AudioDeviceBroker.BtDeviceConnectionInfo(device, state,
- profile, suppressNoisyIntent, a2dpVolume);
- sendMsg(mAudioHandler, MSG_SET_A2DP_DEV_CONNECTION_STATE, SENDMSG_QUEUE,
- 0 /*arg1*/, 0 /*arg2*/,
- /*obj*/ info, 0 /*delay*/);
+ final int profile = info.getProfile();
+ if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK
+ && profile != BluetoothProfile.LE_AUDIO
+ && profile != BluetoothProfile.HEARING_AID) {
+ throw new IllegalArgumentException("Illegal BluetoothProfile profile for device "
+ + previousDevice + " -> " + newDevice + ". Got: " + profile);
+ }
+ AudioDeviceBroker.BtDeviceChangedData data =
+ new AudioDeviceBroker.BtDeviceChangedData(newDevice, previousDevice, info,
+ "AudioService");
+ sendMsg(mAudioHandler, MSG_BT_DEV_CHANGED, SENDMSG_QUEUE, 0, 0,
+ /*obj*/ data, /*delay*/ 0);
}
/** only public for mocking/spying, do not call outside of AudioService */
@@ -6345,19 +6313,6 @@ public class AudioService extends IAudioService.Stub
mStreamStates[AudioSystem.STREAM_MUSIC].muteInternally(mute);
}
- /**
- * See AudioManager.handleBluetoothA2dpDeviceConfigChange()
- * @param device
- */
- public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)
- {
- if (device == null) {
- throw new IllegalArgumentException("Illegal null device");
- }
- sendMsg(mAudioHandler, MSG_A2DP_DEV_CONFIG_CHANGE, SENDMSG_QUEUE, 0, 0,
- /*obj*/ device, /*delay*/ 0);
- }
-
private static final Set<Integer> DEVICE_MEDIA_UNMUTED_ON_PLUG_SET;
static {
DEVICE_MEDIA_UNMUTED_ON_PLUG_SET = new HashSet<>();
@@ -7709,13 +7664,9 @@ public class AudioService extends IAudioService.Stub
}
break;
- case MSG_SET_A2DP_DEV_CONNECTION_STATE:
- mDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- (AudioDeviceBroker.BtDeviceConnectionInfo) msg.obj);
- break;
-
- case MSG_A2DP_DEV_CONFIG_CHANGE:
- mDeviceBroker.postBluetoothA2dpDeviceConfigChange((BluetoothDevice) msg.obj);
+ case MSG_BT_DEV_CHANGED:
+ mDeviceBroker.queueOnBluetoothActiveDeviceChanged(
+ (AudioDeviceBroker.BtDeviceChangedData) msg.obj);
break;
case MSG_DISPATCH_AUDIO_MODE:
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index c924fde23f9d..9273a5d5cf9c 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -31,6 +31,7 @@ import android.content.Intent;
import android.media.AudioDeviceAttributes;
import android.media.AudioManager;
import android.media.AudioSystem;
+import android.media.BtProfileConnectionInfo;
import android.os.Binder;
import android.os.UserHandle;
import android.provider.Settings;
@@ -451,11 +452,11 @@ public class BtHelper {
}
/*package*/ synchronized void disconnectAllBluetoothProfiles() {
- mDeviceBroker.postDisconnectA2dp();
- mDeviceBroker.postDisconnectA2dpSink();
- mDeviceBroker.postDisconnectHeadset();
- mDeviceBroker.postDisconnectHearingAid();
- mDeviceBroker.postDisconnectLeAudio();
+ mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.A2DP);
+ mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.A2DP_SINK);
+ mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.HEADSET);
+ mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.HEARING_AID);
+ mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.LE_AUDIO);
}
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
@@ -474,63 +475,32 @@ public class BtHelper {
mBluetoothHeadset = null;
}
- /*package*/ synchronized void onA2dpProfileConnected(BluetoothA2dp a2dp) {
- mA2dp = a2dp;
- final List<BluetoothDevice> deviceList = mA2dp.getConnectedDevices();
- if (deviceList.isEmpty()) {
+ /*package*/ synchronized void onBtProfileConnected(int profile, BluetoothProfile proxy) {
+ if (profile == BluetoothProfile.HEADSET) {
+ onHeadsetProfileConnected((BluetoothHeadset) proxy);
return;
}
- final BluetoothDevice btDevice = deviceList.get(0);
- // the device is guaranteed CONNECTED
- mDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- new AudioDeviceBroker.BtDeviceConnectionInfo(btDevice,
- BluetoothA2dp.STATE_CONNECTED, BluetoothProfile.A2DP_SINK,
- true, -1));
- }
-
- /*package*/ synchronized void onA2dpSinkProfileConnected(BluetoothProfile profile) {
- final List<BluetoothDevice> deviceList = profile.getConnectedDevices();
- if (deviceList.isEmpty()) {
- return;
+ if (profile == BluetoothProfile.A2DP) {
+ mA2dp = (BluetoothA2dp) proxy;
+ } else if (profile == BluetoothProfile.LE_AUDIO) {
+ mLeAudio = (BluetoothLeAudio) proxy;
}
- final BluetoothDevice btDevice = deviceList.get(0);
- final @BluetoothProfile.BtProfileState int state =
- profile.getConnectionState(btDevice);
- mDeviceBroker.postSetA2dpSourceConnectionState(
- state, new BluetoothA2dpDeviceInfo(btDevice));
- }
-
- /*package*/ synchronized void onHearingAidProfileConnected(BluetoothHearingAid hearingAid) {
- mHearingAid = hearingAid;
- final List<BluetoothDevice> deviceList = mHearingAid.getConnectedDevices();
+ final List<BluetoothDevice> deviceList = proxy.getConnectedDevices();
if (deviceList.isEmpty()) {
return;
}
final BluetoothDevice btDevice = deviceList.get(0);
final @BluetoothProfile.BtProfileState int state =
- mHearingAid.getConnectionState(btDevice);
- mDeviceBroker.postBluetoothHearingAidDeviceConnectionState(
- btDevice, state,
- /*suppressNoisyIntent*/ false,
- /*musicDevice*/ android.media.AudioSystem.DEVICE_NONE,
- /*eventSource*/ "mBluetoothProfileServiceListener");
- }
-
- /*package*/ synchronized void onLeAudioProfileConnected(BluetoothLeAudio leAudio) {
- mLeAudio = leAudio;
- final List<BluetoothDevice> deviceList = mLeAudio.getConnectedDevices();
- if (deviceList.isEmpty()) {
- return;
+ proxy.getConnectionState(btDevice);
+ if (state == BluetoothProfile.STATE_CONNECTED) {
+ mDeviceBroker.queueOnBluetoothActiveDeviceChanged(
+ new AudioDeviceBroker.BtDeviceChangedData(btDevice, null,
+ new BtProfileConnectionInfo(profile), "mBluetoothProfileServiceListener"));
+ } else {
+ mDeviceBroker.queueOnBluetoothActiveDeviceChanged(
+ new AudioDeviceBroker.BtDeviceChangedData(null, btDevice,
+ new BtProfileConnectionInfo(profile), "mBluetoothProfileServiceListener"));
}
-
- final BluetoothDevice btDevice = deviceList.get(0);
- final @BluetoothProfile.BtProfileState int state =
- mLeAudio.getConnectionState(btDevice);
- mDeviceBroker.postBluetoothLeAudioOutDeviceConnectionState(
- btDevice, state,
- /*suppressNoisyIntent*/ false,
- /*musicDevice android.media.AudioSystem.DEVICE_NONE,*/
- /*eventSource*/ "mBluetoothProfileServiceListener");
}
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
@@ -677,36 +647,16 @@ public class BtHelper {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
switch(profile) {
case BluetoothProfile.A2DP:
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "BT profile service: connecting A2DP profile"));
- mDeviceBroker.postBtA2dpProfileConnected((BluetoothA2dp) proxy);
- break;
-
case BluetoothProfile.A2DP_SINK:
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "BT profile service: connecting A2DP_SINK profile"));
- mDeviceBroker.postBtA2dpSinkProfileConnected(proxy);
- break;
-
case BluetoothProfile.HEADSET:
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "BT profile service: connecting HEADSET profile"));
- mDeviceBroker.postBtHeasetProfileConnected((BluetoothHeadset) proxy);
- break;
-
case BluetoothProfile.HEARING_AID:
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "BT profile service: connecting HEARING_AID profile"));
- mDeviceBroker.postBtHearingAidProfileConnected(
- (BluetoothHearingAid) proxy);
- break;
-
case BluetoothProfile.LE_AUDIO:
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "BT profile service: connecting LE_AUDIO profile"));
- mDeviceBroker.postBtLeAudioProfileConnected(
- (BluetoothLeAudio) proxy);
+ "BT profile service: connecting "
+ + BluetoothProfile.getProfileName(profile) + " profile"));
+ mDeviceBroker.postBtProfileConnected(profile, proxy);
break;
+
default:
break;
}
@@ -715,22 +665,11 @@ public class BtHelper {
switch (profile) {
case BluetoothProfile.A2DP:
- mDeviceBroker.postDisconnectA2dp();
- break;
-
case BluetoothProfile.A2DP_SINK:
- mDeviceBroker.postDisconnectA2dpSink();
- break;
-
case BluetoothProfile.HEADSET:
- mDeviceBroker.postDisconnectHeadset();
- break;
-
case BluetoothProfile.HEARING_AID:
- mDeviceBroker.postDisconnectHearingAid();
- break;
case BluetoothProfile.LE_AUDIO:
- mDeviceBroker.postDisconnectLeAudio();
+ mDeviceBroker.postBtProfileDisconnected(profile);
break;
default:
diff --git a/services/core/java/com/android/server/audio/TEST_MAPPING b/services/core/java/com/android/server/audio/TEST_MAPPING
index 90246f849491..5a6c6a51bd97 100644
--- a/services/core/java/com/android/server/audio/TEST_MAPPING
+++ b/services/core/java/com/android/server/audio/TEST_MAPPING
@@ -1,13 +1,13 @@
{
"presubmit-large": [
{
- "name": "CtsMediaTestCases",
+ "name": "CtsMediaAudioTestCases",
"options": [
{
- "include-filter": "android.media.cts.AudioManagerTest"
+ "include-filter": "android.media.audio.cts.AudioManagerTest"
},
{
- "include-filter": "android.media.cts.AudioFocusTest"
+ "include-filter": "android.media.audio.cts.AudioFocusTest"
}
]
}
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 0cd2e3d0ff59..c97ad55ceeec 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -60,6 +60,7 @@ import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
@@ -70,6 +71,7 @@ import com.android.internal.util.ArrayUtils;
import com.android.server.SystemService;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -81,6 +83,8 @@ public class AuthService extends SystemService {
private static final String SETTING_HIDL_DISABLED =
"com.android.server.biometrics.AuthService.hidlDisabled";
private static final int DEFAULT_HIDL_DISABLED = 0;
+ private static final String SYSPROP_FIRST_API_LEVEL = "ro.board.first_api_level";
+ private static final String SYSPROP_API_LEVEL = "ro.board.api_level";
private final Injector mInjector;
@@ -623,7 +627,16 @@ public class AuthService extends SystemService {
final SensorConfig[] hidlConfigs;
if (!mInjector.isHidlDisabled(getContext())) {
- final String[] configStrings = mInjector.getConfiguration(getContext());
+ final int firstApiLevel = SystemProperties.getInt(SYSPROP_FIRST_API_LEVEL, 0);
+ final int apiLevel = SystemProperties.getInt(SYSPROP_API_LEVEL, firstApiLevel);
+ String[] configStrings = mInjector.getConfiguration(getContext());
+ if (configStrings.length == 0 && apiLevel == Build.VERSION_CODES.R) {
+ // For backwards compatibility with R where biometrics could work without being
+ // configured in config_biometric_sensors. In the absence of a vendor provided
+ // configuration, we assume the weakest biometric strength (i.e. convenience).
+ Slog.w(TAG, "Found R vendor partition without config_biometric_sensors");
+ configStrings = generateRSdkCompatibleConfiguration();
+ }
hidlConfigs = new SensorConfig[configStrings.length];
for (int i = 0; i < configStrings.length; ++i) {
hidlConfigs[i] = new SensorConfig(configStrings[i]);
@@ -639,6 +652,31 @@ public class AuthService extends SystemService {
}
/**
+ * Generates an array of string configs with entries that correspond to the biometric features
+ * declared on the device. Returns an empty array if no biometric features are declared.
+ * Biometrics are assumed to be of the weakest strength class, i.e. convenience.
+ */
+ private @NonNull String[] generateRSdkCompatibleConfiguration() {
+ final PackageManager pm = getContext().getPackageManager();
+ final ArrayList<String> modalities = new ArrayList<>();
+ if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+ modalities.add(String.valueOf(BiometricAuthenticator.TYPE_FINGERPRINT));
+ }
+ if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ modalities.add(String.valueOf(BiometricAuthenticator.TYPE_FACE));
+ }
+ final String strength = String.valueOf(Authenticators.BIOMETRIC_CONVENIENCE);
+ final String[] configStrings = new String[modalities.size()];
+ for (int i = 0; i < modalities.size(); ++i) {
+ final String id = String.valueOf(i);
+ final String modality = modalities.get(i);
+ configStrings[i] = String.join(":" /* delimiter */, id, modality, strength);
+ }
+ Slog.d(TAG, "Generated config_biometric_sensors: " + Arrays.toString(configStrings));
+ return configStrings;
+ }
+
+ /**
* Registers HIDL and AIDL authenticators for all of the available modalities.
*
* @param hidlSensors Array of {@link SensorConfig} configuration for all of the HIDL sensors
diff --git a/services/core/java/com/android/server/compat/OWNERS b/services/core/java/com/android/server/compat/OWNERS
index cfd0a4b079ad..ee3086ab2fdb 100644
--- a/services/core/java/com/android/server/compat/OWNERS
+++ b/services/core/java/com/android/server/compat/OWNERS
@@ -1,6 +1 @@
-# Use this reviewer by default.
-platform-compat-eng+reviews@google.com
-
-andreionea@google.com
-mathewi@google.com
-satayev@google.com
+include tools/platform-compat:/OWNERS
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 6ea84ce35002..ee5bda3abc91 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -171,25 +171,28 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
}
private NetworkMetrics getMetricsForNetwork(long timeMs, int netId) {
- collectPendingMetricsSnapshot(timeMs);
NetworkMetrics metrics = mNetworkMetrics.get(netId);
- if (metrics == null) {
- // TODO: allow to change transport for a given netid.
- metrics = new NetworkMetrics(netId, getTransports(netId), mConnectTb);
+ final NetworkCapabilities nc = mCallback.getNetworkCapabilities(netId);
+ final long transports = (nc != null) ? BitUtils.packBits(nc.getTransportTypes()) : 0;
+ final boolean forceCollect =
+ (metrics != null && nc != null && metrics.transports != transports);
+ collectPendingMetricsSnapshot(timeMs, forceCollect);
+ if (metrics == null || forceCollect) {
+ metrics = new NetworkMetrics(netId, transports, mConnectTb);
mNetworkMetrics.put(netId, metrics);
}
return metrics;
}
private NetworkMetricsSnapshot[] getNetworkMetricsSnapshots() {
- collectPendingMetricsSnapshot(System.currentTimeMillis());
+ collectPendingMetricsSnapshot(System.currentTimeMillis(), false /* forceCollect */);
return mNetworkMetricsSnapshots.toArray();
}
- private void collectPendingMetricsSnapshot(long timeMs) {
+ private void collectPendingMetricsSnapshot(long timeMs, boolean forceCollect) {
// Detects time differences larger than the snapshot collection period.
// This is robust against clock jumps and long inactivity periods.
- if (Math.abs(timeMs - mLastSnapshot) <= METRICS_SNAPSHOT_SPAN_MS) {
+ if (!forceCollect && Math.abs(timeMs - mLastSnapshot) <= METRICS_SNAPSHOT_SPAN_MS) {
return;
}
mLastSnapshot = projectSnapshotTime(timeMs);
@@ -394,14 +397,6 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
return list;
}
- private long getTransports(int netId) {
- final NetworkCapabilities nc = mCallback.getNetworkCapabilities(netId);
- if (nc == null) {
- return 0;
- }
- return BitUtils.packBits(nc.getTransportTypes());
- }
-
/** Helper class for buffering summaries of NetworkMetrics at regular time intervals */
static class NetworkMetricsSnapshot {
diff --git a/services/core/java/com/android/server/connectivity/OWNERS b/services/core/java/com/android/server/connectivity/OWNERS
index 7311eee32a4c..62c5737a2e8e 100644
--- a/services/core/java/com/android/server/connectivity/OWNERS
+++ b/services/core/java/com/android/server/connectivity/OWNERS
@@ -1,8 +1,2 @@
set noparent
-
-codewiz@google.com
-ek@google.com
-jchalard@google.com
-lorenzo@google.com
-reminv@google.com
-satk@google.com
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
diff --git a/services/core/java/com/android/server/health/HealthHalCallbackHidl.java b/services/core/java/com/android/server/health/HealthHalCallbackHidl.java
new file mode 100644
index 000000000000..7a6698085c0d
--- /dev/null
+++ b/services/core/java/com/android/server/health/HealthHalCallbackHidl.java
@@ -0,0 +1,117 @@
+/*
+ * 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.health;
+
+import static android.hardware.health.Translate.h2aTranslate;
+
+import android.annotation.NonNull;
+import android.hardware.health.V2_0.IHealth;
+import android.hardware.health.V2_0.Result;
+import android.hardware.health.V2_1.BatteryCapacityLevel;
+import android.hardware.health.V2_1.Constants;
+import android.hardware.health.V2_1.IHealthInfoCallback;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.util.Slog;
+
+/**
+ * On service registration, {@link HealthServiceWrapperHidl.Callback#onRegistration} is called,
+ * which registers {@code this}, a {@link IHealthInfoCallback}, to the health service.
+ *
+ * <p>When the health service has updates to health info, {@link HealthInfoCallback#update} is
+ * called.
+ *
+ * @hide
+ */
+class HealthHalCallbackHidl extends IHealthInfoCallback.Stub
+ implements HealthServiceWrapperHidl.Callback {
+
+ private static final String TAG = HealthHalCallbackHidl.class.getSimpleName();
+
+ private static void traceBegin(String name) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
+ }
+
+ private static void traceEnd() {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+
+ private HealthInfoCallback mCallback;
+
+ HealthHalCallbackHidl(@NonNull HealthInfoCallback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void healthInfoChanged(android.hardware.health.V2_0.HealthInfo props) {
+ android.hardware.health.V2_1.HealthInfo propsLatest =
+ new android.hardware.health.V2_1.HealthInfo();
+ propsLatest.legacy = props;
+
+ propsLatest.batteryCapacityLevel = BatteryCapacityLevel.UNSUPPORTED;
+ propsLatest.batteryChargeTimeToFullNowSeconds =
+ Constants.BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED;
+
+ mCallback.update(h2aTranslate(propsLatest));
+ }
+
+ @Override
+ public void healthInfoChanged_2_1(android.hardware.health.V2_1.HealthInfo props) {
+ mCallback.update(h2aTranslate(props));
+ }
+
+ // on new service registered
+ @Override
+ public void onRegistration(IHealth oldService, IHealth newService, String instance) {
+ if (newService == null) return;
+
+ traceBegin("HealthUnregisterCallback");
+ try {
+ if (oldService != null) {
+ int r = oldService.unregisterCallback(this);
+ if (r != Result.SUCCESS) {
+ Slog.w(
+ TAG,
+ "health: cannot unregister previous callback: " + Result.toString(r));
+ }
+ }
+ } catch (RemoteException ex) {
+ Slog.w(
+ TAG,
+ "health: cannot unregister previous callback (transaction error): "
+ + ex.getMessage());
+ } finally {
+ traceEnd();
+ }
+
+ traceBegin("HealthRegisterCallback");
+ try {
+ int r = newService.registerCallback(this);
+ if (r != Result.SUCCESS) {
+ Slog.w(TAG, "health: cannot register callback: " + Result.toString(r));
+ return;
+ }
+ // registerCallback does NOT guarantee that update is called
+ // immediately, so request a manual update here.
+ newService.update();
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "health: cannot register callback (transaction error): " + ex.getMessage());
+ } finally {
+ traceEnd();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/health/HealthInfoCallback.java b/services/core/java/com/android/server/health/HealthInfoCallback.java
new file mode 100644
index 000000000000..c2a77fc862fa
--- /dev/null
+++ b/services/core/java/com/android/server/health/HealthInfoCallback.java
@@ -0,0 +1,31 @@
+/*
+ * 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.health;
+
+/**
+ * A wrapper over HIDL / AIDL IHealthInfoCallback.
+ *
+ * @hide
+ */
+public interface HealthInfoCallback {
+ /**
+ * Signals to the client that health info is changed.
+ *
+ * @param props the new health info.
+ */
+ void update(android.hardware.health.HealthInfo props);
+}
diff --git a/services/core/java/com/android/server/health/HealthRegCallbackAidl.java b/services/core/java/com/android/server/health/HealthRegCallbackAidl.java
new file mode 100644
index 000000000000..629011a86bb4
--- /dev/null
+++ b/services/core/java/com/android/server/health/HealthRegCallbackAidl.java
@@ -0,0 +1,119 @@
+/*
+ * 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.health;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.health.HealthInfo;
+import android.hardware.health.IHealth;
+import android.hardware.health.IHealthInfoCallback;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * On service registration, {@link #onRegistration} is called, which registers {@code this}, an
+ * {@link IHealthInfoCallback}, to the health service.
+ *
+ * <p>When the health service has updates to health info via {@link IHealthInfoCallback}, {@link
+ * HealthInfoCallback#update} is called.
+ *
+ * <p>AIDL variant of {@link HealthHalCallbackHidl}.
+ *
+ * @hide
+ */
+// It is made public so Mockito can access this class. It should have been package private if not
+// for testing.
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+public class HealthRegCallbackAidl {
+ private static final String TAG = "HealthRegCallbackAidl";
+ private final HealthInfoCallback mServiceInfoCallback;
+ private final IHealthInfoCallback mHalInfoCallback = new HalInfoCallback();
+
+ HealthRegCallbackAidl(@Nullable HealthInfoCallback healthInfoCallback) {
+ mServiceInfoCallback = healthInfoCallback;
+ }
+
+ /**
+ * Called when the service manager sees {@code newService} replacing {@code oldService}.
+ * This unregisters the health info callback from the old service (ignoring errors), then
+ * registers the health info callback to the new service.
+ *
+ * @param oldService the old IHealth service
+ * @param newService the new IHealth service
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public void onRegistration(@Nullable IHealth oldService, @NonNull IHealth newService) {
+ if (mServiceInfoCallback == null) return;
+
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "HealthUnregisterCallbackAidl");
+ try {
+ unregisterCallback(oldService, mHalInfoCallback);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "HealthRegisterCallbackAidl");
+ try {
+ registerCallback(newService, mHalInfoCallback);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+ }
+
+ private static void unregisterCallback(@Nullable IHealth oldService, IHealthInfoCallback cb) {
+ if (oldService == null) return;
+ try {
+ oldService.unregisterCallback(cb);
+ } catch (RemoteException e) {
+ // Ignore errors. The service might have died.
+ Slog.w(
+ TAG,
+ "health: cannot unregister previous callback (transaction error): "
+ + e.getMessage());
+ }
+ }
+
+ private static void registerCallback(@NonNull IHealth newService, IHealthInfoCallback cb) {
+ try {
+ newService.registerCallback(cb);
+ } catch (RemoteException e) {
+ Slog.e(
+ TAG,
+ "health: cannot register callback, framework may cease to"
+ + " receive updates on health / battery info!",
+ e);
+ return;
+ }
+ // registerCallback does NOT guarantee that update is called immediately, so request a
+ // manual update here.
+ try {
+ newService.update();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "health: cannot update after registering health info callback", e);
+ }
+ }
+
+ private class HalInfoCallback extends IHealthInfoCallback.Stub {
+ @Override
+ public void healthInfoChanged(HealthInfo healthInfo) throws RemoteException {
+ mServiceInfoCallback.update(healthInfo);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/health/HealthServiceWrapper.java b/services/core/java/com/android/server/health/HealthServiceWrapper.java
new file mode 100644
index 000000000000..25d1a885bc18
--- /dev/null
+++ b/services/core/java/com/android/server/health/HealthServiceWrapper.java
@@ -0,0 +1,119 @@
+/*
+ * 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.health;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.BatteryProperty;
+import android.os.HandlerThread;
+import android.os.IBatteryPropertiesRegistrar;
+import android.os.RemoteException;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.NoSuchElementException;
+
+/**
+ * HealthServiceWrapper wraps the internal IHealth service and refreshes the service when necessary.
+ * This is essentially a wrapper over IHealth that is useful for BatteryService.
+ *
+ * <p>The implementation may be backed by a HIDL or AIDL HAL.
+ *
+ * <p>On new registration of IHealth service, the internal service is refreshed. On death of an
+ * existing IHealth service, the internal service is NOT cleared to avoid race condition between
+ * death notification and new service notification. Hence, a caller must check for transaction
+ * errors when calling into the service.
+ *
+ * @hide Should only be used internally.
+ */
+public abstract class HealthServiceWrapper {
+ /** @return the handler thread. Exposed for testing. */
+ @VisibleForTesting
+ abstract HandlerThread getHandlerThread();
+
+ /**
+ * Calls into get*() functions in the health HAL. This reads into the kernel interfaces
+ * directly.
+ *
+ * @see IBatteryPropertiesRegistrar#getProperty
+ */
+ public abstract int getProperty(int id, BatteryProperty prop) throws RemoteException;
+
+ /**
+ * Calls update() in the health HAL.
+ *
+ * @see IBatteryPropertiesRegistrar#scheduleUpdate
+ */
+ public abstract void scheduleUpdate() throws RemoteException;
+
+ /**
+ * Calls into getHealthInfo() in the health HAL. This returns a cached value in the health HAL
+ * implementation.
+ *
+ * @return health info. {@code null} if no health HAL service. {@code null} if any
+ * service-specific error when calling {@code getHealthInfo}, e.g. it is unsupported.
+ * @throws RemoteException for any transaction-level errors
+ */
+ public abstract android.hardware.health.HealthInfo getHealthInfo() throws RemoteException;
+
+ /**
+ * Create a new HealthServiceWrapper instance.
+ *
+ * @param healthInfoCallback the callback to call when health info changes
+ * @return the new HealthServiceWrapper instance, which may be backed by HIDL or AIDL service.
+ * @throws RemoteException transaction errors
+ * @throws NoSuchElementException no HIDL or AIDL service is available
+ */
+ public static HealthServiceWrapper create(@Nullable HealthInfoCallback healthInfoCallback)
+ throws RemoteException, NoSuchElementException {
+ return create(
+ healthInfoCallback == null ? null : new HealthRegCallbackAidl(healthInfoCallback),
+ new HealthServiceWrapperAidl.ServiceManagerStub() {},
+ healthInfoCallback == null ? null : new HealthHalCallbackHidl(healthInfoCallback),
+ new HealthServiceWrapperHidl.IServiceManagerSupplier() {},
+ new HealthServiceWrapperHidl.IHealthSupplier() {});
+ }
+
+ /**
+ * Create a new HealthServiceWrapper instance for testing.
+ *
+ * @param aidlRegCallback callback for AIDL service registration, or {@code null} if the client
+ * does not care about AIDL service registration notifications
+ * @param aidlServiceManager Stub for AIDL ServiceManager
+ * @param hidlRegCallback callback for HIDL service registration, or {@code null} if the client
+ * does not care about HIDL service registration notifications
+ * @param hidlServiceManagerSupplier supplier of HIDL service manager
+ * @param hidlHealthSupplier supplier of HIDL health HAL
+ * @return the new HealthServiceWrapper instance, which may be backed by HIDL or AIDL service.
+ */
+ @VisibleForTesting
+ static @NonNull HealthServiceWrapper create(
+ @Nullable HealthRegCallbackAidl aidlRegCallback,
+ @NonNull HealthServiceWrapperAidl.ServiceManagerStub aidlServiceManager,
+ @Nullable HealthServiceWrapperHidl.Callback hidlRegCallback,
+ @NonNull HealthServiceWrapperHidl.IServiceManagerSupplier hidlServiceManagerSupplier,
+ @NonNull HealthServiceWrapperHidl.IHealthSupplier hidlHealthSupplier)
+ throws RemoteException, NoSuchElementException {
+ try {
+ return new HealthServiceWrapperAidl(aidlRegCallback, aidlServiceManager);
+ } catch (NoSuchElementException e) {
+ // Ignore, try HIDL
+ }
+ return new HealthServiceWrapperHidl(
+ hidlRegCallback, hidlServiceManagerSupplier, hidlHealthSupplier);
+ }
+}
diff --git a/services/core/java/com/android/server/health/HealthServiceWrapperAidl.java b/services/core/java/com/android/server/health/HealthServiceWrapperAidl.java
new file mode 100644
index 000000000000..4f2ed68974fa
--- /dev/null
+++ b/services/core/java/com/android/server/health/HealthServiceWrapperAidl.java
@@ -0,0 +1,215 @@
+/*
+ * 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.health;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.health.HealthInfo;
+import android.hardware.health.IHealth;
+import android.os.BatteryManager;
+import android.os.BatteryProperty;
+import android.os.Binder;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.IServiceCallback;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
+import android.os.Trace;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Implement {@link HealthServiceWrapper} backed by the AIDL HAL.
+ *
+ * @hide
+ */
+class HealthServiceWrapperAidl extends HealthServiceWrapper {
+ private static final String TAG = "HealthServiceWrapperAidl";
+ @VisibleForTesting static final String SERVICE_NAME = IHealth.DESCRIPTOR + "/default";
+ private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceBinder");
+ private final AtomicReference<IHealth> mLastService = new AtomicReference<>();
+ private final IServiceCallback mServiceCallback = new ServiceCallback();
+ private final HealthRegCallbackAidl mRegCallback;
+
+ /** Stub interface into {@link ServiceManager} for testing. */
+ interface ServiceManagerStub {
+ default @Nullable IHealth waitForDeclaredService(@NonNull String name) {
+ return IHealth.Stub.asInterface(ServiceManager.waitForDeclaredService(name));
+ }
+
+ default void registerForNotifications(
+ @NonNull String name, @NonNull IServiceCallback callback) throws RemoteException {
+ ServiceManager.registerForNotifications(name, callback);
+ }
+ }
+
+ HealthServiceWrapperAidl(
+ @Nullable HealthRegCallbackAidl regCallback, @NonNull ServiceManagerStub serviceManager)
+ throws RemoteException, NoSuchElementException {
+
+ traceBegin("HealthInitGetServiceAidl");
+ IHealth newService;
+ try {
+ newService = serviceManager.waitForDeclaredService(SERVICE_NAME);
+ } finally {
+ traceEnd();
+ }
+ if (newService == null) {
+ throw new NoSuchElementException(
+ "IHealth service instance isn't available. Perhaps no permission?");
+ }
+ mLastService.set(newService);
+ mRegCallback = regCallback;
+ if (mRegCallback != null) {
+ mRegCallback.onRegistration(null /* oldService */, newService);
+ }
+
+ traceBegin("HealthInitRegisterNotificationAidl");
+ mHandlerThread.start();
+ try {
+ serviceManager.registerForNotifications(SERVICE_NAME, mServiceCallback);
+ } finally {
+ traceEnd();
+ }
+ Slog.i(TAG, "health: HealthServiceWrapper listening to AIDL HAL");
+ }
+
+ @Override
+ @VisibleForTesting
+ public HandlerThread getHandlerThread() {
+ return mHandlerThread;
+ }
+
+ @Override
+ public int getProperty(int id, BatteryProperty prop) throws RemoteException {
+ traceBegin("HealthGetPropertyAidl");
+ try {
+ return getPropertyInternal(id, prop);
+ } finally {
+ traceEnd();
+ }
+ }
+
+ private int getPropertyInternal(int id, BatteryProperty prop) throws RemoteException {
+ IHealth service = mLastService.get();
+ if (service == null) throw new RemoteException("no health service");
+ try {
+ switch (id) {
+ case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
+ prop.setLong(service.getChargeCounterUah());
+ break;
+ case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
+ prop.setLong(service.getCurrentNowMicroamps());
+ break;
+ case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:
+ prop.setLong(service.getCurrentAverageMicroamps());
+ break;
+ case BatteryManager.BATTERY_PROPERTY_CAPACITY:
+ prop.setLong(service.getCapacity());
+ break;
+ case BatteryManager.BATTERY_PROPERTY_STATUS:
+ prop.setLong(service.getChargeStatus());
+ break;
+ case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
+ prop.setLong(service.getEnergyCounterNwh());
+ break;
+ }
+ } catch (UnsupportedOperationException e) {
+ // Leave prop untouched.
+ return -1;
+ } catch (ServiceSpecificException e) {
+ // Leave prop untouched.
+ return -2;
+ }
+ // throws RemoteException as-is. BatteryManager wraps it into a RuntimeException
+ // and throw it to apps.
+
+ // If no error, return 0.
+ return 0;
+ }
+
+ @Override
+ public void scheduleUpdate() throws RemoteException {
+ getHandlerThread()
+ .getThreadHandler()
+ .post(
+ () -> {
+ traceBegin("HealthScheduleUpdate");
+ try {
+ IHealth service = mLastService.get();
+ if (service == null) {
+ Slog.e(TAG, "no health service");
+ return;
+ }
+ service.update();
+ } catch (RemoteException | ServiceSpecificException ex) {
+ Slog.e(TAG, "Cannot call update on health AIDL HAL", ex);
+ } finally {
+ traceEnd();
+ }
+ });
+ }
+
+ @Override
+ public HealthInfo getHealthInfo() throws RemoteException {
+ IHealth service = mLastService.get();
+ if (service == null) return null;
+ try {
+ return service.getHealthInfo();
+ } catch (UnsupportedOperationException | ServiceSpecificException ex) {
+ return null;
+ }
+ }
+
+ private static void traceBegin(String name) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
+ }
+
+ private static void traceEnd() {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+
+ private class ServiceCallback extends IServiceCallback.Stub {
+ @Override
+ public void onRegistration(String name, @NonNull final IBinder newBinder)
+ throws RemoteException {
+ if (!SERVICE_NAME.equals(name)) return;
+ // This runnable only runs on mHandlerThread and ordering is ensured, hence
+ // no locking is needed inside the runnable.
+ getHandlerThread()
+ .getThreadHandler()
+ .post(
+ () -> {
+ IHealth newService =
+ IHealth.Stub.asInterface(Binder.allowBlocking(newBinder));
+ IHealth oldService = mLastService.getAndSet(newService);
+ IBinder oldBinder =
+ oldService != null ? oldService.asBinder() : null;
+ if (Objects.equals(newBinder, oldBinder)) return;
+
+ Slog.i(TAG, "New health AIDL HAL service registered");
+ mRegCallback.onRegistration(oldService, newService);
+ });
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/health/HealthServiceWrapperHidl.java b/services/core/java/com/android/server/health/HealthServiceWrapperHidl.java
new file mode 100644
index 000000000000..0301174a45c6
--- /dev/null
+++ b/services/core/java/com/android/server/health/HealthServiceWrapperHidl.java
@@ -0,0 +1,313 @@
+/*
+ * 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.health;
+
+import static android.hardware.health.Translate.h2aTranslate;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.health.HealthInfo;
+import android.hardware.health.V2_0.IHealth;
+import android.hardware.health.V2_0.Result;
+import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
+import android.os.BatteryManager;
+import android.os.BatteryProperty;
+import android.os.HandlerThread;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.util.MutableInt;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Implement {@link HealthServiceWrapper} backed by the HIDL HAL.
+ *
+ * @hide
+ */
+final class HealthServiceWrapperHidl extends HealthServiceWrapper {
+ private static final String TAG = "HealthServiceWrapperHidl";
+ public static final String INSTANCE_VENDOR = "default";
+
+ private final IServiceNotification mNotification = new Notification();
+ private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceHwbinder");
+ // These variables are fixed after init.
+ private Callback mCallback;
+ private IHealthSupplier mHealthSupplier;
+ private String mInstanceName;
+
+ // Last IHealth service received.
+ private final AtomicReference<IHealth> mLastService = new AtomicReference<>();
+
+ private static void traceBegin(String name) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
+ }
+
+ private static void traceEnd() {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+
+ @Override
+ public int getProperty(int id, final BatteryProperty prop) throws RemoteException {
+ traceBegin("HealthGetProperty");
+ try {
+ IHealth service = mLastService.get();
+ if (service == null) throw new RemoteException("no health service");
+ final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED);
+ switch (id) {
+ case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
+ service.getChargeCounter(
+ (int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
+ service.getCurrentNow(
+ (int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:
+ service.getCurrentAverage(
+ (int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_CAPACITY:
+ service.getCapacity(
+ (int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_STATUS:
+ service.getChargeStatus(
+ (int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
+ service.getEnergyCounter(
+ (int result, long value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ }
+ return outResult.value;
+ } finally {
+ traceEnd();
+ }
+ }
+
+ @Override
+ public void scheduleUpdate() throws RemoteException {
+ getHandlerThread()
+ .getThreadHandler()
+ .post(
+ () -> {
+ traceBegin("HealthScheduleUpdate");
+ try {
+ IHealth service = mLastService.get();
+ if (service == null) {
+ Slog.e(TAG, "no health service");
+ return;
+ }
+ service.update();
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Cannot call update on health HAL", ex);
+ } finally {
+ traceEnd();
+ }
+ });
+ }
+
+ private static class Mutable<T> {
+ public T value;
+ }
+
+ @Override
+ public HealthInfo getHealthInfo() throws RemoteException {
+ IHealth service = mLastService.get();
+ if (service == null) return null;
+ final Mutable<HealthInfo> ret = new Mutable<>();
+ service.getHealthInfo(
+ (result, value) -> {
+ if (result == Result.SUCCESS) {
+ ret.value = h2aTranslate(value.legacy);
+ }
+ });
+ return ret.value;
+ }
+
+ /**
+ * Start monitoring registration of new IHealth services. Only instance {@link #INSTANCE_VENDOR}
+ * and in device / framework manifest are used. This function should only be called once.
+ *
+ * <p>mCallback.onRegistration() is called synchronously (aka in init thread) before this method
+ * returns if callback is not null.
+ *
+ * @throws RemoteException transaction error when talking to IServiceManager
+ * @throws NoSuchElementException if one of the following cases: - No service manager; - {@link
+ * #INSTANCE_VENDOR} is not in manifests (i.e. not available on this device), or none of
+ * these instances are available to current process.
+ * @throws NullPointerException when supplier is null
+ */
+ @VisibleForTesting
+ HealthServiceWrapperHidl(
+ @Nullable Callback callback,
+ @NonNull IServiceManagerSupplier managerSupplier,
+ @NonNull IHealthSupplier healthSupplier)
+ throws RemoteException, NoSuchElementException, NullPointerException {
+ if (managerSupplier == null || healthSupplier == null) {
+ throw new NullPointerException();
+ }
+ mHealthSupplier = healthSupplier;
+
+ // Initialize mLastService and call callback for the first time (in init thread)
+ IHealth newService = null;
+ traceBegin("HealthInitGetService_" + INSTANCE_VENDOR);
+ try {
+ newService = healthSupplier.get(INSTANCE_VENDOR);
+ } catch (NoSuchElementException ex) {
+ /* ignored, handled below */
+ } finally {
+ traceEnd();
+ }
+ if (newService != null) {
+ mInstanceName = INSTANCE_VENDOR;
+ mLastService.set(newService);
+ }
+
+ if (mInstanceName == null || newService == null) {
+ throw new NoSuchElementException(
+ String.format(
+ "IHealth service instance %s isn't available. Perhaps no permission?",
+ INSTANCE_VENDOR));
+ }
+
+ if (callback != null) {
+ mCallback = callback;
+ mCallback.onRegistration(null, newService, mInstanceName);
+ }
+
+ // Register for future service registrations
+ traceBegin("HealthInitRegisterNotification");
+ mHandlerThread.start();
+ try {
+ managerSupplier
+ .get()
+ .registerForNotifications(IHealth.kInterfaceName, mInstanceName, mNotification);
+ } finally {
+ traceEnd();
+ }
+ Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + mInstanceName);
+ }
+
+ @VisibleForTesting
+ public HandlerThread getHandlerThread() {
+ return mHandlerThread;
+ }
+
+ /** Service registration callback. */
+ interface Callback {
+ /**
+ * This function is invoked asynchronously when a new and related IServiceNotification is
+ * received.
+ *
+ * @param service the recently retrieved service from IServiceManager. Can be a dead service
+ * before service notification of a new service is delivered. Implementation must handle
+ * cases for {@link RemoteException}s when calling into service.
+ * @param instance instance name.
+ */
+ void onRegistration(IHealth oldService, IHealth newService, String instance);
+ }
+
+ /**
+ * Supplier of services. Must not return null; throw {@link NoSuchElementException} if a service
+ * is not available.
+ */
+ interface IServiceManagerSupplier {
+ default IServiceManager get() throws NoSuchElementException, RemoteException {
+ return IServiceManager.getService();
+ }
+ }
+
+ /**
+ * Supplier of services. Must not return null; throw {@link NoSuchElementException} if a service
+ * is not available.
+ */
+ interface IHealthSupplier {
+ default IHealth get(String name) throws NoSuchElementException, RemoteException {
+ return IHealth.getService(name, true /* retry */);
+ }
+ }
+
+ private class Notification extends IServiceNotification.Stub {
+ @Override
+ public final void onRegistration(
+ String interfaceName, String instanceName, boolean preexisting) {
+ if (!IHealth.kInterfaceName.equals(interfaceName)) return;
+ if (!mInstanceName.equals(instanceName)) return;
+
+ // This runnable only runs on mHandlerThread and ordering is ensured, hence
+ // no locking is needed inside the runnable.
+ mHandlerThread
+ .getThreadHandler()
+ .post(
+ new Runnable() {
+ @Override
+ public void run() {
+ try {
+ IHealth newService = mHealthSupplier.get(mInstanceName);
+ IHealth oldService = mLastService.getAndSet(newService);
+
+ // preexisting may be inaccurate (race). Check for equality
+ // here.
+ if (Objects.equals(newService, oldService)) return;
+
+ Slog.i(
+ TAG,
+ "health: new instance registered " + mInstanceName);
+ // #init() may be called with null callback. Skip null
+ // callbacks.
+ if (mCallback == null) return;
+ mCallback.onRegistration(
+ oldService, newService, mInstanceName);
+ } catch (NoSuchElementException | RemoteException ex) {
+ Slog.e(
+ TAG,
+ "health: Cannot get instance '"
+ + mInstanceName
+ + "': "
+ + ex.getMessage()
+ + ". Perhaps no permission?");
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/health/Utils.java b/services/core/java/com/android/server/health/Utils.java
new file mode 100644
index 000000000000..a8c978c50e42
--- /dev/null
+++ b/services/core/java/com/android/server/health/Utils.java
@@ -0,0 +1,85 @@
+/*
+ * 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.health;
+
+/**
+ * Utils for {@link om.android.server.BatteryService} to deal with health info structs.
+ *
+ * @hide
+ */
+public class Utils {
+ private Utils() {}
+
+ /**
+ * Copy health info struct.
+ *
+ * @param dst destination
+ * @param src source
+ */
+ public static void copy(
+ android.hardware.health.V1_0.HealthInfo dst,
+ android.hardware.health.V1_0.HealthInfo src) {
+ dst.chargerAcOnline = src.chargerAcOnline;
+ dst.chargerUsbOnline = src.chargerUsbOnline;
+ dst.chargerWirelessOnline = src.chargerWirelessOnline;
+ dst.maxChargingCurrent = src.maxChargingCurrent;
+ dst.maxChargingVoltage = src.maxChargingVoltage;
+ dst.batteryStatus = src.batteryStatus;
+ dst.batteryHealth = src.batteryHealth;
+ dst.batteryPresent = src.batteryPresent;
+ dst.batteryLevel = src.batteryLevel;
+ dst.batteryVoltage = src.batteryVoltage;
+ dst.batteryTemperature = src.batteryTemperature;
+ dst.batteryCurrent = src.batteryCurrent;
+ dst.batteryCycleCount = src.batteryCycleCount;
+ dst.batteryFullCharge = src.batteryFullCharge;
+ dst.batteryChargeCounter = src.batteryChargeCounter;
+ dst.batteryTechnology = src.batteryTechnology;
+ }
+
+ /**
+ * Copy battery fields of {@link android.hardware.health.HealthInfo} V1. This excludes
+ * non-battery fields like {@link android.hardware.health.HealthInfo#diskStats diskStats} and
+ * {@link android.hardware.health.HealthInfo#storageInfos storageInfos}
+ *
+ * @param dst destination
+ * @param src source
+ */
+ public static void copyV1Battery(
+ android.hardware.health.HealthInfo dst, android.hardware.health.HealthInfo src) {
+ dst.chargerAcOnline = src.chargerAcOnline;
+ dst.chargerUsbOnline = src.chargerUsbOnline;
+ dst.chargerWirelessOnline = src.chargerWirelessOnline;
+ dst.maxChargingCurrentMicroamps = src.maxChargingCurrentMicroamps;
+ dst.maxChargingVoltageMicrovolts = src.maxChargingVoltageMicrovolts;
+ dst.batteryStatus = src.batteryStatus;
+ dst.batteryHealth = src.batteryHealth;
+ dst.batteryPresent = src.batteryPresent;
+ dst.batteryLevel = src.batteryLevel;
+ dst.batteryVoltageMillivolts = src.batteryVoltageMillivolts;
+ dst.batteryTemperatureTenthsCelsius = src.batteryTemperatureTenthsCelsius;
+ dst.batteryCurrentMicroamps = src.batteryCurrentMicroamps;
+ dst.batteryCycleCount = src.batteryCycleCount;
+ dst.batteryFullChargeUah = src.batteryFullChargeUah;
+ dst.batteryChargeCounterUah = src.batteryChargeCounterUah;
+ dst.batteryTechnology = src.batteryTechnology;
+ dst.batteryCurrentAverageMicroamps = src.batteryCurrentAverageMicroamps;
+ dst.batteryCapacityLevel = src.batteryCapacityLevel;
+ dst.batteryChargeTimeToFullNowSeconds = src.batteryChargeTimeToFullNowSeconds;
+ dst.batteryFullChargeDesignCapacityUah = src.batteryFullChargeDesignCapacityUah;
+ }
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index dc955337fdbc..3e52f5e07e62 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2582,14 +2582,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
if (mCurToken != null) {
- try {
- if (DEBUG) {
- Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
- + mCurTokenDisplayId);
- }
- mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
- } catch (RemoteException e) {
+ if (DEBUG) {
+ Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
+ + mCurTokenDisplayId);
}
+ mWindowManagerInternal.removeWindowToken(mCurToken, false /* removeWindows */,
+ false /* animateExit */, mCurTokenDisplayId);
// Set IME window status as invisible when unbind current method.
mImeWindowVis = 0;
mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index 73de0f814325..ffc1aed4c672 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -51,6 +51,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
class BluetoothRouteProvider {
private static final String TAG = "BTRouteProvider";
@@ -174,8 +175,9 @@ class BluetoothRouteProvider {
private void buildBluetoothRoutes() {
mBluetoothRoutes.clear();
- if (mBluetoothAdapter.getBondedDevices() != null) {
- for (BluetoothDevice device : mBluetoothAdapter.getBondedDevices()) {
+ Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices();
+ if (bondedDevices != null) {
+ for (BluetoothDevice device : bondedDevices) {
if (device.isConnected()) {
BluetoothRouteInfo newBtRoute = createBluetoothRoute(device);
if (newBtRoute.connectedProfiles.size() > 0) {
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index df1eb6d9fe3c..d17dbde496ce 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -322,8 +322,11 @@ public class IpConfigStore {
gateway = InetAddresses.parseNumericAddress(in.readUTF());
}
// If the destination is a default IPv4 route, use the gateway
- // address unless already set.
- if (dest.getAddress() instanceof Inet4Address
+ // address unless already set. If there is no destination, assume
+ // it is default route and use the gateway address in all cases.
+ if (dest == null) {
+ gatewayAddress = gateway;
+ } else if (dest.getAddress() instanceof Inet4Address
&& dest.getPrefixLength() == 0 && gatewayAddress == null) {
gatewayAddress = gateway;
} else {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index 654b17fb9754..81106b1a5ca7 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -39,6 +39,7 @@ import android.util.Slog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.RingBuffer;
import com.android.server.am.ProcessList;
+import com.android.server.net.NetworkPolicyManagerService.UidBlockedState;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@@ -72,16 +73,6 @@ public class NetworkPolicyLogger {
private static final int EVENT_UPDATE_METERED_RESTRICTED_PKGS = 13;
private static final int EVENT_APP_IDLE_WL_CHANGED = 14;
- static final int NTWK_BLOCKED_POWER = 0;
- static final int NTWK_ALLOWED_NON_METERED = 1;
- static final int NTWK_BLOCKED_DENYLIST = 2;
- static final int NTWK_ALLOWED_ALLOWLIST = 3;
- static final int NTWK_ALLOWED_TMP_ALLOWLIST = 4;
- static final int NTWK_BLOCKED_BG_RESTRICT = 5;
- static final int NTWK_ALLOWED_DEFAULT = 6;
- static final int NTWK_ALLOWED_SYSTEM = 7;
- static final int NTWK_BLOCKED_RESTRICTED_MODE = 8;
-
private final LogBuffer mNetworkBlockedBuffer = new LogBuffer(MAX_NETWORK_BLOCKED_LOG_SIZE);
private final LogBuffer mUidStateChangeBuffer = new LogBuffer(MAX_LOG_SIZE);
private final LogBuffer mEventsBuffer = new LogBuffer(MAX_LOG_SIZE);
@@ -90,12 +81,13 @@ public class NetworkPolicyLogger {
private final Object mLock = new Object();
- void networkBlocked(int uid, int reason) {
+ void networkBlocked(int uid, UidBlockedState uidBlockedState) {
synchronized (mLock) {
if (LOGD || uid == mDebugUid) {
- Slog.d(TAG, uid + " is " + getBlockedReason(reason));
+ Slog.d(TAG, "Blocked state of uid: " + uidBlockedState.toString());
}
- mNetworkBlockedBuffer.networkBlocked(uid, reason);
+ mNetworkBlockedBuffer.networkBlocked(uid, uidBlockedState.blockedReasons,
+ uidBlockedState.allowedReasons, uidBlockedState.effectiveBlockedReasons);
}
}
@@ -269,29 +261,6 @@ public class NetworkPolicyLogger {
}
}
- private static String getBlockedReason(int reason) {
- switch (reason) {
- case NTWK_BLOCKED_POWER:
- return "blocked by power restrictions";
- case NTWK_ALLOWED_NON_METERED:
- return "allowed on unmetered network";
- case NTWK_BLOCKED_DENYLIST:
- return "denylisted on metered network";
- case NTWK_ALLOWED_ALLOWLIST:
- return "allowlisted on metered network";
- case NTWK_ALLOWED_TMP_ALLOWLIST:
- return "temporary allowlisted on metered network";
- case NTWK_BLOCKED_BG_RESTRICT:
- return "blocked when background is restricted";
- case NTWK_ALLOWED_DEFAULT:
- return "allowed by default";
- case NTWK_BLOCKED_RESTRICTED_MODE:
- return "blocked by restricted networking mode";
- default:
- return String.valueOf(reason);
- }
- }
-
private static String getPolicyChangedLog(int uid, int oldPolicy, int newPolicy) {
return "Policy for " + uid + " changed from "
+ NetworkPolicyManager.uidPoliciesToString(oldPolicy) + " to "
@@ -402,14 +371,17 @@ public class NetworkPolicyLogger {
data.timeStamp = System.currentTimeMillis();
}
- public void networkBlocked(int uid, int reason) {
+ public void networkBlocked(int uid, int blockedReasons, int allowedReasons,
+ int effectiveBlockedReasons) {
final Data data = getNextSlot();
if (data == null) return;
data.reset();
data.type = EVENT_NETWORK_BLOCKED;
data.ifield1 = uid;
- data.ifield2 = reason;
+ data.ifield2 = blockedReasons;
+ data.ifield3 = allowedReasons;
+ data.ifield4 = effectiveBlockedReasons;
data.timeStamp = System.currentTimeMillis();
}
@@ -554,7 +526,8 @@ public class NetworkPolicyLogger {
case EVENT_TYPE_GENERIC:
return data.sfield1;
case EVENT_NETWORK_BLOCKED:
- return data.ifield1 + "-" + getBlockedReason(data.ifield2);
+ return data.ifield1 + "-" + UidBlockedState.toString(
+ data.ifield2, data.ifield3, data.ifield4);
case EVENT_UID_STATE_CHANGED:
return data.ifield1 + ":" + ProcessList.makeProcStateString(data.ifield2)
+ ":" + ActivityManager.getCapabilitiesSummary(data.ifield3)
@@ -593,17 +566,24 @@ public class NetworkPolicyLogger {
}
}
- public final static class Data {
- int type;
- long timeStamp;
-
- int ifield1;
- int ifield2;
- int ifield3;
- long lfield1;
- boolean bfield1;
- boolean bfield2;
- String sfield1;
+ /**
+ * Container class for all networkpolicy events data.
+ *
+ * Note: This class needs to be public for RingBuffer class to be able to create
+ * new instances of this.
+ */
+ public static final class Data {
+ public int type;
+ public long timeStamp;
+
+ public int ifield1;
+ public int ifield2;
+ public int ifield3;
+ public int ifield4;
+ public long lfield1;
+ public boolean bfield1;
+ public boolean bfield2;
+ public String sfield1;
public void reset(){
sfield1 = null;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 20687c6764db..5de5fd3cc79c 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -79,14 +79,10 @@ import static android.net.NetworkPolicyManager.ALLOWED_REASON_RESTRICTED_MODE_PE
import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM;
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
-import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
-import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS;
-import static android.net.NetworkPolicyManager.MASK_RESTRICTED_MODE_NETWORKS;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
-import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
@@ -135,15 +131,6 @@ import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute;
import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_ALLOWLIST;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_DEFAULT;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_NON_METERED;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_SYSTEM;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_TMP_ALLOWLIST;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_BG_RESTRICT;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_DENYLIST;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_POWER;
-import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_RESTRICTED_MODE;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -518,8 +505,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
/** Defined UID policies. */
@GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidPolicy = new SparseIntArray();
- /** Currently derived rules for each UID. */
- @GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidRules = new SparseIntArray();
@GuardedBy("mUidRulesFirstLock")
final SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
@@ -598,6 +583,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@GuardedBy("mUidRulesFirstLock")
private final SparseArray<UidBlockedState> mUidBlockedState = new SparseArray<>();
+ /** Objects used temporarily while computing the new blocked state for each uid. */
+ @GuardedBy("mUidRulesFirstLock")
+ private final SparseArray<UidBlockedState> mTmpUidBlockedState = new SparseArray<>();
+
/** Map from network ID to last observed meteredness state */
@GuardedBy("mNetworkPoliciesSecondLock")
private final SparseBooleanArray mNetworkMetered = new SparseBooleanArray();
@@ -3825,7 +3814,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final SparseBooleanArray knownUids = new SparseBooleanArray();
collectKeys(mUidState, knownUids);
- collectKeys(mUidRules, knownUids);
+ collectKeys(mUidBlockedState, knownUids);
fout.println("Status for all known UIDs:");
fout.increaseIndent();
@@ -3843,23 +3832,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
fout.print(uidState.toString());
}
- final int uidRules = mUidRules.get(uid, RULE_NONE);
- fout.print(" rules=");
- fout.print(uidRulesToString(uidRules));
- fout.println();
- }
- fout.decreaseIndent();
-
- fout.println("Status for just UIDs with rules:");
- fout.increaseIndent();
- size = mUidRules.size();
- for (int i = 0; i < size; i++) {
- final int uid = mUidRules.keyAt(i);
- fout.print("UID=");
- fout.print(uid);
- final int uidRules = mUidRules.get(uid, RULE_NONE);
- fout.print(" rules=");
- fout.print(uidRulesToString(uidRules));
+ final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ if (uidBlockedState == null) {
+ fout.print(" blocked_state={null}");
+ } else {
+ fout.print(" blocked_state=");
+ fout.print(uidBlockedState.toString());
+ }
fout.println();
}
fout.decreaseIndent();
@@ -4010,22 +3989,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
void updateRestrictedModeAllowlistUL() {
mUidFirewallRestrictedModeRules.clear();
forEachUid("updateRestrictedModeAllowlist", uid -> {
- final int oldUidRule = mUidRules.get(uid);
- final int newUidRule = getNewRestrictedModeUidRule(uid, oldUidRule);
- final boolean hasUidRuleChanged = oldUidRule != newUidRule;
- final int newFirewallRule = getRestrictedModeFirewallRule(newUidRule);
-
- // setUidFirewallRulesUL will allowlist all uids that are passed to it, so only add
- // non-default rules.
- if (newFirewallRule != FIREWALL_RULE_DEFAULT) {
- mUidFirewallRestrictedModeRules.append(uid, newFirewallRule);
- }
-
- if (hasUidRuleChanged) {
- mUidRules.put(uid, newUidRule);
- mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget();
+ synchronized (mUidRulesFirstLock) {
+ final UidBlockedState uidBlockedState = updateBlockedReasonsForRestrictedModeUL(
+ uid);
+ final int newFirewallRule = getRestrictedModeFirewallRule(uidBlockedState);
+
+ // setUidFirewallRulesUL will allowlist all uids that are passed to it, so only add
+ // non-default rules.
+ if (newFirewallRule != FIREWALL_RULE_DEFAULT) {
+ mUidFirewallRestrictedModeRules.append(uid, newFirewallRule);
+ }
}
- updateBlockedReasonsForRestrictedModeUL(uid);
});
if (mRestrictedNetworkingMode) {
// firewall rules only need to be set when this mode is being enabled.
@@ -4038,15 +4012,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@VisibleForTesting
@GuardedBy("mUidRulesFirstLock")
void updateRestrictedModeForUidUL(int uid) {
- final int oldUidRule = mUidRules.get(uid);
- final int newUidRule = getNewRestrictedModeUidRule(uid, oldUidRule);
- final boolean hasUidRuleChanged = oldUidRule != newUidRule;
-
- if (hasUidRuleChanged) {
- mUidRules.put(uid, newUidRule);
- mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget();
- }
- updateBlockedReasonsForRestrictedModeUL(uid);
+ final UidBlockedState uidBlockedState = updateBlockedReasonsForRestrictedModeUL(uid);
// if restricted networking mode is on, and the app has an access exemption, the uid rule
// will not change, but the firewall rule will have to be updated.
@@ -4054,16 +4020,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// Note: setUidFirewallRule also updates mUidFirewallRestrictedModeRules.
// In this case, default firewall rules can also be added.
setUidFirewallRule(FIREWALL_CHAIN_RESTRICTED, uid,
- getRestrictedModeFirewallRule(newUidRule));
+ getRestrictedModeFirewallRule(uidBlockedState));
}
}
- private void updateBlockedReasonsForRestrictedModeUL(int uid) {
- UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
- if (uidBlockedState == null) {
- uidBlockedState = new UidBlockedState();
- mUidBlockedState.put(uid, uidBlockedState);
- }
+ @GuardedBy("mUidRulesFirstLock")
+ private UidBlockedState updateBlockedReasonsForRestrictedModeUL(int uid) {
+ final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+ mUidBlockedState, uid);
final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
if (mRestrictedNetworkingMode) {
uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE;
@@ -4077,23 +4041,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
uidBlockedState.updateEffectiveBlockedReasons();
if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
- mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
- uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons)
- .sendToTarget();
- }
- }
+ postBlockedReasonsChangedMsg(uid,
+ uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons);
- private int getNewRestrictedModeUidRule(int uid, int oldUidRule) {
- int newRule = oldUidRule;
- newRule &= ~MASK_RESTRICTED_MODE_NETWORKS;
- if (mRestrictedNetworkingMode && !hasRestrictedModeAccess(uid)) {
- newRule |= RULE_REJECT_RESTRICTED_MODE;
+ postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
}
- return newRule;
+ return uidBlockedState;
}
- private static int getRestrictedModeFirewallRule(int uidRule) {
- if ((uidRule & RULE_REJECT_RESTRICTED_MODE) != 0) {
+ private static int getRestrictedModeFirewallRule(UidBlockedState uidBlockedState) {
+ if ((uidBlockedState.effectiveBlockedReasons & BLOCKED_REASON_RESTRICTED_MODE) != 0) {
// rejected in restricted mode, this is the default behavior.
return FIREWALL_RULE_DEFAULT;
} else {
@@ -4301,16 +4258,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
if (!isUidValidForDenylistRulesUL(uid)) {
continue;
}
- int oldRules = mUidRules.get(uid);
- if (enableChain) {
- // Chain wasn't enabled before and the other power-related
- // chains are allowlists, so we can clear the
- // MASK_ALL_NETWORKS part of the rules and re-inform listeners if
- // the effective rules result in blocking network access.
- oldRules &= MASK_METERED_NETWORKS;
- } else {
- // Skip if it had no restrictions to begin with
- if ((oldRules & MASK_ALL_NETWORKS) == 0) continue;
+ final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+ mUidBlockedState, uid);
+ if (!enableChain && (uidBlockedState.blockedReasons & ~BLOCKED_METERED_REASON_MASK)
+ == BLOCKED_REASON_NONE) {
+ // Chain isn't enabled and the uid had no restrictions to begin with.
+ continue;
}
final boolean isUidIdle = !paroled && isUidIdle(uid);
if (isUidIdle && !mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid))
@@ -4320,13 +4273,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} else {
mUidFirewallStandbyRules.put(uid, FIREWALL_RULE_DEFAULT);
}
- final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldRules,
- isUidIdle);
- if (newUidRules == RULE_NONE) {
- mUidRules.delete(uid);
- } else {
- mUidRules.put(uid, newUidRules);
- }
+ updateRulesForPowerRestrictionsUL(uid, isUidIdle);
}
setUidFirewallRulesUL(FIREWALL_CHAIN_STANDBY, blockedUids,
enableChain ? CHAIN_TOGGLE_ENABLE : CHAIN_TOGGLE_DISABLE);
@@ -4544,6 +4491,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mInternetPermissionMap.put(uid, hasPermission);
return hasPermission;
} catch (RemoteException e) {
+ // ignored; service lives in system_server
}
return true;
}
@@ -4554,7 +4502,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@GuardedBy("mUidRulesFirstLock")
private void onUidDeletedUL(int uid) {
// First cleanup in-memory state synchronously...
- mUidRules.delete(uid);
+ mUidBlockedState.delete(uid);
mUidPolicy.delete(uid);
mUidFirewallStandbyRules.delete(uid);
mUidFirewallDozableRules.delete(uid);
@@ -4640,7 +4588,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* permission, since there is no need to change the {@code iptables} rule if the app does not
* have permission to use the internet.
*
- * <p>The {@link #mUidRules} map is used to define the transtion of states of an UID.
+ * <p>The {@link #mUidBlockedState} map is used to define the transition of states of an UID.
*
*/
private void updateRulesForDataUsageRestrictionsUL(int uid) {
@@ -4655,6 +4603,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ @GuardedBy("mUidRulesFirstLock")
private void updateRulesForDataUsageRestrictionsULInner(int uid) {
if (!isUidValidForAllowlistRulesUL(uid)) {
if (LOGD) Slog.d(TAG, "no need to update restrict data rules for uid " + uid);
@@ -4662,38 +4611,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
- final int oldUidRules = mUidRules.get(uid, RULE_NONE);
final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid);
final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid);
- UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
- if (uidBlockedState == null) {
- uidBlockedState = new UidBlockedState();
- mUidBlockedState.put(uid, uidBlockedState);
- }
+ final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+ mUidBlockedState, uid);
+ final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
+ mTmpUidBlockedState, uid);
+ previousUidBlockedState.copyFrom(uidBlockedState);
final boolean isDenied = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
final boolean isAllowed = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0;
- // copy oldUidRules and clear out METERED_NETWORKS rules.
- int newUidRules = oldUidRules & (~MASK_METERED_NETWORKS);
-
- // First step: define the new rule based on user restrictions and foreground state.
- if (isRestrictedByAdmin) {
- newUidRules |= RULE_REJECT_METERED;
- } else if (isForeground) {
- if (isDenied || (mRestrictBackground && !isAllowed)) {
- newUidRules |= RULE_TEMPORARY_ALLOW_METERED;
- } else if (isAllowed) {
- newUidRules |= RULE_ALLOW_METERED;
- }
- } else {
- if (isDenied) {
- newUidRules |= RULE_REJECT_METERED;
- } else if (mRestrictBackground && isAllowed) {
- newUidRules |= RULE_ALLOW_METERED;
- }
- }
-
int newBlockedReasons = BLOCKED_REASON_NONE;
int newAllowedReasons = ALLOWED_REASON_NONE;
newBlockedReasons |= (isRestrictedByAdmin ? BLOCKED_METERED_REASON_ADMIN_DISABLED : 0);
@@ -4704,16 +4632,48 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
newAllowedReasons |= (isForeground ? ALLOWED_METERED_REASON_FOREGROUND : 0);
newAllowedReasons |= (isAllowed ? ALLOWED_METERED_REASON_USER_EXEMPTED : 0);
+ uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
+ & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
+ uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
+ & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
+ uidBlockedState.updateEffectiveBlockedReasons();
+ final int oldEffectiveBlockedReasons = previousUidBlockedState.effectiveBlockedReasons;
+ final int newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) {
+ postBlockedReasonsChangedMsg(uid,
+ newEffectiveBlockedReasons, oldEffectiveBlockedReasons);
+
+ postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
+ }
+
+ // Note that the conditionals below are for avoiding unnecessary calls to netd.
+ // TODO: Measure the performance for doing a no-op call to netd so that we can
+ // remove the conditionals to simplify the logic below. We can also further reduce
+ // some calls to netd if they turn out to be costly.
+ final int denylistReasons = BLOCKED_METERED_REASON_ADMIN_DISABLED
+ | BLOCKED_METERED_REASON_USER_RESTRICTED;
+ if ((oldEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE
+ || (newEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE) {
+ setMeteredNetworkDenylist(uid,
+ (newEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE);
+ }
+ final int allowlistReasons = ALLOWED_METERED_REASON_FOREGROUND
+ | ALLOWED_METERED_REASON_USER_EXEMPTED;
+ final int oldAllowedReasons = previousUidBlockedState.allowedReasons;
+ if ((oldAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE
+ || (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE) {
+ setMeteredNetworkAllowlist(uid,
+ (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE);
+ }
+
if (LOGV) {
Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")"
+ ": isForeground=" +isForeground
+ ", isDenied=" + isDenied
+ ", isAllowed=" + isAllowed
+ ", isRestrictedByAdmin=" + isRestrictedByAdmin
- + ", oldRule=" + uidRulesToString(oldUidRules & MASK_METERED_NETWORKS)
- + ", newRule=" + uidRulesToString(newUidRules & MASK_METERED_NETWORKS)
- + ", newUidRules=" + uidRulesToString(newUidRules)
- + ", oldUidRules=" + uidRulesToString(oldUidRules)
+ + ", oldBlockedState=" + previousUidBlockedState.toString()
+ + ", newBlockedState="
+ ", oldBlockedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString(
uidBlockedState.blockedReasons & BLOCKED_METERED_REASON_MASK)
+ ", oldBlockedMeteredEffectiveReasons="
@@ -4722,84 +4682,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
+ ", oldAllowedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString(
uidBlockedState.allowedReasons & BLOCKED_METERED_REASON_MASK));
}
-
- if (newUidRules == RULE_NONE) {
- mUidRules.delete(uid);
- } else {
- mUidRules.put(uid, newUidRules);
- }
-
- // Second step: apply bw changes based on change of state.
- if (newUidRules != oldUidRules) {
- if (hasRule(newUidRules, RULE_TEMPORARY_ALLOW_METERED)) {
- // Temporarily allow foreground app, removing from denylist if necessary
- // (since bw_penalty_box prevails over bw_happy_box).
-
- setMeteredNetworkAllowlist(uid, true);
- // TODO: if statement below is used to avoid an unnecessary call to netd / iptables,
- // but ideally it should be just:
- // setMeteredNetworkDenylist(uid, isDenied);
- if (isDenied) {
- setMeteredNetworkDenylist(uid, false);
- }
- } else if (hasRule(oldUidRules, RULE_TEMPORARY_ALLOW_METERED)) {
- // Remove temporary exemption from app that is not on foreground anymore.
-
- // TODO: if statements below are used to avoid unnecessary calls to netd / iptables,
- // but ideally they should be just:
- // setMeteredNetworkAllowlist(uid, isAllowed);
- // setMeteredNetworkDenylist(uid, isDenied);
- if (!isAllowed) {
- setMeteredNetworkAllowlist(uid, false);
- }
- if (isDenied || isRestrictedByAdmin) {
- setMeteredNetworkDenylist(uid, true);
- }
- } else if (hasRule(newUidRules, RULE_REJECT_METERED)
- || hasRule(oldUidRules, RULE_REJECT_METERED)) {
- // Flip state because app was explicitly added or removed to denylist.
- setMeteredNetworkDenylist(uid, (isDenied || isRestrictedByAdmin));
- if (hasRule(oldUidRules, RULE_REJECT_METERED) && isAllowed) {
- // Since denial prevails over allowance, we need to handle the special case
- // where app is allowed and denied at the same time (although such
- // scenario should be blocked by the UI), then it is removed from the denylist.
- setMeteredNetworkAllowlist(uid, isAllowed);
- }
- } else if (hasRule(newUidRules, RULE_ALLOW_METERED)
- || hasRule(oldUidRules, RULE_ALLOW_METERED)) {
- // Flip state because app was explicitly added or removed to allowlist.
- setMeteredNetworkAllowlist(uid, isAllowed);
- } else {
- // All scenarios should have been covered above.
- Log.wtf(TAG, "Unexpected change of metered UID state for " + uid
- + ": foreground=" + isForeground
- + ", allowlisted=" + isAllowed
- + ", denylisted=" + isDenied
- + ", isRestrictedByAdmin=" + isRestrictedByAdmin
- + ", newRule=" + uidRulesToString(newUidRules)
- + ", oldRule=" + uidRulesToString(oldUidRules));
- }
-
- // Dispatch changed rule to existing listeners.
- mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget();
- }
-
- final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
- uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
- & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
- uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
- & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
- uidBlockedState.updateEffectiveBlockedReasons();
- if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
- mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
- uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons)
- .sendToTarget();
- }
}
/**
- * Updates the power-related part of the {@link #mUidRules} for a given map, and notify external
- * listeners in case of change.
+ * Updates the power-related part of the {@link #mUidBlockedState} for a given map, and
+ * notify external listeners in case of change.
* <p>
* There are 3 power-related rules that affects whether an app has background access on
* non-metered networks, and when the condition applies and the UID is not allowed for power
@@ -4810,23 +4697,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* <li>Battery Saver Mode is on: {@code fw_powersave} firewall chain.
* </ul>
* <p>
- * This method updates the power-related part of the {@link #mUidRules} for a given uid based on
- * these modes, the UID process state (foreground or not), and the UID allowlist state.
+ * This method updates the power-related part of the {@link #mUidBlockedState} for a given
+ * uid based on these modes, the UID process state (foreground or not), and the UID
+ * allowlist state.
* <p>
* <strong>NOTE: </strong>This method does not update the firewall rules on {@code netd}.
*/
@GuardedBy("mUidRulesFirstLock")
private void updateRulesForPowerRestrictionsUL(int uid) {
- final int oldUidRules = mUidRules.get(uid, RULE_NONE);
-
- final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules,
- isUidIdle(uid));
-
- if (newUidRules == RULE_NONE) {
- mUidRules.delete(uid);
- } else {
- mUidRules.put(uid, newUidRules);
- }
+ updateRulesForPowerRestrictionsUL(uid, isUidIdle(uid));
}
/**
@@ -4835,56 +4714,37 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* @param uid the uid of the app to update rules for
* @param oldUidRules the current rules for the uid, in order to determine if there's a change
* @param isUidIdle whether uid is idle or not
- *
- * @return the new computed rules for the uid
*/
@GuardedBy("mUidRulesFirstLock")
- private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules, boolean isUidIdle) {
+ private void updateRulesForPowerRestrictionsUL(int uid, boolean isUidIdle) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK,
- "updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules + "/"
+ "updateRulesForPowerRestrictionsUL: " + uid + "/"
+ (isUidIdle ? "I" : "-"));
}
try {
- return updateRulesForPowerRestrictionsULInner(uid, oldUidRules, isUidIdle);
+ updateRulesForPowerRestrictionsULInner(uid, isUidIdle);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
}
@GuardedBy("mUidRulesFirstLock")
- private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules,
- boolean isUidIdle) {
+ private void updateRulesForPowerRestrictionsULInner(int uid, boolean isUidIdle) {
if (!isUidValidForDenylistRulesUL(uid)) {
if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid);
- return RULE_NONE;
+ return;
}
- final boolean restrictMode = isUidIdle || mRestrictPower || mDeviceIdleMode;
final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode);
- // Copy existing uid rules and clear ALL_NETWORK rules.
- int newUidRules = oldUidRules & (~MASK_ALL_NETWORKS);
-
- UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
- if (uidBlockedState == null) {
- uidBlockedState = new UidBlockedState();
- mUidBlockedState.put(uid, uidBlockedState);
- }
-
- // First step: define the new rule based on user restrictions and foreground state.
-
- // NOTE: if statements below could be inlined, but it's easier to understand the logic
- // by considering the foreground and non-foreground states.
- if (isForeground) {
- if (restrictMode) {
- newUidRules |= RULE_ALLOW_ALL;
- }
- } else if (restrictMode) {
- newUidRules |= isWhitelisted ? RULE_ALLOW_ALL : RULE_REJECT_ALL;
- }
+ final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
+ mUidBlockedState, uid);
+ final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
+ mTmpUidBlockedState, uid);
+ previousUidBlockedState.copyFrom(uidBlockedState);
int newBlockedReasons = BLOCKED_REASON_NONE;
int newAllowedReasons = ALLOWED_REASON_NONE;
@@ -4899,6 +4759,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0);
newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid)
? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0);
+ newAllowedReasons |= (uidBlockedState.allowedReasons
+ & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS);
+
+ uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
+ & BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
+ uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
+ & ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
+ uidBlockedState.updateEffectiveBlockedReasons();
+ if (previousUidBlockedState.effectiveBlockedReasons
+ != uidBlockedState.effectiveBlockedReasons) {
+ postBlockedReasonsChangedMsg(uid,
+ uidBlockedState.effectiveBlockedReasons,
+ previousUidBlockedState.effectiveBlockedReasons);
+
+ postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
+ }
if (LOGV) {
Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
@@ -4907,43 +4783,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
+ ", mDeviceIdleMode: " + mDeviceIdleMode
+ ", isForeground=" + isForeground
+ ", isWhitelisted=" + isWhitelisted
- + ", oldRule=" + uidRulesToString(oldUidRules & MASK_ALL_NETWORKS)
- + ", newRule=" + uidRulesToString(newUidRules & MASK_ALL_NETWORKS)
- + ", newUidRules=" + uidRulesToString(newUidRules)
- + ", oldUidRules=" + uidRulesToString(oldUidRules));
- }
-
- // Second step: notify listeners if state changed.
- if (newUidRules != oldUidRules) {
- if ((newUidRules & MASK_ALL_NETWORKS) == RULE_NONE || hasRule(newUidRules,
- RULE_ALLOW_ALL)) {
- if (LOGV) Log.v(TAG, "Allowing non-metered access for UID " + uid);
- } else if (hasRule(newUidRules, RULE_REJECT_ALL)) {
- if (LOGV) Log.v(TAG, "Rejecting non-metered access for UID " + uid);
- } else {
- // All scenarios should have been covered above
- Log.wtf(TAG, "Unexpected change of non-metered UID state for " + uid
- + ": foreground=" + isForeground
- + ", whitelisted=" + isWhitelisted
- + ", newRule=" + uidRulesToString(newUidRules)
- + ", oldRule=" + uidRulesToString(oldUidRules));
- }
- mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget();
- }
-
- final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
- uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
- & BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
- uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
- & ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
- uidBlockedState.updateEffectiveBlockedReasons();
- if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
- mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
- uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons)
- .sendToTarget();
+ + ", oldUidBlockedState=" + previousUidBlockedState.toString()
+ + ", newUidBlockedState=" + uidBlockedState.toString());
}
-
- return newUidRules;
}
private class NetPolicyAppIdleStateChangeListener extends AppIdleStateChangeListener {
@@ -4971,10 +4813,23 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ private void postBlockedReasonsChangedMsg(int uid, int newEffectiveBlockedReasons,
+ int oldEffectiveBlockedReasons) {
+ mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
+ newEffectiveBlockedReasons, oldEffectiveBlockedReasons)
+ .sendToTarget();
+ }
+
+ private void postUidRulesChangedMsg(int uid, int uidRules) {
+ mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules)
+ .sendToTarget();
+ }
+
private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) {
try {
listener.onUidRulesChanged(uid, uidRules);
} catch (RemoteException ignored) {
+ // Ignore if there is an error sending the callback to the client.
}
}
@@ -4983,6 +4838,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
listener.onMeteredIfacesChanged(meteredIfaces);
} catch (RemoteException ignored) {
+ // Ignore if there is an error sending the callback to the client.
}
}
@@ -4991,6 +4847,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
listener.onRestrictBackgroundChanged(restrictBackground);
} catch (RemoteException ignored) {
+ // Ignore if there is an error sending the callback to the client.
}
}
@@ -4999,6 +4856,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
listener.onUidPoliciesChanged(uid, uidPolicies);
} catch (RemoteException ignored) {
+ // Ignore if there is an error sending the callback to the client.
}
}
@@ -5007,6 +4865,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
listener.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes);
} catch (RemoteException ignored) {
+ // Ignore if there is an error sending the callback to the client.
}
}
@@ -5015,6 +4874,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
listener.onSubscriptionPlansChanged(subId, plans);
} catch (RemoteException ignored) {
+ // Ignore if there is an error sending the callback to the client.
}
}
@@ -5023,6 +4883,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
listener.onBlockedReasonChanged(uid, oldBlockedReasons, newBlockedReasons);
} catch (RemoteException ignored) {
+ // Ignore if there is an error sending the callback to the client.
}
}
@@ -5033,6 +4894,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
case MSG_RULES_CHANGED: {
final int uid = msg.arg1;
final int uidRules = msg.arg2;
+ if (LOGV) {
+ Slog.v(TAG, "Dispatching rules=" + uidRulesToString(uidRules)
+ + " for uid=" + uid);
+ }
final int length = mListeners.beginBroadcast();
for (int i = 0; i < length; i++) {
final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
@@ -5605,7 +5470,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- private static void collectKeys(SparseArray<UidState> source, SparseBooleanArray target) {
+ private static <T> void collectKeys(SparseArray<T> source, SparseBooleanArray target) {
final int size = source.size();
for (int i = 0; i < size; i++) {
target.put(source.keyAt(i), true);
@@ -5653,90 +5518,38 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final long startTime = mStatLogger.getTime();
mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
- final int uidRules;
- final boolean isBackgroundRestricted;
+ int blockedReasons;
synchronized (mUidRulesFirstLock) {
- uidRules = mUidRules.get(uid, RULE_NONE);
- isBackgroundRestricted = mRestrictBackground;
+ final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ blockedReasons = uidBlockedState == null
+ ? BLOCKED_REASON_NONE : uidBlockedState.effectiveBlockedReasons;
+ if (!isNetworkMetered) {
+ blockedReasons &= ~BLOCKED_METERED_REASON_MASK;
+ }
+ mLogger.networkBlocked(uid, uidBlockedState);
}
- final boolean ret = isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
- isBackgroundRestricted, mLogger);
mStatLogger.logDurationStat(Stats.IS_UID_NETWORKING_BLOCKED, startTime);
- return ret;
+ return blockedReasons != BLOCKED_REASON_NONE;
}
@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;
+ final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
+ int blockedReasons = uidBlockedState == null
+ ? BLOCKED_REASON_NONE : uidBlockedState.effectiveBlockedReasons;
+ blockedReasons &= BLOCKED_METERED_REASON_MASK;
+ return blockedReasons != BLOCKED_REASON_NONE;
}
- // 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;
}
- static boolean isUidNetworkingBlockedInternal(int uid, int uidRules, boolean isNetworkMetered,
- boolean isBackgroundRestricted, @Nullable NetworkPolicyLogger logger) {
- final int reason;
- // Networks are never blocked for system components
- if (isSystem(uid)) {
- reason = NTWK_ALLOWED_SYSTEM;
- } else if (hasRule(uidRules, RULE_REJECT_RESTRICTED_MODE)) {
- reason = NTWK_BLOCKED_RESTRICTED_MODE;
- } else if (hasRule(uidRules, RULE_REJECT_ALL)) {
- reason = NTWK_BLOCKED_POWER;
- } else if (!isNetworkMetered) {
- reason = NTWK_ALLOWED_NON_METERED;
- } else if (hasRule(uidRules, RULE_REJECT_METERED)) {
- reason = NTWK_BLOCKED_DENYLIST;
- } else if (hasRule(uidRules, RULE_ALLOW_METERED)) {
- reason = NTWK_ALLOWED_ALLOWLIST;
- } else if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) {
- reason = NTWK_ALLOWED_TMP_ALLOWLIST;
- } else if (isBackgroundRestricted) {
- reason = NTWK_BLOCKED_BG_RESTRICT;
- } else {
- reason = NTWK_ALLOWED_DEFAULT;
- }
-
- final boolean blocked;
- switch(reason) {
- case NTWK_ALLOWED_DEFAULT:
- case NTWK_ALLOWED_NON_METERED:
- case NTWK_ALLOWED_TMP_ALLOWLIST:
- case NTWK_ALLOWED_ALLOWLIST:
- case NTWK_ALLOWED_SYSTEM:
- blocked = false;
- break;
- case NTWK_BLOCKED_RESTRICTED_MODE:
- case NTWK_BLOCKED_POWER:
- case NTWK_BLOCKED_DENYLIST:
- case NTWK_BLOCKED_BG_RESTRICT:
- blocked = true;
- break;
- default:
- throw new IllegalArgumentException();
- }
- if (logger != null) {
- logger.networkBlocked(uid, reason);
- }
-
- return blocked;
- }
-
private class NetworkPolicyManagerInternalImpl extends NetworkPolicyManagerInternal {
@Override
@@ -5945,6 +5758,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue;
}
+ private static UidBlockedState getOrCreateUidBlockedStateForUid(
+ SparseArray<UidBlockedState> uidBlockedStates, int uid) {
+ UidBlockedState uidBlockedState = uidBlockedStates.get(uid);
+ if (uidBlockedState == null) {
+ uidBlockedState = new UidBlockedState();
+ uidBlockedStates.put(uid, uidBlockedState);
+ }
+ return uidBlockedState;
+ }
+
@VisibleForTesting
static final class UidBlockedState {
public int blockedReasons;
@@ -6008,9 +5831,180 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
return effectiveBlockedReasons;
}
+
+ @Override
+ public String toString() {
+ return toString(blockedReasons, allowedReasons, effectiveBlockedReasons);
+ }
+
+ public static String toString(int blockedReasons, int allowedReasons,
+ int effectiveBlockedReasons) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("{");
+ sb.append("blocked=").append(blockedReasonsToString(blockedReasons)).append(",");
+ sb.append("allowed=").append(allowedReasonsToString(allowedReasons)).append(",");
+ sb.append("effective=").append(blockedReasonsToString(effectiveBlockedReasons));
+ sb.append("}");
+ return sb.toString();
+ }
+
+ private static final int[] BLOCKED_REASONS = {
+ BLOCKED_REASON_BATTERY_SAVER,
+ BLOCKED_REASON_DOZE,
+ BLOCKED_REASON_APP_STANDBY,
+ BLOCKED_REASON_RESTRICTED_MODE,
+ BLOCKED_METERED_REASON_DATA_SAVER,
+ BLOCKED_METERED_REASON_USER_RESTRICTED,
+ BLOCKED_METERED_REASON_ADMIN_DISABLED,
+ };
+
+ private static final int[] ALLOWED_REASONS = {
+ ALLOWED_REASON_SYSTEM,
+ ALLOWED_REASON_FOREGROUND,
+ ALLOWED_REASON_POWER_SAVE_ALLOWLIST,
+ ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST,
+ ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS,
+ ALLOWED_METERED_REASON_USER_EXEMPTED,
+ ALLOWED_METERED_REASON_SYSTEM,
+ ALLOWED_METERED_REASON_FOREGROUND,
+ };
+
+ private static String blockedReasonToString(int blockedReason) {
+ switch (blockedReason) {
+ case BLOCKED_REASON_NONE:
+ return "NONE";
+ case BLOCKED_REASON_BATTERY_SAVER:
+ return "BATTERY_SAVER";
+ case BLOCKED_REASON_DOZE:
+ return "DOZE";
+ case BLOCKED_REASON_APP_STANDBY:
+ return "APP_STANDBY";
+ case BLOCKED_REASON_RESTRICTED_MODE:
+ return "RESTRICTED_MODE";
+ case BLOCKED_METERED_REASON_DATA_SAVER:
+ return "DATA_SAVER";
+ case BLOCKED_METERED_REASON_USER_RESTRICTED:
+ return "METERED_USER_RESTRICTED";
+ case BLOCKED_METERED_REASON_ADMIN_DISABLED:
+ return "METERED_ADMIN_DISABLED";
+ default:
+ Slog.wtfStack(TAG, "Unknown blockedReason: " + blockedReason);
+ return String.valueOf(blockedReason);
+ }
+ }
+
+ private static String allowedReasonToString(int allowedReason) {
+ switch (allowedReason) {
+ case ALLOWED_REASON_NONE:
+ return "NONE";
+ case ALLOWED_REASON_SYSTEM:
+ return "SYSTEM";
+ case ALLOWED_REASON_FOREGROUND:
+ return "FOREGROUND";
+ case ALLOWED_REASON_POWER_SAVE_ALLOWLIST:
+ return "POWER_SAVE_ALLOWLIST";
+ case ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST:
+ return "POWER_SAVE_EXCEPT_IDLE_ALLOWLIST";
+ case ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS:
+ return "RESTRICTED_MODE_PERMISSIONS";
+ case ALLOWED_METERED_REASON_USER_EXEMPTED:
+ return "METERED_USER_EXEMPTED";
+ case ALLOWED_METERED_REASON_SYSTEM:
+ return "METERED_SYSTEM";
+ case ALLOWED_METERED_REASON_FOREGROUND:
+ return "METERED_FOREGROUND";
+ default:
+ Slog.wtfStack(TAG, "Unknown allowedReason: " + allowedReason);
+ return String.valueOf(allowedReason);
+ }
+ }
+
+ public static String blockedReasonsToString(int blockedReasons) {
+ if (blockedReasons == BLOCKED_REASON_NONE) {
+ return blockedReasonToString(BLOCKED_REASON_NONE);
+ }
+ final StringBuilder sb = new StringBuilder();
+ for (int reason : BLOCKED_REASONS) {
+ if ((blockedReasons & reason) != 0) {
+ sb.append(sb.length() == 0 ? "" : "|");
+ sb.append(blockedReasonToString(reason));
+ blockedReasons &= ~reason;
+ }
+ }
+ if (blockedReasons != 0) {
+ sb.append(sb.length() == 0 ? "" : "|");
+ sb.append(String.valueOf(blockedReasons));
+ Slog.wtfStack(TAG, "Unknown blockedReasons: " + blockedReasons);
+ }
+ return sb.toString();
+ }
+
+ public static String allowedReasonsToString(int allowedReasons) {
+ if (allowedReasons == ALLOWED_REASON_NONE) {
+ return allowedReasonToString(ALLOWED_REASON_NONE);
+ }
+ final StringBuilder sb = new StringBuilder();
+ for (int reason : ALLOWED_REASONS) {
+ if ((allowedReasons & reason) != 0) {
+ sb.append(sb.length() == 0 ? "" : "|");
+ sb.append(allowedReasonToString(reason));
+ allowedReasons &= ~reason;
+ }
+ }
+ if (allowedReasons != 0) {
+ sb.append(sb.length() == 0 ? "" : "|");
+ sb.append(String.valueOf(allowedReasons));
+ Slog.wtfStack(TAG, "Unknown allowedReasons: " + allowedReasons);
+ }
+ return sb.toString();
+ }
+
+ public void copyFrom(UidBlockedState uidBlockedState) {
+ blockedReasons = uidBlockedState.blockedReasons;
+ allowedReasons = uidBlockedState.allowedReasons;
+ effectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
+ }
+
+ public int deriveUidRules() {
+ int uidRule = RULE_NONE;
+ if ((effectiveBlockedReasons & BLOCKED_REASON_RESTRICTED_MODE) != 0) {
+ uidRule |= RULE_REJECT_RESTRICTED_MODE;
+ }
+
+ int powerBlockedReasons = BLOCKED_REASON_APP_STANDBY
+ | BLOCKED_REASON_DOZE
+ | BLOCKED_REASON_BATTERY_SAVER;
+ if ((effectiveBlockedReasons & powerBlockedReasons) != 0) {
+ uidRule |= RULE_REJECT_ALL;
+ } else if ((blockedReasons & powerBlockedReasons) != 0) {
+ uidRule |= RULE_ALLOW_ALL;
+ }
+
+ // UidRule doesn't include RestrictBackground (DataSaver) state, so not including in
+ // metered blocked reasons below.
+ int meteredBlockedReasons = BLOCKED_METERED_REASON_ADMIN_DISABLED
+ | BLOCKED_METERED_REASON_USER_RESTRICTED;
+ if ((effectiveBlockedReasons & meteredBlockedReasons) != 0) {
+ uidRule |= RULE_REJECT_METERED;
+ } else if ((blockedReasons & BLOCKED_METERED_REASON_USER_RESTRICTED) != 0
+ && (allowedReasons & ALLOWED_METERED_REASON_FOREGROUND) != 0) {
+ uidRule |= RULE_TEMPORARY_ALLOW_METERED;
+ } else if ((blockedReasons & BLOCKED_METERED_REASON_DATA_SAVER) != 0) {
+ if ((allowedReasons & ALLOWED_METERED_REASON_USER_EXEMPTED) != 0) {
+ uidRule |= RULE_ALLOW_ALL;
+ } else if ((allowedReasons & ALLOWED_METERED_REASON_FOREGROUND) != 0) {
+ uidRule |= RULE_TEMPORARY_ALLOW_METERED;
+ }
+ }
+ if (LOGV) {
+ Slog.v(TAG, "uidBlockedState=" + this.toString()
+ + " -> uidRule=" + uidRulesToString(uidRule));
+ }
+ return uidRule;
+ }
}
- private class NotificationId {
+ private static class NotificationId {
private final String mTag;
private final int mId;
diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java
index 431b00914f02..e6433db11d7b 100644
--- a/services/core/java/com/android/server/net/NetworkStatsFactory.java
+++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java
@@ -159,7 +159,7 @@ public class NetworkStatsFactory {
}
public NetworkStatsFactory() {
- this(new File("/proc/"), new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists());
+ this(new File("/proc/"), true);
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 097b0711eff7..c876d411fac1 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -150,6 +150,7 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.BinderUtils;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
@@ -215,8 +216,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private final PowerManager.WakeLock mWakeLock;
- private final boolean mUseBpfTrafficStats;
-
private final ContentObserver mContentObserver;
private final ContentResolver mContentResolver;
@@ -438,7 +437,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mStatsObservers = Objects.requireNonNull(statsObservers, "missing NetworkStatsObservers");
mSystemDir = Objects.requireNonNull(systemDir, "missing systemDir");
mBaseDir = Objects.requireNonNull(baseDir, "missing baseDir");
- mUseBpfTrafficStats = new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists();
mDeps = Objects.requireNonNull(deps, "missing Dependencies");
final HandlerThread handlerThread = mDeps.makeHandlerThread();
@@ -1084,13 +1082,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
if (callingUid != android.os.Process.SYSTEM_UID && callingUid != uid) {
return UNSUPPORTED;
}
- return nativeGetUidStat(uid, type, checkBpfStatsEnable());
+ return nativeGetUidStat(uid, type);
}
@Override
public long getIfaceStats(@NonNull String iface, int type) {
Objects.requireNonNull(iface);
- long nativeIfaceStats = nativeGetIfaceStat(iface, type, checkBpfStatsEnable());
+ long nativeIfaceStats = nativeGetIfaceStat(iface, type);
if (nativeIfaceStats == -1) {
return nativeIfaceStats;
} else {
@@ -1104,7 +1102,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public long getTotalStats(int type) {
- long nativeTotalStats = nativeGetTotalStat(type, checkBpfStatsEnable());
+ long nativeTotalStats = nativeGetTotalStat(type);
if (nativeTotalStats == -1) {
return nativeTotalStats;
} else {
@@ -1137,10 +1135,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
}
- private boolean checkBpfStatsEnable() {
- return mUseBpfTrafficStats;
- }
-
/**
* Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to
* reflect current {@link #mPersistThreshold} value. Always defers to
@@ -2104,14 +2098,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public void notifyAlertReached() throws RemoteException {
- mAlertObserver.limitReached(LIMIT_GLOBAL_ALERT, null /* unused */);
+ // This binder object can only have been obtained by a process that holds
+ // NETWORK_STATS_PROVIDER. Thus, no additional permission check is required.
+ BinderUtils.withCleanCallingIdentity(() ->
+ mAlertObserver.limitReached(LIMIT_GLOBAL_ALERT, null /* unused */));
}
@Override
public void notifyWarningOrLimitReached() {
Log.d(TAG, mTag + ": notifyWarningOrLimitReached");
- LocalServices.getService(NetworkPolicyManagerInternal.class)
- .onStatsProviderWarningOrLimitReached(mTag);
+ BinderUtils.withCleanCallingIdentity(() ->
+ LocalServices.getService(NetworkPolicyManagerInternal.class)
+ .onStatsProviderWarningOrLimitReached(mTag));
}
@Override
@@ -2249,7 +2247,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
}
- private static native long nativeGetTotalStat(int type, boolean useBpfStats);
- private static native long nativeGetIfaceStat(String iface, int type, boolean useBpfStats);
- private static native long nativeGetUidStat(int uid, int type, boolean useBpfStats);
+ private static native long nativeGetTotalStat(int type);
+ private static native long nativeGetIfaceStat(String iface, int type);
+ private static native long nativeGetUidStat(int uid, int type);
}
diff --git a/services/core/java/com/android/server/net/OWNERS b/services/core/java/com/android/server/net/OWNERS
index 28ae6a417bd3..9c96d46f15b8 100644
--- a/services/core/java/com/android/server/net/OWNERS
+++ b/services/core/java/com/android/server/net/OWNERS
@@ -1,11 +1,6 @@
set noparent
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
-codewiz@google.com
-jchalard@google.com
jsharkey@android.com
-junyulai@google.com
-lorenzo@google.com
-reminv@google.com
-satk@google.com
sudheersai@google.com
yamasani@google.com
diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
index 3019439a430b..5643873bef4d 100644
--- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
+++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
@@ -215,7 +215,7 @@ public class DefaultCrossProfileIntentFiltersUtils {
private static final DefaultCrossProfileIntentFilter RECOGNIZE_SPEECH =
new DefaultCrossProfileIntentFilter.Builder(
DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
- /* flags= */0,
+ /* flags= */ ONLY_IF_NO_MATCH_FOUND,
/* letsPersonalDataIntoProfile= */ false)
.addAction(ACTION_RECOGNIZE_SPEECH)
.addCategory(Intent.CATEGORY_DEFAULT)
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 827dfc0caa16..8e18508adc90 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3538,9 +3538,9 @@ public class PackageManagerService extends IPackageManager.Stub
list.addAll(mApexManager.getFactoryPackages());
} else {
list.addAll(mApexManager.getActivePackages());
- }
- if (listUninstalled) {
- list.addAll(mApexManager.getInactivePackages());
+ if (listUninstalled) {
+ list.addAll(mApexManager.getInactivePackages());
+ }
}
}
return new ParceledListSlice<>(list);
@@ -21917,8 +21917,10 @@ public class PackageManagerService extends IPackageManager.Stub
ApexManager.ActiveApexInfo apexInfo) {
for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) {
ScanPartition sp = SYSTEM_PARTITIONS.get(i);
- if (apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
- sp.getFolder().getAbsolutePath())) {
+ if (apexInfo.preInstalledApexPath.getAbsolutePath().equals(
+ sp.getFolder().getAbsolutePath())
+ || apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
+ sp.getFolder().getAbsolutePath() + File.separator)) {
return new ScanPartition(apexInfo.apexDirectory, sp, SCAN_AS_APK_IN_APEX);
}
}
diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS
index 8c1a90c13513..fc0ee23c4859 100644
--- a/services/core/java/com/android/server/pm/permission/OWNERS
+++ b/services/core/java/com/android/server/pm/permission/OWNERS
@@ -1,7 +1,3 @@
include platform/frameworks/base:/core/java/android/permission/OWNERS
-per-file DefaultPermissionGrantPolicy.java = hackbod@android.com
-per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com
-per-file DefaultPermissionGrantPolicy.java = toddke@google.com
-per-file DefaultPermissionGrantPolicy.java = yamasani@google.com
-per-file DefaultPermissionGrantPolicy.java = patb@google.com
+per-file DefaultPermissionGrantPolicy.java = file:platform/frameworks/base:/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index cda48063e914..94e551a11dae 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -480,9 +480,10 @@ public final class Permission {
r.append("DUP:");
r.append(permissionInfo.name);
}
- if (permission.isRuntime() && (ownerChanged || wasNonRuntime)) {
- // If this is a runtime permission and the owner has changed, or this wasn't a runtime
- // permission, then permission state should be cleaned up
+ if ((permission.isInternal() && ownerChanged)
+ || (permission.isRuntime() && (ownerChanged || wasNonRuntime))) {
+ // If this is an internal/runtime permission and the owner has changed, or this wasn't a
+ // runtime permission, then permission state should be cleaned up.
permission.mDefinitionChanged = true;
}
if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 1133faabcf69..7b12709e4efd 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1643,7 +1643,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
isRolePermission = permission.isRole();
}
final boolean mayRevokeRolePermission = isRolePermission
- && mayManageRolePermission(callingUid);
+ // Allow ourselves to revoke role permissions due to definition changes.
+ && (callingUid == Process.myUid() || mayManageRolePermission(callingUid));
final boolean isRuntimePermission;
synchronized (mLock) {
@@ -2321,11 +2322,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
for (int permNum = 0; permNum < numPermissions; permNum++) {
final String permName = permissionsToRevoke.get(permNum);
+ final boolean isInternalPermission;
synchronized (mLock) {
final Permission bp = mRegistry.getPermission(permName);
- if (bp == null || !bp.isRuntime()) {
+ if (bp == null || !(bp.isInternal() || bp.isRuntime())) {
continue;
}
+ isInternalPermission = bp.isInternal();
}
mPackageManagerInt.forEachPackage(pkg -> {
final String packageName = pkg.getPackageName();
@@ -2345,12 +2348,18 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (permissionState == PackageManager.PERMISSION_GRANTED
&& (flags & flagMask) == 0) {
final int uid = UserHandle.getUid(userId, appId);
- EventLog.writeEvent(0x534e4554, "154505240", uid,
- "Revoking permission " + permName + " from package "
- + packageName + " due to definition change");
- EventLog.writeEvent(0x534e4554, "168319670", uid,
- "Revoking permission " + permName + " from package "
- + packageName + " due to definition change");
+ if (isInternalPermission) {
+ EventLog.writeEvent(0x534e4554, "195338390", uid,
+ "Revoking permission " + permName + " from package "
+ + packageName + " due to definition change");
+ } else {
+ EventLog.writeEvent(0x534e4554, "154505240", uid,
+ "Revoking permission " + permName + " from package "
+ + packageName + " due to definition change");
+ EventLog.writeEvent(0x534e4554, "168319670", uid,
+ "Revoking permission " + permName + " from package "
+ + packageName + " due to definition change");
+ }
Slog.e(TAG, "Revoking permission " + permName + " from package "
+ packageName + " due to definition change");
try {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e40882268e67..4a9772093bb7 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2666,6 +2666,24 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Slog.wtf(TAG, "KEYCODE_VOICE_ASSIST should be handled in"
+ " interceptKeyBeforeQueueing");
return key_consumed;
+ case KeyEvent.KEYCODE_VIDEO_APP_1:
+ case KeyEvent.KEYCODE_VIDEO_APP_2:
+ case KeyEvent.KEYCODE_VIDEO_APP_3:
+ case KeyEvent.KEYCODE_VIDEO_APP_4:
+ case KeyEvent.KEYCODE_VIDEO_APP_5:
+ case KeyEvent.KEYCODE_VIDEO_APP_6:
+ case KeyEvent.KEYCODE_VIDEO_APP_7:
+ case KeyEvent.KEYCODE_VIDEO_APP_8:
+ case KeyEvent.KEYCODE_FEATURED_APP_1:
+ case KeyEvent.KEYCODE_FEATURED_APP_2:
+ case KeyEvent.KEYCODE_FEATURED_APP_3:
+ case KeyEvent.KEYCODE_FEATURED_APP_4:
+ case KeyEvent.KEYCODE_DEMO_APP_1:
+ case KeyEvent.KEYCODE_DEMO_APP_2:
+ case KeyEvent.KEYCODE_DEMO_APP_3:
+ case KeyEvent.KEYCODE_DEMO_APP_4:
+ Slog.wtf(TAG, "KEYCODE_APP_X should be handled in interceptKeyBeforeQueueing");
+ return key_consumed;
case KeyEvent.KEYCODE_SYSRQ:
if (down && repeatCount == 0) {
mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);
@@ -3773,6 +3791,26 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
break;
}
+ case KeyEvent.KEYCODE_VIDEO_APP_1:
+ case KeyEvent.KEYCODE_VIDEO_APP_2:
+ case KeyEvent.KEYCODE_VIDEO_APP_3:
+ case KeyEvent.KEYCODE_VIDEO_APP_4:
+ case KeyEvent.KEYCODE_VIDEO_APP_5:
+ case KeyEvent.KEYCODE_VIDEO_APP_6:
+ case KeyEvent.KEYCODE_VIDEO_APP_7:
+ case KeyEvent.KEYCODE_VIDEO_APP_8:
+ case KeyEvent.KEYCODE_FEATURED_APP_1:
+ case KeyEvent.KEYCODE_FEATURED_APP_2:
+ case KeyEvent.KEYCODE_FEATURED_APP_3:
+ case KeyEvent.KEYCODE_FEATURED_APP_4:
+ case KeyEvent.KEYCODE_DEMO_APP_1:
+ case KeyEvent.KEYCODE_DEMO_APP_2:
+ case KeyEvent.KEYCODE_DEMO_APP_3:
+ case KeyEvent.KEYCODE_DEMO_APP_4: {
+ // Just drop if keys are not intercepted for direct key.
+ result &= ~ACTION_PASS_TO_USER;
+ break;
+ }
}
// Intercept the Accessibility keychord (CTRL + ALT + Z) for keyboard users.
diff --git a/services/core/java/com/android/server/stats/bootstrap/StatsBootstrapAtomService.java b/services/core/java/com/android/server/stats/bootstrap/StatsBootstrapAtomService.java
new file mode 100644
index 000000000000..0d420a535415
--- /dev/null
+++ b/services/core/java/com/android/server/stats/bootstrap/StatsBootstrapAtomService.java
@@ -0,0 +1,98 @@
+/*
+ * 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.stats.bootstrap;
+
+import android.content.Context;
+import android.os.IStatsBootstrapAtomService;
+import android.os.StatsBootstrapAtom;
+import android.os.StatsBootstrapAtomValue;
+import android.util.Slog;
+import android.util.StatsEvent;
+import android.util.StatsLog;
+
+import com.android.server.SystemService;
+
+/**
+ * Proxy service for logging pushed atoms to statsd
+ *
+ * @hide
+ */
+public class StatsBootstrapAtomService extends IStatsBootstrapAtomService.Stub {
+
+ private static final String TAG = "StatsBootstrapAtomService";
+ private static final boolean DEBUG = false;
+
+ @Override
+ public void reportBootstrapAtom(StatsBootstrapAtom atom) {
+ if (atom.atomId < 1 || atom.atomId >= 10000) {
+ Slog.e(TAG, "Atom ID " + atom.atomId + " is not a valid atom ID");
+ return;
+ }
+ StatsEvent.Builder builder = StatsEvent.newBuilder().setAtomId(atom.atomId);
+ for (StatsBootstrapAtomValue value : atom.values) {
+ switch (value.getTag()) {
+ case StatsBootstrapAtomValue.boolValue:
+ builder.writeBoolean(value.getBoolValue());
+ break;
+ case StatsBootstrapAtomValue.intValue:
+ builder.writeInt(value.getIntValue());
+ break;
+ case StatsBootstrapAtomValue.longValue:
+ builder.writeLong(value.getLongValue());
+ break;
+ case StatsBootstrapAtomValue.floatValue:
+ builder.writeFloat(value.getFloatValue());
+ break;
+ case StatsBootstrapAtomValue.stringValue:
+ builder.writeString(value.getStringValue());
+ break;
+ case StatsBootstrapAtomValue.bytesValue:
+ builder.writeByteArray(value.getBytesValue());
+ break;
+ default:
+ Slog.e(TAG, "Unexpected value type " + value.getTag()
+ + " when logging atom " + atom.atomId);
+ return;
+
+ }
+ }
+ StatsLog.write(builder.usePooledBuffer().build());
+ }
+
+ /**
+ * Lifecycle and related code
+ */
+ public static final class Lifecycle extends SystemService {
+ private StatsBootstrapAtomService mStatsBootstrapAtomService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mStatsBootstrapAtomService = new StatsBootstrapAtomService();
+ try {
+ publishBinderService(Context.STATS_BOOTSTRAP_ATOM_SERVICE,
+ mStatsBootstrapAtomService);
+ if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_BOOTSTRAP_ATOM_SERVICE);
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to publishBinderService", e);
+ }
+ }
+ }
+
+}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 68b760a1be34..1ef202511452 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -92,7 +92,6 @@ import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.health.V2_0.IHealth;
import android.net.ConnectivityManager;
import android.net.INetworkStatsService;
import android.net.INetworkStatsSession;
@@ -190,13 +189,13 @@ import com.android.internal.os.SystemServerCpuThreadReader.SystemServiceCpuThrea
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.role.RoleManagerLocal;
-import com.android.server.BatteryService;
import com.android.server.BinderCallsStatsService;
import com.android.server.LocalManagerRegistry;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
import com.android.server.am.MemoryStatUtil.MemoryStat;
+import com.android.server.health.HealthServiceWrapper;
import com.android.server.notification.NotificationManagerService;
import com.android.server.stats.pull.IonMemoryUtil.IonAllocations;
import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot;
@@ -226,6 +225,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
+import java.util.NoSuchElementException;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
@@ -354,7 +354,7 @@ public class StatsPullAtomService extends SystemService {
private File mBaseDir;
@GuardedBy("mHealthHalLock")
- private BatteryService.HealthServiceWrapper mHealthService;
+ private HealthServiceWrapper mHealthService;
@Nullable
@GuardedBy("mCpuTimePerThreadFreqLock")
@@ -799,10 +799,9 @@ public class StatsPullAtomService extends SystemService {
KernelCpuThreadReaderSettingsObserver.getSettingsModifiedReader(mContext);
// Initialize HealthService
- mHealthService = new BatteryService.HealthServiceWrapper();
try {
- mHealthService.init();
- } catch (RemoteException e) {
+ mHealthService = HealthServiceWrapper.create(null);
+ } catch (RemoteException | NoSuchElementException e) {
Slog.e(TAG, "failed to initialize healthHalWrapper");
}
@@ -3975,38 +3974,40 @@ public class StatsPullAtomService extends SystemService {
}
int pullHealthHalLocked(int atomTag, List<StatsEvent> pulledData) {
- IHealth healthService = mHealthService.getLastService();
- if (healthService == null) {
+ if (mHealthService == null) {
return StatsManager.PULL_SKIP;
}
+ android.hardware.health.HealthInfo healthInfo;
try {
- healthService.getHealthInfo((result, value) -> {
- int pulledValue;
- switch(atomTag) {
- case FrameworkStatsLog.BATTERY_LEVEL:
- pulledValue = value.legacy.batteryLevel;
- break;
- case FrameworkStatsLog.REMAINING_BATTERY_CAPACITY:
- pulledValue = value.legacy.batteryChargeCounter;
- break;
- case FrameworkStatsLog.FULL_BATTERY_CAPACITY:
- pulledValue = value.legacy.batteryFullCharge;
- break;
- case FrameworkStatsLog.BATTERY_VOLTAGE:
- pulledValue = value.legacy.batteryVoltage;
- break;
- case FrameworkStatsLog.BATTERY_CYCLE_COUNT:
- pulledValue = value.legacy.batteryCycleCount;
- break;
- default:
- throw new IllegalStateException("Invalid atomTag in healthHal puller: "
- + atomTag);
- }
- pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, pulledValue));
- });
+ healthInfo = mHealthService.getHealthInfo();
} catch (RemoteException | IllegalStateException e) {
return StatsManager.PULL_SKIP;
}
+ if (healthInfo == null) {
+ return StatsManager.PULL_SKIP;
+ }
+
+ int pulledValue;
+ switch (atomTag) {
+ case FrameworkStatsLog.BATTERY_LEVEL:
+ pulledValue = healthInfo.batteryLevel;
+ break;
+ case FrameworkStatsLog.REMAINING_BATTERY_CAPACITY:
+ pulledValue = healthInfo.batteryChargeCounterUah;
+ break;
+ case FrameworkStatsLog.FULL_BATTERY_CAPACITY:
+ pulledValue = healthInfo.batteryFullChargeUah;
+ break;
+ case FrameworkStatsLog.BATTERY_VOLTAGE:
+ pulledValue = healthInfo.batteryVoltageMillivolts;
+ break;
+ case FrameworkStatsLog.BATTERY_CYCLE_COUNT:
+ pulledValue = healthInfo.batteryCycleCount;
+ break;
+ default:
+ return StatsManager.PULL_SKIP;
+ }
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, pulledValue));
return StatsManager.PULL_SUCCESS;
}
diff --git a/services/core/java/com/android/server/storage/AppFuseBridge.java b/services/core/java/com/android/server/storage/AppFuseBridge.java
index b00540fd2a52..292314840efb 100644
--- a/services/core/java/com/android/server/storage/AppFuseBridge.java
+++ b/services/core/java/com/android/server/storage/AppFuseBridge.java
@@ -24,7 +24,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.FuseUnavailableMountException;
import com.android.internal.util.Preconditions;
-import com.android.server.NativeDaemonConnectorException;
+import com.android.server.AppFuseMountException;
import libcore.io.IoUtils;
import java.util.concurrent.CountDownLatch;
@@ -55,7 +55,7 @@ public class AppFuseBridge implements Runnable {
}
public ParcelFileDescriptor addBridge(MountScope mountScope)
- throws FuseUnavailableMountException, NativeDaemonConnectorException {
+ throws FuseUnavailableMountException, AppFuseMountException {
/*
** Dead Lock between Java lock (AppFuseBridge.java) and Native lock (FuseBridgeLoop.cc)
**
@@ -112,7 +112,7 @@ public class AppFuseBridge implements Runnable {
try {
int flags = FileUtils.translateModePfdToPosix(mode);
return scope.openFile(mountId, fileId, flags);
- } catch (NativeDaemonConnectorException error) {
+ } catch (AppFuseMountException error) {
throw new FuseUnavailableMountException(mountId);
}
}
@@ -160,9 +160,9 @@ public class AppFuseBridge implements Runnable {
return mMountResult;
}
- public abstract ParcelFileDescriptor open() throws NativeDaemonConnectorException;
+ public abstract ParcelFileDescriptor open() throws AppFuseMountException;
public abstract ParcelFileDescriptor openFile(int mountId, int fileId, int flags)
- throws NativeDaemonConnectorException;
+ throws AppFuseMountException;
}
private native long native_new();
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 36a854e5374c..2f54f302af6c 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -315,6 +315,7 @@ public final class TvInputManagerService extends SystemService {
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
userId);
List<TvInputInfo> inputList = new ArrayList<>();
+ List<ComponentName> hardwareComponents = new ArrayList<>();
for (ResolveInfo ri : services) {
ServiceInfo si = ri.serviceInfo;
if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) {
@@ -325,6 +326,7 @@ public final class TvInputManagerService extends SystemService {
ComponentName component = new ComponentName(si.packageName, si.name);
if (hasHardwarePermission(pm, component)) {
+ hardwareComponents.add(component);
ServiceState serviceState = userState.serviceStateMap.get(component);
if (serviceState == null) {
// New hardware input found. Create a new ServiceState and connect to the
@@ -397,6 +399,15 @@ public final class TvInputManagerService extends SystemService {
}
}
+ // Clean up ServiceState corresponding to the removed hardware inputs
+ Iterator<ServiceState> it = userState.serviceStateMap.values().iterator();
+ while (it.hasNext()) {
+ ServiceState serviceState = it.next();
+ if (serviceState.isHardware && !hardwareComponents.contains(serviceState.component)) {
+ it.remove();
+ }
+ }
+
userState.inputMap.clear();
userState.inputMap = inputMap;
}
@@ -2304,10 +2315,9 @@ public final class TvInputManagerService extends SystemService {
public void requestChannelBrowsable(Uri channelUri, int userId)
throws RemoteException {
final String callingPackageName = getCallingPackageName();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, "requestChannelBrowsable");
final long identity = Binder.clearCallingIdentity();
- final int callingUid = Binder.getCallingUid();
- final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
- userId, "requestChannelBrowsable");
try {
Intent intent = new Intent(TvContract.ACTION_CHANNEL_BROWSABLE_REQUESTED);
List<ResolveInfo> list = getContext().getPackageManager()
@@ -2975,32 +2985,47 @@ public final class TvInputManagerService extends SystemService {
public void addHardwareInput(int deviceId, TvInputInfo inputInfo) {
ensureHardwarePermission();
ensureValidInput(inputInfo);
- synchronized (mLock) {
- mTvInputHardwareManager.addHardwareInput(deviceId, inputInfo);
- addHardwareInputLocked(inputInfo);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ mTvInputHardwareManager.addHardwareInput(deviceId, inputInfo);
+ addHardwareInputLocked(inputInfo);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
public void addHdmiInput(int id, TvInputInfo inputInfo) {
ensureHardwarePermission();
ensureValidInput(inputInfo);
- synchronized (mLock) {
- mTvInputHardwareManager.addHdmiInput(id, inputInfo);
- addHardwareInputLocked(inputInfo);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ mTvInputHardwareManager.addHdmiInput(id, inputInfo);
+ addHardwareInputLocked(inputInfo);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
public void removeHardwareInput(String inputId) {
ensureHardwarePermission();
- synchronized (mLock) {
- ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
- boolean removed = serviceState.hardwareInputMap.remove(inputId) != null;
- if (removed) {
- buildTvInputListLocked(mUserId, null);
- mTvInputHardwareManager.removeHardwareInput(inputId);
- } else {
- Slog.e(TAG, "failed to remove input " + inputId);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
+ boolean removed = serviceState.hardwareInputMap.remove(inputId) != null;
+ if (removed) {
+ buildTvInputListLocked(mUserId, null);
+ mTvInputHardwareManager.removeHardwareInput(inputId);
+ } else {
+ Slog.e(TAG, "failed to remove input " + inputId);
+ }
}
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
}
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 7dec4e785f5c..584530c0f3bd 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -77,6 +77,7 @@ import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.Process;
import android.os.SystemClock;
+import android.provider.Settings;
import android.util.ArraySet;
import android.util.Slog;
@@ -87,9 +88,10 @@ import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.internal.util.WakeupMessage;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
-import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
-import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback;
import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
+import com.android.server.vcn.routeselection.UnderlyingNetworkController;
+import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkControllerCallback;
+import com.android.server.vcn.routeselection.UnderlyingNetworkRecord;
import com.android.server.vcn.util.LogUtils;
import com.android.server.vcn.util.MtuUtils;
import com.android.server.vcn.util.OneWayBoolean;
@@ -98,6 +100,7 @@ import java.io.IOException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
+import java.net.NetworkInterface;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -200,7 +203,7 @@ public class VcnGatewayConnection extends StateMachine {
private interface EventInfo {}
/**
- * Sent when there are changes to the underlying network (per the UnderlyingNetworkTracker).
+ * Sent when there are changes to the underlying network (per the UnderlyingNetworkController).
*
* <p>May indicate an entirely new underlying network, OR a change in network properties.
*
@@ -521,11 +524,14 @@ public class VcnGatewayConnection extends StateMachine {
@NonNull private final VcnContext mVcnContext;
@NonNull private final ParcelUuid mSubscriptionGroup;
- @NonNull private final UnderlyingNetworkTracker mUnderlyingNetworkTracker;
+ @NonNull private final UnderlyingNetworkController mUnderlyingNetworkController;
@NonNull private final VcnGatewayConnectionConfig mConnectionConfig;
@NonNull private final VcnGatewayStatusCallback mGatewayStatusCallback;
@NonNull private final Dependencies mDeps;
- @NonNull private final VcnUnderlyingNetworkTrackerCallback mUnderlyingNetworkTrackerCallback;
+
+ @NonNull
+ private final VcnUnderlyingNetworkControllerCallback mUnderlyingNetworkControllerCallback;
+
private final boolean mIsMobileDataEnabled;
@NonNull private final IpSecManager mIpSecManager;
@@ -673,17 +679,17 @@ public class VcnGatewayConnection extends StateMachine {
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
- mUnderlyingNetworkTrackerCallback = new VcnUnderlyingNetworkTrackerCallback();
+ mUnderlyingNetworkControllerCallback = new VcnUnderlyingNetworkControllerCallback();
mWakeLock =
mDeps.newWakeLock(mVcnContext.getContext(), PowerManager.PARTIAL_WAKE_LOCK, TAG);
- mUnderlyingNetworkTracker =
- mDeps.newUnderlyingNetworkTracker(
+ mUnderlyingNetworkController =
+ mDeps.newUnderlyingNetworkController(
mVcnContext,
subscriptionGroup,
mLastSnapshot,
- mUnderlyingNetworkTrackerCallback);
+ mUnderlyingNetworkControllerCallback);
mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class);
addState(mDisconnectedState);
@@ -747,7 +753,7 @@ public class VcnGatewayConnection extends StateMachine {
cancelRetryTimeoutAlarm();
cancelSafeModeAlarm();
- mUnderlyingNetworkTracker.teardown();
+ mUnderlyingNetworkController.teardown();
mGatewayStatusCallback.onQuit();
}
@@ -763,12 +769,13 @@ public class VcnGatewayConnection extends StateMachine {
mVcnContext.ensureRunningOnLooperThread();
mLastSnapshot = snapshot;
- mUnderlyingNetworkTracker.updateSubscriptionSnapshot(mLastSnapshot);
+ mUnderlyingNetworkController.updateSubscriptionSnapshot(mLastSnapshot);
sendMessageAndAcquireWakeLock(EVENT_SUBSCRIPTIONS_CHANGED, TOKEN_ALL);
}
- private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback {
+ private class VcnUnderlyingNetworkControllerCallback
+ implements UnderlyingNetworkControllerCallback {
@Override
public void onSelectedUnderlyingNetworkChanged(
@Nullable UnderlyingNetworkRecord underlying) {
@@ -782,8 +789,19 @@ public class VcnGatewayConnection extends StateMachine {
// TODO(b/179091925): Move the delayed-message handling to BaseState
// If underlying is null, all underlying networks have been lost. Disconnect VCN after a
- // timeout.
+ // timeout (or immediately if in airplane mode, since the device user has indicated that
+ // the radios should all be turned off).
if (underlying == null) {
+ if (mDeps.isAirplaneModeOn(mVcnContext)) {
+ sendMessageAndAcquireWakeLock(
+ EVENT_UNDERLYING_NETWORK_CHANGED,
+ TOKEN_ALL,
+ new EventUnderlyingNetworkChangedInfo(null));
+ sendDisconnectRequestedAndAcquireWakelock(
+ DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */);
+ return;
+ }
+
setDisconnectRequestAlarm();
} else {
// Received a new Network so any previous alarm is irrelevant - cancel + clear it,
@@ -1663,8 +1681,6 @@ public class VcnGatewayConnection extends StateMachine {
} /* validationStatusCallback */);
agent.register();
- agent.setUnderlyingNetworks(
- mUnderlying == null ? null : Collections.singletonList(mUnderlying.network));
agent.markConnected();
return agent;
@@ -2039,6 +2055,7 @@ public class VcnGatewayConnection extends StateMachine {
"Unknown transport type or missing TransportInfo/NetworkSpecifier for"
+ " non-null underlying network");
}
+ builder.setUnderlyingNetworks(List.of(underlying.network));
} else {
Slog.wtf(
TAG,
@@ -2049,7 +2066,8 @@ public class VcnGatewayConnection extends StateMachine {
return builder.build();
}
- private static LinkProperties buildConnectedLinkProperties(
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ LinkProperties buildConnectedLinkProperties(
@NonNull VcnGatewayConnectionConfig gatewayConnectionConfig,
@NonNull IpSecTunnelInterface tunnelIface,
@NonNull VcnChildSessionConfiguration childConfig,
@@ -2077,6 +2095,13 @@ public class VcnGatewayConnection extends StateMachine {
lp.setTcpBufferSizes(underlyingLp.getTcpBufferSizes());
underlyingMtu = underlyingLp.getMtu();
+
+ // WiFi LinkProperties uses DHCP as the sole source of MTU information, and as a result
+ // often lists MTU as 0 (see b/184678973). Use the interface MTU as retrieved by
+ // NetworkInterface APIs.
+ if (underlyingMtu == 0 && underlyingLp.getInterfaceName() != null) {
+ underlyingMtu = mDeps.getUnderlyingIfaceMtu(underlyingLp.getInterfaceName());
+ }
} else {
Slog.wtf(
TAG,
@@ -2256,7 +2281,7 @@ public class VcnGatewayConnection extends StateMachine {
+ (mNetworkAgent == null ? null : mNetworkAgent.getNetwork()));
pw.println();
- mUnderlyingNetworkTracker.dump(pw);
+ mUnderlyingNetworkController.dump(pw);
pw.println();
pw.decreaseIndent();
@@ -2268,8 +2293,8 @@ public class VcnGatewayConnection extends StateMachine {
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
- UnderlyingNetworkTrackerCallback getUnderlyingNetworkTrackerCallback() {
- return mUnderlyingNetworkTrackerCallback;
+ UnderlyingNetworkControllerCallback getUnderlyingNetworkControllerCallback() {
+ return mUnderlyingNetworkControllerCallback;
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
@@ -2348,17 +2373,14 @@ public class VcnGatewayConnection extends StateMachine {
/** External dependencies used by VcnGatewayConnection, for injection in tests */
@VisibleForTesting(visibility = Visibility.PRIVATE)
public static class Dependencies {
- /** Builds a new UnderlyingNetworkTracker. */
- public UnderlyingNetworkTracker newUnderlyingNetworkTracker(
+ /** Builds a new UnderlyingNetworkController. */
+ public UnderlyingNetworkController newUnderlyingNetworkController(
VcnContext vcnContext,
ParcelUuid subscriptionGroup,
TelephonySubscriptionSnapshot snapshot,
- UnderlyingNetworkTrackerCallback callback) {
- return new UnderlyingNetworkTracker(
- vcnContext,
- subscriptionGroup,
- snapshot,
- callback);
+ UnderlyingNetworkControllerCallback callback) {
+ return new UnderlyingNetworkController(
+ vcnContext, subscriptionGroup, snapshot, callback);
}
/** Builds a new IkeSession. */
@@ -2414,10 +2436,27 @@ public class VcnGatewayConnection extends StateMachine {
validationStatusCallback);
}
+ /** Checks if airplane mode is enabled. */
+ public boolean isAirplaneModeOn(@NonNull VcnContext vcnContext) {
+ return Settings.Global.getInt(vcnContext.getContext().getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
+ }
+
/** Gets the elapsed real time since boot, in millis. */
public long getElapsedRealTime() {
return SystemClock.elapsedRealtime();
}
+
+ /** Gets the MTU for the given underlying interface. */
+ public int getUnderlyingIfaceMtu(String ifaceName) {
+ try {
+ final NetworkInterface underlyingIface = NetworkInterface.getByName(ifaceName);
+ return underlyingIface == null ? 0 : underlyingIface.getMTU();
+ } catch (IOException e) {
+ Slog.d(TAG, "Could not get MTU of underlying network", e);
+ return 0;
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
new file mode 100644
index 000000000000..bea8ae932a9d
--- /dev/null
+++ b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
@@ -0,0 +1,196 @@
+/*
+ * 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.vcn.routeselection;
+
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
+import static com.android.server.VcnManagementService.LOCAL_LOG;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.NetworkCapabilities;
+import android.net.vcn.VcnManager;
+import android.os.ParcelUuid;
+import android.os.PersistableBundle;
+import android.telephony.SubscriptionManager;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+
+import java.util.Set;
+
+/** @hide */
+class NetworkPriorityClassifier {
+ @NonNull private static final String TAG = NetworkPriorityClassifier.class.getSimpleName();
+ /**
+ * Minimum signal strength for a WiFi network to be eligible for switching to
+ *
+ * <p>A network that satisfies this is eligible to become the selected underlying network with
+ * no additional conditions
+ */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final int WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT = -70;
+ /**
+ * Minimum signal strength to continue using a WiFi network
+ *
+ * <p>A network that satisfies the conditions may ONLY continue to be used if it is already
+ * selected as the underlying network. A WiFi network satisfying this condition, but NOT the
+ * prospective-network RSSI threshold CANNOT be switched to.
+ */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final int WIFI_EXIT_RSSI_THRESHOLD_DEFAULT = -74;
+ /** Priority for any cellular network for which the subscription is listed as opportunistic */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final int PRIORITY_OPPORTUNISTIC_CELLULAR = 0;
+ /** Priority for any WiFi network which is in use, and satisfies the in-use RSSI threshold */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final int PRIORITY_WIFI_IN_USE = 1;
+ /** Priority for any WiFi network which satisfies the prospective-network RSSI threshold */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final int PRIORITY_WIFI_PROSPECTIVE = 2;
+ /** Priority for any standard macro cellular network */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final int PRIORITY_MACRO_CELLULAR = 3;
+ /** Priority for any other networks (including unvalidated, etc) */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final int PRIORITY_ANY = Integer.MAX_VALUE;
+
+ private static final SparseArray<String> PRIORITY_TO_STRING_MAP = new SparseArray<>();
+
+ static {
+ PRIORITY_TO_STRING_MAP.put(
+ PRIORITY_OPPORTUNISTIC_CELLULAR, "PRIORITY_OPPORTUNISTIC_CELLULAR");
+ PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_IN_USE, "PRIORITY_WIFI_IN_USE");
+ PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_PROSPECTIVE, "PRIORITY_WIFI_PROSPECTIVE");
+ PRIORITY_TO_STRING_MAP.put(PRIORITY_MACRO_CELLULAR, "PRIORITY_MACRO_CELLULAR");
+ PRIORITY_TO_STRING_MAP.put(PRIORITY_ANY, "PRIORITY_ANY");
+ }
+
+ /**
+ * Gives networks a priority class, based on the following priorities:
+ *
+ * <ol>
+ * <li>Opportunistic cellular
+ * <li>Carrier WiFi, signal strength >= WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT
+ * <li>Carrier WiFi, active network + signal strength >= WIFI_EXIT_RSSI_THRESHOLD_DEFAULT
+ * <li>Macro cellular
+ * <li>Any others
+ * </ol>
+ */
+ static int calculatePriorityClass(
+ UnderlyingNetworkRecord networkRecord,
+ ParcelUuid subscriptionGroup,
+ TelephonySubscriptionSnapshot snapshot,
+ UnderlyingNetworkRecord currentlySelected,
+ PersistableBundle carrierConfig) {
+ final NetworkCapabilities caps = networkRecord.networkCapabilities;
+
+ // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED
+
+ if (networkRecord.isBlocked) {
+ logWtf("Network blocked for System Server: " + networkRecord.network);
+ return PRIORITY_ANY;
+ }
+
+ if (caps.hasTransport(TRANSPORT_CELLULAR)
+ && isOpportunistic(snapshot, caps.getSubscriptionIds())) {
+ // If this carrier is the active data provider, ensure that opportunistic is only
+ // ever prioritized if it is also the active data subscription. This ensures that
+ // if an opportunistic subscription is still in the process of being switched to,
+ // or switched away from, the VCN does not attempt to continue using it against the
+ // decision made at the telephony layer. Failure to do so may result in the modem
+ // switching back and forth.
+ //
+ // Allow the following two cases:
+ // 1. Active subId is NOT in the group that this VCN is supporting
+ // 2. This opportunistic subscription is for the active subId
+ if (!snapshot.getAllSubIdsInGroup(subscriptionGroup)
+ .contains(SubscriptionManager.getActiveDataSubscriptionId())
+ || caps.getSubscriptionIds()
+ .contains(SubscriptionManager.getActiveDataSubscriptionId())) {
+ return PRIORITY_OPPORTUNISTIC_CELLULAR;
+ }
+ }
+
+ if (caps.hasTransport(TRANSPORT_WIFI)) {
+ if (caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig)
+ && currentlySelected != null
+ && networkRecord.network.equals(currentlySelected.network)) {
+ return PRIORITY_WIFI_IN_USE;
+ }
+
+ if (caps.getSignalStrength() >= getWifiEntryRssiThreshold(carrierConfig)) {
+ return PRIORITY_WIFI_PROSPECTIVE;
+ }
+ }
+
+ // Disallow opportunistic subscriptions from matching PRIORITY_MACRO_CELLULAR, as might
+ // be the case when Default Data SubId (CBRS) != Active Data SubId (MACRO), as might be
+ // the case if the Default Data SubId does not support certain services (eg voice
+ // calling)
+ if (caps.hasTransport(TRANSPORT_CELLULAR)
+ && !isOpportunistic(snapshot, caps.getSubscriptionIds())) {
+ return PRIORITY_MACRO_CELLULAR;
+ }
+
+ return PRIORITY_ANY;
+ }
+
+ static boolean isOpportunistic(
+ @NonNull TelephonySubscriptionSnapshot snapshot, Set<Integer> subIds) {
+ if (snapshot == null) {
+ logWtf("Got null snapshot");
+ return false;
+ }
+ for (int subId : subIds) {
+ if (snapshot.isOpportunistic(subId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static int getWifiEntryRssiThreshold(@Nullable PersistableBundle carrierConfig) {
+ if (carrierConfig != null) {
+ return carrierConfig.getInt(
+ VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY,
+ WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT);
+ }
+ return WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT;
+ }
+
+ static int getWifiExitRssiThreshold(@Nullable PersistableBundle carrierConfig) {
+ if (carrierConfig != null) {
+ return carrierConfig.getInt(
+ VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY,
+ WIFI_EXIT_RSSI_THRESHOLD_DEFAULT);
+ }
+ return WIFI_EXIT_RSSI_THRESHOLD_DEFAULT;
+ }
+
+ static String priorityClassToString(int priorityClass) {
+ return PRIORITY_TO_STRING_MAP.get(priorityClass, "unknown");
+ }
+
+ private static void logWtf(String msg) {
+ Slog.wtf(TAG, msg);
+ LOCAL_LOG.log(TAG + " WTF: " + msg);
+ }
+}
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
index 7ddd1355a2d6..071c7a683cbf 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-package com.android.server.vcn;
+package com.android.server.vcn.routeselection;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
import static com.android.server.VcnManagementService.LOCAL_LOG;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.getWifiEntryRssiThreshold;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.getWifiExitRssiThreshold;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.isOpportunistic;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -31,27 +32,23 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.TelephonyNetworkSpecifier;
-import android.net.vcn.VcnManager;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
-import android.telephony.SubscriptionManager;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.Slog;
-import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import com.android.server.vcn.VcnContext;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -61,68 +58,18 @@ import java.util.TreeSet;
/**
* Tracks a set of Networks underpinning a VcnGatewayConnection.
*
- * <p>A single UnderlyingNetworkTracker is built to serve a SINGLE VCN Gateway Connection, and MUST
- * be torn down with the VcnGatewayConnection in order to ensure underlying networks are allowed to
- * be reaped.
+ * <p>A single UnderlyingNetworkController is built to serve a SINGLE VCN Gateway Connection, and
+ * MUST be torn down with the VcnGatewayConnection in order to ensure underlying networks are
+ * allowed to be reaped.
*
* @hide
*/
-public class UnderlyingNetworkTracker {
- @NonNull private static final String TAG = UnderlyingNetworkTracker.class.getSimpleName();
-
- /**
- * Minimum signal strength for a WiFi network to be eligible for switching to
- *
- * <p>A network that satisfies this is eligible to become the selected underlying network with
- * no additional conditions
- */
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- static final int WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT = -70;
-
- /**
- * Minimum signal strength to continue using a WiFi network
- *
- * <p>A network that satisfies the conditions may ONLY continue to be used if it is already
- * selected as the underlying network. A WiFi network satisfying this condition, but NOT the
- * prospective-network RSSI threshold CANNOT be switched to.
- */
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- static final int WIFI_EXIT_RSSI_THRESHOLD_DEFAULT = -74;
-
- /** Priority for any cellular network for which the subscription is listed as opportunistic */
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- static final int PRIORITY_OPPORTUNISTIC_CELLULAR = 0;
-
- /** Priority for any WiFi network which is in use, and satisfies the in-use RSSI threshold */
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- static final int PRIORITY_WIFI_IN_USE = 1;
-
- /** Priority for any WiFi network which satisfies the prospective-network RSSI threshold */
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- static final int PRIORITY_WIFI_PROSPECTIVE = 2;
-
- /** Priority for any standard macro cellular network */
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- static final int PRIORITY_MACRO_CELLULAR = 3;
-
- /** Priority for any other networks (including unvalidated, etc) */
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- static final int PRIORITY_ANY = Integer.MAX_VALUE;
-
- private static final SparseArray<String> PRIORITY_TO_STRING_MAP = new SparseArray<>();
-
- static {
- PRIORITY_TO_STRING_MAP.put(
- PRIORITY_OPPORTUNISTIC_CELLULAR, "PRIORITY_OPPORTUNISTIC_CELLULAR");
- PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_IN_USE, "PRIORITY_WIFI_IN_USE");
- PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_PROSPECTIVE, "PRIORITY_WIFI_PROSPECTIVE");
- PRIORITY_TO_STRING_MAP.put(PRIORITY_MACRO_CELLULAR, "PRIORITY_MACRO_CELLULAR");
- PRIORITY_TO_STRING_MAP.put(PRIORITY_ANY, "PRIORITY_ANY");
- }
+public class UnderlyingNetworkController {
+ @NonNull private static final String TAG = UnderlyingNetworkController.class.getSimpleName();
@NonNull private final VcnContext mVcnContext;
@NonNull private final ParcelUuid mSubscriptionGroup;
- @NonNull private final UnderlyingNetworkTrackerCallback mCb;
+ @NonNull private final UnderlyingNetworkControllerCallback mCb;
@NonNull private final Dependencies mDeps;
@NonNull private final Handler mHandler;
@NonNull private final ConnectivityManager mConnectivityManager;
@@ -142,11 +89,11 @@ public class UnderlyingNetworkTracker {
@Nullable private UnderlyingNetworkRecord mCurrentRecord;
@Nullable private UnderlyingNetworkRecord.Builder mRecordInProgress;
- public UnderlyingNetworkTracker(
+ public UnderlyingNetworkController(
@NonNull VcnContext vcnContext,
@NonNull ParcelUuid subscriptionGroup,
@NonNull TelephonySubscriptionSnapshot snapshot,
- @NonNull UnderlyingNetworkTrackerCallback cb) {
+ @NonNull UnderlyingNetworkControllerCallback cb) {
this(
vcnContext,
subscriptionGroup,
@@ -155,11 +102,11 @@ public class UnderlyingNetworkTracker {
new Dependencies());
}
- private UnderlyingNetworkTracker(
+ private UnderlyingNetworkController(
@NonNull VcnContext vcnContext,
@NonNull ParcelUuid subscriptionGroup,
@NonNull TelephonySubscriptionSnapshot snapshot,
- @NonNull UnderlyingNetworkTrackerCallback cb,
+ @NonNull UnderlyingNetworkControllerCallback cb,
@NonNull Dependencies deps) {
mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext");
mSubscriptionGroup = Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup");
@@ -271,8 +218,8 @@ public class UnderlyingNetworkTracker {
* subscription group, while the VCN networks are excluded by virtue of not having subIds set on
* the VCN-exposed networks.
*
- * <p>If the VCN that this UnderlyingNetworkTracker belongs to is in test-mode, this will return
- * a NetworkRequest that only matches Test Networks.
+ * <p>If the VCN that this UnderlyingNetworkController belongs to is in test-mode, this will
+ * return a NetworkRequest that only matches Test Networks.
*/
private NetworkRequest getRouteSelectionRequest() {
if (mVcnContext.isInTestMode()) {
@@ -373,9 +320,9 @@ public class UnderlyingNetworkTracker {
}
/**
- * Update this UnderlyingNetworkTracker's TelephonySubscriptionSnapshot.
+ * Update this UnderlyingNetworkController's TelephonySubscriptionSnapshot.
*
- * <p>Updating the TelephonySubscriptionSnapshot will cause this UnderlyingNetworkTracker to
+ * <p>Updating the TelephonySubscriptionSnapshot will cause this UnderlyingNetworkController to
* reevaluate its NetworkBringupCallbacks. This may result in NetworkRequests being registered
* or unregistered if the subIds mapped to the this Tracker's SubscriptionGroup change.
*/
@@ -410,7 +357,7 @@ public class UnderlyingNetworkTracker {
private void reevaluateNetworks() {
if (mIsQuitting || mRouteSelectionCallback == null) {
- return; // UnderlyingNetworkTracker has quit.
+ return; // UnderlyingNetworkController has quit.
}
TreeSet<UnderlyingNetworkRecord> sorted =
@@ -424,22 +371,6 @@ public class UnderlyingNetworkTracker {
mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord);
}
- private static boolean isOpportunistic(
- @NonNull TelephonySubscriptionSnapshot snapshot, Set<Integer> subIds) {
- if (snapshot == null) {
- logWtf("Got null snapshot");
- return false;
- }
-
- for (int subId : subIds) {
- if (snapshot.isOpportunistic(subId)) {
- return true;
- }
- }
-
- return false;
- }
-
/**
* NetworkBringupCallback is used to keep background, VCN-managed Networks from being reaped.
*
@@ -544,230 +475,6 @@ public class UnderlyingNetworkTracker {
}
}
- private static int getWifiEntryRssiThreshold(@Nullable PersistableBundle carrierConfig) {
- if (carrierConfig != null) {
- return carrierConfig.getInt(
- VcnManager.VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY,
- WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT);
- }
-
- return WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT;
- }
-
- private static int getWifiExitRssiThreshold(@Nullable PersistableBundle carrierConfig) {
- if (carrierConfig != null) {
- return carrierConfig.getInt(
- VcnManager.VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY,
- WIFI_EXIT_RSSI_THRESHOLD_DEFAULT);
- }
-
- return WIFI_EXIT_RSSI_THRESHOLD_DEFAULT;
- }
-
- /** A record of a single underlying network, caching relevant fields. */
- public static class UnderlyingNetworkRecord {
- @NonNull public final Network network;
- @NonNull public final NetworkCapabilities networkCapabilities;
- @NonNull public final LinkProperties linkProperties;
- public final boolean isBlocked;
-
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- UnderlyingNetworkRecord(
- @NonNull Network network,
- @NonNull NetworkCapabilities networkCapabilities,
- @NonNull LinkProperties linkProperties,
- boolean isBlocked) {
- this.network = network;
- this.networkCapabilities = networkCapabilities;
- this.linkProperties = linkProperties;
- this.isBlocked = isBlocked;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof UnderlyingNetworkRecord)) return false;
- final UnderlyingNetworkRecord that = (UnderlyingNetworkRecord) o;
-
- return network.equals(that.network)
- && networkCapabilities.equals(that.networkCapabilities)
- && linkProperties.equals(that.linkProperties)
- && isBlocked == that.isBlocked;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(network, networkCapabilities, linkProperties, isBlocked);
- }
-
- /**
- * Gives networks a priority class, based on the following priorities:
- *
- * <ol>
- * <li>Opportunistic cellular
- * <li>Carrier WiFi, signal strength >= WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT
- * <li>Carrier WiFi, active network + signal strength >= WIFI_EXIT_RSSI_THRESHOLD_DEFAULT
- * <li>Macro cellular
- * <li>Any others
- * </ol>
- */
- private int calculatePriorityClass(
- ParcelUuid subscriptionGroup,
- TelephonySubscriptionSnapshot snapshot,
- UnderlyingNetworkRecord currentlySelected,
- PersistableBundle carrierConfig) {
- final NetworkCapabilities caps = networkCapabilities;
-
- // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED
-
- if (isBlocked) {
- logWtf("Network blocked for System Server: " + network);
- return PRIORITY_ANY;
- }
-
- if (caps.hasTransport(TRANSPORT_CELLULAR)
- && isOpportunistic(snapshot, caps.getSubscriptionIds())) {
- // If this carrier is the active data provider, ensure that opportunistic is only
- // ever prioritized if it is also the active data subscription. This ensures that
- // if an opportunistic subscription is still in the process of being switched to,
- // or switched away from, the VCN does not attempt to continue using it against the
- // decision made at the telephony layer. Failure to do so may result in the modem
- // switching back and forth.
- //
- // Allow the following two cases:
- // 1. Active subId is NOT in the group that this VCN is supporting
- // 2. This opportunistic subscription is for the active subId
- if (!snapshot.getAllSubIdsInGroup(subscriptionGroup)
- .contains(SubscriptionManager.getActiveDataSubscriptionId())
- || caps.getSubscriptionIds()
- .contains(SubscriptionManager.getActiveDataSubscriptionId())) {
- return PRIORITY_OPPORTUNISTIC_CELLULAR;
- }
- }
-
- if (caps.hasTransport(TRANSPORT_WIFI)) {
- if (caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig)
- && currentlySelected != null
- && network.equals(currentlySelected.network)) {
- return PRIORITY_WIFI_IN_USE;
- }
-
- if (caps.getSignalStrength() >= getWifiEntryRssiThreshold(carrierConfig)) {
- return PRIORITY_WIFI_PROSPECTIVE;
- }
- }
-
- // Disallow opportunistic subscriptions from matching PRIORITY_MACRO_CELLULAR, as might
- // be the case when Default Data SubId (CBRS) != Active Data SubId (MACRO), as might be
- // the case if the Default Data SubId does not support certain services (eg voice
- // calling)
- if (caps.hasTransport(TRANSPORT_CELLULAR)
- && !isOpportunistic(snapshot, caps.getSubscriptionIds())) {
- return PRIORITY_MACRO_CELLULAR;
- }
-
- return PRIORITY_ANY;
- }
-
- private static Comparator<UnderlyingNetworkRecord> getComparator(
- ParcelUuid subscriptionGroup,
- TelephonySubscriptionSnapshot snapshot,
- UnderlyingNetworkRecord currentlySelected,
- PersistableBundle carrierConfig) {
- return (left, right) -> {
- return Integer.compare(
- left.calculatePriorityClass(
- subscriptionGroup, snapshot, currentlySelected, carrierConfig),
- right.calculatePriorityClass(
- subscriptionGroup, snapshot, currentlySelected, carrierConfig));
- };
- }
-
- /** Dumps the state of this record for logging and debugging purposes. */
- private void dump(
- IndentingPrintWriter pw,
- ParcelUuid subscriptionGroup,
- TelephonySubscriptionSnapshot snapshot,
- UnderlyingNetworkRecord currentlySelected,
- PersistableBundle carrierConfig) {
- pw.println("UnderlyingNetworkRecord:");
- pw.increaseIndent();
-
- final int priorityClass =
- calculatePriorityClass(
- subscriptionGroup, snapshot, currentlySelected, carrierConfig);
- pw.println(
- "Priority class: " + PRIORITY_TO_STRING_MAP.get(priorityClass) + " ("
- + priorityClass + ")");
- pw.println("mNetwork: " + network);
- pw.println("mNetworkCapabilities: " + networkCapabilities);
- pw.println("mLinkProperties: " + linkProperties);
-
- pw.decreaseIndent();
- }
-
- /** Builder to incrementally construct an UnderlyingNetworkRecord. */
- private static class Builder {
- @NonNull private final Network mNetwork;
-
- @Nullable private NetworkCapabilities mNetworkCapabilities;
- @Nullable private LinkProperties mLinkProperties;
- boolean mIsBlocked;
- boolean mWasIsBlockedSet;
-
- @Nullable private UnderlyingNetworkRecord mCached;
-
- private Builder(@NonNull Network network) {
- mNetwork = network;
- }
-
- @NonNull
- private Network getNetwork() {
- return mNetwork;
- }
-
- private void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
- mNetworkCapabilities = networkCapabilities;
- mCached = null;
- }
-
- @Nullable
- private NetworkCapabilities getNetworkCapabilities() {
- return mNetworkCapabilities;
- }
-
- private void setLinkProperties(@NonNull LinkProperties linkProperties) {
- mLinkProperties = linkProperties;
- mCached = null;
- }
-
- private void setIsBlocked(boolean isBlocked) {
- mIsBlocked = isBlocked;
- mWasIsBlockedSet = true;
- mCached = null;
- }
-
- private boolean isValid() {
- return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet;
- }
-
- private UnderlyingNetworkRecord build() {
- if (!isValid()) {
- throw new IllegalArgumentException(
- "Called build before UnderlyingNetworkRecord was valid");
- }
-
- if (mCached == null) {
- mCached =
- new UnderlyingNetworkRecord(
- mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked);
- }
-
- return mCached;
- }
- }
- }
-
private static void logWtf(String msg) {
Slog.wtf(TAG, msg);
LOCAL_LOG.log(TAG + " WTF: " + msg);
@@ -780,7 +487,7 @@ public class UnderlyingNetworkTracker {
/** Dumps the state of this record for logging and debugging purposes. */
public void dump(IndentingPrintWriter pw) {
- pw.println("UnderlyingNetworkTracker:");
+ pw.println("UnderlyingNetworkController:");
pw.increaseIndent();
pw.println("Carrier WiFi Entry Threshold: " + getWifiEntryRssiThreshold(mCarrierConfig));
@@ -811,7 +518,7 @@ public class UnderlyingNetworkTracker {
}
/** Callbacks for being notified of the changes in, or to the selected underlying network. */
- public interface UnderlyingNetworkTrackerCallback {
+ public interface UnderlyingNetworkControllerCallback {
/**
* Fired when a new underlying network is selected, or properties have changed.
*
diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java
new file mode 100644
index 000000000000..65c69dedcb28
--- /dev/null
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java
@@ -0,0 +1,175 @@
+/*
+ * 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.vcn.routeselection;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.os.ParcelUuid;
+import android.os.PersistableBundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+
+import java.util.Comparator;
+import java.util.Objects;
+
+/**
+ * A record of a single underlying network, caching relevant fields.
+ *
+ * @hide
+ */
+public class UnderlyingNetworkRecord {
+ @NonNull public final Network network;
+ @NonNull public final NetworkCapabilities networkCapabilities;
+ @NonNull public final LinkProperties linkProperties;
+ public final boolean isBlocked;
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public UnderlyingNetworkRecord(
+ @NonNull Network network,
+ @NonNull NetworkCapabilities networkCapabilities,
+ @NonNull LinkProperties linkProperties,
+ boolean isBlocked) {
+ this.network = network;
+ this.networkCapabilities = networkCapabilities;
+ this.linkProperties = linkProperties;
+ this.isBlocked = isBlocked;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof UnderlyingNetworkRecord)) return false;
+ final UnderlyingNetworkRecord that = (UnderlyingNetworkRecord) o;
+
+ return network.equals(that.network)
+ && networkCapabilities.equals(that.networkCapabilities)
+ && linkProperties.equals(that.linkProperties)
+ && isBlocked == that.isBlocked;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(network, networkCapabilities, linkProperties, isBlocked);
+ }
+
+ static Comparator<UnderlyingNetworkRecord> getComparator(
+ ParcelUuid subscriptionGroup,
+ TelephonySubscriptionSnapshot snapshot,
+ UnderlyingNetworkRecord currentlySelected,
+ PersistableBundle carrierConfig) {
+ return (left, right) -> {
+ return Integer.compare(
+ NetworkPriorityClassifier.calculatePriorityClass(
+ left, subscriptionGroup, snapshot, currentlySelected, carrierConfig),
+ NetworkPriorityClassifier.calculatePriorityClass(
+ right, subscriptionGroup, snapshot, currentlySelected, carrierConfig));
+ };
+ }
+
+ /** Dumps the state of this record for logging and debugging purposes. */
+ void dump(
+ IndentingPrintWriter pw,
+ ParcelUuid subscriptionGroup,
+ TelephonySubscriptionSnapshot snapshot,
+ UnderlyingNetworkRecord currentlySelected,
+ PersistableBundle carrierConfig) {
+ pw.println("UnderlyingNetworkRecord:");
+ pw.increaseIndent();
+
+ final int priorityClass =
+ NetworkPriorityClassifier.calculatePriorityClass(
+ this, subscriptionGroup, snapshot, currentlySelected, carrierConfig);
+ pw.println(
+ "Priority class: "
+ + NetworkPriorityClassifier.priorityClassToString(priorityClass)
+ + " ("
+ + priorityClass
+ + ")");
+ pw.println("mNetwork: " + network);
+ pw.println("mNetworkCapabilities: " + networkCapabilities);
+ pw.println("mLinkProperties: " + linkProperties);
+
+ pw.decreaseIndent();
+ }
+
+ /** Builder to incrementally construct an UnderlyingNetworkRecord. */
+ static class Builder {
+ @NonNull private final Network mNetwork;
+
+ @Nullable private NetworkCapabilities mNetworkCapabilities;
+ @Nullable private LinkProperties mLinkProperties;
+ boolean mIsBlocked;
+ boolean mWasIsBlockedSet;
+
+ @Nullable private UnderlyingNetworkRecord mCached;
+
+ Builder(@NonNull Network network) {
+ mNetwork = network;
+ }
+
+ @NonNull
+ Network getNetwork() {
+ return mNetwork;
+ }
+
+ void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
+ mNetworkCapabilities = networkCapabilities;
+ mCached = null;
+ }
+
+ @Nullable
+ NetworkCapabilities getNetworkCapabilities() {
+ return mNetworkCapabilities;
+ }
+
+ void setLinkProperties(@NonNull LinkProperties linkProperties) {
+ mLinkProperties = linkProperties;
+ mCached = null;
+ }
+
+ void setIsBlocked(boolean isBlocked) {
+ mIsBlocked = isBlocked;
+ mWasIsBlockedSet = true;
+ mCached = null;
+ }
+
+ boolean isValid() {
+ return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet;
+ }
+
+ UnderlyingNetworkRecord build() {
+ if (!isValid()) {
+ throw new IllegalArgumentException(
+ "Called build before UnderlyingNetworkRecord was valid");
+ }
+
+ if (mCached == null) {
+ mCached =
+ new UnderlyingNetworkRecord(
+ mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked);
+ }
+
+ return mCached;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java b/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
index 5c1b5ffb2209..1c675c228554 100644
--- a/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
+++ b/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
@@ -46,6 +46,7 @@ public class PersistableBundleUtils {
private static final String PARCEL_UUID_KEY = "PARCEL_UUID";
private static final String BYTE_ARRAY_KEY = "BYTE_ARRAY_KEY";
private static final String INTEGER_KEY = "INTEGER_KEY";
+ private static final String STRING_KEY = "STRING_KEY";
/**
* Functional interface to convert an object of the specified type to a PersistableBundle.
@@ -91,6 +92,21 @@ public class PersistableBundleUtils {
return bundle.getInt(INTEGER_KEY);
};
+ /** Serializer to convert s String to a PersistableBundle. */
+ public static final Serializer<String> STRING_SERIALIZER =
+ (i) -> {
+ final PersistableBundle result = new PersistableBundle();
+ result.putString(STRING_KEY, i);
+ return result;
+ };
+
+ /** Deserializer to convert a PersistableBundle to a String. */
+ public static final Deserializer<String> STRING_DESERIALIZER =
+ (bundle) -> {
+ Objects.requireNonNull(bundle, "PersistableBundle is null");
+ return bundle.getString(STRING_KEY);
+ };
+
/**
* Converts a ParcelUuid to a PersistableBundle.
*
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index bbea094ba2e3..d1f21778177d 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -140,6 +140,7 @@ import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING;
import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START;
import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN;
import static com.android.server.wm.ActivityRecordProto.LAST_SURFACE_SHOWING;
+import static com.android.server.wm.ActivityRecordProto.MIN_ASPECT_RATIO;
import static com.android.server.wm.ActivityRecordProto.NAME;
import static com.android.server.wm.ActivityRecordProto.NUM_DRAWN_WINDOWS;
import static com.android.server.wm.ActivityRecordProto.NUM_INTERESTING_WINDOWS;
@@ -656,6 +657,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean mLastImeShown;
/**
+ * When set to true, the IME insets will be frozen until the next app becomes IME input target.
+ * @see InsetsPolicy#adjustVisibilityForIme
+ */
+ boolean mImeInsetsFrozenUntilStartInput;
+
+ /**
* A flag to determine if this AR is in the process of closing or entering PIP. This is needed
* to help AR know that the app is in the process of closing but hasn't yet started closing on
* the WM side.
@@ -1357,6 +1364,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
if (newTask != null && isState(RESUMED)) {
newTask.setResumedActivity(this, "onParentChanged");
+ mImeInsetsFrozenUntilStartInput = false;
}
if (rootTask != null && rootTask.topRunningActivity() == this) {
@@ -4767,6 +4775,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
&& imeInputTarget.getWindow().mActivityRecord == this
&& mDisplayContent.mInputMethodWindow != null
&& mDisplayContent.mInputMethodWindow.isVisible();
+ mImeInsetsFrozenUntilStartInput = true;
}
final DisplayContent displayContent = getDisplayContent();
@@ -5885,6 +5894,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// closing activity having to wait until idle timeout to be stopped or destroyed if the
// next activity won't report idle (e.g. repeated view animation).
mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
+
+ // If the activity is visible, but no windows are eligible to start input, unfreeze
+ // to avoid permanently frozen IME insets.
+ if (mImeInsetsFrozenUntilStartInput && getWindow(
+ win -> WindowManager.LayoutParams.mayUseInputMethod(win.mAttrs.flags))
+ == null) {
+ mImeInsetsFrozenUntilStartInput = false;
+ }
}
}
@@ -7800,6 +7817,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
+ @Override
+ void onResize() {
+ // Reset freezing IME insets flag when the activity resized.
+ mImeInsetsFrozenUntilStartInput = false;
+ super.onResize();
+ }
+
/** Returns true if the configuration is compatible with this activity. */
boolean isConfigurationCompatible(Configuration config) {
final int orientation = getRequestedOrientation();
@@ -8649,6 +8673,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled());
proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode());
+ proto.write(MIN_ASPECT_RATIO, info.getMinAspectRatio());
}
@Override
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index dbc1116ad389..9335846e7805 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1165,10 +1165,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
- WindowToken removeWindowToken(IBinder binder) {
+ WindowToken removeWindowToken(IBinder binder, boolean animateExit) {
final WindowToken token = mTokenMap.remove(binder);
if (token != null && token.asActivityRecord() == null) {
- token.setExiting();
+ token.setExiting(animateExit);
}
return token;
}
@@ -1252,7 +1252,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
void removeAppToken(IBinder binder) {
- final WindowToken token = removeWindowToken(binder);
+ final WindowToken token = removeWindowToken(binder, true /* animateExit */);
if (token == null) {
Slog.w(TAG_WM, "removeAppToken: Attempted to remove non-existing token: " + binder);
return;
@@ -3971,6 +3971,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
void updateImeInputAndControlTarget(WindowState target) {
if (mImeInputTarget != target) {
ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target);
+ if (target != null && target.mActivityRecord != null) {
+ target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false;
+ }
setImeInputTarget(target);
updateImeControlTarget();
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index f2f192686ad5..a8e1c1cda72b 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -211,7 +211,7 @@ class InsetsPolicy {
InsetsState getInsetsForWindow(WindowState target) {
final InsetsState originalState = mStateController.getInsetsForWindow(target);
final InsetsState state = adjustVisibilityForTransientTypes(originalState);
- return target.mIsImWindow ? adjustVisibilityForIme(state, state == originalState) : state;
+ return adjustVisibilityForIme(target, state, state == originalState);
}
/**
@@ -241,16 +241,37 @@ class InsetsPolicy {
return state;
}
- // Navigation bar insets is always visible to IME.
- private static InsetsState adjustVisibilityForIme(InsetsState originalState,
+ private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState,
boolean copyState) {
- final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR);
- if (originalNavSource != null && !originalNavSource.isVisible()) {
- final InsetsState state = copyState ? new InsetsState(originalState) : originalState;
- final InsetsSource navSource = new InsetsSource(originalNavSource);
- navSource.setVisible(true);
- state.addSource(navSource);
- return state;
+ if (w.mIsImWindow) {
+ // Navigation bar insets is always visible to IME.
+ final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR);
+ if (originalNavSource != null && !originalNavSource.isVisible()) {
+ final InsetsState state = copyState ? new InsetsState(originalState)
+ : originalState;
+ final InsetsSource navSource = new InsetsSource(originalNavSource);
+ navSource.setVisible(true);
+ state.addSource(navSource);
+ return state;
+ }
+ } else if (w.mActivityRecord != null && w.mActivityRecord.mImeInsetsFrozenUntilStartInput) {
+ // During switching tasks with gestural navigation, if the IME is attached to
+ // one app window on that time, even the next app window is behind the IME window,
+ // conceptually the window should not receive the IME insets if the next window is
+ // not eligible IME requester and ready to show IME on top of it.
+ final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp();
+ final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME);
+
+ if (shouldImeAttachedToApp && originalImeSource != null) {
+ final boolean imeVisibility =
+ w.mActivityRecord.mLastImeShown || w.getRequestedVisibility(ITYPE_IME);
+ final InsetsState state = copyState ? new InsetsState(originalState)
+ : originalState;
+ final InsetsSource imeSource = new InsetsSource(originalImeSource);
+ imeSource.setVisible(imeVisibility);
+ state.addSource(imeSource);
+ return state;
+ }
}
return originalState;
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index fe1020c86041..a7216da9bed5 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -190,8 +190,7 @@ class KeyguardController {
if (keyguardChanged) {
// Irrelevant to AOD.
- dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */,
- false /* turningScreenOn */);
+ dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */);
mKeyguardGoingAway = false;
if (keyguardShowing) {
mDismissalRequested = false;
@@ -385,6 +384,8 @@ class KeyguardController {
mService.continueWindowLayout();
}
}
+ dismissMultiWindowModeForTaskIfNeeded(topActivity != null
+ ? topActivity.getRootTask() : null);
}
/**
@@ -410,21 +411,6 @@ class KeyguardController {
}
}
- /**
- * Called when somebody wants to turn screen on.
- */
- private void handleTurnScreenOn(int displayId) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
-
- mTaskSupervisor.wakeUp("handleTurnScreenOn");
- if (mKeyguardShowing && canDismissKeyguard()) {
- mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
- mDismissalRequested = true;
- }
- }
-
boolean isDisplayOccluded(int displayId) {
return getDisplayState(displayId).mOccluded;
}
@@ -438,11 +424,9 @@ class KeyguardController {
}
private void dismissMultiWindowModeForTaskIfNeeded(
- @Nullable Task currentTaskControllingOcclusion, boolean turningScreenOn) {
- // If turningScreenOn is true, it means that the visibility state has changed from
- // currentTaskControllingOcclusion and we should update windowing mode.
+ @Nullable Task currentTaskControllingOcclusion) {
// TODO(b/113840485): Handle docked stack for individual display.
- if (!turningScreenOn && (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY))) {
+ if (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY)) {
return;
}
@@ -581,26 +565,17 @@ class KeyguardController {
&& controller.mWindowManager.isKeyguardSecure(
controller.mService.getCurrentUserId());
- boolean occludingChange = false;
- boolean turningScreenOn = false;
if (mTopTurnScreenOnActivity != lastTurnScreenOnActivity
&& mTopTurnScreenOnActivity != null
&& !mService.mWindowManager.mPowerManager.isInteractive()
- && (mRequestDismissKeyguard || occludedByActivity
- || controller.canDismissKeyguard())) {
- turningScreenOn = true;
- controller.handleTurnScreenOn(mDisplayId);
+ && (mRequestDismissKeyguard || occludedByActivity)) {
+ controller.mTaskSupervisor.wakeUp("handleTurnScreenOn");
mTopTurnScreenOnActivity.setCurrentLaunchCanTurnScreenOn(false);
}
if (lastOccluded != mOccluded) {
- occludingChange = true;
controller.handleOccludedChanged(mDisplayId, mTopOccludesActivity);
}
-
- if (occludingChange || turningScreenOn) {
- controller.dismissMultiWindowModeForTaskIfNeeded(task, turningScreenOn);
- }
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index e74371036619..a518222c3bde 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -118,6 +118,11 @@ class TaskSnapshotController {
*/
private final boolean mIsRunningOnWear;
+ /**
+ * Flag indicating if device configuration has disabled app snapshots.
+ */
+ private final boolean mConfigDisableTaskSnapshots;
+
TaskSnapshotController(WindowManagerService service) {
mService = service;
mPersister = new TaskSnapshotPersister(mService, Environment::getDataSystemCeDirectory);
@@ -131,6 +136,8 @@ class TaskSnapshotController {
PackageManager.FEATURE_WATCH);
mHighResTaskSnapshotScale = mService.mContext.getResources().getFloat(
com.android.internal.R.dimen.config_highResTaskSnapshotScale);
+ mConfigDisableTaskSnapshots = mService.mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_disableTaskSnapshots);
}
void systemReady() {
@@ -488,7 +495,8 @@ class TaskSnapshotController {
}
boolean shouldDisableSnapshots() {
- return mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT;
+ return mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT
+ || mConfigDisableTaskSnapshots;
}
/**
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 194f48f57cc4..b54e8b7a7b4e 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -66,8 +66,8 @@ class WallpaperWindowToken extends WindowToken {
}
@Override
- void setExiting() {
- super.setExiting();
+ void setExiting(boolean animateExit) {
+ super.setExiting(animateExit);
mDisplayContent.mWallpaperController.removeWallpaperToken(this);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 47087cfbd147..4fac05c349c5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -445,8 +445,21 @@ public abstract class WindowManagerInternal {
* @param removeWindows Whether to also remove the windows associated with the token.
* @param displayId The display to remove the token from.
*/
+ public final void removeWindowToken(android.os.IBinder token, boolean removeWindows,
+ int displayId) {
+ removeWindowToken(token, removeWindows, true /* animateExit */, displayId);
+ }
+
+ /**
+ * Removes a window token.
+ *
+ * @param token The toke to remove.
+ * @param removeWindows Whether to also remove the windows associated with the token.
+ * @param animateExit Whether to play the windows exit animation after the token removal.
+ * @param displayId The display to remove the token from.
+ */
public abstract void removeWindowToken(android.os.IBinder token, boolean removeWindows,
- int displayId);
+ boolean animateExit, int displayId);
/**
* Registers a listener to be notified about app transition events.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1ec9187d7a76..3421b28454f0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -167,8 +167,10 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
-import android.hardware.configstore.V1_0.ISurfaceFlingerConfigs;
import android.hardware.configstore.V1_0.OptionalBool;
+import android.hardware.configstore.V1_1.DisplayOrientation;
+import android.hardware.configstore.V1_1.ISurfaceFlingerConfigs;
+import android.hardware.configstore.V1_1.OptionalDisplayOrientation;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.InputManager;
@@ -220,6 +222,7 @@ import android.util.TypedValue;
import android.util.proto.ProtoOutputStream;
import android.view.Choreographer;
import android.view.Display;
+import android.view.DisplayAddress;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IAppTransitionAnimationSpecsFuture;
@@ -465,6 +468,8 @@ public class WindowManagerService extends IWindowManager.Stub
*/
static final boolean ENABLE_FIXED_ROTATION_TRANSFORM =
SystemProperties.getBoolean("persist.wm.fixed_rotation_transform", true);
+ private @Surface.Rotation int mPrimaryDisplayOrientation = Surface.ROTATION_0;
+ private DisplayAddress mPrimaryDisplayPhysicalAddress;
// Enums for animation scale update types.
@Retention(RetentionPolicy.SOURCE)
@@ -2461,16 +2466,21 @@ public class WindowManagerService extends IWindowManager.Stub
configChanged = displayContent.updateOrientation();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- final DisplayInfo rotatedDisplayInfo =
- win.mToken.getFixedRotationTransformDisplayInfo();
- if (rotatedDisplayInfo != null) {
- outSurfaceControl.setTransformHint(rotatedDisplayInfo.rotation);
- } else {
- // We have to update the transform hint of display here, but we need to get if from
- // SurfaceFlinger, so set it as rotation of display for most cases, then
- // SurfaceFlinger would still update the transform hint of display in next frame.
- outSurfaceControl.setTransformHint(displayContent.getDisplayInfo().rotation);
- }
+ final DisplayInfo displayInfo = win.getDisplayInfo();
+ int transformHint = displayInfo.rotation;
+ // If the window is on the primary display, use the panel orientation to adjust the
+ // transform hint
+ final boolean isPrimaryDisplay = displayInfo.address != null &&
+ displayInfo.address.equals(mPrimaryDisplayPhysicalAddress);
+ if (isPrimaryDisplay) {
+ transformHint = (transformHint + mPrimaryDisplayOrientation) % 4;
+ }
+ outSurfaceControl.setTransformHint(transformHint);
+ ProtoLog.v(WM_DEBUG_ORIENTATION,
+ "Passing transform hint %d for window %s%s",
+ transformHint, win,
+ isPrimaryDisplay ? " on primary display with orientation "
+ + mPrimaryDisplayOrientation : "");
if (toBeDisplayed && win.mIsWallpaper) {
displayContent.mWallpaperController.updateWallpaperOffset(win, false /* sync */);
@@ -2816,6 +2826,31 @@ public class WindowManagerService extends IWindowManager.Stub
}
+ void removeWindowToken(IBinder binder, boolean removeWindows, boolean animateExit,
+ int displayId) {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+
+ if (dc == null) {
+ ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
+ + " for non-exiting displayId=%d", binder, displayId);
+ return;
+ }
+ final WindowToken token = dc.removeWindowToken(binder, animateExit);
+ if (token == null) {
+ ProtoLog.w(WM_ERROR,
+ "removeWindowToken: Attempted to remove non-existing token: %s",
+ binder);
+ return;
+ }
+
+ if (removeWindows) {
+ token.removeAllWindowsIfPossible();
+ }
+ dc.getInputMonitor().updateInputWindowsLw(true /* force */);
+ }
+ }
+
@Override
public void removeWindowToken(IBinder binder, int displayId) {
if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeWindowToken()")) {
@@ -2823,23 +2858,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
final long origId = Binder.clearCallingIdentity();
try {
- synchronized (mGlobalLock) {
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
-
- if (dc == null) {
- ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
- + " for non-exiting displayId=%d", binder, displayId);
- return;
- }
- final WindowToken token = dc.removeWindowToken(binder);
- if (token == null) {
- ProtoLog.w(WM_ERROR,
- "removeWindowToken: Attempted to remove non-existing token: %s",
- binder);
- return;
- }
- dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
- }
+ removeWindowToken(binder, false /* removeWindows */, true /* animateExit */, displayId);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -4859,6 +4878,9 @@ public class WindowManagerService extends IWindowManager.Stub
mTaskSnapshotController.systemReady();
mHasWideColorGamutSupport = queryWideColorGamutSupport();
mHasHdrSupport = queryHdrSupport();
+ mPrimaryDisplayOrientation = queryPrimaryDisplayOrientation();
+ mPrimaryDisplayPhysicalAddress =
+ DisplayAddress.fromPhysicalDisplayId(SurfaceControl.getPrimaryPhysicalDisplayId());
UiThread.getHandler().post(mSettingsObserver::loadSettings);
IVrManager vrManager = IVrManager.Stub.asInterface(
ServiceManager.getService(Context.VR_SERVICE));
@@ -4878,6 +4900,9 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+
+ // Keep logic in sync with SurfaceFlingerProperties.cpp
+ // Consider exposing properties via ISurfaceComposer instead.
private static boolean queryWideColorGamutSupport() {
boolean defaultValue = false;
Optional<Boolean> hasWideColorProp = SurfaceFlingerProperties.has_wide_color_display();
@@ -4918,6 +4943,39 @@ public class WindowManagerService extends IWindowManager.Stub
return false;
}
+ private static @Surface.Rotation int queryPrimaryDisplayOrientation() {
+ Optional<SurfaceFlingerProperties.primary_display_orientation_values> prop =
+ SurfaceFlingerProperties.primary_display_orientation();
+ if (prop.isPresent()) {
+ switch (prop.get()) {
+ case ORIENTATION_90: return Surface.ROTATION_90;
+ case ORIENTATION_180: return Surface.ROTATION_180;
+ case ORIENTATION_270: return Surface.ROTATION_270;
+ case ORIENTATION_0:
+ default:
+ return Surface.ROTATION_0;
+ }
+ }
+ try {
+ ISurfaceFlingerConfigs surfaceFlinger = ISurfaceFlingerConfigs.getService();
+ OptionalDisplayOrientation primaryDisplayOrientation =
+ surfaceFlinger.primaryDisplayOrientation();
+ if (primaryDisplayOrientation != null && primaryDisplayOrientation.specified) {
+ switch (primaryDisplayOrientation.value) {
+ case DisplayOrientation.ORIENTATION_90: return Surface.ROTATION_90;
+ case DisplayOrientation.ORIENTATION_180: return Surface.ROTATION_180;
+ case DisplayOrientation.ORIENTATION_270: return Surface.ROTATION_270;
+ case DisplayOrientation.ORIENTATION_0:
+ default:
+ return Surface.ROTATION_0;
+ }
+ }
+ } catch (Exception e) {
+ // Use default value if we can't talk to config store.
+ }
+ return Surface.ROTATION_0;
+ }
+
void reportFocusChanged(IBinder oldToken, IBinder newToken) {
WindowState lastFocus;
WindowState newFocus;
@@ -7536,28 +7594,10 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void removeWindowToken(IBinder binder, boolean removeWindows, int displayId) {
- synchronized (mGlobalLock) {
- if (removeWindows) {
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
- if (dc == null) {
- ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
- + " for non-exiting displayId=%d", binder, displayId);
- return;
- }
-
- final WindowToken token = dc.removeWindowToken(binder);
- if (token == null) {
- ProtoLog.w(WM_ERROR,
- "removeWindowToken: Attempted to remove non-existing token: %s",
- binder);
- return;
- }
-
- token.removeAllWindowsIfPossible();
- }
- WindowManagerService.this.removeWindowToken(binder, displayId);
- }
+ public void removeWindowToken(IBinder binder, boolean removeWindows, boolean animateExit,
+ int displayId) {
+ WindowManagerService.this.removeWindowToken(binder, removeWindows, animateExit,
+ displayId);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c3fc99554bcc..5e042efa2f11 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2180,11 +2180,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- boolean onSetAppExiting() {
+ boolean onSetAppExiting(boolean animateExit) {
final DisplayContent displayContent = getDisplayContent();
boolean changed = false;
- if (isVisibleNow()) {
+ if (!animateExit) {
+ // Hide the window permanently if no window exist animation is performed, so we can
+ // avoid the window surface becoming visible again unexpectedly during the next
+ // relayout.
+ mPermanentlyHidden = true;
+ hide(false /* doAnimation */, false /* requestAnim */);
+ }
+ if (isVisibleNow() && animateExit) {
mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
if (mWmService.mAccessibilityController != null) {
mWmService.mAccessibilityController.onWindowTransition(this, TRANSIT_EXIT);
@@ -2197,7 +2204,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = mChildren.get(i);
- changed |= c.onSetAppExiting();
+ changed |= c.onSetAppExiting(animateExit);
}
return changed;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index fbfa400ba852..3cbc67c004cd 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -24,6 +24,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -232,7 +233,7 @@ class WindowToken extends WindowContainer<WindowState> {
}
}
- void setExiting() {
+ void setExiting(boolean animateExit) {
if (isEmpty()) {
super.removeImmediately();
return;
@@ -247,11 +248,12 @@ class WindowToken extends WindowContainer<WindowState> {
final int count = mChildren.size();
boolean changed = false;
- final boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN);
+ final boolean delayed = isAnimating(TRANSITION | PARENTS)
+ || (isAnimating(CHILDREN, ANIMATION_TYPE_WINDOW_ANIMATION) && animateExit);
for (int i = 0; i < count; i++) {
final WindowState win = mChildren.get(i);
- changed |= win.onSetAppExiting();
+ changed |= win.onSetAppExiting(animateExit);
}
final ActivityRecord app = asActivityRecord();
@@ -353,7 +355,7 @@ class WindowToken extends WindowContainer<WindowState> {
@Override
void removeImmediately() {
if (mDisplayContent != null) {
- mDisplayContent.removeWindowToken(token);
+ mDisplayContent.removeWindowToken(token, true /* animateExit */);
}
// Needs to occur after the token is removed from the display above to avoid attempt at
// duplicate removal of this window container from it's parent.
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 710a304545af..e7005daf5626 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -85,6 +85,7 @@ cc_library_static {
header_libs: [
"bionic_libc_platform_headers",
+ "bpf_connectivity_headers",
],
}
diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
index 10b248a70e7e..5178132e4a2e 100644
--- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp
+++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
@@ -38,9 +38,6 @@ using android::bpf::bpfGetIfaceStats;
namespace android {
-static const char* QTAGUID_IFACE_STATS = "/proc/net/xt_qtaguid/iface_stat_fmt";
-static const char* QTAGUID_UID_STATS = "/proc/net/xt_qtaguid/stats";
-
// NOTE: keep these in sync with TrafficStats.java
static const uint64_t UNKNOWN = -1;
@@ -72,102 +69,17 @@ static uint64_t getStatsType(Stats* stats, StatsType type) {
}
}
-static int parseIfaceStats(const char* iface, Stats* stats) {
- FILE *fp = fopen(QTAGUID_IFACE_STATS, "r");
- if (fp == NULL) {
- return -1;
- }
-
- char buffer[384];
- char cur_iface[32];
- bool foundTcp = false;
- uint64_t rxBytes, rxPackets, txBytes, txPackets, tcpRxPackets, tcpTxPackets;
-
- while (fgets(buffer, sizeof(buffer), fp) != NULL) {
- int matched = sscanf(buffer, "%31s %" SCNu64 " %" SCNu64 " %" SCNu64
- " %" SCNu64 " " "%*u %" SCNu64 " %*u %*u %*u %*u "
- "%*u %" SCNu64 " %*u %*u %*u %*u", cur_iface, &rxBytes,
- &rxPackets, &txBytes, &txPackets, &tcpRxPackets, &tcpTxPackets);
- if (matched >= 5) {
- if (matched == 7) {
- foundTcp = true;
- }
- if (!iface || !strcmp(iface, cur_iface)) {
- stats->rxBytes += rxBytes;
- stats->rxPackets += rxPackets;
- stats->txBytes += txBytes;
- stats->txPackets += txPackets;
- if (matched == 7) {
- stats->tcpRxPackets += tcpRxPackets;
- stats->tcpTxPackets += tcpTxPackets;
- }
- }
- }
- }
-
- if (!foundTcp) {
- stats->tcpRxPackets = UNKNOWN;
- stats->tcpTxPackets = UNKNOWN;
- }
-
- if (fclose(fp) != 0) {
- return -1;
- }
- return 0;
-}
-
-static int parseUidStats(const uint32_t uid, Stats* stats) {
- FILE *fp = fopen(QTAGUID_UID_STATS, "r");
- if (fp == NULL) {
- return -1;
- }
-
- char buffer[384];
- char iface[32];
- uint32_t idx, cur_uid, set;
- uint64_t tag, rxBytes, rxPackets, txBytes, txPackets;
-
- while (fgets(buffer, sizeof(buffer), fp) != NULL) {
- if (sscanf(buffer,
- "%" SCNu32 " %31s 0x%" SCNx64 " %u %u %" SCNu64 " %" SCNu64
- " %" SCNu64 " %" SCNu64 "",
- &idx, iface, &tag, &cur_uid, &set, &rxBytes, &rxPackets,
- &txBytes, &txPackets) == 9) {
- if (uid == cur_uid && tag == 0L) {
- stats->rxBytes += rxBytes;
- stats->rxPackets += rxPackets;
- stats->txBytes += txBytes;
- stats->txPackets += txPackets;
- }
- }
- }
-
- if (fclose(fp) != 0) {
- return -1;
- }
- return 0;
-}
-
-static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type, jboolean useBpfStats) {
+static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) {
Stats stats = {};
- if (useBpfStats) {
- if (bpfGetIfaceStats(NULL, &stats) == 0) {
- return getStatsType(&stats, (StatsType) type);
- } else {
- return UNKNOWN;
- }
- }
-
- if (parseIfaceStats(NULL, &stats) == 0) {
+ if (bpfGetIfaceStats(NULL, &stats) == 0) {
return getStatsType(&stats, (StatsType) type);
} else {
return UNKNOWN;
}
}
-static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type,
- jboolean useBpfStats) {
+static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) {
ScopedUtfChars iface8(env, iface);
if (iface8.c_str() == NULL) {
return UNKNOWN;
@@ -175,33 +87,17 @@ static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type,
Stats stats = {};
- if (useBpfStats) {
- if (bpfGetIfaceStats(iface8.c_str(), &stats) == 0) {
- return getStatsType(&stats, (StatsType) type);
- } else {
- return UNKNOWN;
- }
- }
-
- if (parseIfaceStats(iface8.c_str(), &stats) == 0) {
+ if (bpfGetIfaceStats(iface8.c_str(), &stats) == 0) {
return getStatsType(&stats, (StatsType) type);
} else {
return UNKNOWN;
}
}
-static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type, jboolean useBpfStats) {
+static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) {
Stats stats = {};
- if (useBpfStats) {
- if (bpfGetUidStats(uid, &stats) == 0) {
- return getStatsType(&stats, (StatsType) type);
- } else {
- return UNKNOWN;
- }
- }
-
- if (parseUidStats(uid, &stats) == 0) {
+ if (bpfGetUidStats(uid, &stats) == 0) {
return getStatsType(&stats, (StatsType) type);
} else {
return UNKNOWN;
@@ -209,9 +105,9 @@ static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type, jboolean
}
static const JNINativeMethod gMethods[] = {
- {"nativeGetTotalStat", "(IZ)J", (void*) getTotalStat},
- {"nativeGetIfaceStat", "(Ljava/lang/String;IZ)J", (void*) getIfaceStat},
- {"nativeGetUidStat", "(IIZ)J", (void*) getUidStat},
+ {"nativeGetTotalStat", "(I)J", (void*)getTotalStat},
+ {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*)getIfaceStat},
+ {"nativeGetUidStat", "(II)J", (void*)getUidStat},
};
int register_android_server_net_NetworkStatsService(JNIEnv* env) {
diff --git a/services/java/com/android/server/SystemConfigService.java b/services/java/com/android/server/SystemConfigService.java
index 3a9b2dca3921..cb52e5f72d5f 100644
--- a/services/java/com/android/server/SystemConfigService.java
+++ b/services/java/com/android/server/SystemConfigService.java
@@ -19,6 +19,7 @@ import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import android.Manifest;
+import android.content.ComponentName;
import android.content.Context;
import android.os.ISystemConfig;
import android.util.ArrayMap;
@@ -87,14 +88,14 @@ public class SystemConfigService extends SystemService {
}
@Override
- public List<String> getEnabledComponentOverrides(String packageName) {
+ public List<ComponentName> getEnabledComponentOverrides(String packageName) {
ArrayMap<String, Boolean> systemComponents = SystemConfig.getInstance()
.getComponentsEnabledStates(packageName);
- List<String> enabledComponent = new ArrayList<>();
+ List<ComponentName> enabledComponent = new ArrayList<>();
if (systemComponents != null) {
for (Map.Entry<String, Boolean> entry : systemComponents.entrySet()) {
if (Boolean.TRUE.equals(entry.getValue())) {
- enabledComponent.add(entry.getKey());
+ enabledComponent.add(new ComponentName(packageName, entry.getKey()));
}
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index aca7cc9070b1..1f96c6674a12 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -264,6 +264,8 @@ public final class SystemServer implements Dumpable {
"com.android.server.stats.StatsCompanion$Lifecycle";
private static final String STATS_PULL_ATOM_SERVICE_CLASS =
"com.android.server.stats.pull.StatsPullAtomService";
+ private static final String STATS_BOOTSTRAP_ATOM_SERVICE_LIFECYCLE_CLASS =
+ "com.android.server.stats.bootstrap.StatsBootstrapAtomService$Lifecycle";
private static final String USB_SERVICE_CLASS =
"com.android.server.usb.UsbService$Lifecycle";
private static final String MIDI_SERVICE_CLASS =
@@ -364,6 +366,8 @@ public final class SystemServer implements Dumpable {
"com.android.server.blob.BlobStoreManagerService";
private static final String APP_SEARCH_MANAGER_SERVICE_CLASS =
"com.android.server.appsearch.AppSearchManagerService";
+ private static final String ISOLATED_COMPILATION_SERVICE_CLASS =
+ "com.android.server.compos.IsolatedCompilationService";
private static final String ROLLBACK_MANAGER_SERVICE_CLASS =
"com.android.server.rollback.RollbackManagerService";
private static final String ALARM_MANAGER_SERVICE_CLASS =
@@ -2487,6 +2491,11 @@ public final class SystemServer implements Dumpable {
mSystemServiceManager.startService(STATS_PULL_ATOM_SERVICE_CLASS);
t.traceEnd();
+ // Log atoms to statsd from bootstrap processes.
+ t.traceBegin("StatsBootstrapAtomService");
+ mSystemServiceManager.startService(STATS_BOOTSTRAP_ATOM_SERVICE_LIFECYCLE_CLASS);
+ t.traceEnd();
+
// Incidentd and dumpstated helper
t.traceBegin("StartIncidentCompanionService");
mSystemServiceManager.startService(IncidentCompanionService.class);
@@ -2651,6 +2660,12 @@ public final class SystemServer implements Dumpable {
mSystemServiceManager.startService(APP_SEARCH_MANAGER_SERVICE_CLASS);
t.traceEnd();
+ if (SystemProperties.getBoolean("ro.config.isolated_compilation_enabled", false)) {
+ t.traceBegin("IsolatedCompilationService");
+ mSystemServiceManager.startService(ISOLATED_COMPILATION_SERVICE_CLASS);
+ t.traceEnd();
+ }
+
t.traceBegin("StartMediaCommunicationService");
mSystemServiceManager.startService(MEDIA_COMMUNICATION_SERVICE_CLASS);
t.traceEnd();
diff --git a/services/net/OWNERS b/services/net/OWNERS
index d3836d4c6c57..62c5737a2e8e 100644
--- a/services/net/OWNERS
+++ b/services/net/OWNERS
@@ -1,8 +1,2 @@
set noparent
-
-codewiz@google.com
-jchalard@google.com
-junyulai@google.com
-lorenzo@google.com
-reminv@google.com
-satk@google.com
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
diff --git a/services/people/java/com/android/server/people/data/CallLogQueryHelper.java b/services/people/java/com/android/server/people/data/CallLogQueryHelper.java
index 45e0aac24ca7..ff901af3defa 100644
--- a/services/people/java/com/android/server/people/data/CallLogQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/CallLogQueryHelper.java
@@ -93,6 +93,9 @@ class CallLogQueryHelper {
hasResults = true;
}
}
+ } catch (SecurityException ex) {
+ Slog.e(TAG, "Query call log failed: " + ex);
+ return false;
}
return hasResults;
}
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index fdf23d3836ac..62a16f7f24fd 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -23,7 +23,6 @@ import android.app.job.JobService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ResolveInfo;
import android.os.Handler;
import android.os.IBinder.DeathRecipient;
import android.os.Looper;
@@ -32,12 +31,11 @@ import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UpdateEngine;
import android.os.UpdateEngineCallback;
-import android.os.UserHandle;
-import android.os.UserManager;
import android.provider.DeviceConfig;
import android.util.Log;
import com.android.internal.R;
+import com.android.internal.os.BackgroundThread;
import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -45,9 +43,6 @@ import com.android.server.wm.ActivityMetricsLaunchObserver;
import com.android.server.wm.ActivityMetricsLaunchObserverRegistry;
import com.android.server.wm.ActivityTaskManagerInternal;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
@@ -96,10 +91,12 @@ public final class ProfcollectForwardingService extends SystemService {
if (mIProfcollect == null) {
return;
}
- if (serviceHasSupportedTraceProvider()) {
- registerObservers();
- }
- ProfcollectBGJobService.schedule(getContext());
+ BackgroundThread.get().getThreadHandler().post(() -> {
+ if (serviceHasSupportedTraceProvider()) {
+ registerObservers();
+ ProfcollectBGJobService.schedule(getContext());
+ }
+ });
}
}
@@ -152,7 +149,7 @@ public final class ProfcollectForwardingService extends SystemService {
connectNativeService();
break;
default:
- throw new AssertionError("Unknown message: " + message.toString());
+ throw new AssertionError("Unknown message: " + message);
}
}
}
@@ -196,11 +193,14 @@ public final class ProfcollectForwardingService extends SystemService {
Log.d(LOG_TAG, "Starting background process job");
}
- try {
- sSelfService.mIProfcollect.process(false);
- } catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage());
- }
+ BackgroundThread.get().getThreadHandler().post(
+ () -> {
+ try {
+ sSelfService.mIProfcollect.process();
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, e.getMessage());
+ }
+ });
return true;
}
@@ -236,14 +236,16 @@ public final class ProfcollectForwardingService extends SystemService {
"applaunch_trace_freq", 2);
int randomNum = ThreadLocalRandom.current().nextInt(100);
if (randomNum < traceFrequency) {
- try {
- if (DEBUG) {
- Log.d(LOG_TAG, "Tracing on app launch event: " + packageName);
- }
- mIProfcollect.trace_once("applaunch");
- } catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage());
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Tracing on app launch event: " + packageName);
}
+ BackgroundThread.get().getThreadHandler().post(() -> {
+ try {
+ mIProfcollect.trace_once("applaunch");
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, e.getMessage());
+ }
+ });
}
}
@@ -306,79 +308,27 @@ public final class ProfcollectForwardingService extends SystemService {
return;
}
- if (!getUploaderEnabledConfig(getContext())) {
- return;
- }
-
- new Thread(() -> {
+ Context context = getContext();
+ BackgroundThread.get().getThreadHandler().post(() -> {
try {
- Context context = getContext();
- final String uploaderPkg = getUploaderPackageName(context);
- final String uploaderAction = getUploaderActionName(context);
- String reportUuid = mIProfcollect.report();
-
- final int profileId = getBBProfileId();
- String reportDir = "/data/user/" + profileId
- + "/com.google.android.apps.internal.betterbug/cache/";
- String reportPath = reportDir + reportUuid + ".zip";
-
- if (!Files.exists(Paths.get(reportDir))) {
- Log.i(LOG_TAG, "Destination directory does not exist, abort upload.");
- return;
- }
+ // Prepare profile report
+ String reportName = mIProfcollect.report() + ".zip";
- Intent uploadIntent =
- new Intent(uploaderAction)
- .setPackage(uploaderPkg)
- .putExtra("EXTRA_DESTINATION", "PROFCOLLECT")
- .putExtra("EXTRA_PACKAGE_NAME", getContext().getPackageName())
- .putExtra("EXTRA_PROFILE_PATH", reportPath)
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-
- List<ResolveInfo> receivers =
- context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0);
- if (receivers == null || receivers.isEmpty()) {
- Log.i(LOG_TAG, "No one to receive upload intent, abort upload.");
+ if (!context.getResources().getBoolean(
+ R.bool.config_profcollectReportUploaderEnabled)) {
+ Log.i(LOG_TAG, "Upload is not enabled.");
return;
}
- mIProfcollect.copy_report_to_bb(profileId, reportUuid);
- context.sendBroadcast(uploadIntent);
- mIProfcollect.delete_report(reportUuid);
+
+ // Upload the report
+ Intent intent = new Intent()
+ .setPackage("com.android.shell")
+ .setAction("com.android.shell.action.PROFCOLLECT_UPLOAD")
+ .putExtra("filename", reportName);
+ context.sendBroadcast(intent);
} catch (RemoteException e) {
Log.e(LOG_TAG, e.getMessage());
}
- }).start();
- }
-
- /**
- * Get BetterBug's profile ID. It is the work profile ID, if it exists. Otherwise the system
- * user ID.
- *
- * @return BetterBug's profile ID.
- */
- private int getBBProfileId() {
- UserManager userManager = UserManager.get(getContext());
- int[] profiles = userManager.getProfileIds(UserHandle.USER_SYSTEM, false);
- for (int p : profiles) {
- if (userManager.getUserInfo(p).isManagedProfile()) {
- return p;
- }
- }
- return UserHandle.USER_SYSTEM;
- }
-
- private boolean getUploaderEnabledConfig(Context context) {
- return context.getResources().getBoolean(
- R.bool.config_profcollectReportUploaderEnabled);
- }
-
- private String getUploaderPackageName(Context context) {
- return context.getResources().getString(
- R.string.config_defaultProfcollectReportUploaderApp);
- }
-
- private String getUploaderActionName(Context context) {
- return context.getResources().getString(
- R.string.config_defaultProfcollectReportUploaderAction);
+ });
}
}
diff --git a/services/proguard.flags b/services/proguard.flags
new file mode 100644
index 000000000000..30dd6cf545b9
--- /dev/null
+++ b/services/proguard.flags
@@ -0,0 +1,11 @@
+# TODO(b/196084106): Refine and optimize this configuration. Note that this
+# configuration is only used when `SOONG_CONFIG_ANDROID_SYSTEM_OPTIMIZE_JAVA=true`.
+-keep,allowoptimization,allowaccessmodification class ** {
+ *;
+}
+
+# Various classes subclassed in ethernet-service (avoid marking final).
+-keep public class android.net.** { *; }
+
+# Referenced via CarServiceHelperService in car-frameworks-service (avoid removing).
+-keep public class com.android.server.utils.Slogf { *; } \ No newline at end of file
diff --git a/services/tests/mockingservicestests/OWNERS b/services/tests/mockingservicestests/OWNERS
new file mode 100644
index 000000000000..0fb0c3021486
--- /dev/null
+++ b/services/tests/mockingservicestests/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/services/core/java/com/android/server/am/OWNERS
diff --git a/services/tests/servicestests/OWNERS b/services/tests/servicestests/OWNERS
new file mode 100644
index 000000000000..0fb0c3021486
--- /dev/null
+++ b/services/tests/servicestests/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/services/core/java/com/android/server/am/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java b/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
deleted file mode 100644
index a2ecbc30ec64..000000000000
--- a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static junit.framework.Assert.*;
-
-import static org.mockito.Mockito.*;
-
-import android.hardware.health.V2_0.IHealth;
-import android.hidl.manager.V1_0.IServiceManager;
-import android.hidl.manager.V1_0.IServiceNotification;
-import android.test.AndroidTestCase;
-
-import androidx.test.filters.SmallTest;
-
-import org.mockito.ArgumentMatcher;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.NoSuchElementException;
-
-public class BatteryServiceTest extends AndroidTestCase {
-
- @Mock IServiceManager mMockedManager;
- @Mock IHealth mMockedHal;
- @Mock IHealth mMockedHal2;
-
- @Mock BatteryService.HealthServiceWrapper.Callback mCallback;
- @Mock BatteryService.HealthServiceWrapper.IServiceManagerSupplier mManagerSupplier;
- @Mock BatteryService.HealthServiceWrapper.IHealthSupplier mHealthServiceSupplier;
- BatteryService.HealthServiceWrapper mWrapper;
-
- private static final String VENDOR = BatteryService.HealthServiceWrapper.INSTANCE_VENDOR;
-
- @Override
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- }
-
- @Override
- public void tearDown() {
- if (mWrapper != null)
- mWrapper.getHandlerThread().quitSafely();
- }
-
- public static <T> ArgumentMatcher<T> isOneOf(Collection<T> collection) {
- return new ArgumentMatcher<T>() {
- @Override public boolean matches(T e) {
- return collection.contains(e);
- }
- @Override public String toString() {
- return collection.toString();
- }
- };
- }
-
- private void initForInstances(String... instanceNamesArr) throws Exception {
- final Collection<String> instanceNames = Arrays.asList(instanceNamesArr);
- doAnswer((invocation) -> {
- // technically, preexisting is ignored by
- // BatteryService.HealthServiceWrapper.Notification, but still call it correctly.
- sendNotification(invocation, true);
- sendNotification(invocation, true);
- sendNotification(invocation, false);
- return null;
- }).when(mMockedManager).registerForNotifications(
- eq(IHealth.kInterfaceName),
- argThat(isOneOf(instanceNames)),
- any(IServiceNotification.class));
-
- doReturn(mMockedManager).when(mManagerSupplier).get();
- doReturn(mMockedHal) // init calls this
- .doReturn(mMockedHal) // notification 1
- .doReturn(mMockedHal) // notification 2
- .doReturn(mMockedHal2) // notification 3
- .doThrow(new RuntimeException("Should not call getService for more than 4 times"))
- .when(mHealthServiceSupplier).get(argThat(isOneOf(instanceNames)));
-
- mWrapper = new BatteryService.HealthServiceWrapper();
- }
-
- private void waitHandlerThreadFinish() throws Exception {
- for (int i = 0; i < 5; i++) {
- if (!mWrapper.getHandlerThread().getThreadHandler().hasMessagesOrCallbacks()) {
- return;
- }
- Thread.sleep(300);
- }
- assertFalse(mWrapper.getHandlerThread().getThreadHandler().hasMessagesOrCallbacks());
- }
-
- private static void sendNotification(InvocationOnMock invocation, boolean preexisting)
- throws Exception {
- ((IServiceNotification)invocation.getArguments()[2]).onRegistration(
- IHealth.kInterfaceName,
- (String)invocation.getArguments()[1],
- preexisting);
- }
-
- @SmallTest
- public void testWrapPreferVendor() throws Exception {
- initForInstances(VENDOR);
- mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier);
- waitHandlerThreadFinish();
- verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(VENDOR));
- verify(mCallback, never()).onRegistration(same(mMockedHal), same(mMockedHal), anyString());
- verify(mCallback, times(1)).onRegistration(same(mMockedHal), same(mMockedHal2), eq(VENDOR));
- }
-
- @SmallTest
- public void testNoService() throws Exception {
- initForInstances("unrelated");
- try {
- mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier);
- fail("Expect NoSuchElementException");
- } catch (NoSuchElementException ex) {
- // expected
- }
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java b/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java
index 3ace3f4c79dc..a1d4c203de18 100644
--- a/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java
+++ b/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java
@@ -66,7 +66,7 @@ public class BluetoothAirplaneModeListenerTest {
when(mHelper.isBluetoothOn()).thenReturn(true);
Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange());
- when(mHelper.isA2dpOrHearingAidConnected()).thenReturn(true);
+ when(mHelper.isMediaProfileConnected()).thenReturn(true);
Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange());
when(mHelper.isAirplaneModeOn()).thenReturn(true);
@@ -83,7 +83,7 @@ public class BluetoothAirplaneModeListenerTest {
public void testHandleAirplaneModeChange_NotInvokeAirplaneModeChanged_NotPopToast() {
mBluetoothAirplaneModeListener.mToastCount = BluetoothAirplaneModeListener.MAX_TOAST_COUNT;
when(mHelper.isBluetoothOn()).thenReturn(true);
- when(mHelper.isA2dpOrHearingAidConnected()).thenReturn(true);
+ when(mHelper.isMediaProfileConnected()).thenReturn(true);
when(mHelper.isAirplaneModeOn()).thenReturn(true);
mBluetoothAirplaneModeListener.handleAirplaneModeChange();
@@ -97,7 +97,7 @@ public class BluetoothAirplaneModeListenerTest {
public void testHandleAirplaneModeChange_NotInvokeAirplaneModeChanged_PopToast() {
mBluetoothAirplaneModeListener.mToastCount = 0;
when(mHelper.isBluetoothOn()).thenReturn(true);
- when(mHelper.isA2dpOrHearingAidConnected()).thenReturn(true);
+ when(mHelper.isMediaProfileConnected()).thenReturn(true);
when(mHelper.isAirplaneModeOn()).thenReturn(true);
mBluetoothAirplaneModeListener.handleAirplaneModeChange();
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
index 5c53d43fa1df..9e1445cf589d 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
@@ -26,11 +26,11 @@ import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.AudioSystem;
+import android.media.BtProfileConnectionInfo;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -98,16 +98,12 @@ public class AudioDeviceBrokerTest {
Log.i(TAG, "starting testPostA2dpDeviceConnectionChange");
Assert.assertNotNull("invalid null BT device", mFakeBtDevice);
- mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice,
- BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1));
+ mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged(
+ new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null,
+ BtProfileConnectionInfo.a2dpInfo(true, 1), "testSource"));
Thread.sleep(2 * MAX_MESSAGE_HANDLING_DELAY_MS);
- verify(mSpyDevInventory, times(1)).setBluetoothA2dpDeviceConnectionState(
- any(BluetoothDevice.class),
- ArgumentMatchers.eq(BluetoothProfile.STATE_CONNECTED) /*state*/,
- ArgumentMatchers.eq(BluetoothProfile.A2DP) /*profile*/,
- ArgumentMatchers.eq(true) /*suppressNoisyIntent*/, anyInt() /*musicDevice*/,
- ArgumentMatchers.eq(1) /*a2dpVolume*/
+ verify(mSpyDevInventory, times(1)).setBluetoothActiveDevice(
+ any(AudioDeviceBroker.BtDeviceInfo.class)
);
// verify the connection was reported to AudioSystem
@@ -210,30 +206,29 @@ public class AudioDeviceBrokerTest {
((NoOpAudioSystemAdapter) mSpyAudioSystem).configureIsStreamActive(mockMediaPlayback);
// first connection: ensure the device is connected as a starting condition for the test
- mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice,
- BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1));
+ mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged(
+ new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null,
+ BtProfileConnectionInfo.a2dpInfo(true, 1), "testSource"));
Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS);
// disconnection
- mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice,
- BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP, false, -1));
+ mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged(
+ new AudioDeviceBroker.BtDeviceChangedData(null, mFakeBtDevice,
+ BtProfileConnectionInfo.a2dpInfo(false, -1), "testSource"));
if (delayAfterDisconnection > 0) {
Thread.sleep(delayAfterDisconnection);
}
// reconnection
- mAudioDeviceBroker.queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- new AudioDeviceBroker.BtDeviceConnectionInfo(mFakeBtDevice,
- BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 2));
+ mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged(
+ new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null,
+ BtProfileConnectionInfo.a2dpInfo(true, 2), "testSource"));
Thread.sleep(AudioService.BECOMING_NOISY_DELAY_MS + MAX_MESSAGE_HANDLING_DELAY_MS);
// Verify disconnection has been cancelled and we're seeing two connections attempts,
// with the device connected at the end of the test
- verify(mSpyDevInventory, times(2)).onSetA2dpSinkConnectionState(
- any(BtHelper.BluetoothA2dpDeviceInfo.class),
- ArgumentMatchers.eq(BluetoothProfile.STATE_CONNECTED));
+ verify(mSpyDevInventory, times(2)).onSetBtActiveDevice(
+ any(AudioDeviceBroker.BtDeviceInfo.class), anyInt());
Assert.assertTrue("Mock device not connected",
mSpyDevInventory.isA2dpDeviceConnected(mFakeBtDevice));
diff --git a/services/tests/servicestests/src/com/android/server/health/HealthServiceWrapperTest.java b/services/tests/servicestests/src/com/android/server/health/HealthServiceWrapperTest.java
new file mode 100644
index 000000000000..16d97a454050
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/health/HealthServiceWrapperTest.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.health;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.fail;
+
+import static org.mockito.AdditionalMatchers.not;
+import static org.mockito.Mockito.*;
+
+import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
+import android.os.IServiceCallback;
+import android.os.RemoteException;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.NoSuchElementException;
+
+@RunWith(AndroidJUnit4.class)
+public class HealthServiceWrapperTest {
+ @Mock IServiceManager mMockedManager;
+ @Mock android.hardware.health.V2_0.IHealth mMockedHal;
+ @Mock android.hardware.health.V2_0.IHealth mMockedHal2;
+
+ @Mock HealthServiceWrapperHidl.Callback mCallback;
+ @Mock HealthServiceWrapperHidl.IServiceManagerSupplier mManagerSupplier;
+ @Mock HealthServiceWrapperHidl.IHealthSupplier mHealthServiceSupplier;
+
+ @Mock android.hardware.health.IHealth.Stub mMockedAidlHal;
+ @Mock android.hardware.health.IHealth.Stub mMockedAidlHal2;
+ @Mock HealthServiceWrapperAidl.ServiceManagerStub mMockedAidlManager;
+ @Mock HealthRegCallbackAidl mRegCallbackAidl;
+
+ HealthServiceWrapper mWrapper;
+
+ private static final String VENDOR = HealthServiceWrapperHidl.INSTANCE_VENDOR;
+ private static final String AIDL_SERVICE_NAME = HealthServiceWrapperAidl.SERVICE_NAME;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ // Mocks the conversion between IHealth and IBinder.
+ when(mMockedAidlHal.asBinder()).thenCallRealMethod(); // returns mMockedAidlHal
+ when(mMockedAidlHal2.asBinder()).thenCallRealMethod(); // returns mMockedAidlHal2
+ when(mMockedAidlHal.queryLocalInterface(android.hardware.health.IHealth.DESCRIPTOR))
+ .thenReturn(mMockedAidlHal);
+ when(mMockedAidlHal2.queryLocalInterface(android.hardware.health.IHealth.DESCRIPTOR))
+ .thenReturn(mMockedAidlHal2);
+ }
+
+ @After
+ public void tearDown() {
+ validateMockitoUsage();
+ if (mWrapper != null) mWrapper.getHandlerThread().quitSafely();
+ }
+
+ public static <T> ArgumentMatcher<T> isOneOf(T[] collection) {
+ return isOneOf(Arrays.asList(collection));
+ }
+
+ public static <T> ArgumentMatcher<T> isOneOf(Collection<T> collection) {
+ return new ArgumentMatcher<T>() {
+ @Override
+ public boolean matches(T e) {
+ return collection.contains(e);
+ }
+
+ @Override
+ public String toString() {
+ return "is one of " + collection.toString();
+ }
+ };
+ }
+
+ /**
+ * Set up mock objects to pretend that the given AIDL and HIDL instances exists.
+ *
+ * <p>Also, when registering service notifications, the mocked service managers immediately
+ * sends 3 registration notifications, including 2 referring to the original HAL and 1 referring
+ * to the new HAL.
+ *
+ * @param aidlInstances e.g. {"android.hardware.health.IHealth/default"}
+ * @param hidlInstances e.g. {"default", "backup"}
+ * @throws Exception
+ */
+ private void initForInstances(String[] aidlInstances, String[] hidlInstances) throws Exception {
+ doAnswer(
+ (invocation) -> {
+ sendAidlRegCallback(invocation, mMockedAidlHal);
+ sendAidlRegCallback(invocation, mMockedAidlHal);
+ sendAidlRegCallback(invocation, mMockedAidlHal2);
+ return null;
+ })
+ .when(mMockedAidlManager)
+ .registerForNotifications(
+ argThat(isOneOf(aidlInstances)), any(IServiceCallback.class));
+ when(mMockedAidlManager.waitForDeclaredService(argThat(isOneOf(aidlInstances))))
+ .thenReturn(mMockedAidlHal)
+ .thenThrow(new RuntimeException("waitForDeclaredService called more than once"));
+ when(mMockedAidlManager.waitForDeclaredService(not(argThat(isOneOf(aidlInstances)))))
+ .thenReturn(null);
+
+ doAnswer(
+ (invocation) -> {
+ // technically, preexisting is ignored by
+ // HealthServiceWrapperHidl.Notification, but still call it correctly.
+ sendNotification(invocation, true);
+ sendNotification(invocation, true);
+ sendNotification(invocation, false);
+ return null;
+ })
+ .when(mMockedManager)
+ .registerForNotifications(
+ eq(android.hardware.health.V2_0.IHealth.kInterfaceName),
+ argThat(isOneOf(hidlInstances)),
+ any(IServiceNotification.class));
+
+ doReturn(mMockedManager).when(mManagerSupplier).get();
+ doReturn(mMockedHal) // init calls this
+ .doReturn(mMockedHal) // notification 1
+ .doReturn(mMockedHal) // notification 2
+ .doReturn(mMockedHal2) // notification 3
+ .doThrow(new RuntimeException("Should not call getService for more than 4 times"))
+ .when(mHealthServiceSupplier)
+ .get(argThat(isOneOf(hidlInstances)));
+ }
+
+ private void waitHandlerThreadFinish() throws Exception {
+ for (int i = 0; i < 5; i++) {
+ if (!mWrapper.getHandlerThread().getThreadHandler().hasMessagesOrCallbacks()) {
+ return;
+ }
+ Thread.sleep(300);
+ }
+ assertFalse(mWrapper.getHandlerThread().getThreadHandler().hasMessagesOrCallbacks());
+ }
+
+ private static void sendNotification(InvocationOnMock invocation, boolean preexisting)
+ throws Exception {
+ ((IServiceNotification) invocation.getArguments()[2])
+ .onRegistration(
+ android.hardware.health.V2_0.IHealth.kInterfaceName,
+ (String) invocation.getArguments()[1],
+ preexisting);
+ }
+
+ private static void sendAidlRegCallback(
+ InvocationOnMock invocation, android.hardware.health.IHealth service) throws Exception {
+ ((IServiceCallback) invocation.getArguments()[1])
+ .onRegistration((String) invocation.getArguments()[0], service.asBinder());
+ }
+
+ private void createWrapper() throws RemoteException {
+ mWrapper =
+ HealthServiceWrapper.create(
+ mRegCallbackAidl,
+ mMockedAidlManager,
+ mCallback,
+ mManagerSupplier,
+ mHealthServiceSupplier);
+ }
+
+ @SmallTest
+ @Test
+ public void testWrapAidlOnly() throws Exception {
+ initForInstances(new String[] {AIDL_SERVICE_NAME}, new String[0]);
+ createWrapper();
+ waitHandlerThreadFinish();
+ verify(mRegCallbackAidl, times(1)).onRegistration(same(null), same(mMockedAidlHal));
+ verify(mRegCallbackAidl, never())
+ .onRegistration(same(mMockedAidlHal), same(mMockedAidlHal));
+ verify(mRegCallbackAidl, times(1))
+ .onRegistration(same(mMockedAidlHal), same(mMockedAidlHal2));
+ verify(mCallback, never()).onRegistration(any(), any(), anyString());
+ }
+
+ @SmallTest
+ @Test
+ public void testWrapPreferAidl() throws Exception {
+ initForInstances(new String[] {AIDL_SERVICE_NAME}, new String[] {VENDOR});
+ createWrapper();
+ waitHandlerThreadFinish();
+ verify(mRegCallbackAidl, times(1)).onRegistration(same(null), same(mMockedAidlHal));
+ verify(mRegCallbackAidl, never())
+ .onRegistration(same(mMockedAidlHal), same(mMockedAidlHal));
+ verify(mRegCallbackAidl, times(1))
+ .onRegistration(same(mMockedAidlHal), same(mMockedAidlHal2));
+ verify(mCallback, never()).onRegistration(any(), any(), anyString());
+ }
+
+ @SmallTest
+ @Test
+ public void testWrapFallbackHidl() throws Exception {
+ initForInstances(new String[0], new String[] {VENDOR});
+ createWrapper();
+ waitHandlerThreadFinish();
+ verify(mRegCallbackAidl, never()).onRegistration(any(), any());
+ verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(VENDOR));
+ verify(mCallback, never()).onRegistration(same(mMockedHal), same(mMockedHal), anyString());
+ verify(mCallback, times(1)).onRegistration(same(mMockedHal), same(mMockedHal2), eq(VENDOR));
+ }
+
+ @SmallTest
+ @Test
+ public void testNoService() throws Exception {
+ initForInstances(new String[0], new String[] {"unrelated"});
+ try {
+ createWrapper();
+ fail("Expect NoSuchElementException");
+ } catch (NoSuchElementException ex) {
+ // expected
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/health/OWNERS b/services/tests/servicestests/src/com/android/server/health/OWNERS
new file mode 100644
index 000000000000..81522fcaa09f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/health/OWNERS
@@ -0,0 +1 @@
+file:platform/hardware/interfaces:/health/aidl/OWNERS
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
index b4fbf5fe40eb..184ea521e828 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
@@ -110,18 +110,20 @@ public class ActivityOptionsTest {
@Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
- t.setVisibility(leash, true /* visible */).apply();
+ t.show(leash).apply();
}
int cookieIndex = -1;
if (trampoline.equals(taskInfo.baseActivity)) {
cookieIndex = 0;
} else if (main.equals(taskInfo.baseActivity)) {
cookieIndex = 1;
- mainLatch.countDown();
}
if (cookieIndex >= 0) {
appearedCookies[cookieIndex] = taskInfo.launchCookies.isEmpty()
? null : taskInfo.launchCookies.get(0);
+ if (cookieIndex == 1) {
+ mainLatch.countDown();
+ }
}
}
};
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 293e862a6b74..6f04f176afd8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -39,6 +39,7 @@ import static android.os.Process.NOBODY_UID;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -2816,6 +2817,73 @@ public class ActivityRecordTests extends WindowTestsBase {
assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
}
+ @Test
+ public void testImeInsetsFrozenFlag_resetWhenReparented() {
+ final ActivityRecord activity = createActivityWithTask();
+ final WindowState app = createWindow(null, TYPE_APPLICATION, activity, "app");
+ final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
+ final Task newTask = new TaskBuilder(mSupervisor).build();
+ makeWindowVisible(app, imeWindow);
+ mDisplayContent.mInputMethodWindow = imeWindow;
+ mDisplayContent.setImeLayeringTarget(app);
+ mDisplayContent.setImeInputTarget(app);
+
+ // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
+ app.mActivityRecord.commitVisibility(false, false);
+ assertTrue(app.mActivityRecord.mLastImeShown);
+ assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+ // Expect IME insets frozen state will reset when the activity is reparent to the new task.
+ activity.setState(RESUMED, "test");
+ activity.reparent(newTask, 0 /* top */, "test");
+ assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+ }
+
+ @UseTestDisplay(addWindows = W_INPUT_METHOD)
+ @Test
+ public void testImeInsetsFrozenFlag_resetWhenResized() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ makeWindowVisibleAndDrawn(app, mImeWindow);
+ mDisplayContent.setImeLayeringTarget(app);
+ mDisplayContent.setImeInputTarget(app);
+
+ // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
+ app.mActivityRecord.commitVisibility(false, false);
+ assertTrue(app.mActivityRecord.mLastImeShown);
+ assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+ // Expect IME insets frozen state will reset when the activity is reparent to the new task.
+ app.mActivityRecord.onResize();
+ assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+ }
+
+ @UseTestDisplay(addWindows = W_INPUT_METHOD)
+ @Test
+ public void testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ makeWindowVisibleAndDrawn(app, mImeWindow);
+ mDisplayContent.setImeLayeringTarget(app);
+ mDisplayContent.setImeInputTarget(app);
+
+ // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
+ app.mActivityRecord.commitVisibility(false, false);
+ app.mActivityRecord.onWindowsGone();
+
+ assertTrue(app.mActivityRecord.mLastImeShown);
+ assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+ // Expect IME insets frozen state will reset when the activity has no IME focusable window.
+ app.mActivityRecord.forAllWindowsUnchecked(w -> {
+ w.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
+ return true;
+ }, true);
+
+ app.mActivityRecord.commitVisibility(true, false);
+ app.mActivityRecord.onWindowsVisible();
+
+ assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+ }
+
private void assertHasStartingWindow(ActivityRecord atoken) {
assertNotNull(atoken.mStartingSurface);
assertNotNull(atoken.mStartingData);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index a8e17534e6ed..8e7ba4bc3293 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -258,6 +258,7 @@ public class SystemServicesTestRule implements TestRule {
final ActivityManagerInternal amInternal = mAmService.mInternal;
spyOn(amInternal);
doNothing().when(amInternal).trimApplications();
+ doNothing().when(amInternal).scheduleAppGcs();
doNothing().when(amInternal).updateCpuStats();
doNothing().when(amInternal).updateOomAdj();
doNothing().when(amInternal).updateBatteryStats(any(), anyInt(), anyInt(), anyBoolean());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 92b670ed9699..d88ac256be5c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -891,6 +891,40 @@ public class WindowStateTests extends WindowTestsBase {
assertTrue(mAppWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR));
}
+ @Test
+ public void testAdjustImeInsetsVisibilityWhenSwitchingApps() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2");
+ final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
+ spyOn(imeWindow);
+ doReturn(true).when(imeWindow).isVisible();
+ mDisplayContent.mInputMethodWindow = imeWindow;
+
+ final InsetsStateController controller = mDisplayContent.getInsetsStateController();
+ controller.getImeSourceProvider().setWindow(imeWindow, null, null);
+
+ // Simulate app requests IME with updating all windows Insets State when IME is above app.
+ mDisplayContent.setImeLayeringTarget(app);
+ mDisplayContent.setImeInputTarget(app);
+ assertTrue(mDisplayContent.shouldImeAttachedToApp());
+ controller.getImeSourceProvider().scheduleShowImePostLayout(app);
+ controller.getImeSourceProvider().getSource().setVisible(true);
+ controller.updateAboveInsetsState(imeWindow, false);
+
+ // Expect all app windows behind IME can receive IME insets visible.
+ assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
+ assertTrue(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
+
+ // Simulate app plays closing transition to app2.
+ app.mActivityRecord.commitVisibility(false, false);
+ assertTrue(app.mActivityRecord.mLastImeShown);
+ assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+ // Verify the IME insets is visible on app, but not for app2 during app task switching.
+ assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
+ assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
+ }
+
@UseTestDisplay(addWindows = { W_ACTIVITY })
@Test
public void testUpdateImeControlTargetWhenLeavingMultiWindow() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index d048f1842aa3..589f9134f227 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -44,6 +45,7 @@ import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mockito;
import java.util.function.BiFunction;
@@ -126,7 +128,7 @@ public class WindowTokenTests extends WindowTestsBase {
final WindowState window1 = createWindow(null, TYPE_TOAST, token, "window1");
final WindowState window2 = createWindow(null, TYPE_TOAST, token, "window2");
- mDisplayContent.removeWindowToken(token.token);
+ mDisplayContent.removeWindowToken(token.token, true /* animateExit */);
// Verify that the token is no longer mapped on the display
assertNull(mDisplayContent.getWindowToken(token.token));
// Verify that the token is still attached to its parent
@@ -261,4 +263,29 @@ public class WindowTokenTests extends WindowTestsBase {
assertNotNull(app.getFrozenInsetsState());
assertNull(mDisplayContent.mInputMethodWindow.getFrozenInsetsState());
}
+
+ @Test
+ public void testRemoveWindowToken_noAnimateExitWhenSet() {
+ final TestWindowToken token = createTestWindowToken(0, mDisplayContent);
+ final WindowState win = createWindow(null, TYPE_APPLICATION, token, "win");
+ makeWindowVisible(win);
+ assertTrue(win.isOnScreen());
+ spyOn(win);
+ spyOn(win.mWinAnimator);
+ spyOn(win.mToken);
+
+ // Invoking removeWindowToken with setting no window exit animation and not remove window
+ // immediately. verify the window will hide without applying exit animation.
+ mWm.removeWindowToken(win.mToken.token, false /* removeWindows */, false /* animateExit */,
+ mDisplayContent.mDisplayId);
+ verify(win).onSetAppExiting(Mockito.eq(false) /* animateExit */);
+ verify(win).hide(false /* doAnimation */, false /* requestAnim */);
+ assertFalse(win.isOnScreen());
+ verify(win.mWinAnimator, Mockito.never()).applyAnimationLocked(TRANSIT_EXIT, false);
+ assertTrue(win.mToken.hasChild());
+
+ // Even though the window is being removed afterwards, it won't apply exit animation.
+ win.removeIfPossible();
+ verify(win.mWinAnimator, Mockito.never()).applyAnimationLocked(TRANSIT_EXIT, false);
+ }
}
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index cac716efe78f..0ddd52dfc76d 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -69,7 +69,14 @@ import java.util.List;
* them know that the app has crashed and that their call was continued using the pre-loaded dialer
* app.
* <p>
- * Further, the pre-loaded dialer will ALWAYS be used when the user places an emergency call.
+ * The pre-loaded dialer will ALWAYS be used when the user places an emergency call, even if your
+ * app fills the {@link android.app.role.RoleManager#ROLE_DIALER} role. To ensure an optimal
+ * experience when placing an emergency call, the default dialer should ALWAYS use
+ * {@link android.telecom.TelecomManager#placeCall(Uri, Bundle)} to place calls (including
+ * emergency calls). This ensures that the platform is able to verify that the request came from
+ * the default dialer. If a non-preloaded dialer app uses {@link Intent#ACTION_CALL} to place an
+ * emergency call, it will be raised to the preloaded dialer app using {@link Intent#ACTION_DIAL}
+ * for confirmation; this is a suboptimal user experience.
* <p>
* Below is an example manifest registration for an {@code InCallService}. The meta-data
* {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} indicates that this particular
diff --git a/telephony/OWNERS b/telephony/OWNERS
index 4df8a4bc6413..4016ba7de379 100644
--- a/telephony/OWNERS
+++ b/telephony/OWNERS
@@ -1,6 +1,5 @@
set noparent
-amitmahajan@google.com
breadley@google.com
fionaxu@google.com
jackyu@google.com
@@ -8,10 +7,10 @@ rgreenwalt@google.com
tgunn@google.com
jminjie@google.com
shuoq@google.com
-nazaninb@google.com
sarahchin@google.com
xiaotonj@google.com
huiwang@google.com
jayachandranc@google.com
chinmayd@google.com
amruthr@google.com
+sasindran@google.com
diff --git a/telephony/common/Android.bp b/telephony/common/Android.bp
index 1cacc0365fe1..b0a812bf57a3 100644
--- a/telephony/common/Android.bp
+++ b/telephony/common/Android.bp
@@ -21,7 +21,10 @@ filegroup {
filegroup {
name: "framework-mms-shared-srcs",
- visibility: ["//packages/apps/Bluetooth"],
+ visibility: [
+ "//packages/apps/Bluetooth",
+ "//packages/modules/Bluetooth/android/app",
+ ],
srcs: [
"com/google/android/mms/**/*.java",
],
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 4d81b5e54470..ce4363f66d1c 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -107,6 +107,26 @@ public final class TelephonyPermissions {
}
}
+
+ /**
+ * Check whether the caller (or self, if not processing an IPC) has non dangerous
+ * read phone state permission.
+ * @param context app context
+ * @param message detail message
+ * @return true if permission is granted, else false
+ */
+ public static boolean checkCallingOrSelfReadNonDangerousPhoneStateNoThrow(
+ Context context, String message) {
+ try {
+ context.enforcePermission(
+ Manifest.permission.READ_BASIC_PHONE_STATE,
+ Binder.getCallingPid(), Binder.getCallingUid(), message);
+ return true;
+ } catch (SecurityException se) {
+ return false;
+ }
+ }
+
/**
* Check whether the app with the given pid/uid can read phone state.
*
diff --git a/telephony/java/android/telephony/AvailableNetworkInfo.java b/telephony/java/android/telephony/AvailableNetworkInfo.java
index ae597e02f33c..2b355ae216e3 100644
--- a/telephony/java/android/telephony/AvailableNetworkInfo.java
+++ b/telephony/java/android/telephony/AvailableNetworkInfo.java
@@ -16,11 +16,14 @@
package android.telephony;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.RadioAccessSpecifier;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -32,7 +35,6 @@ import java.util.Objects;
* Network Service when passed through {@link TelephonyManager#updateAvailableNetworks}
*/
public final class AvailableNetworkInfo implements Parcelable {
-
/*
* Defines number of priority level high.
*/
@@ -48,6 +50,14 @@ public final class AvailableNetworkInfo implements Parcelable {
*/
public static final int PRIORITY_LOW = 3;
+ /** @hide */
+ @IntDef({
+ PRIORITY_HIGH,
+ PRIORITY_MED,
+ PRIORITY_LOW,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AvailableNetworkInfoPriority {}
/**
* subscription Id of the available network. This value must be one of the entry retrieved from
* {@link SubscriptionManager#getOpportunisticSubscriptions}
@@ -62,7 +72,7 @@ public final class AvailableNetworkInfo implements Parcelable {
* for network selection. If there are more than one subId with highest priority then the
* network with highest RSRP is chosen.
*/
- private int mPriority;
+ private @AvailableNetworkInfoPriority int mPriority;
/**
* Describes the List of PLMN ids (MCC-MNC) associated with mSubId.
@@ -77,8 +87,7 @@ public final class AvailableNetworkInfo implements Parcelable {
* Opportunistic network service will use these bands to scan.
*
* When no specific bands are specified (empty array or null) CBRS band
- * {@link AccessNetworkConstants.EutranBand.BAND_48
- * } will be used for network scan.
+ * {@link AccessNetworkConstants.EutranBand.BAND_48} will be used for network scan.
*
* See {@link AccessNetworkConstants} for details.
*
@@ -94,7 +103,7 @@ public final class AvailableNetworkInfo implements Parcelable {
* If this entry is left empty, {@link RadioAcccessSpecifier}s with {@link AccessNetworkType}s
* of {@link AccessNetworkConstants.AccessNetworkType.EUTRAN} and {@link
* AccessNetworkConstants.AccessNetworkType.NGRAN} with bands 48 and 71 on each will be assumed
- * by Opportunistic network service.
+ * by Opportunistic network service for a network scan.
*/
private ArrayList<RadioAccessSpecifier> mRadioAccessSpecifiers;
@@ -117,6 +126,7 @@ public final class AvailableNetworkInfo implements Parcelable {
* network with highest RSRP is chosen.
* @return priority level
*/
+ @AvailableNetworkInfoPriority
public int getPriority() {
return mPriority;
}
@@ -149,15 +159,9 @@ public final class AvailableNetworkInfo implements Parcelable {
* Returns a list of {@link RadioAccessSpecifier} associated with the available network.
* Opportunistic network service will use this to determine which bands to scan for.
*
- * the returned value is one of {@link AccessNetworkConstants.AccessNetworkType}. When no
- * specific access network type is specified, {@link RadioAccessSpecifier}s with {@link
- * AccessNetworkType}s of {@link AccessNetworkConstants.AccessNetworkType.EUTRAN} and {@link
- * AccessNetworkConstants.AccessNetworkType.NGRAN} with bands 48 and 71 on each will be assumed
- * by Opportunistic network service.
* @return the access network type associated with the available network.
- * @hide
*/
- public List<RadioAccessSpecifier> getRadioAccessSpecifiers() {
+ public @NonNull List<RadioAccessSpecifier> getRadioAccessSpecifiers() {
return (List<RadioAccessSpecifier>) mRadioAccessSpecifiers.clone();
}
@@ -193,9 +197,9 @@ public final class AvailableNetworkInfo implements Parcelable {
}
/** @hide */
- private AvailableNetworkInfo(int subId, int priority, @NonNull List<String> mccMncs,
- @NonNull List<Integer> bands, @NonNull List<RadioAccessSpecifier>
- radioAccessSpecifiers) {
+ private AvailableNetworkInfo(int subId, @AvailableNetworkInfoPriority int priority,
+ @NonNull List<String> mccMncs, @NonNull List<Integer> bands,
+ @NonNull List<RadioAccessSpecifier> radioAccessSpecifiers) {
mSubId = subId;
mPriority = priority;
mMccMncs = new ArrayList<String>(mccMncs);
@@ -261,27 +265,39 @@ public final class AvailableNetworkInfo implements Parcelable {
*
* <pre><code>
*
- * AvailableNetworkInfo aNI = new AvailableNetworkInfo.Builder()
- * .setSubId(1)
+ * AvailableNetworkInfo aNI = new AvailableNetworkInfo.Builder(subId)
* .setPriority(AvailableNetworkInfo.PRIORITY_MED)
+ * .setRadioAccessSpecifiers(radioAccessSpecifiers)
+ * .setMccMncs(mccMncs)
* .build();
* </code></pre>
- *
- * @hide
*/
public static final class Builder {
private int mSubId = Integer.MIN_VALUE;
- private int mPriority = AvailableNetworkInfo.PRIORITY_LOW;
+ private @AvailableNetworkInfoPriority int mPriority = AvailableNetworkInfo.PRIORITY_LOW;
private ArrayList<String> mMccMncs = new ArrayList<>();
- private ArrayList<Integer> mBands = new ArrayList<>();
private ArrayList<RadioAccessSpecifier> mRadioAccessSpecifiers = new ArrayList<>();
- public @NonNull Builder setSubId(int subId) {
+ /**
+ *
+ */
+ /**
+ * Creates an AvailableNetworkInfo Builder with specified subscription id.
+ *
+ * @param subId of the availableNetwork.
+ */
+ public Builder(int subId) {
mSubId = subId;
- return this;
}
- public @NonNull Builder setPriority(int priority) {
+ /**
+ * Sets the priority for the subscription id.
+ *
+ * @param priority of the subscription id. See {@link AvailableNetworkInfo#getPriority} for
+ * more details
+ * @return the original Builder object.
+ */
+ public @NonNull Builder setPriority(@AvailableNetworkInfoPriority int priority) {
if (priority > AvailableNetworkInfo.PRIORITY_LOW
|| priority < AvailableNetworkInfo.PRIORITY_HIGH) {
throw new IllegalArgumentException("A valid priority must be set");
@@ -290,30 +306,48 @@ public final class AvailableNetworkInfo implements Parcelable {
return this;
}
- public @NonNull Builder setMccMncs(@NonNull ArrayList<String> mccMncs) {
- Objects.requireNonNull(mccMncs, "A non-null ArrayList of mccmncs must be set. An empty "
- + "list is still accepted. Please read documentation in "
- + "AvailableNetworkService to see consequences of an empty Arraylist.");
- mMccMncs = mccMncs;
+ /**
+ * Sets the list of mccmncs associated with the subscription id.
+ *
+ * @param mccMncs nonull list of mccmncs. An empty List is still accepted. Please read
+ * documentation in {@link AvailableNetworkInfo} to see consequences of an empty List.
+ * @return the original Builder object.
+ */
+ public @NonNull Builder setMccMncs(@NonNull List<String> mccMncs) {
+ Objects.requireNonNull(mccMncs, "A non-null List of mccmncs must be set. An empty "
+ + "List is still accepted. Please read documentation in "
+ + "AvailableNetworkInfo to see consequences of an empty List.");
+ mMccMncs = new ArrayList<>(mccMncs);
return this;
}
+ /**
+ * Sets the list of mccmncs associated with the subscription id.
+ *
+ * @param radioAccessSpecifiers nonull list of radioAccessSpecifiers. An empty List is still
+ * accepted. Please read documentation in {@link AvailableNetworkInfo} to see
+ * consequences of an empty List.
+ * @return the original Builder object.
+ */
public @NonNull Builder setRadioAccessSpecifiers(
- @NonNull ArrayList<RadioAccessSpecifier> radioAccessSpecifiers) {
- Objects.requireNonNull(radioAccessSpecifiers, "A non-null ArrayList of "
- + "RadioAccessSpecifiers must be set. An empty list is still accepted. Please "
- + "read documentation in AvailableNetworkService to see consequences of an "
- + "empty Arraylist.");
- mRadioAccessSpecifiers = radioAccessSpecifiers;
+ @NonNull List<RadioAccessSpecifier> radioAccessSpecifiers) {
+ Objects.requireNonNull(radioAccessSpecifiers, "A non-null List of "
+ + "RadioAccessSpecifiers must be set. An empty List is still accepted. Please "
+ + "read documentation in AvailableNetworkInfo to see consequences of an "
+ + "empty List.");
+ mRadioAccessSpecifiers = new ArrayList<>(radioAccessSpecifiers);
return this;
}
+ /**
+ * @return an AvailableNetworkInfo object with all the fields previously set by the Builder.
+ */
public @NonNull AvailableNetworkInfo build() {
if (mSubId == Integer.MIN_VALUE) {
throw new IllegalArgumentException("A valid subId must be set");
}
- return new AvailableNetworkInfo(mSubId, mPriority, mMccMncs, mBands,
+ return new AvailableNetworkInfo(mSubId, mPriority, mMccMncs, new ArrayList<>(),
mRadioAccessSpecifiers);
}
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index d11c66702d99..5ffe45f8c489 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -21,6 +21,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressAutoDoc;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -3674,6 +3675,49 @@ public class CarrierConfigManager {
"show_wifi_calling_icon_in_status_bar_bool";
/**
+ * Configuration to indicate that the carrier supports opportunistic data
+ * auto provisioning. Based on this flag, the device downloads and activates
+ * corresponding opportunistic profile.
+ */
+ public static final String KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL =
+ "carrier_supports_opp_data_auto_provisioning_bool";
+
+ /**
+ * SMDP+ server address for downloading opportunistic eSIM profile.
+ * FQDN (Fully Qualified Domain Name) of the SM-DP+ (e.g., smdp.gsma.com) restricted to the
+ * Alphanumeric mode character set defined in table 5 of ISO/IEC 18004 [15] excluding '$'.
+ */
+ public static final String KEY_SMDP_SERVER_ADDRESS_STRING =
+ "smdp_server_address_string";
+
+ /**
+ * This timer value is used in the eSIM Exponential Backoff download retry algorithm.
+ * Value should be in seconds.
+ * <OL>
+ * <LI>When the first download failure occurs, retry download after BACKOFF_TIMER_VALUE
+ * seconds.</LI>
+ *
+ * <LI>If download fails again then, retry after either BACKOFF_TIMER_VALUE,
+ * 2xBACKOFF_TIMER_VALUE, or 3xBACKOFF_TIMER_VALUE seconds.</LI>
+ *
+ * <LI>In general after the cth failed attempt, retry after k * BACKOFF_TIMER_VALUE
+ * seconds, where k is a random integer between 1 and 2^c − 1. Max c value is
+ * {@link #KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT}</LI>
+ * </OL>
+ */
+ public static final String KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT =
+ "esim_download_retry_backoff_timer_sec_int";
+
+ /**
+ * If eSIM profile download fails then, the number of retry attempts by UE
+ * will be based on this configuration. If download still fails even after the
+ * MAX attempts configured by this item then the retry is postponed until next
+ * device bootup.
+ */
+ public static final String KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT =
+ "esim_max_download_retry_attempts_int";
+
+ /**
* Controls RSRP threshold at which OpportunisticNetworkService will decide whether
* the opportunistic network is good enough for internet data.
*/
@@ -3883,6 +3927,30 @@ public class CarrierConfigManager {
public static final String KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL =
"enabled_4g_opportunistic_network_scan_bool";
+ /**
+ * Only relevant when the device supports opportunistic networks but does not support
+ * simultaneuous 5G+5G. Controls how long, in milliseconds, to wait before opportunistic network
+ * goes out of service before switching the 5G capability back to primary stack. The idea of
+ * waiting a few seconds is to minimize the calling of the expensive capability switching
+ * operation in the case where CBRS goes back into service shortly after going out of it.
+ *
+ * @hide
+ */
+ public static final String KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG =
+ "time_to_switch_back_to_primary_if_opportunistic_oos_long";
+
+ /**
+ * Only relevant when the device supports opportunistic networks but does not support
+ * simultaneuous 5G+5G. Controls how long, in milliseconds, after 5G capability has switched back
+ * to primary stack due to opportunistic network being OOS. The idea is to minimizing the
+ * 'ping-ponging' effect where device is constantly witching capability back and forth between
+ * primary and opportunistic stack.
+ *
+ * @hide
+ */
+ public static final String KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG
+ = "opportunistic_time_to_scan_after_capability_switch_to_primary_long";
+
/**
* Indicates zero or more emergency number prefix(es), because some carrier requires
* if users dial an emergency number address with a specific prefix, the combination of the
@@ -5073,16 +5141,6 @@ public class CarrierConfigManager {
"call_composer_picture_server_url_string";
/**
- * For Android 11, provide a temporary solution for OEMs to use the lower of the two MTU values
- * for IPv4 and IPv6 if both are sent.
- * TODO: remove in later release
- *
- * @hide
- */
- public static final String KEY_USE_LOWER_MTU_VALUE_IF_BOTH_RECEIVED =
- "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,
@@ -5191,6 +5249,26 @@ public class CarrierConfigManager {
"display_no_data_notification_on_permanent_failure_bool";
/**
+ * Boolean indicating if the VoNR setting is visible in the Call Settings menu.
+ * If true, the VoNR setting menu will be visible. If false, the menu will be gone.
+ *
+ * Disabled by default.
+ *
+ * @hide
+ */
+ public static final String KEY_VONR_SETTING_VISIBILITY_BOOL = "vonr_setting_visibility_bool";
+
+ /**
+ * Flag specifying whether VoNR should be enabled for carrier.
+ * If true, VoNr will be enabled. If false, hard disabled.
+ *
+ * Disabled by default.
+ *
+ * @hide
+ */
+ public static final String KEY_VONR_ENABLED_BOOL = "vonr_enabled_bool";
+
+ /**
* Determine whether unthrottle data retry when tracking area code (TAC/LAC) from cell changes
*
* @hide
@@ -5692,6 +5770,10 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_UNMETERED_NR_SA_SUB6_BOOL, false);
sDefaults.putBoolean(KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_WIFI_CALLING_ICON_IN_STATUS_BAR_BOOL, false);
+ sDefaults.putBoolean(KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL, false);
+ sDefaults.putString(KEY_SMDP_SERVER_ADDRESS_STRING, "");
+ sDefaults.putInt(KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT, 5);
+ sDefaults.putInt(KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT, 60);
/* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */
sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -108);
/* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_MODERATE */
@@ -5735,6 +5817,10 @@ public class CarrierConfigManager {
/* Default value is 2 seconds. */
sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 2000);
sDefaults.putBoolean(KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL, true);
+ sDefaults.putInt(KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG, 60000);
+ sDefaults.putInt(
+ KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG,
+ 120000);
sDefaults.putAll(Gps.getDefaults());
sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY,
new int[] {
@@ -5792,7 +5878,6 @@ public class CarrierConfigManager {
sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, "");
sDefaults.putBoolean(KEY_SUPPORTS_CALL_COMPOSER_BOOL, false);
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.putBoolean(KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL, true);
sDefaults.putInt(KEY_DEFAULT_RTT_MODE_INT, 0);
@@ -5806,6 +5891,8 @@ public class CarrierConfigManager {
sDefaults.putString(KEY_CARRIER_PROVISIONING_APP_STRING, "");
sDefaults.putBoolean(KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL, false);
sDefaults.putBoolean(KEY_UNTHROTTLE_DATA_RETRY_WHEN_TAC_CHANGES_BOOL, false);
+ sDefaults.putBoolean(KEY_VONR_SETTING_VISIBILITY_BOOL, false);
+ sDefaults.putBoolean(KEY_VONR_ENABLED_BOOL, false);
}
/**
@@ -5874,12 +5961,15 @@ public class CarrierConfigManager {
* any carrier specific configuration has been applied.
*
* <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}, or the calling app
+ * has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}).
*
* @param subId the subscription ID, normally obtained from {@link SubscriptionManager}.
* @return A {@link PersistableBundle} containing the config for the given subId, or default
* values for an invalid subId.
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
@Nullable
public PersistableBundle getConfigForSubId(int subId) {
try {
@@ -5968,10 +6058,13 @@ public class CarrierConfigManager {
* called to confirm whether any carrier specific configuration has been applied.
*
* <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}, or the calling app
+ * has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}).
*
* @see #getConfigForSubId
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
@Nullable
public PersistableBundle getConfig() {
return getConfigForSubId(SubscriptionManager.getDefaultSubscriptionId());
@@ -5980,8 +6073,8 @@ public class CarrierConfigManager {
/**
* Determines whether a configuration {@link PersistableBundle} obtained from
* {@link #getConfig()} or {@link #getConfigForSubId(int)} corresponds to an identified carrier.
- * <p>
- * When an app receives the {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED}
+ *
+ * <p>When an app receives the {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED}
* broadcast which informs it that the carrier configuration has changed, it is possible
* that another reload of the carrier configuration has begun since the intent was sent.
* In this case, the carrier configuration the app fetches (e.g. via {@link #getConfig()})
@@ -5990,14 +6083,12 @@ public class CarrierConfigManager {
* return true because it may belong to another previous identified carrier. Users should
* always call {@link #getConfig()} or {@link #getConfigForSubId(int)} after receiving the
* broadcast {@link #ACTION_CARRIER_CONFIG_CHANGED}.
- * </p>
- * <p>
- * After using {@link #getConfig()} or {@link #getConfigForSubId(int)} an app should always
+ *
+ * <p>After using {@link #getConfig()} or {@link #getConfigForSubId(int)} an app should always
* use this method to confirm whether any carrier specific configuration has been applied.
* Especially when an app misses the broadcast {@link #ACTION_CARRIER_CONFIG_CHANGED} but it
* still needs to get the current configuration, it must use this method to verify whether the
* configuration is default or carrier overridden.
- * </p>
*
* @param bundle the configuration bundle to be checked.
* @return boolean true if any carrier specific configuration bundle has been applied, false
@@ -6009,19 +6100,20 @@ public class CarrierConfigManager {
/**
* Calling this method triggers telephony services to fetch the current carrier configuration.
- * <p>
- * Normally this does not need to be called because the platform reloads config on its own.
+ *
+ * <p>Normally this does not need to be called because the platform reloads config on its own.
* This should be called by a carrier service app if it wants to update config at an arbitrary
* moment.
- * </p>
- * <p>Requires that the calling app has carrier privileges.
- * <p>
- * This method returns before the reload has completed, and
- * {@link android.service.carrier.CarrierService#onLoadConfig} will be called from an
- * arbitrary thread.
- * </p>
- * @see TelephonyManager#hasCarrierPrivileges
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or the calling app
+ * has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}).
+ *
+ * <p>This method returns before the reload has completed, and {@link
+ * android.service.carrier.CarrierService#onLoadConfig} will be called from an arbitrary thread.
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void notifyConfigChangedForSubId(int subId) {
try {
ICarrierConfigLoader loader = getICarrierConfigLoader();
@@ -6037,11 +6129,10 @@ public class CarrierConfigManager {
}
/**
- * Request the carrier config loader to update the cofig for phoneId.
- * <p>
- * Depending on simState, the config may be cleared or loaded from config app. This is only used
- * by SubscriptionInfoUpdater.
- * </p>
+ * Request the carrier config loader to update the config for phoneId.
+ *
+ * <p>Depending on simState, the config may be cleared or loaded from config app. This is only
+ * used by SubscriptionInfoUpdater.
*
* @hide
*/
@@ -6112,13 +6203,16 @@ public class CarrierConfigManager {
* Gets the configuration values for a component using its prefix.
*
* <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}, or the calling app
+ * has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges()}).
*
* @param prefix prefix of the component.
* @param subId the subscription ID, normally obtained from {@link SubscriptionManager}.
*
* @see #getConfigForSubId
*/
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
@Nullable
public PersistableBundle getConfigByComponentForSubId(@NonNull String prefix, int subId) {
PersistableBundle configs = getConfigForSubId(subId);
diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java
index 42d7707c97d9..fc76f99cf074 100644
--- a/telephony/java/android/telephony/ImsManager.java
+++ b/telephony/java/android/telephony/ImsManager.java
@@ -119,7 +119,7 @@ public class ImsManager {
throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
}
- return new ImsRcsManager(mContext, subscriptionId, sRcsCache);
+ return new ImsRcsManager(mContext, subscriptionId, sRcsCache, sTelephonyCache);
}
/**
@@ -135,7 +135,7 @@ public class ImsManager {
throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
}
- return new ImsMmTelManager(subscriptionId, sTelephonyCache);
+ return new ImsMmTelManager(mContext, subscriptionId, sTelephonyCache);
}
/**
@@ -157,7 +157,7 @@ public class ImsManager {
throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
}
- return new SipDelegateManager(mContext, subscriptionId, sRcsCache);
+ return new SipDelegateManager(mContext, subscriptionId, sRcsCache, sTelephonyCache);
}
private static IImsRcsController getIImsRcsControllerInterface() {
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index d250088c2f10..95448c7807cc 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -242,6 +242,11 @@ public final class PhysicalChannelConfig implements Parcelable {
}
/**
+ * The physical cell ID which differentiates cells using the same radio channel.
+ *
+ * In GERAN, this value is the BSIC. The range is [0-63].
+ * Reference: 3GPP TS 3.03 section 4.2.2.
+ *
* In UTRAN, this value is primary scrambling code. The range is [0, 511].
* Reference: 3GPP TS 25.213 section 5.2.2.
*
diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
index 41e24ddb3fa6..9cb80f1814f9 100644
--- a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
@@ -17,6 +17,8 @@
package android.telephony;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
@@ -66,10 +68,10 @@ public final class SignalStrengthUpdateRequest implements Parcelable {
private final IBinder mLiveToken;
private SignalStrengthUpdateRequest(
- @NonNull List<SignalThresholdInfo> signalThresholdInfos,
+ @Nullable List<SignalThresholdInfo> signalThresholdInfos,
boolean isReportingRequestedWhileIdle,
boolean isSystemThresholdReportingRequestedWhileIdle) {
- validate(signalThresholdInfos);
+ validate(signalThresholdInfos, isSystemThresholdReportingRequestedWhileIdle);
mSignalThresholdInfos = signalThresholdInfos;
mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle;
@@ -128,13 +130,15 @@ public final class SignalStrengthUpdateRequest implements Parcelable {
/**
* Set the builder object if require reporting on the system thresholds when device is idle.
*
- * This can only used by the system caller.
+ * <p>This can only used by the system caller. Requires permission
+ * {@link android.Manifest.permission#LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH}.
*
* @param isSystemThresholdReportingRequestedWhileIdle true if request reporting on the
* system thresholds when device is idle
* @return the builder to facilitate the chaining
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
public @NonNull Builder setSystemThresholdReportingRequestedWhileIdle(
boolean isSystemThresholdReportingRequestedWhileIdle) {
mIsSystemThresholdReportingRequestedWhileIdle =
@@ -265,8 +269,12 @@ public final class SignalStrengthUpdateRequest implements Parcelable {
* Throw IAE if SignalThresholdInfo collection is null or empty,
* or the SignalMeasurementType for the same RAN in the collection is not unique.
*/
- private static void validate(Collection<SignalThresholdInfo> infos) {
- if (infos == null || infos.isEmpty()) {
+ private static void validate(Collection<SignalThresholdInfo> infos,
+ boolean isSystemThresholdReportingRequestedWhileIdle) {
+ // System app (like Bluetooth) can specify the request to report system thresholds while
+ // device is idle (with permission protection). In this case, the request doesn't need to
+ // provide a non-empty list of SignalThresholdInfo which is only asked for public apps.
+ if (infos == null || (infos.isEmpty() && !isSystemThresholdReportingRequestedWhileIdle)) {
throw new IllegalArgumentException("SignalThresholdInfo collection is null or empty");
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 3b44a34048b8..d5315acf60d5 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -949,6 +949,15 @@ public class SubscriptionManager {
public static final String VOIMS_OPT_IN_STATUS = SimInfo.COLUMN_VOIMS_OPT_IN_STATUS;
/**
+ * TelephonyProvider column name for NR Advanced calling
+ * Determines if the user has enabled VoNR settings for this subscription.
+ *
+ * @hide
+ */
+ public static final String NR_ADVANCED_CALLING_ENABLED =
+ SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED;
+
+ /**
* Profile class of the subscription
* @hide
*/
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a1bed29dec70..453547c49498 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -315,6 +315,12 @@ public class TelephonyManager {
*/
public static final int UNINITIALIZED_CARD_ID = -2;
+ /**
+ * Default port index for the UICC Card
+ * @hide
+ */
+ public static final int DEFAULT_PORT_INDEX = 0;
+
private final Context mContext;
private final int mSubId;
@UnsupportedAppUsage
@@ -1889,9 +1895,10 @@ public class TelephonyManager {
* the IMEI/SV for GSM phones. Return null if the software version is
* not available.
* <p>
- * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}.
*/
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_BASIC_PHONE_STATE})
@Nullable
public String getDeviceSoftwareVersion() {
return getDeviceSoftwareVersion(getSlotIndex());
@@ -2953,7 +2960,9 @@ public class TelephonyManager {
* when opportunistic network is providing cellular internet connection to the user.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * or {@link android.Manifest.permission#READ_BASIC_PHONE_STATE
+ * READ_BASIC_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link #hasCarrierPrivileges}).
*
* @return the network type
*
@@ -2976,7 +2985,9 @@ public class TelephonyManager {
* @see #NETWORK_TYPE_NR
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_BASIC_PHONE_STATE})
public @NetworkType int getDataNetworkType() {
return getDataNetworkType(getSubId(SubscriptionManager.getActiveDataSubscriptionId()));
}
@@ -3014,10 +3025,14 @@ public class TelephonyManager {
* Returns the NETWORK_TYPE_xxxx for voice
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * or {@link android.Manifest.permission#READ_BASIC_PHONE_STATE
+ * READ_BASIC_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link #hasCarrierPrivileges}).
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_BASIC_PHONE_STATE})
public @NetworkType int getVoiceNetworkType() {
return getVoiceNetworkType(getSubId());
}
@@ -6581,12 +6596,7 @@ public class TelephonyManager {
* @param AID Application id. See ETSI 102.221 and 101.220.
* @param p2 P2 parameter (described in ISO 7816-4).
* @return an IccOpenLogicalChannelResponse object.
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openLogicalChannel(byte[], byte)}.
*/
- @Deprecated
public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID, int p2) {
return iccOpenLogicalChannel(getSubId(), AID, p2);
}
@@ -6617,12 +6627,7 @@ public class TelephonyManager {
* @param p2 P2 parameter (described in ISO 7816-4).
* @return an IccOpenLogicalChannelResponse object.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openLogicalChannel(byte[], byte)}.
*/
- @Deprecated
public IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID, int p2) {
try {
ITelephony telephony = getITelephony();
@@ -6650,10 +6655,7 @@ public class TelephonyManager {
* iccOpenLogicalChannel.
* @return true if the channel was closed successfully.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.Channel#close()}.
*/
- @Deprecated
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@SystemApi
public boolean iccCloseLogicalChannelBySlot(int slotIndex, int channel) {
@@ -6680,10 +6682,7 @@ public class TelephonyManager {
* @param channel is the channel id to be closed as returned by a successful
* iccOpenLogicalChannel.
* @return true if the channel was closed successfully.
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.Channel#close()}.
*/
- @Deprecated
public boolean iccCloseLogicalChannel(int channel) {
return iccCloseLogicalChannel(getSubId(), channel);
}
@@ -6702,10 +6701,7 @@ public class TelephonyManager {
* iccOpenLogicalChannel.
* @return true if the channel was closed successfully.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.Channel#close()}.
*/
- @Deprecated
public boolean iccCloseLogicalChannel(int subId, int channel) {
try {
ITelephony telephony = getITelephony();
@@ -6741,10 +6737,7 @@ public class TelephonyManager {
* @return The APDU response from the ICC card with the status appended at the end, or null if
* there is an issue connecting to the Telephony service.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@SystemApi
@Nullable
@@ -6782,10 +6775,7 @@ public class TelephonyManager {
* @param data Data to be sent with the APDU.
* @return The APDU response from the ICC card with the status appended at
* the end.
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
public String iccTransmitApduLogicalChannel(int channel, int cla,
int instruction, int p1, int p2, int p3, String data) {
return iccTransmitApduLogicalChannel(getSubId(), channel, cla,
@@ -6814,10 +6804,7 @@ public class TelephonyManager {
* @return The APDU response from the ICC card with the status appended at
* the end.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
public String iccTransmitApduLogicalChannel(int subId, int channel, int cla,
int instruction, int p1, int p2, int p3, String data) {
try {
@@ -6853,13 +6840,7 @@ public class TelephonyManager {
* @return The APDU response from the ICC card with the status appended at
* the end.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@SystemApi
@NonNull
@@ -6895,13 +6876,7 @@ public class TelephonyManager {
* @param data Data to be sent with the APDU.
* @return The APDU response from the ICC card with the status appended at
* the end.
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
public String iccTransmitApduBasicChannel(int cla,
int instruction, int p1, int p2, int p3, String data) {
return iccTransmitApduBasicChannel(getSubId(), cla,
@@ -6928,13 +6903,7 @@ public class TelephonyManager {
* @return The APDU response from the ICC card with the status appended at
* the end.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
public String iccTransmitApduBasicChannel(int subId, int cla,
int instruction, int p1, int p2, int p3, String data) {
try {
@@ -6962,13 +6931,7 @@ public class TelephonyManager {
* @param p3 P3 value of the APDU command.
* @param filePath
* @return The APDU response.
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
String filePath) {
return iccExchangeSimIO(getSubId(), fileID, command, p1, p2, p3, filePath);
@@ -6990,13 +6953,7 @@ public class TelephonyManager {
* @param filePath
* @return The APDU response.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
public byte[] iccExchangeSimIO(int subId, int fileID, int command, int p1, int p2,
int p3, String filePath) {
try {
@@ -7022,13 +6979,7 @@ public class TelephonyManager {
* @return The APDU response from the ICC card in hexadecimal format
* with the last 4 bytes being the status word. If the command fails,
* returns an empty string.
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
public String sendEnvelopeWithStatus(String content) {
return sendEnvelopeWithStatus(getSubId(), content);
}
@@ -7048,13 +6999,7 @@ public class TelephonyManager {
* with the last 4 bytes being the status word. If the command fails,
* returns an empty string.
* @hide
- * @deprecated Use {@link android.se.omapi.SEService} APIs instead. See
- * {@link android.se.omapi.SEService#getUiccReader(int)},
- * {@link android.se.omapi.Reader#openSession()},
- * {@link android.se.omapi.Session#openBasicChannel(byte[], byte)},
- * {@link android.se.omapi.Channel#transmit(byte[])}.
*/
- @Deprecated
public String sendEnvelopeWithStatus(int subId, String content) {
try {
ITelephony telephony = getITelephony();
@@ -9969,7 +9914,9 @@ public class TelephonyManager {
*
* <p>Requires one of the following permissions:
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE},
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE}, or that the calling app has carrier
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE}, or
+ * {@link android.Manifest.permission#READ_BASIC_PHONE_STATE
+ * READ_BASIC_PHONE_STATE} or that the calling app has carrier
* privileges (see {@link #hasCarrierPrivileges}).
*
* <p>Note that this does not take into account any data restrictions that may be present on the
@@ -9980,7 +9927,8 @@ public class TelephonyManager {
*/
@RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE,
android.Manifest.permission.MODIFY_PHONE_STATE,
- android.Manifest.permission.READ_PHONE_STATE})
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_BASIC_PHONE_STATE})
public boolean isDataEnabled() {
try {
return isDataEnabledForReason(DATA_ENABLED_REASON_USER);
@@ -9999,14 +9947,17 @@ public class TelephonyManager {
*
* <p>Requires one of the following permissions:
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE},
- * {@link android.Manifest.permission#READ_PHONE_STATE} or that the calling app
+ * {@link android.Manifest.permission#READ_PHONE_STATE} or
+ * {@link android.Manifest.permission#READ_BASIC_PHONE_STATE
+ * READ_BASIC_PHONE_STATE} or that the calling app
* has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @return {@code true} if the data roaming is enabled on the subscription, otherwise return
* {@code false}.
*/
@RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE,
- android.Manifest.permission.READ_PHONE_STATE})
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_BASIC_PHONE_STATE})
public boolean isDataRoamingEnabled() {
boolean isDataRoamingEnabled = false;
try {
@@ -12148,6 +12099,100 @@ public class TelephonyManager {
}
/**
+ * No error. Operation succeeded.
+ * @hide
+ */
+ public static final int ENABLE_VONR_SUCCESS = 0;
+
+ /**
+ * Radio is not available.
+ * @hide
+ */
+ public static final int ENABLE_VONR_RADIO_NOT_AVAILABLE = 2;
+
+ /**
+ * Internal Radio error.
+ * @hide
+ */
+ public static final int ENABLE_VONR_RADIO_ERROR = 3;
+
+ /**
+ * Voice over NR enable/disable request is received when system is in invalid state.
+ * @hide
+ */
+ public static final int ENABLE_VONR_RADIO_INVALID_STATE = 4;
+
+ /**
+ * Voice over NR enable/disable request is not supported.
+ * @hide
+ */
+ public static final int ENABLE_VONR_REQUEST_NOT_SUPPORTED = 5;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"EnableVoNrResult"}, value = {
+ ENABLE_VONR_SUCCESS,
+ ENABLE_VONR_RADIO_NOT_AVAILABLE,
+ ENABLE_VONR_RADIO_ERROR,
+ ENABLE_VONR_RADIO_INVALID_STATE,
+ ENABLE_VONR_REQUEST_NOT_SUPPORTED})
+ public @interface EnableVoNrResult {}
+
+ /**
+ * Enable or disable Voice over NR (VoNR)
+ *
+ * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+ *
+ * @param enabled enable or disable VoNR.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public @EnableVoNrResult int setVoNrEnabled(boolean enabled) {
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ return service.setVoNrEnabled(
+ getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enabled);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#setVoNrEnabled", e);
+ }
+
+ return ENABLE_VONR_RADIO_INVALID_STATE;
+ }
+
+ /**
+ * Is Voice over NR (VoNR) enabled.
+ * @return true if Voice over NR (VoNR) is enabled else false. Enabled state does not mean
+ * voice call over NR is active or voice ove NR is available. It means the device is allowed to
+ * register IMS over NR.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean isVoNrEnabled() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.isVoNrEnabled(getSubId());
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "isVoNrEnabled RemoteException", ex);
+ ex.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
+ /**
* Carrier action to start or stop reporting default network available events.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
@@ -12311,16 +12356,21 @@ public class TelephonyManager {
* <p>If this object has been created with {@link #createForSubscriptionId}, applies
* to the given subId. Otherwise, applies to
* {@link SubscriptionManager#getDefaultDataSubscriptionId()}
- *
* @param reason the reason the data enable change is taking place
* @return whether data is enabled for a reason.
* <p>Requires Permission:
+ * The calling app has carrier privileges (see {@link #hasCarrierPrivileges}) or
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} or
- * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE} or
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+ * {@link android.Manifest.permission#READ_BASIC_PHONE_STATE}
* @throws IllegalStateException if the Telephony process is not currently available.
*/
@RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE,
- android.Manifest.permission.READ_PHONE_STATE})
+ android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ android.Manifest.permission.READ_BASIC_PHONE_STATE
+ })
public boolean isDataEnabledForReason(@DataEnabledReason int reason) {
return isDataEnabledForReason(getSubId(), reason);
}
@@ -12425,26 +12475,6 @@ public class TelephonyManager {
}
/**
- * Enable or disable signal strength changes from radio will always be reported in any
- * condition (e.g. screen is off). This is only allowed for System caller.
- *
- * @param isEnabled {@code true} for enabling; {@code false} for disabling.
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void setAlwaysReportSignalStrength(boolean isEnabled) {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null) {
- telephony.setAlwaysReportSignalStrength(getSubId(), isEnabled);
- }
- } catch (RemoteException ex) {
- Log.e(TAG, "setAlwaysReportSignalStrength RemoteException", ex);
- ex.rethrowAsRuntimeException();
- }
- }
-
- /**
* Get the most recently available signal strength information.
*
* Get the most recent SignalStrength information reported by the modem. Due
@@ -12475,14 +12505,11 @@ public class TelephonyManager {
* <LI>And possibly others.</LI>
* </UL>
* @return {@code true} if the overall data connection is allowed; {@code false} if not.
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} or
- * {@link android.Manifest.permission#ACCESS_NETWORK_STATE} or
- * android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE
*/
@RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE,
android.Manifest.permission.READ_PHONE_STATE,
- android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE})
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_BASIC_PHONE_STATE})
public boolean isDataConnectionAllowed() {
boolean retVal = false;
try {
@@ -13547,15 +13574,18 @@ public class TelephonyManager {
}
/**
- * It indicates whether modem is enabled or not per slot.
- * It's the corresponding status of TelephonyManager.enableModemForSlot.
+ * Indicates whether or not there is a modem stack enabled for the given SIM slot.
*
* <p>Requires Permission:
- * READ_PRIVILEGED_PHONE_STATE or
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE},
+ * READ_PRIVILEGED_PHONE_STATE or that the calling app has carrier privileges (see
+ * {@link #hasCarrierPrivileges()}).
+ *
* @param slotIndex which slot it's checking.
*/
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(anyOf = {android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE})
public boolean isModemEnabledForSlot(int slotIndex) {
try {
ITelephony telephony = getITelephony();
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index be1502ad49f2..1ef04be8f242 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -147,7 +147,12 @@ public class ApnSetting implements Parcelable {
}
// Possible values for authentication types.
- /** No authentication type. */
+ /**
+ * Authentication type is unknown.
+ * @hide
+ */
+ public static final int AUTH_TYPE_UNKNOWN = -1;
+ /** Authentication is not required. */
public static final int AUTH_TYPE_NONE = 0;
/** Authentication type for PAP. */
public static final int AUTH_TYPE_PAP = 1;
@@ -357,6 +362,7 @@ public class ApnSetting implements Parcelable {
/** @hide */
@IntDef(prefix = { "AUTH_TYPE_" }, value = {
+ AUTH_TYPE_UNKNOWN,
AUTH_TYPE_NONE,
AUTH_TYPE_PAP,
AUTH_TYPE_CHAP,
@@ -498,7 +504,8 @@ public class ApnSetting implements Parcelable {
private final String mOperatorNumeric;
private final int mProtocol;
private final int mRoamingProtocol;
- private final int mMtu;
+ private final int mMtuV4;
+ private final int mMtuV6;
private final boolean mCarrierEnabled;
@@ -522,13 +529,25 @@ public class ApnSetting implements Parcelable {
private final int mSkip464Xlat;
/**
- * Returns the MTU size of the mobile interface to which the APN connected.
+ * Returns the MTU size of the IPv4 mobile interface to which the APN connected. Note this value
+ * is used only if MTU size is not provided in {@link DataCallResponse}.
*
* @return the MTU size of the APN
* @hide
*/
- public int getMtu() {
- return mMtu;
+ public int getMtuV4() {
+ return mMtuV4;
+ }
+
+ /**
+ * Returns the MTU size of the IPv6 mobile interface to which the APN connected. Note this value
+ * is used only if MTU size is not provided in {@link DataCallResponse}.
+ *
+ * @return the MTU size of the APN
+ * @hide
+ */
+ public int getMtuV6() {
+ return mMtuV6;
}
/**
@@ -879,13 +898,18 @@ public class ApnSetting implements Parcelable {
this.mMmsProxyPort = builder.mMmsProxyPort;
this.mUser = builder.mUser;
this.mPassword = builder.mPassword;
- this.mAuthType = builder.mAuthType;
+ this.mAuthType = (builder.mAuthType != AUTH_TYPE_UNKNOWN)
+ ? builder.mAuthType
+ : TextUtils.isEmpty(builder.mUser)
+ ? AUTH_TYPE_NONE
+ : AUTH_TYPE_PAP_OR_CHAP;
this.mApnTypeBitmask = builder.mApnTypeBitmask;
this.mId = builder.mId;
this.mOperatorNumeric = builder.mOperatorNumeric;
this.mProtocol = builder.mProtocol;
this.mRoamingProtocol = builder.mRoamingProtocol;
- this.mMtu = builder.mMtu;
+ this.mMtuV4 = builder.mMtuV4;
+ this.mMtuV6 = builder.mMtuV6;
this.mCarrierEnabled = builder.mCarrierEnabled;
this.mNetworkTypeBitmask = builder.mNetworkTypeBitmask;
this.mProfileId = builder.mProfileId;
@@ -903,66 +927,6 @@ public class ApnSetting implements Parcelable {
/**
* @hide
*/
- public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName,
- String apnName, String proxyAddress, int proxyPort, Uri mmsc,
- String mmsProxyAddress, int mmsProxyPort, String user, String password,
- int authType, int mApnTypeBitmask, int protocol, int roamingProtocol,
- boolean carrierEnabled, int networkTypeBitmask, int profileId,
- boolean modemCognitive, int maxConns, int waitTime, int maxConnsTime, int mtu,
- int mvnoType, String mvnoMatchData, int apnSetId, int carrierId, int skip464xlat) {
- return new Builder()
- .setId(id)
- .setOperatorNumeric(operatorNumeric)
- .setEntryName(entryName)
- .setApnName(apnName)
- .setProxyAddress(proxyAddress)
- .setProxyPort(proxyPort)
- .setMmsc(mmsc)
- .setMmsProxyAddress(mmsProxyAddress)
- .setMmsProxyPort(mmsProxyPort)
- .setUser(user)
- .setPassword(password)
- .setAuthType(authType)
- .setApnTypeBitmask(mApnTypeBitmask)
- .setProtocol(protocol)
- .setRoamingProtocol(roamingProtocol)
- .setCarrierEnabled(carrierEnabled)
- .setNetworkTypeBitmask(networkTypeBitmask)
- .setProfileId(profileId)
- .setModemCognitive(modemCognitive)
- .setMaxConns(maxConns)
- .setWaitTime(waitTime)
- .setMaxConnsTime(maxConnsTime)
- .setMtu(mtu)
- .setMvnoType(mvnoType)
- .setMvnoMatchData(mvnoMatchData)
- .setApnSetId(apnSetId)
- .setCarrierId(carrierId)
- .setSkip464Xlat(skip464xlat)
- .buildWithoutCheck();
- }
-
- /**
- * @hide
- */
- public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName,
- String apnName, String proxyAddress, int proxyPort, Uri mmsc,
- String mmsProxyAddress, int mmsProxyPort, String user, String password,
- int authType, int mApnTypeBitmask, int protocol, int roamingProtocol,
- boolean carrierEnabled, int networkTypeBitmask, int profileId, boolean modemCognitive,
- int maxConns, int waitTime, int maxConnsTime, int mtu, int mvnoType,
- String mvnoMatchData) {
- return makeApnSetting(id, operatorNumeric, entryName, apnName, proxyAddress, proxyPort,
- mmsc, mmsProxyAddress, mmsProxyPort, user, password, authType, mApnTypeBitmask,
- protocol, roamingProtocol, carrierEnabled, networkTypeBitmask, profileId,
- modemCognitive, maxConns, waitTime, maxConnsTime, mtu, mvnoType, mvnoMatchData,
- Carriers.NO_APN_SET_ID, TelephonyManager.UNKNOWN_CARRIER_ID,
- Carriers.SKIP_464XLAT_DEFAULT);
- }
-
- /**
- * @hide
- */
public static ApnSetting makeApnSetting(Cursor cursor) {
final int apnTypesBitmask = getApnTypesBitmaskFromString(
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE)));
@@ -975,272 +939,99 @@ public class ApnSetting implements Parcelable {
ServiceState.convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask);
}
- return makeApnSetting(
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
- cursor.getString(
- cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)),
- portFromString(cursor.getString(
- cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))),
- UriFromString(cursor.getString(
- cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
- cursor.getString(
- cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)),
- portFromString(cursor.getString(
- cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)),
- apnTypesBitmask,
- getProtocolIntFromString(
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL))),
- getProtocolIntFromString(
- cursor.getString(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.ROAMING_PROTOCOL))),
- cursor.getInt(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.CARRIER_ENABLED)) == 1,
- networkTypeBitmask,
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)),
- cursor.getInt(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.MODEM_PERSIST)) == 1,
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNECTIONS)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME_RETRY)),
- cursor.getInt(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)),
- getMvnoTypeIntFromString(
- cursor.getString(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.MVNO_TYPE))),
- cursor.getString(cursor.getColumnIndexOrThrow(
- Telephony.Carriers.MVNO_MATCH_DATA)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.CARRIER_ID)),
- cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.SKIP_464XLAT)));
+ return new Builder()
+ .setId(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)))
+ .setOperatorNumeric(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)))
+ .setEntryName(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)))
+ .setApnName(cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)))
+ .setProxyAddress(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)))
+ .setProxyPort(portFromString(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT))))
+ .setMmsc(UriFromString(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))))
+ .setMmsProxyAddress(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)))
+ .setMmsProxyPort(portFromString(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT))))
+ .setUser(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)))
+ .setPassword(cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)))
+ .setAuthType(cursor.getInt(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)))
+ .setApnTypeBitmask(apnTypesBitmask)
+ .setProtocol(getProtocolIntFromString(
+ cursor.getString(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL))))
+ .setRoamingProtocol(getProtocolIntFromString(
+ cursor.getString(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.ROAMING_PROTOCOL))))
+ .setCarrierEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.CARRIER_ENABLED)) == 1)
+ .setNetworkTypeBitmask(networkTypeBitmask)
+ .setProfileId(cursor.getInt(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)))
+ .setModemCognitive(cursor.getInt(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.MODEM_PERSIST)) == 1)
+ .setMaxConns(cursor.getInt(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNECTIONS)))
+ .setWaitTime(cursor.getInt(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME_RETRY)))
+ .setMaxConnsTime(cursor.getInt(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS)))
+ .setMtuV4(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)))
+ .setMtuV6(UNSET_MTU) // TODO: Add corresponding support in telephony provider
+ .setMvnoType(getMvnoTypeIntFromString(
+ cursor.getString(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.MVNO_TYPE))))
+ .setMvnoMatchData(cursor.getString(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.MVNO_MATCH_DATA)))
+ .setApnSetId(cursor.getInt(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID)))
+ .setCarrierId(cursor.getInt(
+ cursor.getColumnIndexOrThrow(Telephony.Carriers.CARRIER_ID)))
+ .setSkip464Xlat(cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.SKIP_464XLAT)))
+ .buildWithoutCheck();
}
/**
* @hide
*/
public static ApnSetting makeApnSetting(ApnSetting apn) {
- return makeApnSetting(apn.mId, apn.mOperatorNumeric, apn.mEntryName, apn.mApnName,
- apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress,
- apn.mMmsProxyPort, apn.mUser, apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask,
- apn.mProtocol, apn.mRoamingProtocol, apn.mCarrierEnabled, apn.mNetworkTypeBitmask,
- apn.mProfileId, apn.mPersistent, apn.mMaxConns, apn.mWaitTime,
- apn.mMaxConnsTime, apn.mMtu, apn.mMvnoType, apn.mMvnoMatchData, apn.mApnSetId,
- apn.mCarrierId, apn.mSkip464Xlat);
- }
-
- /**
- * Creates an ApnSetting object from a string.
- *
- * @param data the string to read.
- *
- * The string must be in one of two formats (newlines added for clarity,
- * spaces are optional):
- *
- * v1 format:
- * <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
- * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
- * <type>[| <type>...],
- *
- * v2 format:
- * [ApnSettingV2] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
- * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
- * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
- *
- * v3 format:
- * [ApnSettingV3] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
- * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
- * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
- * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
- * <mvnoType>, <mvnoMatchData>
- *
- * v4 format:
- * [ApnSettingV4] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
- * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
- * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
- * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
- * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>
- *
- * v5 format:
- * [ApnSettingV5] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
- * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
- * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
- * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
- * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId>
- *
- * v6 format:
- * [ApnSettingV6] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
- * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
- * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
- * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
- * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId>, <carrierId>
- *
- * v7 format:
- * [ApnSettingV7] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
- * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
- * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
- * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
- * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId>, <carrierId>, <skip464xlat>
- *
- * Note that the strings generated by {@link #toString()} do not contain the username
- * and password and thus cannot be read by this method.
- *
- * This method may return {@code null} if the input string is invalid.
- *
- * @hide
- */
- public static ApnSetting fromString(String data) {
- if (data == null) return null;
-
- int version;
- // matches() operates on the whole string, so append .* to the regex.
- if (data.matches(V7_FORMAT_REGEX + ".*")) {
- version = 7;
- data = data.replaceFirst(V7_FORMAT_REGEX, "");
- } else if (data.matches(V6_FORMAT_REGEX + ".*")) {
- version = 6;
- data = data.replaceFirst(V6_FORMAT_REGEX, "");
- } else if (data.matches(V5_FORMAT_REGEX + ".*")) {
- version = 5;
- data = data.replaceFirst(V5_FORMAT_REGEX, "");
- } else if (data.matches(V4_FORMAT_REGEX + ".*")) {
- version = 4;
- data = data.replaceFirst(V4_FORMAT_REGEX, "");
- } else if (data.matches(V3_FORMAT_REGEX + ".*")) {
- version = 3;
- data = data.replaceFirst(V3_FORMAT_REGEX, "");
- } else if (data.matches(V2_FORMAT_REGEX + ".*")) {
- version = 2;
- data = data.replaceFirst(V2_FORMAT_REGEX, "");
- } else {
- version = 1;
- }
-
- String[] a = data.split("\\s*,\\s*", -1);
- if (a.length < 14) {
- return null;
- }
-
- int authType;
- try {
- authType = Integer.parseInt(a[12]);
- } catch (NumberFormatException e) {
- authType = 0;
- }
-
- String[] typeArray;
- String protocol, roamingProtocol;
- boolean carrierEnabled;
- int bearerBitmask = 0;
- int networkTypeBitmask = 0;
- int profileId = 0;
- boolean modemCognitive = false;
- int maxConns = 0;
- int waitTime = 0;
- int maxConnsTime = 0;
- int mtu = UNSET_MTU;
- String mvnoType = "";
- String mvnoMatchData = "";
- int apnSetId = Carriers.NO_APN_SET_ID;
- int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
- int skip464xlat = Carriers.SKIP_464XLAT_DEFAULT;
- if (version == 1) {
- typeArray = new String[a.length - 13];
- System.arraycopy(a, 13, typeArray, 0, a.length - 13);
- protocol = PROTOCOL_INT_MAP.get(PROTOCOL_IP);
- roamingProtocol = PROTOCOL_INT_MAP.get(PROTOCOL_IP);
- carrierEnabled = true;
- } else {
- if (a.length < 18) {
- return null;
- }
- typeArray = a[13].split("\\s*\\|\\s*");
- protocol = a[14];
- roamingProtocol = a[15];
- carrierEnabled = Boolean.parseBoolean(a[16]);
-
- bearerBitmask = ServiceState.getBitmaskFromString(a[17]);
-
- if (a.length > 22) {
- modemCognitive = Boolean.parseBoolean(a[19]);
- try {
- profileId = Integer.parseInt(a[18]);
- maxConns = Integer.parseInt(a[20]);
- waitTime = Integer.parseInt(a[21]);
- maxConnsTime = Integer.parseInt(a[22]);
- } catch (NumberFormatException e) {
- }
- }
- if (a.length > 23) {
- try {
- mtu = Integer.parseInt(a[23]);
- } catch (NumberFormatException e) {
- }
- }
- if (a.length > 25) {
- mvnoType = a[24];
- mvnoMatchData = a[25];
- }
- if (a.length > 26) {
- networkTypeBitmask = ServiceState.getBitmaskFromString(a[26]);
- }
- if (a.length > 27) {
- apnSetId = Integer.parseInt(a[27]);
- }
- if (a.length > 28) {
- carrierId = Integer.parseInt(a[28]);
- }
- if (a.length > 29) {
- try {
- skip464xlat = Integer.parseInt(a[29]);
- } catch (NumberFormatException e) {
- }
- }
- }
-
- // If both bearerBitmask and networkTypeBitmask were specified, bearerBitmask would be
- // ignored.
- if (networkTypeBitmask == 0) {
- networkTypeBitmask =
- ServiceState.convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask);
- }
- return makeApnSetting(-1, a[10] + a[11], a[0], a[1], a[2],
- portFromString(a[3]), UriFromString(a[7]), a[8],
- portFromString(a[9]), a[4], a[5], authType,
- getApnTypesBitmaskFromString(TextUtils.join(",", typeArray)),
- getProtocolIntFromString(protocol), getProtocolIntFromString(roamingProtocol),
- carrierEnabled, networkTypeBitmask, profileId, modemCognitive, maxConns, waitTime,
- maxConnsTime, mtu, getMvnoTypeIntFromString(mvnoType), mvnoMatchData, apnSetId,
- carrierId, skip464xlat);
- }
-
- /**
- * Creates an array of ApnSetting objects from a string.
- *
- * @param data the string to read.
- *
- * Builds on top of the same format used by fromString, but allows for multiple entries
- * separated by ";".
- *
- * @hide
- */
- public static List<ApnSetting> arrayFromString(String data) {
- List<ApnSetting> retVal = new ArrayList<ApnSetting>();
- if (TextUtils.isEmpty(data)) {
- return retVal;
- }
- String[] apnStrings = data.split("\\s*;\\s*");
- for (String apnString : apnStrings) {
- ApnSetting apn = fromString(apnString);
- if (apn != null) {
- retVal.add(apn);
- }
- }
- return retVal;
+ return new Builder()
+ .setId(apn.mId)
+ .setOperatorNumeric(apn.mOperatorNumeric)
+ .setEntryName(apn.mEntryName)
+ .setApnName(apn.mApnName)
+ .setProxyAddress(apn.mProxyAddress)
+ .setProxyPort(apn.mProxyPort)
+ .setMmsc(apn.mMmsc)
+ .setMmsProxyAddress(apn.mMmsProxyAddress)
+ .setMmsProxyPort(apn.mMmsProxyPort)
+ .setUser(apn.mUser)
+ .setPassword(apn.mPassword)
+ .setAuthType(apn.mAuthType)
+ .setApnTypeBitmask(apn.mApnTypeBitmask)
+ .setProtocol(apn.mProtocol)
+ .setRoamingProtocol(apn.mRoamingProtocol)
+ .setCarrierEnabled(apn.mCarrierEnabled)
+ .setNetworkTypeBitmask(apn.mNetworkTypeBitmask)
+ .setProfileId(apn.mProfileId)
+ .setModemCognitive(apn.mPersistent)
+ .setMaxConns(apn.mMaxConns)
+ .setWaitTime(apn.mWaitTime)
+ .setMaxConnsTime(apn.mMaxConnsTime)
+ .setMtuV4(apn.mMtuV4)
+ .setMtuV6(apn.mMtuV6)
+ .setMvnoType(apn.mMvnoType)
+ .setMvnoMatchData(apn.mMvnoMatchData)
+ .setApnSetId(apn.mApnSetId)
+ .setCarrierId(apn.mCarrierId)
+ .setSkip464Xlat(apn.mSkip464Xlat)
+ .buildWithoutCheck();
}
/**
@@ -1251,7 +1042,7 @@ public class ApnSetting implements Parcelable {
*/
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append("[ApnSettingV7] ")
+ sb.append("[ApnSetting] ")
.append(mEntryName)
.append(", ").append(mId)
.append(", ").append(mOperatorNumeric)
@@ -1272,7 +1063,8 @@ public class ApnSetting implements Parcelable {
sb.append(", ").append(mMaxConns);
sb.append(", ").append(mWaitTime);
sb.append(", ").append(mMaxConnsTime);
- sb.append(", ").append(mMtu);
+ sb.append(", ").append(mMtuV4);
+ sb.append(", ").append(mMtuV6);
sb.append(", ").append(MVNO_TYPE_INT_MAP.get(mMvnoType));
sb.append(", ").append(mMvnoMatchData);
sb.append(", ").append(mPermanentFailed);
@@ -1343,9 +1135,9 @@ public class ApnSetting implements Parcelable {
public int hashCode() {
return Objects.hash(mApnName, mProxyAddress, mProxyPort, mMmsc, mMmsProxyAddress,
mMmsProxyPort, mUser, mPassword, mAuthType, mApnTypeBitmask, mId, mOperatorNumeric,
- mProtocol, mRoamingProtocol, mMtu, mCarrierEnabled, mNetworkTypeBitmask, mProfileId,
- mPersistent, mMaxConns, mWaitTime, mMaxConnsTime, mMvnoType, mMvnoMatchData,
- mApnSetId, mCarrierId, mSkip464Xlat);
+ mProtocol, mRoamingProtocol, mMtuV4, mMtuV6, mCarrierEnabled, mNetworkTypeBitmask,
+ mProfileId, mPersistent, mMaxConns, mWaitTime, mMaxConnsTime, mMvnoType,
+ mMvnoMatchData, mApnSetId, mCarrierId, mSkip464Xlat);
}
@Override
@@ -1357,33 +1149,34 @@ public class ApnSetting implements Parcelable {
ApnSetting other = (ApnSetting) o;
return mEntryName.equals(other.mEntryName)
- && Objects.equals(mId, other.mId)
- && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
- && Objects.equals(mApnName, other.mApnName)
- && Objects.equals(mProxyAddress, other.mProxyAddress)
- && Objects.equals(mMmsc, other.mMmsc)
- && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
- && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
- && Objects.equals(mProxyPort, other.mProxyPort)
- && Objects.equals(mUser, other.mUser)
- && Objects.equals(mPassword, other.mPassword)
- && Objects.equals(mAuthType, other.mAuthType)
- && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
- && Objects.equals(mProtocol, other.mProtocol)
- && Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
- && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
- && Objects.equals(mProfileId, other.mProfileId)
- && Objects.equals(mPersistent, other.mPersistent)
- && Objects.equals(mMaxConns, other.mMaxConns)
- && Objects.equals(mWaitTime, other.mWaitTime)
- && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
- && Objects.equals(mMtu, other.mMtu)
- && Objects.equals(mMvnoType, other.mMvnoType)
- && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
- && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask)
- && Objects.equals(mApnSetId, other.mApnSetId)
- && Objects.equals(mCarrierId, other.mCarrierId)
- && Objects.equals(mSkip464Xlat, other.mSkip464Xlat);
+ && Objects.equals(mId, other.mId)
+ && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
+ && Objects.equals(mApnName, other.mApnName)
+ && Objects.equals(mProxyAddress, other.mProxyAddress)
+ && Objects.equals(mMmsc, other.mMmsc)
+ && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
+ && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
+ && Objects.equals(mProxyPort, other.mProxyPort)
+ && Objects.equals(mUser, other.mUser)
+ && Objects.equals(mPassword, other.mPassword)
+ && Objects.equals(mAuthType, other.mAuthType)
+ && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
+ && Objects.equals(mProtocol, other.mProtocol)
+ && Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
+ && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
+ && Objects.equals(mProfileId, other.mProfileId)
+ && Objects.equals(mPersistent, other.mPersistent)
+ && Objects.equals(mMaxConns, other.mMaxConns)
+ && Objects.equals(mWaitTime, other.mWaitTime)
+ && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
+ && Objects.equals(mMtuV4, other.mMtuV4)
+ && Objects.equals(mMtuV6, other.mMtuV6)
+ && Objects.equals(mMvnoType, other.mMvnoType)
+ && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
+ && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask)
+ && Objects.equals(mApnSetId, other.mApnSetId)
+ && Objects.equals(mCarrierId, other.mCarrierId)
+ && Objects.equals(mSkip464Xlat, other.mSkip464Xlat);
}
/**
@@ -1406,31 +1199,32 @@ public class ApnSetting implements Parcelable {
ApnSetting other = (ApnSetting) o;
return mEntryName.equals(other.mEntryName)
- && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
- && Objects.equals(mApnName, other.mApnName)
- && Objects.equals(mProxyAddress, other.mProxyAddress)
- && Objects.equals(mMmsc, other.mMmsc)
- && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
- && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
- && Objects.equals(mProxyPort, other.mProxyPort)
- && Objects.equals(mUser, other.mUser)
- && Objects.equals(mPassword, other.mPassword)
- && Objects.equals(mAuthType, other.mAuthType)
- && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
- && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol))
- && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
- && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
- && Objects.equals(mProfileId, other.mProfileId)
- && Objects.equals(mPersistent, other.mPersistent)
- && Objects.equals(mMaxConns, other.mMaxConns)
- && Objects.equals(mWaitTime, other.mWaitTime)
- && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
- && Objects.equals(mMtu, other.mMtu)
- && Objects.equals(mMvnoType, other.mMvnoType)
- && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
- && Objects.equals(mApnSetId, other.mApnSetId)
- && Objects.equals(mCarrierId, other.mCarrierId)
- && Objects.equals(mSkip464Xlat, other.mSkip464Xlat);
+ && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
+ && Objects.equals(mApnName, other.mApnName)
+ && Objects.equals(mProxyAddress, other.mProxyAddress)
+ && Objects.equals(mMmsc, other.mMmsc)
+ && Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
+ && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
+ && Objects.equals(mProxyPort, other.mProxyPort)
+ && Objects.equals(mUser, other.mUser)
+ && Objects.equals(mPassword, other.mPassword)
+ && Objects.equals(mAuthType, other.mAuthType)
+ && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
+ && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol))
+ && (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
+ && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
+ && Objects.equals(mProfileId, other.mProfileId)
+ && Objects.equals(mPersistent, other.mPersistent)
+ && Objects.equals(mMaxConns, other.mMaxConns)
+ && Objects.equals(mWaitTime, other.mWaitTime)
+ && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
+ && Objects.equals(mMtuV4, other.mMtuV4)
+ && Objects.equals(mMtuV6, other.mMtuV6)
+ && Objects.equals(mMvnoType, other.mMvnoType)
+ && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
+ && Objects.equals(mApnSetId, other.mApnSetId)
+ && Objects.equals(mCarrierId, other.mCarrierId)
+ && Objects.equals(mSkip464Xlat, other.mSkip464Xlat);
}
/**
@@ -1732,7 +1526,7 @@ public class ApnSetting implements Parcelable {
dest.writeString(mApnName);
dest.writeString(mProxyAddress);
dest.writeInt(mProxyPort);
- dest.writeValue(mMmsc);
+ dest.writeParcelable(mMmsc, flags);
dest.writeString(mMmsProxyAddress);
dest.writeInt(mMmsProxyPort);
dest.writeString(mUser);
@@ -1742,40 +1536,53 @@ public class ApnSetting implements Parcelable {
dest.writeInt(mProtocol);
dest.writeInt(mRoamingProtocol);
dest.writeBoolean(mCarrierEnabled);
- dest.writeInt(mMvnoType);
dest.writeInt(mNetworkTypeBitmask);
+ dest.writeInt(mProfileId);
+ dest.writeBoolean(mPersistent);
+ dest.writeInt(mMaxConns);
+ dest.writeInt(mWaitTime);
+ dest.writeInt(mMaxConnsTime);
+ dest.writeInt(mMtuV4);
+ dest.writeInt(mMtuV6);
+ dest.writeInt(mMvnoType);
+ dest.writeString(mMvnoMatchData);
dest.writeInt(mApnSetId);
dest.writeInt(mCarrierId);
dest.writeInt(mSkip464Xlat);
}
private static ApnSetting readFromParcel(Parcel in) {
- final int id = in.readInt();
- final String operatorNumeric = in.readString();
- final String entryName = in.readString();
- final String apnName = in.readString();
- final String proxy = in.readString();
- final int port = in.readInt();
- final Uri mmsc = (Uri) in.readValue(Uri.class.getClassLoader());
- final String mmsProxy = in.readString();
- final int mmsPort = in.readInt();
- final String user = in.readString();
- final String password = in.readString();
- final int authType = in.readInt();
- final int apnTypesBitmask = in.readInt();
- final int protocol = in.readInt();
- final int roamingProtocol = in.readInt();
- final boolean carrierEnabled = in.readBoolean();
- final int mvnoType = in.readInt();
- final int networkTypeBitmask = in.readInt();
- final int apnSetId = in.readInt();
- final int carrierId = in.readInt();
- final int skip464xlat = in.readInt();
-
- return makeApnSetting(id, operatorNumeric, entryName, apnName,
- proxy, port, mmsc, mmsProxy, mmsPort, user, password, authType, apnTypesBitmask,
- protocol, roamingProtocol, carrierEnabled, networkTypeBitmask, 0, false,
- 0, 0, 0, 0, mvnoType, null, apnSetId, carrierId, skip464xlat);
+ return new Builder()
+ .setId(in.readInt())
+ .setOperatorNumeric(in.readString())
+ .setEntryName(in.readString())
+ .setApnName(in.readString())
+ .setProxyAddress(in.readString())
+ .setProxyPort(in.readInt())
+ .setMmsc(in.readParcelable(Uri.class.getClassLoader()))
+ .setMmsProxyAddress(in.readString())
+ .setMmsProxyPort(in.readInt())
+ .setUser(in.readString())
+ .setPassword(in.readString())
+ .setAuthType(in.readInt())
+ .setApnTypeBitmask(in.readInt())
+ .setProtocol(in.readInt())
+ .setRoamingProtocol(in.readInt())
+ .setCarrierEnabled(in.readBoolean())
+ .setNetworkTypeBitmask(in.readInt())
+ .setProfileId(in.readInt())
+ .setModemCognitive(in.readBoolean())
+ .setMaxConns(in.readInt())
+ .setWaitTime(in.readInt())
+ .setMaxConnsTime(in.readInt())
+ .setMtuV4(in.readInt())
+ .setMtuV6(in.readInt())
+ .setMvnoType(in.readInt())
+ .setMvnoMatchData(in.readString())
+ .setApnSetId(in.readInt())
+ .setCarrierId(in.readInt())
+ .setSkip464Xlat(in.readInt())
+ .buildWithoutCheck();
}
public static final @android.annotation.NonNull Parcelable.Creator<ApnSetting> CREATOR =
@@ -1834,13 +1641,14 @@ public class ApnSetting implements Parcelable {
private int mMmsProxyPort = UNSPECIFIED_INT;
private String mUser;
private String mPassword;
- private int mAuthType;
+ private int mAuthType = AUTH_TYPE_UNKNOWN;
private int mApnTypeBitmask;
private int mId;
private String mOperatorNumeric;
private int mProtocol = UNSPECIFIED_INT;
private int mRoamingProtocol = UNSPECIFIED_INT;
- private int mMtu;
+ private int mMtuV4;
+ private int mMtuV6;
private int mNetworkTypeBitmask;
private boolean mCarrierEnabled;
private int mProfileId;
@@ -1863,20 +1671,34 @@ public class ApnSetting implements Parcelable {
* Sets the unique database id for this entry.
*
* @param id the unique database id to set for this entry
+ * @hide
*/
- private Builder setId(int id) {
+ public Builder setId(int id) {
this.mId = id;
return this;
}
/**
- * Set the MTU size of the mobile interface to which the APN connected.
+ * Set the MTU size of the IPv4 mobile interface to which the APN connected. Note this value
+ * is used only if MTU size is not provided in {@link DataCallResponse}.
+ *
+ * @param mtuV4 the MTU size to set for the APN
+ * @hide
+ */
+ public Builder setMtuV4(int mtuV4) {
+ this.mMtuV4 = mtuV4;
+ return this;
+ }
+
+ /**
+ * Set the MTU size of the IPv6 mobile interface to which the APN connected. Note this value
+ * is used only if MTU size is not provided in {@link DataCallResponse}.
*
- * @param mtu the MTU size to set for the APN
+ * @param mtuV6 the MTU size to set for the APN
* @hide
*/
- public Builder setMtu(int mtu) {
- this.mMtu = mtu;
+ public Builder setMtuV6(int mtuV6) {
+ this.mMtuV6 = mtuV6;
return this;
}
@@ -2237,7 +2059,8 @@ public class ApnSetting implements Parcelable {
| TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX
| TYPE_XCAP | TYPE_VSIM | TYPE_BIP | TYPE_ENTERPRISE)) == 0
|| TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) {
- return null;
+ throw new IllegalArgumentException("mApName=" + mApnName + ", mEntryName="
+ + mEntryName + ", mApnTypeBitmask=" + mApnTypeBitmask);
}
return new ApnSetting(this);
}
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index f2a124901bc4..93903d2658cd 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -25,13 +25,11 @@ import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.Annotation.ApnType;
+import android.telephony.TelephonyManager;
import android.telephony.TelephonyManager.NetworkTypeBitMask;
import android.telephony.data.ApnSetting.AuthType;
import android.text.TextUtils;
-import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.util.TelephonyUtils;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
@@ -62,152 +60,141 @@ public final class DataProfile implements Parcelable {
/** 3GPP2 type data profile */
public static final int TYPE_3GPP2 = 2;
- private final int mProfileId;
-
- private final String mApn;
-
- @ProtocolType
- private final int mProtocolType;
-
- @AuthType
- private final int mAuthType;
-
- private final String mUserName;
-
- private final String mPassword;
-
- @Type
- private final int mType;
-
- private final int mMaxConnectionsTime;
-
- private final int mMaxConnections;
-
- private final int mWaitTime;
-
- private final boolean mEnabled;
-
- @ApnType
- private final int mSupportedApnTypesBitmask;
-
- @ProtocolType
- private final int mRoamingProtocolType;
-
- @NetworkTypeBitMask
- private final int mBearerBitmask;
+ private final @Type int mType;
- private final int mMtuV4;
+ private final @Nullable ApnSetting mApnSetting;
- private final int mMtuV6;
-
- private final boolean mPersistent;
+ private final @Nullable TrafficDescriptor mTrafficDescriptor;
private final boolean mPreferred;
- /** @hide */
- private DataProfile(int profileId, String apn, @ProtocolType int protocolType, int authType,
- String userName, String password, int type, int maxConnectionsTime,
- int maxConnections, int waitTime, boolean enabled,
- @ApnType int supportedApnTypesBitmask, @ProtocolType int roamingProtocolType,
- @NetworkTypeBitMask int bearerBitmask, int mtuV4, int mtuV6, boolean persistent,
- boolean preferred) {
- this.mProfileId = profileId;
- this.mApn = apn;
- this.mProtocolType = protocolType;
- if (authType == -1) {
- authType = TextUtils.isEmpty(userName) ? RILConstants.SETUP_DATA_AUTH_NONE
- : RILConstants.SETUP_DATA_AUTH_PAP_CHAP;
- }
- this.mAuthType = authType;
- this.mUserName = userName;
- this.mPassword = password;
- this.mType = type;
- this.mMaxConnectionsTime = maxConnectionsTime;
- this.mMaxConnections = maxConnections;
- this.mWaitTime = waitTime;
- this.mEnabled = enabled;
- this.mSupportedApnTypesBitmask = supportedApnTypesBitmask;
- this.mRoamingProtocolType = roamingProtocolType;
- this.mBearerBitmask = bearerBitmask;
- this.mMtuV4 = mtuV4;
- this.mMtuV6 = mtuV6;
- this.mPersistent = persistent;
- this.mPreferred = preferred;
+ private DataProfile(@NonNull Builder builder) {
+ mApnSetting = builder.mApnSetting;
+ mTrafficDescriptor = builder.mTrafficDescriptor;
+ mPreferred = builder.mPreferred;
+
+ if (builder.mType != -1) {
+ mType = builder.mType;
+ } else if (mApnSetting != null) {
+ int networkTypes = mApnSetting.getNetworkTypeBitmask();
+
+ if (networkTypes == 0) {
+ mType = DataProfile.TYPE_COMMON;
+ } else if ((networkTypes & TelephonyManager.NETWORK_STANDARDS_FAMILY_BITMASK_3GPP2)
+ == networkTypes) {
+ mType = DataProfile.TYPE_3GPP2;
+ } else if ((networkTypes & TelephonyManager.NETWORK_STANDARDS_FAMILY_BITMASK_3GPP)
+ == networkTypes) {
+ mType = DataProfile.TYPE_3GPP;
+ } else {
+ mType = DataProfile.TYPE_COMMON;
+ }
+ } else {
+ mType = DataProfile.TYPE_COMMON;
+ }
}
private DataProfile(Parcel source) {
- mProfileId = source.readInt();
- mApn = source.readString();
- mProtocolType = source.readInt();
- mAuthType = source.readInt();
- mUserName = source.readString();
- mPassword = source.readString();
mType = source.readInt();
- mMaxConnectionsTime = source.readInt();
- mMaxConnections = source.readInt();
- mWaitTime = source.readInt();
- mEnabled = source.readBoolean();
- mSupportedApnTypesBitmask = source.readInt();
- mRoamingProtocolType = source.readInt();
- mBearerBitmask = source.readInt();
- mMtuV4 = source.readInt();
- mMtuV6 = source.readInt();
- mPersistent = source.readBoolean();
+ mApnSetting = source.readParcelable(ApnSetting.class.getClassLoader());
+ mTrafficDescriptor = source.readParcelable(TrafficDescriptor.class.getClassLoader());
mPreferred = source.readBoolean();
}
/**
* @return Id of the data profile.
*/
- public int getProfileId() { return mProfileId; }
+ public int getProfileId() {
+ if (mApnSetting != null) {
+ return mApnSetting.getProfileId();
+ }
+ return 0;
+ }
/**
* @return The APN (Access Point Name) to establish data connection. This is a string
* specifically defined by the carrier.
*/
@NonNull
- public String getApn() { return mApn; }
+ public String getApn() {
+ if (mApnSetting != null) {
+ return TextUtils.emptyIfNull(mApnSetting.getApnName());
+ }
+ return "";
+ }
/**
* @return The connection protocol defined in 3GPP TS 27.007 section 10.1.1.
*/
- public @ProtocolType int getProtocolType() { return mProtocolType; }
+ public @ProtocolType int getProtocolType() {
+ if (mApnSetting != null) {
+ return mApnSetting.getProtocol();
+ }
+ return ApnSetting.PROTOCOL_IP;
+ }
/**
* @return The authentication protocol used for this PDP context.
*/
- public @AuthType int getAuthType() { return mAuthType; }
+ public @AuthType int getAuthType() {
+ if (mApnSetting != null) {
+ return mApnSetting.getAuthType();
+ }
+ return ApnSetting.AUTH_TYPE_NONE;
+ }
/**
* @return The username for APN. Can be null.
*/
@Nullable
- public String getUserName() { return mUserName; }
+ public String getUserName() {
+ if (mApnSetting != null) {
+ return mApnSetting.getUser();
+ }
+ return null;
+ }
/**
* @return The password for APN. Can be null.
*/
@Nullable
- public String getPassword() { return mPassword; }
+ public String getPassword() {
+ if (mApnSetting != null) {
+ return mApnSetting.getPassword();
+ }
+ return null;
+ }
/**
* @return The profile type.
*/
- public @Type int getType() { return mType; }
+ public @Type int getType() {
+ return mType;
+ }
/**
* @return The period in seconds to limit the maximum connections.
*
* @hide
*/
- public int getMaxConnectionsTime() { return mMaxConnectionsTime; }
+ public int getMaxConnectionsTime() {
+ if (mApnSetting != null) {
+ return mApnSetting.getMaxConnsTime();
+ }
+ return 0;
+ }
/**
* @return The maximum connections allowed.
*
* @hide
*/
- public int getMaxConnections() { return mMaxConnections; }
+ public int getMaxConnections() {
+ if (mApnSetting != null) {
+ return mApnSetting.getMaxConns();
+ }
+ return 0;
+ }
/**
* @return The required wait time in seconds after a successful UE initiated disconnect of a
@@ -216,57 +203,117 @@ public final class DataProfile implements Parcelable {
*
* @hide
*/
- public int getWaitTime() { return mWaitTime; }
+ public int getWaitTime() {
+ if (mApnSetting != null) {
+ return mApnSetting.getWaitTime();
+ }
+ return 0;
+ }
/**
* @return True if the profile is enabled.
*/
- public boolean isEnabled() { return mEnabled; }
+ public boolean isEnabled() {
+ if (mApnSetting != null) {
+ return mApnSetting.isEnabled();
+ }
+ return false;
+ }
/**
* @return The supported APN types bitmask.
*/
- public @ApnType int getSupportedApnTypesBitmask() { return mSupportedApnTypesBitmask; }
+ public @ApnType int getSupportedApnTypesBitmask() {
+ if (mApnSetting != null) {
+ return mApnSetting.getApnTypeBitmask();
+ }
+ return ApnSetting.TYPE_NONE;
+ }
/**
* @return The connection protocol on roaming network defined in 3GPP TS 27.007 section 10.1.1.
*/
- public @ProtocolType int getRoamingProtocolType() { return mRoamingProtocolType; }
+ public @ProtocolType int getRoamingProtocolType() {
+ if (mApnSetting != null) {
+ return mApnSetting.getRoamingProtocol();
+ }
+ return ApnSetting.PROTOCOL_IP;
+ }
/**
* @return The bearer bitmask indicating the applicable networks for this data profile.
*/
- public @NetworkTypeBitMask int getBearerBitmask() { return mBearerBitmask; }
+ public @NetworkTypeBitMask int getBearerBitmask() {
+ if (mApnSetting != null) {
+ return mApnSetting.getNetworkTypeBitmask();
+ }
+ return (int) TelephonyManager.NETWORK_TYPE_BITMASK_UNKNOWN;
+ }
/**
* @return The maximum transmission unit (MTU) size in bytes.
* @deprecated use {@link #getMtuV4} or {@link #getMtuV6} instead.
*/
@Deprecated
- public int getMtu() { return mMtuV4; }
+ public int getMtu() {
+ return getMtuV4();
+ }
/**
* This replaces the deprecated method getMtu.
* @return The maximum transmission unit (MTU) size in bytes, for IPv4.
*/
- public int getMtuV4() { return mMtuV4; }
+ public int getMtuV4() {
+ if (mApnSetting != null) {
+ return mApnSetting.getMtuV4();
+ }
+ return 0;
+ }
/**
* @return The maximum transmission unit (MTU) size in bytes, for IPv6.
*/
- public int getMtuV6() { return mMtuV6; }
+ public int getMtuV6() {
+ if (mApnSetting != null) {
+ return mApnSetting.getMtuV6();
+ }
+ return 0;
+ }
/**
* @return {@code true} if modem must persist this data profile.
*/
- public boolean isPersistent() { return mPersistent; }
+ public boolean isPersistent() {
+ if (mApnSetting != null) {
+ return mApnSetting.isPersistent();
+ }
+ return false;
+ }
/**
* @return {@code true} if this data profile was used to bring up the last default
* (i.e internet) data connection successfully, or the one chosen by the user in Settings'
* APN editor. For one carrier there can be only one profiled preferred.
*/
- public boolean isPreferred() { return mPreferred; }
+ public boolean isPreferred() {
+ return mPreferred;
+ }
+
+ /**
+ * @return The APN setting
+ * @hide TODO: Remove before T is released.
+ */
+ public @Nullable ApnSetting getApnSetting() {
+ return mApnSetting;
+ }
+
+ /**
+ * @return The traffic descriptor
+ * @hide TODO: Remove before T is released.
+ */
+ public @Nullable TrafficDescriptor getTrafficDescriptor() {
+ return mTrafficDescriptor;
+ }
@Override
public int describeContents() {
@@ -276,34 +323,15 @@ public final class DataProfile implements Parcelable {
@NonNull
@Override
public String toString() {
- return "DataProfile=" + mProfileId + "/" + mProtocolType + "/" + mAuthType
- + "/" + (TelephonyUtils.IS_USER ? "***/***/***" :
- (mApn + "/" + mUserName + "/" + mPassword)) + "/" + mType + "/"
- + mMaxConnectionsTime + "/" + mMaxConnections + "/"
- + mWaitTime + "/" + mEnabled + "/" + mSupportedApnTypesBitmask + "/"
- + mRoamingProtocolType + "/" + mBearerBitmask + "/" + mMtuV4 + "/" + mMtuV6 + "/"
- + mPersistent + "/" + mPreferred;
+ return "DataProfile=" + mApnSetting + ", " + mTrafficDescriptor + ", preferred="
+ + mPreferred;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mProfileId);
- dest.writeString(mApn);
- dest.writeInt(mProtocolType);
- dest.writeInt(mAuthType);
- dest.writeString(mUserName);
- dest.writeString(mPassword);
dest.writeInt(mType);
- dest.writeInt(mMaxConnectionsTime);
- dest.writeInt(mMaxConnections);
- dest.writeInt(mWaitTime);
- dest.writeBoolean(mEnabled);
- dest.writeInt(mSupportedApnTypesBitmask);
- dest.writeInt(mRoamingProtocolType);
- dest.writeInt(mBearerBitmask);
- dest.writeInt(mMtuV4);
- dest.writeInt(mMtuV6);
- dest.writeBoolean(mPersistent);
+ dest.writeParcelable(mApnSetting, flags);
+ dest.writeParcelable(mTrafficDescriptor, flags);
dest.writeBoolean(mPreferred);
}
@@ -321,36 +349,18 @@ public final class DataProfile implements Parcelable {
};
@Override
- public boolean equals(@Nullable Object o) {
+ public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DataProfile that = (DataProfile) o;
- return mProfileId == that.mProfileId
- && mProtocolType == that.mProtocolType
- && mAuthType == that.mAuthType
- && mType == that.mType
- && mMaxConnectionsTime == that.mMaxConnectionsTime
- && mMaxConnections == that.mMaxConnections
- && mWaitTime == that.mWaitTime
- && mEnabled == that.mEnabled
- && mSupportedApnTypesBitmask == that.mSupportedApnTypesBitmask
- && mRoamingProtocolType == that.mRoamingProtocolType
- && mBearerBitmask == that.mBearerBitmask
- && mMtuV4 == that.mMtuV4
- && mMtuV6 == that.mMtuV6
- && mPersistent == that.mPersistent
- && mPreferred == that.mPreferred
- && Objects.equals(mApn, that.mApn)
- && Objects.equals(mUserName, that.mUserName)
- && Objects.equals(mPassword, that.mPassword);
+ return mType == that.mType
+ && Objects.equals(mApnSetting, that.mApnSetting)
+ && Objects.equals(mTrafficDescriptor, that.mTrafficDescriptor);
}
@Override
public int hashCode() {
- return Objects.hash(mProfileId, mApn, mProtocolType, mAuthType, mUserName, mPassword, mType,
- mMaxConnectionsTime, mMaxConnections, mWaitTime, mEnabled,
- mSupportedApnTypesBitmask, mRoamingProtocolType, mBearerBitmask, mMtuV4, mMtuV6,
- mPersistent, mPreferred);
+ return Objects.hash(mType, mApnSetting, mTrafficDescriptor);
}
/**
@@ -383,13 +393,7 @@ public final class DataProfile implements Parcelable {
private String mPassword;
@Type
- private int mType;
-
- private int mMaxConnectionsTime;
-
- private int mMaxConnections;
-
- private int mWaitTime;
+ private int mType = -1;
private boolean mEnabled;
@@ -410,6 +414,10 @@ public final class DataProfile implements Parcelable {
private boolean mPreferred;
+ private ApnSetting mApnSetting;
+
+ private TrafficDescriptor mTrafficDescriptor;
+
/**
* Default constructor for Builder.
*/
@@ -496,48 +504,6 @@ public final class DataProfile implements Parcelable {
}
/**
- * Set the period in seconds to limit the maximum connections.
- *
- * @param maxConnectionsTime The profile type
- * @return The same instance of the builder.
- *
- * @hide
- */
- public @NonNull Builder setMaxConnectionsTime(int maxConnectionsTime) {
- mMaxConnectionsTime = maxConnectionsTime;
- return this;
- }
-
- /**
- * Set the maximum connections allowed.
- *
- * @param maxConnections The maximum connections allowed.
- * @return The same instance of the builder.
- *
- * @hide
- */
- public @NonNull Builder setMaxConnections(int maxConnections) {
- mMaxConnections = maxConnections;
- return this;
- }
-
- /**
- * Set the period in seconds to limit the maximum connections.
- *
- * @param waitTime The required wait time in seconds after a successful UE initiated
- * disconnect of a given PDN connection before the device can send a new PDN connection
- * request for that given PDN.
- *
- * @return The same instance of the builder.
- *
- * @hide
- */
- public @NonNull Builder setWaitTime(int waitTime) {
- mWaitTime = waitTime;
- return this;
- }
-
- /**
* Enable the data profile
*
* @param isEnabled {@code true} to enable the data profile, otherwise disable.
@@ -587,8 +553,9 @@ public final class DataProfile implements Parcelable {
*
* @param mtu The maximum transmission unit (MTU) size in bytes.
* @return The same instance of the builder.
- * @deprecated use {@link #setMtuV4} or {@link #setMtuV6} instead.
+ * @deprecated use {@link #setApnSetting(ApnSetting)} instead.
*/
+ @Deprecated
public @NonNull Builder setMtu(int mtu) {
mMtuV4 = mMtuV6 = mtu;
return this;
@@ -631,7 +598,7 @@ public final class DataProfile implements Parcelable {
}
/**
- * Set data profile as persistent/non-persistent
+ * Set data profile as persistent/non-persistent.
*
* @param isPersistent {@code true} if this data profile was used to bring up the last
* default (i.e internet) data connection successfully.
@@ -643,15 +610,63 @@ public final class DataProfile implements Parcelable {
}
/**
+ * Set APN setting.
+ *
+ * @param apnSetting APN setting
+ * @return The same instance of the builder
+ *
+ * @hide // TODO: Remove before T is released.
+ */
+ public @NonNull Builder setApnSetting(@NonNull ApnSetting apnSetting) {
+ mApnSetting = apnSetting;
+ return this;
+ }
+
+ /**
+ * Set traffic descriptor.
+ *
+ * @param trafficDescriptor Traffic descriptor
+ * @return The same instance of the builder
+ *
+ * @hide // TODO: Remove before T is released.
+ */
+ public @NonNull Builder setTrafficDescriptor(@NonNull TrafficDescriptor trafficDescriptor) {
+ mTrafficDescriptor = trafficDescriptor;
+ return this;
+ }
+
+ /**
* Build the DataProfile object
*
* @return The data profile object
*/
public @NonNull DataProfile build() {
- return new DataProfile(mProfileId, mApn, mProtocolType, mAuthType, mUserName, mPassword,
- mType, mMaxConnectionsTime, mMaxConnections, mWaitTime, mEnabled,
- mSupportedApnTypesBitmask, mRoamingProtocolType, mBearerBitmask, mMtuV4, mMtuV6,
- mPersistent, mPreferred);
+ if (mApnSetting == null && mApn != null) {
+ // This is for backwards compatibility.
+ mApnSetting = new ApnSetting.Builder()
+ .setEntryName(mApn)
+ .setApnName(mApn)
+ .setApnTypeBitmask(mSupportedApnTypesBitmask)
+ .setAuthType(mAuthType)
+ .setCarrierEnabled(mEnabled)
+ .setModemCognitive(mPersistent)
+ .setMtuV4(mMtuV4)
+ .setMtuV6(mMtuV6)
+ .setNetworkTypeBitmask(mBearerBitmask)
+ .setProfileId(mProfileId)
+ .setPassword(mPassword)
+ .setProtocol(mProtocolType)
+ .setRoamingProtocol(mRoamingProtocolType)
+ .setUser(mUserName)
+ .build();
+ }
+
+ if (mApnSetting == null && mTrafficDescriptor == null) {
+ throw new IllegalArgumentException("APN setting and traffic descriptor can't be "
+ + "both null.");
+ }
+
+ return new DataProfile(this);
}
}
}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 36082dc8180e..683bb92845ba 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -25,6 +25,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SuppressAutoDoc;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.content.Context;
import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
@@ -45,6 +46,7 @@ import com.android.internal.telephony.ITelephony;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -214,6 +216,7 @@ public class ImsMmTelManager implements RegistrationManager {
}
}
+ private final Context mContext;
private final int mSubId;
private final BinderCacheManager<ITelephony> mBinderCache;
@@ -255,6 +258,16 @@ public class ImsMmTelManager implements RegistrationManager {
*/
@VisibleForTesting
public ImsMmTelManager(int subId, BinderCacheManager<ITelephony> binderCache) {
+ this(null, subId, binderCache);
+ }
+
+ /**
+ * Only visible for testing, use {@link ImsManager#getImsMmTelManager(int)} instead.
+ * @hide
+ */
+ @VisibleForTesting
+ public ImsMmTelManager(Context context, int subId, BinderCacheManager<ITelephony> binderCache) {
+ mContext = context;
mSubId = subId;
mBinderCache = binderCache;
}
@@ -1482,6 +1495,74 @@ public class ImsMmTelManager implements RegistrationManager {
}
}
+ /**
+ * Register a new callback, which is used to notify the registrant of changes to
+ * the state of the underlying IMS service that is attached to telephony to
+ * implement IMS functionality. If the manager is created for
+ * the {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID},
+ * this throws an {@link ImsException}.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE READ_PRECISE_PHONE_STATE}
+ * or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @param executor the Executor that will be used to call the {@link ImsStateCallback}.
+ * @param callback The callback instance being registered.
+ * @throws ImsException in the case that the callback can not be registered.
+ * See {@link ImsException#getCode} for more information on when this is called.
+ */
+ @RequiresPermission(anyOf = {Manifest.permission.READ_PRECISE_PHONE_STATE,
+ Manifest.permission.READ_PRIVILEGED_PHONE_STATE})
+ public void registerImsStateCallback(@NonNull Executor executor,
+ @NonNull ImsStateCallback callback) throws ImsException {
+ Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
+ Objects.requireNonNull(executor, "Must include a non-null Executor.");
+
+ callback.init(executor);
+ ITelephony telephony = mBinderCache.listenOnBinder(callback, callback::binderDied);
+ if (telephony == null) {
+ throw new ImsException("Telephony server is down",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
+ try {
+ telephony.registerImsStateCallback(
+ mSubId, ImsFeature.FEATURE_MMTEL,
+ callback.getCallbackBinder(), getOpPackageName());
+ } catch (ServiceSpecificException e) {
+ throw new ImsException(e.getMessage(), e.errorCode);
+ } catch (RemoteException | IllegalStateException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ }
+
+ /**
+ * Unregisters a previously registered callback.
+ *
+ * @param callback The callback instance to be unregistered.
+ */
+ public void unregisterImsStateCallback(@NonNull ImsStateCallback callback) {
+ Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
+
+ ITelephony telephony = mBinderCache.removeRunnable(callback);
+ try {
+ if (telephony != null) {
+ telephony.unregisterImsStateCallback(callback.getCallbackBinder());
+ }
+ } catch (RemoteException ignore) {
+ // ignore it
+ }
+ }
+
+ private String getOpPackageName() {
+ if (mContext != null) {
+ return mContext.getOpPackageName();
+ } else {
+ return null;
+ }
+ }
+
private ITelephony getITelephony() {
return mBinderCache.getBinder();
}
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 8d6fa4141b5c..1b047c77d80b 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -39,9 +39,11 @@ import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.util.Log;
import com.android.internal.telephony.IIntegerConsumer;
+import com.android.internal.telephony.ITelephony;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -159,6 +161,7 @@ public class ImsRcsManager {
private final int mSubId;
private final Context mContext;
private final BinderCacheManager<IImsRcsController> mBinderCache;
+ private final BinderCacheManager<ITelephony> mTelephonyBinderCache;
private final Map<OnAvailabilityChangedListener, AvailabilityCallbackAdapter>
mAvailabilityChangedCallbacks;
@@ -167,11 +170,13 @@ public class ImsRcsManager {
* @hide
*/
public ImsRcsManager(Context context, int subId,
- BinderCacheManager<IImsRcsController> binderCache) {
+ BinderCacheManager<IImsRcsController> binderCache,
+ BinderCacheManager<ITelephony> telephonyBinderCache) {
mSubId = subId;
mContext = context;
mBinderCache = binderCache;
mAvailabilityChangedCallbacks = new HashMap<>();
+ mTelephonyBinderCache = telephonyBinderCache;
}
/**
@@ -534,6 +539,67 @@ public class ImsRcsManager {
}
/**
+ * Register a new callback, which is used to notify the registrant of changes to
+ * the state of the underlying IMS service that is attached to telephony to
+ * implement IMS functionality. If the manager is created for
+ * the {@link android.telephony.SubscriptionManager#DEFAULT_SUBSCRIPTION_ID},
+ * this throws an {@link ImsException}.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE READ_PRECISE_PHONE_STATE}
+ * or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @param executor the Executor that will be used to call the {@link ImsStateCallback}.
+ * @param callback The callback instance being registered.
+ * @throws ImsException in the case that the callback can not be registered.
+ * See {@link ImsException#getCode} for more information on when this is called.
+ */
+ @RequiresPermission(anyOf = {Manifest.permission.READ_PRECISE_PHONE_STATE,
+ Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE})
+ public void registerImsStateCallback(@NonNull Executor executor,
+ @NonNull ImsStateCallback callback) throws ImsException {
+ Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
+ Objects.requireNonNull(executor, "Must include a non-null Executor.");
+
+ callback.init(executor);
+ ITelephony telephony = mTelephonyBinderCache.listenOnBinder(callback, callback::binderDied);
+ if (telephony == null) {
+ throw new ImsException("Telephony server is down",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
+ try {
+ telephony.registerImsStateCallback(
+ mSubId, ImsFeature.FEATURE_RCS,
+ callback.getCallbackBinder(), mContext.getOpPackageName());
+ } catch (ServiceSpecificException e) {
+ throw new ImsException(e.getMessage(), e.errorCode);
+ } catch (RemoteException | IllegalStateException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ }
+
+ /**
+ * Unregisters a previously registered callback.
+ *
+ * @param callback The callback instance to be unregistered.
+ */
+ public void unregisterImsStateCallback(@NonNull ImsStateCallback callback) {
+ Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
+
+ ITelephony telephony = mTelephonyBinderCache.removeRunnable(callback);
+ try {
+ if (telephony != null) {
+ telephony.unregisterImsStateCallback(callback.getCallbackBinder());
+ }
+ } catch (RemoteException ignore) {
+ // ignore it
+ }
+ }
+
+ /**
* Add the {@link OnAvailabilityChangedListener} to collection for tracking.
* @param executor The executor that will be used when the publish state is changed and the
* {@link OnAvailabilityChangedListener} is called.
diff --git a/telephony/java/android/telephony/ims/ImsStateCallback.java b/telephony/java/android/telephony/ims/ImsStateCallback.java
new file mode 100644
index 000000000000..b9ba93ff0db6
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsStateCallback.java
@@ -0,0 +1,184 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Binder;
+
+import com.android.internal.telephony.IImsStateCallback;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+import java.util.concurrent.Executor;
+
+/**
+ * A callback class used for monitoring changes in IMS service connection states
+ * for a specific subscription.
+ * <p>
+ * @see ImsMmTelManager#registerImsStateCallback(Executor, ImsStateCallback)
+ * @see ImsRcsManager#registerImsStateCallback(Executor, ImsStateCallback)
+ */
+public abstract class ImsStateCallback {
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "REASON_", value = {
+ REASON_UNKNOWN_TEMPORARY_ERROR,
+ REASON_UNKNOWN_PERMANENT_ERROR,
+ REASON_IMS_SERVICE_DISCONNECTED,
+ REASON_NO_IMS_SERVICE_CONFIGURED,
+ REASON_SUBSCRIPTION_INACTIVE,
+ REASON_IMS_SERVICE_NOT_READY
+ })
+ public @interface DisconnectedReason {}
+
+ /**
+ * The underlying IMS service is temporarily unavailable for the
+ * associated subscription.
+ * {@link #onAvailable} will be called when the IMS service becomes
+ * available again.
+ */
+ public static final int REASON_UNKNOWN_TEMPORARY_ERROR = 1;
+
+ /**
+ * The underlying IMS service is permanently unavailable for the
+ * associated subscription and there will be no Manager available for
+ * this subscription.
+ */
+ public static final int REASON_UNKNOWN_PERMANENT_ERROR = 2;
+
+ /**
+ * The underlying IMS service has died, is reconfiguring, or has never
+ * come up yet and as a result is currently unavailable.
+ * {@link #onAvailable} will be called when the IMS service becomes
+ * available. All callbacks should be unregistered now and registered again
+ * if the IMS service moves back to available.
+ */
+ public static final int REASON_IMS_SERVICE_DISCONNECTED = 3;
+
+ /**
+ * There is no IMS service configured for the subscription ID specified.
+ * This is a permanent error and there will be no Manager available for
+ * this subscription.
+ */
+ public static final int REASON_NO_IMS_SERVICE_CONFIGURED = 4;
+
+ /**
+ * The subscription associated with this Manager has moved to an inactive
+ * state (e.g. SIM removed) and the IMS service has torn down the resources
+ * related to this subscription. This has caused this callback
+ * to be deregistered. The callback must be re-registered when this subscription
+ * becomes active in order to continue listening to the IMS service state.
+ */
+ public static final int REASON_SUBSCRIPTION_INACTIVE = 5;
+
+ /**
+ * The IMS service is connected, but in a NOT_READY state. Once the
+ * service moves to ready, {@link #onAvailable} will be called.
+ */
+ public static final int REASON_IMS_SERVICE_NOT_READY = 6;
+
+ private IImsStateCallbackStub mCallback;
+
+ /**
+ * @hide
+ */
+ public void init(@NonNull @CallbackExecutor Executor executor) {
+ if (executor == null) {
+ throw new IllegalArgumentException("ImsStateCallback Executor must be non-null");
+ }
+ mCallback = new IImsStateCallbackStub(this, executor);
+ }
+
+ /**
+ * Using a static class and weak reference here to avoid memory leak caused by the
+ * IImsStateCallback.Stub callback retaining references to the outside ImsStateCallback.
+ */
+ private static class IImsStateCallbackStub extends IImsStateCallback.Stub {
+ private WeakReference<ImsStateCallback> mImsStateCallbackWeakRef;
+ private Executor mExecutor;
+
+ IImsStateCallbackStub(ImsStateCallback imsStateCallback, Executor executor) {
+ mImsStateCallbackWeakRef = new WeakReference<ImsStateCallback>(imsStateCallback);
+ mExecutor = executor;
+ }
+
+ Executor getExecutor() {
+ return mExecutor;
+ }
+
+ public void onAvailable() {
+ ImsStateCallback callback = mImsStateCallbackWeakRef.get();
+ if (callback == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> callback.onAvailable()));
+ }
+
+ public void onUnavailable(int reason) {
+ ImsStateCallback callback = mImsStateCallbackWeakRef.get();
+ if (callback == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> callback.onUnavailable(reason)));
+ }
+ }
+
+ /**
+ * The IMS service has disconnected or is reporting NOT_READY and is no longer
+ * available to users. The user should clean up all related state and
+ * unregister callbacks. If it is a temporary error, {@link #onAvailable} will
+ * be called when the IMS service becomes available again.
+ *
+ * @param reason the specified reason
+ */
+ public abstract void onUnavailable(@DisconnectedReason int reason);
+
+ /**
+ * The IMS service is connected and is ready for communication over the
+ * provided Manager.
+ */
+ public abstract void onAvailable();
+
+ /**
+ * An unexpected error has occurred and the Telephony process has crashed. This
+ * has caused this callback to be deregistered. The callback must be
+ * re-registered in order to continue listening to the IMS service state.
+ */
+ public abstract void onError();
+
+ /**
+ * The callback to notify the death of telephony process
+ * @hide
+ */
+ public final void binderDied() {
+ if (mCallback != null) {
+ mCallback.getExecutor().execute(() -> onError());
+ }
+ }
+
+ /**
+ * Return the callback binder
+ * @hide
+ */
+ public IImsStateCallbackStub getCallbackBinder() {
+ return mCallback;
+ }
+}
diff --git a/telephony/java/android/telephony/ims/SipDelegateManager.java b/telephony/java/android/telephony/ims/SipDelegateManager.java
index 5a8066320e99..f913df588f40 100644
--- a/telephony/java/android/telephony/ims/SipDelegateManager.java
+++ b/telephony/java/android/telephony/ims/SipDelegateManager.java
@@ -28,15 +28,16 @@ import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.telephony.BinderCacheManager;
-import android.telephony.CarrierConfigManager;
import android.telephony.ims.aidl.IImsRcsController;
import android.telephony.ims.aidl.SipDelegateConnectionAidlWrapper;
+import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.stub.DelegateConnectionMessageCallback;
import android.telephony.ims.stub.DelegateConnectionStateCallback;
import android.telephony.ims.stub.SipDelegate;
import android.util.ArrayMap;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.ITelephony;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -282,6 +283,7 @@ public class SipDelegateManager {
private final Context mContext;
private final int mSubId;
private final BinderCacheManager<IImsRcsController> mBinderCache;
+ private final BinderCacheManager<ITelephony> mTelephonyBinderCache;
/**
* Only visible for testing. To instantiate an instance of this class, please use
@@ -290,10 +292,12 @@ public class SipDelegateManager {
*/
@VisibleForTesting
public SipDelegateManager(Context context, int subId,
- BinderCacheManager<IImsRcsController> binderCache) {
+ BinderCacheManager<IImsRcsController> binderCache,
+ BinderCacheManager<ITelephony> telephonyBinderCache) {
mContext = context;
mSubId = subId;
mBinderCache = binderCache;
+ mTelephonyBinderCache = telephonyBinderCache;
}
/**
@@ -446,4 +450,65 @@ public class SipDelegateManager {
+ " into this method");
}
}
+
+ /**
+ * Register a new callback, which is used to notify the registrant of changes to
+ * the state of the underlying IMS service that is attached to telephony to
+ * implement IMS functionality. If the manager is created for
+ * the {@link android.telephony.SubscriptionManager#DEFAULT_SUBSCRIPTION_ID},
+ * this throws an {@link ImsException}.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE READ_PRECISE_PHONE_STATE}
+ * or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @param executor the Executor that will be used to call the {@link ImsStateCallback}.
+ * @param callback The callback instance being registered.
+ * @throws ImsException in the case that the callback can not be registered.
+ * See {@link ImsException#getCode} for more information on when this is called.
+ */
+ @RequiresPermission(anyOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION})
+ public void registerImsStateCallback(@NonNull Executor executor,
+ @NonNull ImsStateCallback callback) throws ImsException {
+ Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
+ Objects.requireNonNull(executor, "Must include a non-null Executor.");
+
+ callback.init(executor);
+ ITelephony telephony = mTelephonyBinderCache.listenOnBinder(callback, callback::binderDied);
+ if (telephony == null) {
+ throw new ImsException("Telephony server is down",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
+ try {
+ telephony.registerImsStateCallback(
+ mSubId, ImsFeature.FEATURE_RCS,
+ callback.getCallbackBinder(), mContext.getOpPackageName());
+ } catch (ServiceSpecificException e) {
+ throw new ImsException(e.getMessage(), e.errorCode);
+ } catch (RemoteException | IllegalStateException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ }
+
+ /**
+ * Unregisters a previously registered callback.
+ *
+ * @param callback The callback instance to be unregistered.
+ */
+ public void unregisterImsStateCallback(@NonNull ImsStateCallback callback) {
+ Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
+
+ ITelephony telephony = mTelephonyBinderCache.removeRunnable(callback);
+
+ try {
+ if (telephony != null) {
+ telephony.unregisterImsStateCallback(callback.getCallbackBinder());
+ }
+ } catch (RemoteException ignore) {
+ // ignore it
+ }
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/IImsStateCallback.aidl b/telephony/java/com/android/internal/telephony/IImsStateCallback.aidl
new file mode 100644
index 000000000000..e04b01d26e47
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IImsStateCallback.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.internal.telephony;
+
+oneway interface IImsStateCallback {
+ void onUnavailable(int reason);
+ void onAvailable();
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 63732b5ee444..6b33a6894365 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -67,6 +67,7 @@ import com.android.ims.internal.IImsServiceFeatureCallback;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.IBooleanConsumer;
import com.android.internal.telephony.ICallForwardingInfoCallback;
+import com.android.internal.telephony.IImsStateCallback;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.INumberVerificationCallback;
import com.android.internal.telephony.OperatorInfo;
@@ -1002,11 +1003,6 @@ interface ITelephony {
boolean isManualNetworkSelectionAllowed(int subId);
/**
- * Enable or disable always reporting signal strength changes from radio.
- */
- void setAlwaysReportSignalStrength(int subId, boolean isEnable);
-
- /**
* Get P-CSCF address from PCO after data connection is established or modified.
* @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
* @param callingPackage The package making the call.
@@ -2229,6 +2225,20 @@ interface ITelephony {
List<String> getEquivalentHomePlmns(int subId, String callingPackage, String callingFeatureId);
/**
+ * Enable or disable Voice over NR (VoNR)
+ * @param subId the subscription ID that this action applies to.
+ * @param enabled enable or disable VoNR.
+ * @return operation result.
+ */
+ int setVoNrEnabled(int subId, boolean enabled);
+
+ /**
+ * Is voice over NR enabled
+ * @return true if VoNR is enabled else false
+ */
+ boolean isVoNrEnabled(int subId);
+
+ /**
* Enable/Disable E-UTRA-NR Dual Connectivity
* @return operation result. See TelephonyManager.EnableNrDualConnectivityResult for
* details
@@ -2488,4 +2498,15 @@ interface ITelephony {
* NSSAIs (configured, allowed and rejected).
*/
void getSlicingConfig(in ResultReceiver callback);
+
+ /**
+ * Register an IMS connection state callback
+ */
+ void registerImsStateCallback(int subId, int feature, in IImsStateCallback cb,
+ in String callingPackage);
+
+ /**
+ * Unregister an IMS connection state callback
+ */
+ void unregisterImsStateCallback(in IImsStateCallback cb);
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index b73f8271da1f..866fd2c7394e 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -528,6 +528,8 @@ public interface RILConstants {
int RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP = 222;
int RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP = 223;
int RIL_REQUEST_GET_SLICING_CONFIG = 224;
+ int RIL_REQUEST_ENABLE_VONR = 225;
+ int RIL_REQUEST_IS_VONR_ENABLED = 226;
/* Responses begin */
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 0bb61987a514..22320fd53631 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -27,9 +27,8 @@ package {
java_sdk_library {
name: "android.test.mock",
-
- srcs: [
- ":android-test-mock-sources",
+ srcs: [":android-test-mock-sources"],
+ api_srcs: [
// Note: Below are NOT APIs of this library. We only take APIs under
// the android.test.mock package. They however provide private APIs that
// android.test.mock APIs references to. We need to have the classes in
@@ -44,15 +43,9 @@ java_sdk_library {
"app-compat-annotations",
"unsupportedappusage",
],
-
api_packages: [
"android.test.mock",
],
- // Only include android.test.mock.* classes. Jarjar rules below removes
- // classes in other packages like android.content. In order to keep the
- // list up-to-date, permitted_packages ensures that the library contains
- // clases under android.test.mock after the jarjar rules are applied.
- jarjar_rules: "jarjar-rules.txt",
permitted_packages: [
"android.test.mock",
],
diff --git a/test-mock/jarjar-rules.txt b/test-mock/jarjar-rules.txt
deleted file mode 100644
index 4420a4413f5b..000000000000
--- a/test-mock/jarjar-rules.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-zap android.accounts.**
-zap android.app.**
-zap android.content.**
-zap android.database.**
-zap android.os.**
-zap android.util.**
-zap android.view.**
diff --git a/tests/AttestationVerificationTest/OWNERS b/tests/AttestationVerificationTest/OWNERS
new file mode 100644
index 000000000000..a7a6ef156eda
--- /dev/null
+++ b/tests/AttestationVerificationTest/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/security/attestationverification/OWNERS
diff --git a/tests/FlickerTests/OWNERS b/tests/FlickerTests/OWNERS
index b5561010e7f9..c1221e3940d2 100644
--- a/tests/FlickerTests/OWNERS
+++ b/tests/FlickerTests/OWNERS
@@ -1,3 +1,4 @@
# Bug component: 909476
include /services/core/java/com/android/server/wm/OWNERS
-natanieljr@google.com \ No newline at end of file
+natanieljr@google.com
+pablogamito@google.com
diff --git a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
index 84448333a8c6..525a78486efc 100644
--- a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
+++ b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
@@ -207,17 +207,6 @@ public class SystemPreparer extends ExternalResource {
default:
device.executeShellCommand("stop");
device.executeShellCommand("start");
- ITestDevice.RecoveryMode cachedRecoveryMode = device.getRecoveryMode();
- device.setRecoveryMode(ITestDevice.RecoveryMode.ONLINE);
-
- if (device.isEncryptionSupported()) {
- if (device.isDeviceEncrypted()) {
- LogUtil.CLog.e("Device is encrypted after userspace reboot!");
- device.unlockDevice();
- }
- }
-
- device.setRecoveryMode(cachedRecoveryMode);
device.waitForDeviceAvailable();
break;
}
diff --git a/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java b/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java
new file mode 100644
index 000000000000..f7d3697029d6
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkPriorityTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_ANY;
+import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class VcnCellUnderlyingNetworkPriorityTest {
+ private static final Set<String> ALLOWED_PLMN_IDS = new HashSet<>();
+ private static final Set<Integer> ALLOWED_CARRIER_IDS = new HashSet<>();
+
+ // Package private for use in VcnGatewayConnectionConfigTest
+ static VcnCellUnderlyingNetworkPriority getTestNetworkPriority() {
+ return new VcnCellUnderlyingNetworkPriority.Builder()
+ .setNetworkQuality(NETWORK_QUALITY_OK)
+ .setAllowMetered(true /* allowMetered */)
+ .setAllowedPlmnIds(ALLOWED_PLMN_IDS)
+ .setAllowedSpecificCarrierIds(ALLOWED_CARRIER_IDS)
+ .setAllowRoaming(true /* allowRoaming */)
+ .setRequireOpportunistic(true /* requireOpportunistic */)
+ .build();
+ }
+
+ @Test
+ public void testBuilderAndGetters() {
+ final VcnCellUnderlyingNetworkPriority networkPriority = getTestNetworkPriority();
+ assertEquals(NETWORK_QUALITY_OK, networkPriority.getNetworkQuality());
+ assertTrue(networkPriority.allowMetered());
+ assertEquals(ALLOWED_PLMN_IDS, networkPriority.getAllowedPlmnIds());
+ assertEquals(ALLOWED_CARRIER_IDS, networkPriority.getAllowedSpecificCarrierIds());
+ assertTrue(networkPriority.allowRoaming());
+ assertTrue(networkPriority.requireOpportunistic());
+ }
+
+ @Test
+ public void testBuilderAndGettersForDefaultValues() {
+ final VcnCellUnderlyingNetworkPriority networkPriority =
+ new VcnCellUnderlyingNetworkPriority.Builder().build();
+ assertEquals(NETWORK_QUALITY_ANY, networkPriority.getNetworkQuality());
+ assertFalse(networkPriority.allowMetered());
+ assertEquals(new HashSet<String>(), networkPriority.getAllowedPlmnIds());
+ assertEquals(new HashSet<Integer>(), networkPriority.getAllowedSpecificCarrierIds());
+ assertFalse(networkPriority.allowRoaming());
+ assertFalse(networkPriority.requireOpportunistic());
+ }
+
+ @Test
+ public void testPersistableBundle() {
+ final VcnCellUnderlyingNetworkPriority networkPriority = getTestNetworkPriority();
+ assertEquals(
+ networkPriority,
+ VcnUnderlyingNetworkPriority.fromPersistableBundle(
+ networkPriority.toPersistableBundle()));
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index dc338ae0fdc7..724c33ffb354 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -38,6 +38,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Arrays;
+import java.util.LinkedHashSet;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
@@ -50,9 +51,17 @@ public class VcnGatewayConnectionConfigTest {
};
public static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN};
+ private static final LinkedHashSet<VcnUnderlyingNetworkPriority> UNDERLYING_NETWORK_PRIORITIES =
+ new LinkedHashSet();
+
static {
Arrays.sort(EXPOSED_CAPS);
Arrays.sort(UNDERLYING_CAPS);
+
+ UNDERLYING_NETWORK_PRIORITIES.add(
+ VcnCellUnderlyingNetworkPriorityTest.getTestNetworkPriority());
+ UNDERLYING_NETWORK_PRIORITIES.add(
+ VcnWifiUnderlyingNetworkPriorityTest.getTestNetworkPriority());
}
public static final long[] RETRY_INTERVALS_MS =
@@ -82,7 +91,10 @@ public class VcnGatewayConnectionConfigTest {
// Public for use in VcnGatewayConnectionTest
public static VcnGatewayConnectionConfig buildTestConfig() {
- return buildTestConfigWithExposedCaps(EXPOSED_CAPS);
+ final VcnGatewayConnectionConfig.Builder builder =
+ newBuilder().setVcnUnderlyingNetworkPriorities(UNDERLYING_NETWORK_PRIORITIES);
+
+ return buildTestConfigWithExposedCaps(builder, EXPOSED_CAPS);
}
private static VcnGatewayConnectionConfig.Builder newBuilder() {
@@ -159,6 +171,15 @@ public class VcnGatewayConnectionConfigTest {
}
@Test
+ public void testBuilderRequiresNonNullNetworkPriorities() {
+ try {
+ newBuilder().setVcnUnderlyingNetworkPriorities(null);
+ fail("Expected exception due to invalid underlyingNetworkPriorities");
+ } catch (NullPointerException e) {
+ }
+ }
+
+ @Test
public void testBuilderRequiresNonNullRetryInterval() {
try {
newBuilder().setRetryIntervalsMillis(null);
@@ -195,6 +216,7 @@ public class VcnGatewayConnectionConfigTest {
Arrays.sort(exposedCaps);
assertArrayEquals(EXPOSED_CAPS, exposedCaps);
+ assertEquals(UNDERLYING_NETWORK_PRIORITIES, config.getVcnUnderlyingNetworkPriorities());
assertEquals(TUNNEL_CONNECTION_PARAMS, config.getTunnelConnectionParams());
assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis());
diff --git a/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java b/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java
new file mode 100644
index 000000000000..dd272cb38596
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkPriorityTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_ANY;
+import static android.net.vcn.VcnUnderlyingNetworkPriority.NETWORK_QUALITY_OK;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+public class VcnWifiUnderlyingNetworkPriorityTest {
+ private static final String SSID = "TestWifi";
+ private static final int INVALID_NETWORK_QUALITY = -1;
+
+ // Package private for use in VcnGatewayConnectionConfigTest
+ static VcnWifiUnderlyingNetworkPriority getTestNetworkPriority() {
+ return new VcnWifiUnderlyingNetworkPriority.Builder()
+ .setNetworkQuality(NETWORK_QUALITY_OK)
+ .setAllowMetered(true /* allowMetered */)
+ .setSsid(SSID)
+ .build();
+ }
+
+ @Test
+ public void testBuilderAndGetters() {
+ final VcnWifiUnderlyingNetworkPriority networkPriority = getTestNetworkPriority();
+ assertEquals(NETWORK_QUALITY_OK, networkPriority.getNetworkQuality());
+ assertTrue(networkPriority.allowMetered());
+ assertEquals(SSID, networkPriority.getSsid());
+ }
+
+ @Test
+ public void testBuilderAndGettersForDefaultValues() {
+ final VcnWifiUnderlyingNetworkPriority networkPriority =
+ new VcnWifiUnderlyingNetworkPriority.Builder().build();
+ assertEquals(NETWORK_QUALITY_ANY, networkPriority.getNetworkQuality());
+ assertFalse(networkPriority.allowMetered());
+ assertNull(SSID, networkPriority.getSsid());
+ }
+
+ @Test
+ public void testBuildWithInvalidNetworkQuality() {
+ try {
+ new VcnWifiUnderlyingNetworkPriority.Builder()
+ .setNetworkQuality(INVALID_NETWORK_QUALITY);
+ fail("Expected to fail due to the invalid network quality");
+ } catch (Exception expected) {
+ }
+ }
+
+ @Test
+ public void testPersistableBundle() {
+ final VcnWifiUnderlyingNetworkPriority networkPriority = getTestNetworkPriority();
+ assertEquals(
+ networkPriority,
+ VcnUnderlyingNetworkPriority.fromPersistableBundle(
+ networkPriority.toPersistableBundle()));
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index c9a8947ab5ef..e547400fff73 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -118,8 +118,10 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
@Test
public void testNullNetworkDoesNotTriggerDisconnect() throws Exception {
+ doReturn(false).when(mDeps).isAirplaneModeOn(any());
+
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(null);
mTestLooper.dispatchAll();
@@ -129,9 +131,22 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
}
@Test
+ public void testNullNetworkAirplaneModeDisconnects() throws Exception {
+ doReturn(true).when(mDeps).isAirplaneModeOn(any());
+
+ mGatewayConnection
+ .getUnderlyingNetworkControllerCallback()
+ .onSelectedUnderlyingNetworkChanged(null);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).kill();
+ }
+
+ @Test
public void testNewNetworkTriggersMigration() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
mTestLooper.dispatchAll();
@@ -143,7 +158,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
@Test
public void testSameNetworkDoesNotTriggerMigration() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
mTestLooper.dispatchAll();
@@ -203,7 +218,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
triggerChildOpened();
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
getChildSessionCallback()
.onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform());
@@ -297,8 +312,6 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
any(),
any());
verify(mNetworkAgent).register();
- verify(mNetworkAgent)
- .setUnderlyingNetworks(eq(singletonList(TEST_UNDERLYING_NETWORK_RECORD_1.network)));
verify(mNetworkAgent).markConnected();
verify(mIpSecSvc)
@@ -313,6 +326,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
final NetworkCapabilities nc = ncCaptor.getValue();
assertTrue(nc.hasTransport(TRANSPORT_CELLULAR));
assertFalse(nc.hasTransport(TRANSPORT_WIFI));
+ assertEquals(List.of(TEST_UNDERLYING_NETWORK_RECORD_1.network), nc.getUnderlyingNetworks());
for (int cap : mConfig.getAllExposedCapabilities()) {
assertTrue(nc.hasCapability(cap));
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
index d1f3a210d870..3c70759a2fa6 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
@@ -64,7 +64,7 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio
@Test
public void testNullNetworkTriggersDisconnect() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(null);
mTestLooper.dispatchAll();
@@ -76,7 +76,7 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio
@Test
public void testNewNetworkTriggersReconnect() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
mTestLooper.dispatchAll();
@@ -89,7 +89,7 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio
@Test
public void testSameNetworkDoesNotTriggerReconnect() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
mTestLooper.dispatchAll();
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
index 2056eea42ce6..f3eb82f46de7 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
@@ -78,7 +78,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
@Test
public void testNetworkChangesTriggerStateTransitions() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
mTestLooper.dispatchAll();
@@ -89,7 +89,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
@Test
public void testNullNetworkDoesNotTriggerStateTransition() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(null);
mTestLooper.dispatchAll();
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
index 1c859790a2fe..6568cdd44377 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
@@ -58,7 +58,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect
@Test
public void testNewNetworkTriggerRetry() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
mTestLooper.dispatchAll();
@@ -72,7 +72,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect
@Test
public void testSameNetworkDoesNotTriggerRetry() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
mTestLooper.dispatchAll();
@@ -86,7 +86,7 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect
@Test
public void testNullNetworkTriggersDisconnect() throws Exception {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(null);
mTestLooper.dispatchAll();
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
index a7001713533c..b9dfda38a01c 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -16,6 +16,7 @@
package com.android.server.vcn;
+import static android.net.IpSecManager.IpSecTunnelInterface;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
@@ -24,6 +25,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR;
+import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration;
import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
@@ -36,8 +39,11 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.net.IpSecManager;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -53,14 +59,17 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
-import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
+import com.android.server.vcn.routeselection.UnderlyingNetworkRecord;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.net.InetAddress;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -70,6 +79,8 @@ import java.util.UUID;
public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
private static final int TEST_UID = Process.myUid() + 1;
+ private static final String LOOPBACK_IFACE = "lo";
+
private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID());
private static final int TEST_SIM_SLOT_INDEX = 1;
private static final int TEST_SUBSCRIPTION_ID_1 = 2;
@@ -77,6 +88,12 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
private static final int TEST_SUBSCRIPTION_ID_2 = 3;
private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class);
private static final Map<Integer, ParcelUuid> TEST_SUBID_TO_GROUP_MAP;
+ private static final String TEST_TCP_BUFFER_SIZES = "1,2,3,4,5,6";
+ private static final int TEST_MTU = 1300;
+ private static final int TEST_MTU_DELTA = 64;
+ private static final List<LinkAddress> TEST_INTERNAL_ADDRESSES =
+ Arrays.asList(new LinkAddress(DUMMY_ADDR, 16));
+ private static final List<InetAddress> TEST_DNS_ADDRESSES = Arrays.asList(DUMMY_ADDR);
private static final int TEST_UPSTREAM_BANDWIDTH = 1234;
private static final int TEST_DOWNSTREAM_BANDWIDTH = 2345;
@@ -116,8 +133,9 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
capBuilder.setLinkUpstreamBandwidthKbps(TEST_UPSTREAM_BANDWIDTH);
capBuilder.setLinkDownstreamBandwidthKbps(TEST_DOWNSTREAM_BANDWIDTH);
capBuilder.setAdministratorUids(new int[] {TEST_UID});
+ final Network underlyingNetwork = mock(Network.class, CALLS_REAL_METHODS);
UnderlyingNetworkRecord record = new UnderlyingNetworkRecord(
- mock(Network.class, CALLS_REAL_METHODS),
+ underlyingNetwork,
capBuilder.build(), new LinkProperties(), false);
final NetworkCapabilities vcnCaps =
VcnGatewayConnection.buildNetworkCapabilities(
@@ -128,6 +146,7 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
assertTrue(vcnCaps.hasTransport(TRANSPORT_CELLULAR));
assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_METERED));
assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+ assertTrue(vcnCaps.getUnderlyingNetworks().equals(List.of(underlyingNetwork)));
for (int cap : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
if (cap == NET_CAPABILITY_INTERNET || cap == NET_CAPABILITY_DUN) {
@@ -166,14 +185,67 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
}
@Test
- public void testSubscriptionSnapshotUpdateNotifiesUnderlyingNetworkTracker() {
+ public void testBuildLinkProperties() throws Exception {
+ final IpSecTunnelInterface tunnelIface =
+ mContext.getSystemService(IpSecManager.class)
+ .createIpSecTunnelInterface(
+ DUMMY_ADDR, DUMMY_ADDR, TEST_UNDERLYING_NETWORK_RECORD_1.network);
+
+ final LinkProperties underlyingLp = new LinkProperties();
+ underlyingLp.setInterfaceName(LOOPBACK_IFACE);
+ underlyingLp.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES);
+ doReturn(TEST_MTU).when(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE);
+
+ final VcnChildSessionConfiguration childSessionConfig =
+ mock(VcnChildSessionConfiguration.class);
+ doReturn(TEST_INTERNAL_ADDRESSES).when(childSessionConfig).getInternalAddresses();
+ doReturn(TEST_DNS_ADDRESSES).when(childSessionConfig).getInternalDnsServers();
+
+ UnderlyingNetworkRecord record =
+ new UnderlyingNetworkRecord(
+ mock(Network.class, CALLS_REAL_METHODS),
+ new NetworkCapabilities.Builder().build(),
+ underlyingLp,
+ false);
+
+ final LinkProperties vcnLp1 =
+ mGatewayConnection.buildConnectedLinkProperties(
+ VcnGatewayConnectionConfigTest.buildTestConfig(),
+ tunnelIface,
+ childSessionConfig,
+ record);
+
+ verify(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE);
+
+ // Instead of having to recalculate the final MTU (after accounting for IPsec overhead),
+ // calculate another set of Link Properties with a lower MTU, and calculate the delta.
+ doReturn(TEST_MTU - TEST_MTU_DELTA).when(mDeps).getUnderlyingIfaceMtu(LOOPBACK_IFACE);
+
+ final LinkProperties vcnLp2 =
+ mGatewayConnection.buildConnectedLinkProperties(
+ VcnGatewayConnectionConfigTest.buildTestConfig(),
+ tunnelIface,
+ childSessionConfig,
+ record);
+
+ verify(mDeps, times(2)).getUnderlyingIfaceMtu(LOOPBACK_IFACE);
+
+ assertEquals(tunnelIface.getInterfaceName(), vcnLp1.getInterfaceName());
+ assertEquals(TEST_INTERNAL_ADDRESSES, vcnLp1.getLinkAddresses());
+ assertEquals(TEST_DNS_ADDRESSES, vcnLp1.getDnsServers());
+ assertEquals(TEST_TCP_BUFFER_SIZES, vcnLp1.getTcpBufferSizes());
+ assertEquals(TEST_MTU_DELTA, vcnLp1.getMtu() - vcnLp2.getMtu());
+ }
+
+ @Test
+ public void testSubscriptionSnapshotUpdateNotifiesUnderlyingNetworkController() {
verifyWakeLockSetUp();
final TelephonySubscriptionSnapshot updatedSnapshot =
mock(TelephonySubscriptionSnapshot.class);
mGatewayConnection.updateSubscriptionSnapshot(updatedSnapshot);
- verify(mUnderlyingNetworkTracker).updateSubscriptionSnapshot(eq(updatedSnapshot));
+ verify(mUnderlyingNetworkController).updateSubscriptionSnapshot(eq(updatedSnapshot));
verifyWakeLockAcquired();
mTestLooper.dispatchAll();
@@ -184,13 +256,13 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
@Test
public void testNonNullUnderlyingNetworkRecordUpdateCancelsAlarm() {
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(null);
verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */);
mGatewayConnection
- .getUnderlyingNetworkTrackerCallback()
+ .getUnderlyingNetworkControllerCallback()
.onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
verify(mDisconnectRequestAlarm).cancel();
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 64d0bca15ce9..8a0af2dff8c8 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -16,7 +16,6 @@
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.VcnGatewayConnection.VcnNetworkAgent;
import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
@@ -62,6 +61,8 @@ import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscription
import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback;
import com.android.server.vcn.VcnGatewayConnection.VcnWakeLock;
+import com.android.server.vcn.routeselection.UnderlyingNetworkController;
+import com.android.server.vcn.routeselection.UnderlyingNetworkRecord;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
@@ -137,7 +138,7 @@ public class VcnGatewayConnectionTestBase {
@NonNull protected final VcnGatewayConnectionConfig mConfig;
@NonNull protected final VcnGatewayStatusCallback mGatewayStatusCallback;
@NonNull protected final VcnGatewayConnection.Dependencies mDeps;
- @NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker;
+ @NonNull protected final UnderlyingNetworkController mUnderlyingNetworkController;
@NonNull protected final VcnWakeLock mWakeLock;
@NonNull protected final WakeupMessage mTeardownTimeoutAlarm;
@NonNull protected final WakeupMessage mDisconnectRequestAlarm;
@@ -158,7 +159,7 @@ public class VcnGatewayConnectionTestBase {
mConfig = VcnGatewayConnectionConfigTest.buildTestConfig();
mGatewayStatusCallback = mock(VcnGatewayStatusCallback.class);
mDeps = mock(VcnGatewayConnection.Dependencies.class);
- mUnderlyingNetworkTracker = mock(UnderlyingNetworkTracker.class);
+ mUnderlyingNetworkController = mock(UnderlyingNetworkController.class);
mWakeLock = mock(VcnWakeLock.class);
mTeardownTimeoutAlarm = mock(WakeupMessage.class);
mDisconnectRequestAlarm = mock(WakeupMessage.class);
@@ -176,9 +177,9 @@ public class VcnGatewayConnectionTestBase {
doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
- doReturn(mUnderlyingNetworkTracker)
+ doReturn(mUnderlyingNetworkController)
.when(mDeps)
- .newUnderlyingNetworkTracker(any(), any(), any(), any());
+ .newUnderlyingNetworkController(any(), any(), any(), any());
doReturn(mWakeLock)
.when(mDeps)
.newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any());
diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
index 5af69b5d1bf2..c954cb84df7f 100644
--- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
@@ -14,9 +14,11 @@
* limitations under the License.
*/
-package com.android.server.vcn;
+package com.android.server.vcn.routeselection;
import static com.android.server.vcn.VcnTestUtils.setupSystemService;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
@@ -48,10 +50,11 @@ import android.telephony.TelephonyManager;
import android.util.ArraySet;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
-import com.android.server.vcn.UnderlyingNetworkTracker.NetworkBringupCallback;
-import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkListener;
-import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
-import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback;
+import com.android.server.vcn.VcnContext;
+import com.android.server.vcn.VcnNetworkProvider;
+import com.android.server.vcn.routeselection.UnderlyingNetworkController.NetworkBringupCallback;
+import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkControllerCallback;
+import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkListener;
import org.junit.Before;
import org.junit.Test;
@@ -64,7 +67,7 @@ import java.util.Arrays;
import java.util.Set;
import java.util.UUID;
-public class UnderlyingNetworkTrackerTest {
+public class UnderlyingNetworkControllerTest {
private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0));
private static final int INITIAL_SUB_ID_1 = 1;
private static final int INITIAL_SUB_ID_2 = 2;
@@ -102,14 +105,14 @@ public class UnderlyingNetworkTrackerTest {
@Mock private TelephonyManager mTelephonyManager;
@Mock private CarrierConfigManager mCarrierConfigManager;
@Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
- @Mock private UnderlyingNetworkTrackerCallback mNetworkTrackerCb;
+ @Mock private UnderlyingNetworkControllerCallback mNetworkControllerCb;
@Mock private Network mNetwork;
@Captor private ArgumentCaptor<UnderlyingNetworkListener> mUnderlyingNetworkListenerCaptor;
private TestLooper mTestLooper;
private VcnContext mVcnContext;
- private UnderlyingNetworkTracker mUnderlyingNetworkTracker;
+ private UnderlyingNetworkController mUnderlyingNetworkController;
@Before
public void setUp() {
@@ -140,12 +143,9 @@ public class UnderlyingNetworkTrackerTest {
when(mSubscriptionSnapshot.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(INITIAL_SUB_IDS);
- mUnderlyingNetworkTracker =
- new UnderlyingNetworkTracker(
- mVcnContext,
- SUB_GROUP,
- mSubscriptionSnapshot,
- mNetworkTrackerCb);
+ mUnderlyingNetworkController =
+ new UnderlyingNetworkController(
+ mVcnContext, SUB_GROUP, mSubscriptionSnapshot, mNetworkControllerCb);
}
private void resetVcnContext() {
@@ -181,11 +181,8 @@ public class UnderlyingNetworkTrackerTest {
mVcnNetworkProvider,
true /* isInTestMode */);
- new UnderlyingNetworkTracker(
- vcnContext,
- SUB_GROUP,
- mSubscriptionSnapshot,
- mNetworkTrackerCb);
+ new UnderlyingNetworkController(
+ vcnContext, SUB_GROUP, mSubscriptionSnapshot, mNetworkControllerCb);
verify(cm)
.registerNetworkCallback(
@@ -233,7 +230,7 @@ public class UnderlyingNetworkTrackerTest {
mock(TelephonySubscriptionSnapshot.class);
when(subscriptionUpdate.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(UPDATED_SUB_IDS);
- mUnderlyingNetworkTracker.updateSubscriptionSnapshot(subscriptionUpdate);
+ mUnderlyingNetworkController.updateSubscriptionSnapshot(subscriptionUpdate);
// verify that initially-filed bringup requests are unregistered (cell + wifi)
verify(mConnectivityManager, times(INITIAL_SUB_IDS.size() + 3))
@@ -255,7 +252,7 @@ public class UnderlyingNetworkTrackerTest {
return getExpectedRequestBase()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.setSubscriptionIds(netCapsSubIds)
- .setSignalStrength(UnderlyingNetworkTracker.WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT)
+ .setSignalStrength(WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT)
.build();
}
@@ -264,7 +261,7 @@ public class UnderlyingNetworkTrackerTest {
return getExpectedRequestBase()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.setSubscriptionIds(netCapsSubIds)
- .setSignalStrength(UnderlyingNetworkTracker.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT)
+ .setSignalStrength(WIFI_EXIT_RSSI_THRESHOLD_DEFAULT)
.build();
}
@@ -304,7 +301,7 @@ public class UnderlyingNetworkTrackerTest {
@Test
public void testTeardown() {
- mUnderlyingNetworkTracker.teardown();
+ mUnderlyingNetworkController.teardown();
// Expect 5 NetworkBringupCallbacks to be unregistered: 1 for WiFi, 2 for Cellular (1x for
// each subId), and 1 for each of the Wifi signal strength thresholds
@@ -368,7 +365,7 @@ public class UnderlyingNetworkTrackerTest {
networkCapabilities,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
return cb;
}
@@ -384,7 +381,7 @@ public class UnderlyingNetworkTrackerTest {
UPDATED_NETWORK_CAPABILITIES,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
}
@Test
@@ -399,7 +396,7 @@ public class UnderlyingNetworkTrackerTest {
INITIAL_NETWORK_CAPABILITIES,
UPDATED_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
}
@Test
@@ -414,11 +411,13 @@ public class UnderlyingNetworkTrackerTest {
SUSPENDED_NETWORK_CAPABILITIES,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkControllerCb, times(1))
+ .onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
// onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
// change.
cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES);
- verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkControllerCb, times(1))
+ .onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
}
@Test
@@ -434,11 +433,13 @@ public class UnderlyingNetworkTrackerTest {
INITIAL_NETWORK_CAPABILITIES,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkControllerCb, times(1))
+ .onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
// onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
// change.
cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
- verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkControllerCb, times(1))
+ .onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
}
@Test
@@ -453,7 +454,7 @@ public class UnderlyingNetworkTrackerTest {
INITIAL_NETWORK_CAPABILITIES,
INITIAL_LINK_PROPERTIES,
true /* isBlocked */);
- verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
}
@Test
@@ -462,7 +463,7 @@ public class UnderlyingNetworkTrackerTest {
cb.onLost(mNetwork);
- verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(null);
+ verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(null);
}
@Test
@@ -471,20 +472,20 @@ public class UnderlyingNetworkTrackerTest {
cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
- // Verify no more calls to the UnderlyingNetworkTrackerCallback when the
+ // Verify no more calls to the UnderlyingNetworkControllerCallback when the
// UnderlyingNetworkRecord does not actually change
- verifyNoMoreInteractions(mNetworkTrackerCb);
+ verifyNoMoreInteractions(mNetworkControllerCb);
}
@Test
public void testRecordTrackerCallbackNotifiedAfterTeardown() {
UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
- mUnderlyingNetworkTracker.teardown();
+ mUnderlyingNetworkController.teardown();
cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES);
// Verify that the only call was during onAvailable()
- verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(any());
+ verify(mNetworkControllerCb, times(1)).onSelectedUnderlyingNetworkChanged(any());
}
// TODO (b/187991063): Add tests for network prioritization
diff --git a/tools/aapt2/OWNERS b/tools/aapt2/OWNERS
index 69dfcc98340d..4f655e54a7c2 100644
--- a/tools/aapt2/OWNERS
+++ b/tools/aapt2/OWNERS
@@ -1,4 +1,4 @@
set noparent
toddke@google.com
-rtmitchell@google.com
+zyy@google.com
patb@google.com \ No newline at end of file
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 5d57de6a9fb1..be09545abb45 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -154,7 +154,7 @@ StringPiece GetFilename(const StringPiece& path) {
const char* end = path.end();
const char* last_dir_sep = path.begin();
for (const char* c = path.begin(); c != end; ++c) {
- if (*c == sDirSep) {
+ if (*c == sDirSep || *c == sInvariantDirSep) {
last_dir_sep = c + 1;
}
}
diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h
index 481a4cdb6ad0..e50cb505bf66 100644
--- a/tools/aapt2/util/Files.h
+++ b/tools/aapt2/util/Files.h
@@ -41,6 +41,8 @@ constexpr const char sDirSep = '/';
constexpr const char sPathSep = ':';
#endif
+constexpr const char sInvariantDirSep = '/';
+
enum class FileType {
kUnknown = 0,
kNonexistant,
diff --git a/tools/aosp/aosp_sha.sh b/tools/aosp/aosp_sha.sh
index ac23c3d9cb4a..36bea57b710f 100755
--- a/tools/aosp/aosp_sha.sh
+++ b/tools/aosp/aosp_sha.sh
@@ -1,7 +1,7 @@
#!/bin/bash
LOCAL_DIR="$( dirname "${BASH_SOURCE}" )"
-if git branch -vv | grep -q -P "^\*[^\[]+\[aosp/"; then
+if git branch -vv | grep -q -E "^\*[^\[]+\[aosp/"; then
# Change appears to be in AOSP
exit 0
elif git log -n 1 --format='%B' $1 | grep -q -E "^Ignore-AOSP-First: .+" ; then