summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/AccessibilityEventsLogger/Android.bp9
-rw-r--r--tests/AccessibilityEventsLogger/AndroidManifest.xml41
-rw-r--r--tests/AccessoryDisplay/common/Android.bp9
-rw-r--r--tests/AccessoryDisplay/sink/Android.bp9
-rw-r--r--tests/AccessoryDisplay/sink/AndroidManifest.xml21
-rw-r--r--tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/SinkActivity.java2
-rw-r--r--tests/AccessoryDisplay/source/Android.bp9
-rw-r--r--tests/AccessoryDisplay/source/AndroidManifest.xml21
-rw-r--r--tests/ActivityManagerPerfTests/OWNERS1
-rw-r--r--tests/ActivityManagerPerfTests/stub-app/Android.bp10
-rw-r--r--tests/ActivityManagerPerfTests/stub-app/AndroidManifest.xml45
-rw-r--r--tests/ActivityManagerPerfTests/test-app/Android.bp9
-rw-r--r--tests/ActivityManagerPerfTests/tests/Android.bp10
-rw-r--r--tests/ActivityManagerPerfTests/tests/AndroidTest.xml17
-rw-r--r--tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/OomAdjPerfTest.java10
-rw-r--r--tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java16
-rw-r--r--tests/ActivityManagerPerfTests/utils/Android.bp9
-rw-r--r--tests/ActivityTests/Android.bp9
-rw-r--r--tests/ActivityTests/AndroidManifest.xml107
-rw-r--r--tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java6
-rw-r--r--tests/ActivityViewTest/Android.bp6
-rw-r--r--tests/ActivityViewTest/AndroidManifest.xml66
-rw-r--r--tests/ActivityViewTest/res/layout/activity_view_activity.xml47
-rw-r--r--tests/ActivityViewTest/res/layout/activity_view_resize_activity.xml51
-rw-r--r--tests/ActivityViewTest/res/layout/activity_view_scroll_activity.xml57
-rw-r--r--tests/ActivityViewTest/res/layout/activity_view_test_activity.xml70
-rw-r--r--tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml46
-rw-r--r--tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java56
-rw-r--r--tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java42
-rw-r--r--tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewResizeActivity.java79
-rw-r--r--tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewScrollActivity.java44
-rw-r--r--tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java116
-rw-r--r--tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java75
-rw-r--r--tests/AmSlam/Android.bp9
-rw-r--r--tests/AmSlam/AndroidManifest.xml425
-rw-r--r--tests/AmSlam/OWNERS1
-rw-r--r--tests/ApkVerityTest/Android.bp13
-rw-r--r--tests/ApkVerityTest/ApkVerityTestApp/Android.bp9
-rw-r--r--tests/ApkVerityTest/OWNERS3
-rw-r--r--tests/ApkVerityTest/block_device_writer/Android.bp15
-rw-r--r--tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java100
-rw-r--r--tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java210
-rw-r--r--tests/ApkVerityTest/testdata/Android.bp12
-rw-r--r--tests/AppLaunch/Android.bp9
-rw-r--r--tests/AppLaunchWear/Android.bp9
-rw-r--r--tests/AppResourcesLoaders/Android.bp9
-rw-r--r--tests/AppResourcesLoaders/AndroidManifest.xml13
-rw-r--r--tests/AppResourcesLoaders/Overlay/Android.bp9
-rw-r--r--tests/Assist/Android.bp9
-rw-r--r--tests/Assist/AndroidManifest.xml38
-rw-r--r--tests/AutoVerify/app1/Android.bp11
-rw-r--r--tests/AutoVerify/app1/AndroidManifest.xml43
-rw-r--r--tests/AutoVerify/app1/res/values/strings.xml21
-rw-r--r--tests/AutoVerify/app2/Android.bp11
-rw-r--r--tests/AutoVerify/app2/AndroidManifest.xml44
-rw-r--r--tests/AutoVerify/app2/res/values/strings.xml21
-rw-r--r--tests/AutoVerify/app3/Android.bp11
-rw-r--r--tests/AutoVerify/app3/AndroidManifest.xml44
-rw-r--r--tests/AutoVerify/app3/res/values/strings.xml21
-rw-r--r--tests/AutoVerify/app4/Android.bp11
-rw-r--r--tests/AutoVerify/app4/res/values/strings.xml21
-rw-r--r--tests/BackgroundDexOptServiceIntegrationTests/Android.bp9
-rw-r--r--tests/BackgroundDexOptServiceIntegrationTests/OWNERS1
-rw-r--r--tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java47
-rw-r--r--tests/BandwidthTests/Android.bp9
-rw-r--r--tests/BandwidthTests/AndroidManifest.xml19
-rw-r--r--tests/BatteryStatsPerfTest/Android.bp34
-rw-r--r--tests/BatteryStatsPerfTest/AndroidManifest.xml27
-rw-r--r--tests/BatteryStatsPerfTest/AndroidTest.xml (renamed from tests/net/smoketest/AndroidTest.xml)18
-rw-r--r--tests/BatteryStatsPerfTest/OWNERS1
-rw-r--r--tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryStatsHelperPerfTest.java135
-rw-r--r--tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java74
-rw-r--r--tests/BatteryWaster/Android.bp9
-rw-r--r--tests/BatteryWaster/AndroidManifest.xml18
-rw-r--r--tests/BatteryWaster/OWNERS1
-rw-r--r--tests/BiDiTests/Android.bp9
-rw-r--r--tests/BiDiTests/AndroidManifest.xml19
-rw-r--r--tests/BlobStoreTestUtils/Android.bp11
-rw-r--r--tests/BlobStoreTestUtils/OWNERS1
-rw-r--r--tests/BlobStoreTestUtils/src/com/android/utils/blob/FakeBlobData.java (renamed from tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java)8
-rw-r--r--tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java11
-rw-r--r--tests/BootImageProfileTest/Android.bp9
-rw-r--r--tests/BootImageProfileTest/OWNERS4
-rw-r--r--tests/BrowserPowerTest/Android.bp9
-rw-r--r--tests/BrowserPowerTest/AndroidManifest.xml37
-rw-r--r--tests/Camera2Tests/CameraToo/Android.mk3
-rw-r--r--tests/Camera2Tests/CameraToo/AndroidManifest.xml17
-rw-r--r--tests/Camera2Tests/CameraToo/tests/Android.mk3
-rw-r--r--tests/Camera2Tests/OWNERS1
-rw-r--r--tests/Camera2Tests/SmartCamera/SimpleCamera/Android.mk3
-rw-r--r--tests/Camera2Tests/SmartCamera/SimpleCamera/AndroidManifest.xml25
-rw-r--r--tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp10
-rw-r--r--tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk3
-rw-r--r--tests/CameraPrewarmTest/Android.bp9
-rw-r--r--tests/CameraPrewarmTest/AndroidManifest.xml28
-rw-r--r--tests/CanvasCompare/Android.mk3
-rw-r--r--tests/CanvasCompare/AndroidManifest.xml40
-rw-r--r--tests/CanvasCompare/OWNERS1
-rw-r--r--tests/Codegen/Android.bp9
-rw-r--r--tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java8
-rw-r--r--tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java8
-rw-r--r--tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java8
-rw-r--r--tests/Codegen/src/com/android/codegentest/SampleDataClass.java208
-rw-r--r--tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java8
-rw-r--r--tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java18
-rw-r--r--tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java32
-rw-r--r--tests/Compatibility/Android.bp11
-rw-r--r--tests/Compatibility/OWNERS1
-rw-r--r--tests/CoreTests/android/Android.bp9
-rw-r--r--tests/DataIdleTest/Android.bp9
-rw-r--r--tests/DozeTest/Android.bp9
-rw-r--r--tests/DozeTest/OWNERS1
-rw-r--r--tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java2
-rw-r--r--tests/DpiTest/Android.bp9
-rw-r--r--tests/DpiTest/AndroidManifest.xml34
-rw-r--r--tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java24
-rw-r--r--tests/DynamicCodeLoggerIntegrationTests/Android.mk15
-rw-r--r--tests/FeatureSplit/base/Android.bp9
-rw-r--r--tests/FeatureSplit/base/AndroidManifest.xml12
-rw-r--r--tests/FeatureSplit/feature1/Android.bp9
-rw-r--r--tests/FeatureSplit/feature1/AndroidManifest.xml16
-rw-r--r--tests/FeatureSplit/feature2/Android.bp9
-rw-r--r--tests/FixVibrateSetting/Android.bp9
-rw-r--r--tests/FixVibrateSetting/AndroidManifest.xml16
-rw-r--r--tests/FixVibrateSetting/OWNERS1
-rw-r--r--tests/FlickerTests/Android.bp49
-rw-r--r--tests/FlickerTests/AndroidManifest.xml16
-rw-r--r--tests/FlickerTests/AndroidTest.xml13
-rw-r--r--tests/FlickerTests/OWNERS3
-rw-r--r--tests/FlickerTests/README.md190
-rw-r--r--tests/FlickerTests/TEST_MAPPING13
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java162
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java77
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java69
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java78
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java94
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt223
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java325
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java188
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java142
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java80
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java85
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java99
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java85
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java73
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java186
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java177
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/SplitScreenToLauncherTest.java100
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt57
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt57
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt142
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java31
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt (renamed from tests/AutoVerify/app4/src/com/android/test/autoverify/MainActivity.java)13
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java31
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt48
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java41
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt84
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java43
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt32
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt32
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt153
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt162
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt159
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt167
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt141
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt165
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt178
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt143
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt29
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt109
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt104
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt154
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt88
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt104
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt159
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt133
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/Android.bp11
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml52
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java22
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java45
-rw-r--r--tests/FrameworkPerf/Android.bp9
-rw-r--r--tests/FrameworkPerf/AndroidManifest.xml33
-rw-r--r--tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java2
-rw-r--r--tests/GamePerformance/Android.bp41
-rw-r--r--tests/GamePerformance/Android.mk39
-rw-r--r--tests/GamePerformance/AndroidManifest.xml26
-rw-r--r--tests/GridLayoutTest/Android.bp9
-rw-r--r--tests/GridLayoutTest/AndroidManifest.xml42
-rw-r--r--tests/HierarchyViewerTest/Android.bp9
-rw-r--r--tests/HierarchyViewerTest/AndroidManifest.xml20
-rw-r--r--tests/HugeBackup/Android.bp9
-rw-r--r--tests/HugeBackup/AndroidManifest.xml22
-rw-r--r--tests/HugeBackup/OWNERS1
-rw-r--r--tests/HwAccelerationTest/Android.bp9
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml1288
-rw-r--r--tests/HwAccelerationTest/OWNERS1
-rw-r--r--tests/HwAccelerationTest/res/layout/image_filter_activity.xml28
-rw-r--r--tests/HwAccelerationTest/res/layout/scrolling_stretch_surfaceview.xml76
-rw-r--r--tests/HwAccelerationTest/res/layout/stretch_layout.xml86
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java162
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java35
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java (renamed from tests/AutoVerify/app1/src/com/android/test/autoverify/MainActivity.java)16
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java62
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java87
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectShaderActivity.java107
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java186
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/ScrollingStretchSurfaceViewActivity.java113
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java537
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java158
-rw-r--r--tests/Input/Android.bp25
-rw-r--r--tests/Input/AndroidManifest.xml34
-rw-r--r--tests/Input/AndroidTest.xml25
-rw-r--r--tests/Input/OWNERS1
-rw-r--r--tests/Input/TEST_MAPPING7
-rw-r--r--tests/Input/src/com/android/test/input/AnrTest.kt115
-rw-r--r--tests/Input/src/com/android/test/input/InputDeviceTest.java98
-rw-r--r--tests/Input/src/com/android/test/input/InputEventAssignerTest.kt130
-rw-r--r--tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt165
-rw-r--r--tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt52
-rw-r--r--tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt72
-rw-r--r--tests/Internal/Android.bp10
-rw-r--r--tests/Internal/AndroidManifest.xml25
-rw-r--r--tests/Internal/src/android/app/WallpaperColorsTest.java25
-rw-r--r--tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java462
-rw-r--r--tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java114
-rw-r--r--tests/Internal/src/com/android/internal/protolog/common/LogDataTypeTest.java85
-rw-r--r--tests/JankBench/Android.bp9
-rw-r--r--tests/JankBench/app/src/main/AndroidManifest.xml67
-rw-r--r--tests/JobSchedulerPerfTests/Android.bp9
-rw-r--r--tests/JobSchedulerPerfTests/OWNERS1
-rw-r--r--tests/JobSchedulerTestApp/Android.bp9
-rw-r--r--tests/JobSchedulerTestApp/AndroidManifest.xml38
-rw-r--r--tests/JobSchedulerTestApp/OWNERS1
-rw-r--r--tests/LargeAssetTest/Android.bp9
-rw-r--r--tests/LargeAssetTest/AndroidManifest.xml14
-rw-r--r--tests/LegacyAssistant/Android.bp9
-rw-r--r--tests/LegacyAssistant/AndroidManifest.xml11
-rw-r--r--tests/LocalizationTest/Android.bp50
-rw-r--r--tests/LocalizationTest/AndroidManifest.xml29
-rw-r--r--tests/LocalizationTest/AndroidTest.xml34
-rw-r--r--tests/LocalizationTest/java/com/android/internal/app/LocalizationTest.kt118
-rw-r--r--tests/LocationTracker/Android.bp9
-rw-r--r--tests/LocationTracker/AndroidManifest.xml29
-rw-r--r--tests/LocationTracker/OWNERS1
-rw-r--r--tests/LockTaskTests/Android.mk3
-rw-r--r--tests/LockTaskTests/AndroidManifest.xml79
-rw-r--r--tests/LotsOfApps/Android.bp9
-rw-r--r--tests/LotsOfApps/AndroidManifest.xml1014
-rw-r--r--tests/LowStorageTest/Android.bp9
-rw-r--r--tests/LowStorageTest/AndroidManifest.xml12
-rw-r--r--tests/LowStorageTest/OWNERS1
-rw-r--r--tests/ManagedProfileLifecycleStressTest/Android.bp9
-rw-r--r--tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp9
-rw-r--r--tests/ManagedProfileLifecycleStressTest/app/DummyDPC/AndroidManifest.xml15
-rw-r--r--tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java52
-rw-r--r--tests/MemoryUsage/Android.bp9
-rw-r--r--tests/MirrorSurfaceTest/Android.bp9
-rw-r--r--tests/MirrorSurfaceTest/AndroidManifest.xml9
-rw-r--r--tests/NativeProcessesMemoryTest/Android.bp9
-rw-r--r--tests/NetworkSecurityConfigTest/Android.bp9
-rw-r--r--tests/NetworkSecurityConfigTest/OWNERS1
-rw-r--r--tests/NullHomeTest/Android.bp11
-rw-r--r--tests/NullHomeTest/AndroidManifest.xml2
-rw-r--r--tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java3
-rw-r--r--tests/OdmApps/Android.bp9
-rw-r--r--tests/OdmApps/app/Android.bp9
-rw-r--r--tests/OdmApps/priv-app/Android.bp9
-rw-r--r--tests/OneMedia/Android.bp9
-rw-r--r--tests/OneMedia/AndroidManifest.xml40
-rw-r--r--tests/OneMedia/src/com/android/onemedia/NotificationHelper.java12
-rw-r--r--tests/PackageWatchdog/Android.bp9
-rw-r--r--tests/PackageWatchdog/OWNERS1
-rw-r--r--tests/PackageWatchdog/TEST_MAPPING7
-rw-r--r--tests/PackageWatchdog/src/com/android/server/OWNERS1
-rw-r--r--tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java280
-rw-r--r--tests/PlatformCompatGating/Android.bp9
-rw-r--r--tests/PlatformCompatGating/OWNERS1
-rw-r--r--tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt17
-rw-r--r--tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatPermissionsTest.java13
-rw-r--r--tests/PlatformCompatGating/test-rules/Android.bp11
-rw-r--r--tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java15
-rw-r--r--tests/ProtoInputStreamTests/Android.bp (renamed from tests/net/common/Android.bp)37
-rw-r--r--tests/ProtoInputStreamTests/Android.mk34
-rw-r--r--tests/RemoteDisplayProvider/Android.bp9
-rw-r--r--tests/RenderThreadTest/Android.bp9
-rw-r--r--tests/RenderThreadTest/AndroidManifest.xml28
-rw-r--r--tests/RollbackTest/Android.bp24
-rw-r--r--tests/RollbackTest/MultiUserRollbackTest.xml2
-rw-r--r--tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java11
-rw-r--r--tests/RollbackTest/NetworkStagedRollbackTest.xml2
-rw-r--r--tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java17
-rw-r--r--tests/RollbackTest/OWNERS1
-rw-r--r--tests/RollbackTest/README.txt4
-rw-r--r--tests/RollbackTest/RollbackTest.xml2
-rw-r--r--tests/RollbackTest/RollbackTest/AndroidManifest.xml2
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java5
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java54
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java182
-rw-r--r--tests/RollbackTest/StagedRollbackTest.xml2
-rw-r--r--tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java462
-rw-r--r--tests/RollbackTest/TEST_MAPPING2
-rw-r--r--tests/RollbackTest/lib/src/com/android/tests/rollback/host/WatchdogEventLogger.java120
-rw-r--r--tests/SerialChat/Android.bp9
-rw-r--r--tests/SerialChat/AndroidManifest.xml12
-rw-r--r--tests/ServiceCrashTest/Android.bp9
-rw-r--r--tests/ServiceCrashTest/AndroidManifest.xml15
-rw-r--r--tests/SharedLibrary/client/Android.bp9
-rw-r--r--tests/SharedLibrary/client/AndroidManifest.xml23
-rw-r--r--tests/SharedLibrary/lib/Android.bp9
-rw-r--r--tests/SharedLibrary/lib/AndroidManifest.xml13
-rw-r--r--tests/ShowWhenLockedApp/Android.bp9
-rw-r--r--tests/ShowWhenLockedApp/AndroidManifest.xml9
-rw-r--r--tests/SilkFX/Android.bp37
-rw-r--r--tests/SilkFX/AndroidManifest.xml (renamed from tests/AutoVerify/app4/AndroidManifest.xml)46
-rw-r--r--tests/SilkFX/OWNERS1
-rw-r--r--tests/SilkFX/res/drawable-hdpi/background1.jpegbin0 -> 200459 bytes
-rw-r--r--tests/SilkFX/res/drawable-hdpi/background2.jpegbin0 -> 110703 bytes
-rw-r--r--tests/SilkFX/res/drawable-hdpi/background3.jpegbin0 -> 318853 bytes
-rw-r--r--tests/SilkFX/res/drawable-hdpi/noise.pngbin0 -> 494875 bytes
-rw-r--r--tests/SilkFX/res/drawable-nodpi/dark_notification.pngbin0 -> 42263 bytes
-rw-r--r--tests/SilkFX/res/drawable-nodpi/light_notification.pngbin0 -> 37096 bytes
-rw-r--r--tests/SilkFX/res/layout-television/activity_glass.xml302
-rw-r--r--tests/SilkFX/res/layout/activity_glass.xml303
-rw-r--r--tests/SilkFX/res/layout/bling_notifications.xml35
-rw-r--r--tests/SilkFX/res/layout/color_mode_controls.xml64
-rw-r--r--tests/SilkFX/res/layout/common_base.xml39
-rw-r--r--tests/SilkFX/res/layout/hdr_glows.xml51
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/Main.kt129
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt77
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt45
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/app/WindowObserver.kt (renamed from tests/AutoVerify/app3/src/com/android/test/autoverify/MainActivity.java)8
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt43
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt150
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt50
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt99
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/hdr/GlowActivity.kt (renamed from tests/AutoVerify/app2/src/com/android/test/autoverify/MainActivity.java)14
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt85
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt91
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt162
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt230
-rw-r--r--tests/SmokeTest/Android.bp9
-rw-r--r--tests/SmokeTest/AndroidManifest.xml15
-rw-r--r--tests/SmokeTest/tests/Android.bp9
-rw-r--r--tests/SmokeTestApps/Android.bp9
-rw-r--r--tests/SmokeTestApps/AndroidManifest.xml23
-rw-r--r--tests/SoundTriggerTestApp/Android.bp9
-rw-r--r--tests/SoundTriggerTestApp/AndroidManifest.xml37
-rw-r--r--tests/SoundTriggerTestApp/OWNERS1
-rw-r--r--tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java22
-rw-r--r--tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java35
-rw-r--r--tests/SoundTriggerTests/Android.mk3
-rw-r--r--tests/SoundTriggerTests/OWNERS1
-rw-r--r--tests/Split/Android.bp9
-rw-r--r--tests/Split/AndroidManifest.xml11
-rw-r--r--tests/StagedInstallTest/Android.bp41
-rw-r--r--tests/StagedInstallTest/OWNERS5
-rw-r--r--tests/StagedInstallTest/StagedInstallInternalTest.xml2
-rw-r--r--tests/StagedInstallTest/TEST_MAPPING12
-rw-r--r--tests/StagedInstallTest/app/AndroidManifest.xml2
-rw-r--r--tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java318
-rw-r--r--tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java408
-rw-r--r--tests/StatusBar/Android.bp9
-rw-r--r--tests/StatusBar/AndroidManifest.xml78
-rw-r--r--tests/StatusBar/OWNERS1
-rw-r--r--tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java4
-rw-r--r--tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java20
-rw-r--r--tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java2
-rw-r--r--tests/SurfaceComposition/Android.bp9
-rw-r--r--tests/SurfaceComposition/AndroidManifest.xml17
-rw-r--r--tests/SurfaceControlViewHostTest/Android.bp9
-rw-r--r--tests/SurfaceControlViewHostTest/AndroidManifest.xml6
-rw-r--r--tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java8
-rw-r--r--tests/SurfaceViewBufferTests/Android.bp70
-rw-r--r--tests/SurfaceViewBufferTests/AndroidManifest.xml57
-rw-r--r--tests/SurfaceViewBufferTests/AndroidTest.xml35
-rw-r--r--tests/SurfaceViewBufferTests/OWNERS1
-rw-r--r--tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp248
-rw-r--r--tests/SurfaceViewBufferTests/res/values/styles.xml (renamed from tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml)21
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt173
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt152
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt224
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt76
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/MainActivity.kt141
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/ScreenRecordTestBase.kt83
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeScreenRecordTests.kt67
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt90
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt67
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt120
-rw-r--r--tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt97
-rw-r--r--tests/SystemMemoryTest/device/Android.bp9
-rw-r--r--tests/SystemMemoryTest/host/Android.bp9
-rw-r--r--tests/SystemUIDemoModeController/Android.bp9
-rw-r--r--tests/SystemUIDemoModeController/AndroidManifest.xml26
-rw-r--r--tests/TaskOrganizerTest/Android.bp26
-rw-r--r--tests/TaskOrganizerTest/AndroidManifest.xml43
-rw-r--r--tests/TaskOrganizerTest/AndroidTest.xml35
-rw-r--r--tests/TaskOrganizerTest/OWNERS1
-rw-r--r--tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt111
-rw-r--r--tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java255
-rw-r--r--tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java82
-rw-r--r--tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java106
-rw-r--r--tests/TelephonyCommonTests/Android.bp9
-rw-r--r--tests/TelephonyCommonTests/OWNERS1
-rw-r--r--tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java7
-rw-r--r--tests/TouchLatency/Android.bp9
-rw-r--r--tests/TouchLatency/app/src/main/AndroidManifest.xml21
-rw-r--r--tests/TouchLatency/gradle/wrapper/gradle-wrapper.jarbin49896 -> 54417 bytes
-rw-r--r--tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties3
-rwxr-xr-xtests/TouchLatency/gradlew78
-rw-r--r--tests/TouchLatency/gradlew.bat14
-rw-r--r--tests/TransformTest/Android.bp9
-rw-r--r--tests/TransformTest/AndroidManifest.xml12
-rw-r--r--tests/TransitionTests/Android.bp11
-rw-r--r--tests/TransitionTests/AndroidManifest.xml256
-rw-r--r--tests/TtsTests/Android.bp9
-rw-r--r--tests/TtsTests/AndroidManifest.xml23
-rw-r--r--tests/UiBench/Android.bp9
-rw-r--r--tests/UiBench/AndroidManifest.xml352
-rw-r--r--tests/UiBench/res/layout/recycler_view.xml1
-rw-r--r--tests/UpdatableSystemFontTest/Android.bp51
-rw-r--r--tests/UpdatableSystemFontTest/AndroidManifest.xml30
-rw-r--r--tests/UpdatableSystemFontTest/AndroidTest.xml44
-rw-r--r--tests/UpdatableSystemFontTest/EmojiRenderingTestApp/Android.bp32
-rw-r--r--tests/UpdatableSystemFontTest/EmojiRenderingTestApp/AndroidManifest.xml24
-rw-r--r--tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java40
-rw-r--r--tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/GetAvailableFontsTestActivity.java53
-rw-r--r--tests/UpdatableSystemFontTest/OWNERS3
-rw-r--r--tests/UpdatableSystemFontTest/TEST_MAPPING7
-rw-r--r--tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java451
-rw-r--r--tests/UpdatableSystemFontTest/testdata/Android.bp122
-rw-r--r--tests/UpdatableSystemFontTest/testdata/NotoColorEmoji.ttfbin0 -> 1820 bytes
-rw-r--r--tests/UpdatableSystemFontTest/testdata/NotoColorEmoji.ttx208
-rw-r--r--tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestCert.derbin0 -> 1341 bytes
-rw-r--r--tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestCert.pem30
-rw-r--r--tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestKey.pem52
-rw-r--r--tests/UsageReportingTest/Android.bp9
-rw-r--r--tests/UsageReportingTest/AndroidManifest.xml11
-rw-r--r--tests/UsageReportingTest/OWNERS1
-rw-r--r--tests/UsageStatsPerfTests/Android.bp9
-rw-r--r--tests/UsageStatsPerfTests/OWNERS1
-rw-r--r--tests/UsageStatsTest/Android.bp9
-rw-r--r--tests/UsageStatsTest/AndroidManifest.xml19
-rw-r--r--tests/UsageStatsTest/OWNERS1
-rw-r--r--tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java4
-rw-r--r--tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.bp9
-rw-r--r--tests/UsbHostExternalManagmentTest/AoapTestDevice/AndroidManifest.xml17
-rw-r--r--tests/UsbHostExternalManagmentTest/AoapTestDevice/src/com/android/hardware/usb/aoapdevicetest/UsbAoapDeviceTestActivity.java2
-rw-r--r--tests/UsbHostExternalManagmentTest/AoapTestHost/Android.bp9
-rw-r--r--tests/UsbHostExternalManagmentTest/AoapTestHost/AndroidManifest.xml17
-rw-r--r--tests/UsbHostExternalManagmentTest/OWNERS1
-rw-r--r--tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.bp9
-rw-r--r--tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/AndroidManifest.xml16
-rw-r--r--tests/UsbManagerTests/Android.bp9
-rw-r--r--tests/UsbManagerTests/OWNERS1
-rw-r--r--tests/UsbManagerTests/lib/Android.bp9
-rw-r--r--tests/UsbTests/Android.bp9
-rw-r--r--tests/UsbTests/OWNERS1
-rw-r--r--tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java18
-rw-r--r--tests/UsbTests/src/com/android/server/usb/UsbManagerNoPermTest.java37
-rw-r--r--tests/UsesFeature2Test/Android.bp9
-rw-r--r--tests/UsesFeature2Test/AndroidManifest.xml4
-rw-r--r--tests/VectorDrawableTest/Android.bp9
-rw-r--r--tests/VectorDrawableTest/AndroidManifest.xml163
-rw-r--r--tests/VoiceEnrollment/Android.bp9
-rw-r--r--tests/VoiceEnrollment/AndroidManifest.xml26
-rw-r--r--tests/VoiceInteraction/Android.bp9
-rw-r--r--tests/VoiceInteraction/AndroidManifest.xml94
-rw-r--r--tests/VoiceInteraction/OWNERS1
-rw-r--r--tests/WallpaperTest/Android.bp9
-rw-r--r--tests/WallpaperTest/AndroidManifest.xml34
-rw-r--r--tests/WindowAnimationJank/Android.bp9
-rw-r--r--tests/WindowAnimationJank/AndroidManifest.xml17
-rw-r--r--tests/WindowAnimationJank/OWNERS1
-rw-r--r--tests/WindowInsetsTests/Android.bp10
-rw-r--r--tests/WindowInsetsTests/AndroidManifest.xml17
-rw-r--r--tests/WindowInsetsTests/OWNERS1
-rw-r--r--tests/WindowInsetsTests/res/layout/chat_activity.xml (renamed from tests/WindowInsetsTests/res/layout/window_inset_activity.xml)0
-rw-r--r--tests/WindowInsetsTests/res/layout/controller_activity.xml106
-rw-r--r--tests/WindowInsetsTests/res/layout/main_activity.xml (renamed from tests/ActivityViewTest/res/layout/activity_view_main_activity.xml)23
-rw-r--r--tests/WindowInsetsTests/res/values/strings.xml11
-rw-r--r--tests/WindowInsetsTests/res/values/styles.xml8
-rw-r--r--tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ChatActivity.java (renamed from tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java)9
-rw-r--r--tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java204
-rw-r--r--tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsTestsMainActivity.java36
-rw-r--r--tests/appwidgets/AppWidgetHostTest/Android.bp9
-rw-r--r--tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml39
-rw-r--r--tests/appwidgets/AppWidgetProviderTest/Android.bp9
-rw-r--r--tests/appwidgets/AppWidgetProviderTest/AndroidManifest.xml14
-rw-r--r--tests/backup/Android.mk6
-rw-r--r--tests/backup/AndroidManifest.xml14
-rw-r--r--tests/backup/OWNERS1
-rw-r--r--tests/benchmarks/Android.bp9
-rw-r--r--tests/benchmarks/internal/Android.bp (renamed from tests/net/deflake/Android.bp)30
-rw-r--r--tests/benchmarks/internal/AndroidManifest.xml28
-rw-r--r--tests/benchmarks/internal/AndroidTest.xml28
-rw-r--r--tests/benchmarks/internal/src/com/android/internal/LambdaPerfTest.java454
-rw-r--r--tests/benchmarks/src/com/android/server/net/OWNERS1
-rw-r--r--tests/libs-permissions/Android.bp9
-rw-r--r--tests/net/Android.bp71
-rw-r--r--tests/net/AndroidManifest.xml61
-rw-r--r--tests/net/OWNERS8
-rw-r--r--tests/net/TEST_MAPPING12
-rw-r--r--tests/net/common/java/android/net/CaptivePortalDataTest.kt117
-rw-r--r--tests/net/common/java/android/net/CaptivePortalTest.java109
-rw-r--r--tests/net/common/java/android/net/DependenciesTest.java113
-rw-r--r--tests/net/common/java/android/net/DhcpInfoTest.java112
-rw-r--r--tests/net/common/java/android/net/IpPrefixTest.java365
-rw-r--r--tests/net/common/java/android/net/KeepalivePacketDataTest.kt120
-rw-r--r--tests/net/common/java/android/net/LinkAddressTest.java503
-rw-r--r--tests/net/common/java/android/net/LinkPropertiesTest.java1303
-rw-r--r--tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt50
-rw-r--r--tests/net/common/java/android/net/NattKeepalivePacketDataTest.kt114
-rw-r--r--tests/net/common/java/android/net/NetworkAgentConfigTest.kt72
-rw-r--r--tests/net/common/java/android/net/NetworkCapabilitiesTest.java935
-rw-r--r--tests/net/common/java/android/net/NetworkProviderTest.kt187
-rw-r--r--tests/net/common/java/android/net/NetworkSpecifierTest.kt67
-rw-r--r--tests/net/common/java/android/net/NetworkStackTest.java92
-rw-r--r--tests/net/common/java/android/net/NetworkTest.java160
-rw-r--r--tests/net/common/java/android/net/RouteInfoTest.java434
-rw-r--r--tests/net/common/java/android/net/StaticIpConfigurationTest.java269
-rw-r--r--tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java99
-rw-r--r--tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt72
-rw-r--r--tests/net/common/java/android/net/metrics/ApfStatsTest.kt57
-rw-r--r--tests/net/common/java/android/net/metrics/DhcpClientEventTest.kt43
-rw-r--r--tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt65
-rw-r--r--tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java161
-rw-r--r--tests/net/common/java/android/net/metrics/IpManagerEventTest.kt39
-rw-r--r--tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt38
-rw-r--r--tests/net/common/java/android/net/metrics/NetworkEventTest.kt43
-rw-r--r--tests/net/common/java/android/net/metrics/RaEventTest.kt72
-rw-r--r--tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt72
-rw-r--r--tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt209
-rw-r--r--tests/net/common/java/android/net/util/SocketUtilsTest.kt90
-rw-r--r--tests/net/deflake/src/com/android/server/net/FrameworksNetDeflakeTest.kt28
-rw-r--r--tests/net/integration/Android.bp65
-rw-r--r--tests/net/integration/AndroidManifest.xml65
-rw-r--r--tests/net/integration/res/values/config.xml15
-rw-r--r--tests/net/integration/src/android/net/TestNetworkStackClient.kt80
-rw-r--r--tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt208
-rw-r--r--tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl19
-rw-r--r--tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt44
-rw-r--r--tests/net/integration/src/com/android/server/net/integrationtests/INetworkStackInstrumentation.aidl25
-rw-r--r--tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt81
-rw-r--r--tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt96
-rw-r--r--tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt41
-rw-r--r--tests/net/integration/util/com/android/server/NetworkAgentWrapper.java270
-rw-r--r--tests/net/integration/util/com/android/server/TestNetIdManager.kt39
-rw-r--r--tests/net/java/android/app/usage/NetworkStatsManagerTest.java212
-rw-r--r--tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java384
-rw-r--r--tests/net/java/android/net/ConnectivityManagerTest.java372
-rw-r--r--tests/net/java/android/net/Ikev2VpnProfileTest.java437
-rw-r--r--tests/net/java/android/net/IpMemoryStoreTest.java332
-rw-r--r--tests/net/java/android/net/IpSecAlgorithmTest.java130
-rw-r--r--tests/net/java/android/net/IpSecConfigTest.java103
-rw-r--r--tests/net/java/android/net/IpSecManagerTest.java305
-rw-r--r--tests/net/java/android/net/IpSecTransformTest.java62
-rw-r--r--tests/net/java/android/net/MacAddressTest.java312
-rw-r--r--tests/net/java/android/net/NetworkStatsHistoryTest.java599
-rw-r--r--tests/net/java/android/net/NetworkStatsTest.java1023
-rw-r--r--tests/net/java/android/net/NetworkTemplateTest.kt158
-rw-r--r--tests/net/java/android/net/NetworkUtilsTest.java188
-rw-r--r--tests/net/java/android/net/TcpKeepalivePacketDataTest.java151
-rw-r--r--tests/net/java/android/net/TelephonyNetworkSpecifierTest.java113
-rw-r--r--tests/net/java/android/net/UidRangeTest.java67
-rw-r--r--tests/net/java/android/net/VpnManagerTest.java120
-rw-r--r--tests/net/java/android/net/ipmemorystore/ParcelableTests.java124
-rw-r--r--tests/net/java/android/net/nsd/NsdManagerTest.java388
-rw-r--r--tests/net/java/android/net/nsd/NsdServiceInfoTest.java188
-rw-r--r--tests/net/java/android/net/util/DnsUtilsTest.java216
-rw-r--r--tests/net/java/android/net/util/IpUtilsTest.java166
-rw-r--r--tests/net/java/android/net/util/KeepaliveUtilsTest.kt129
-rw-r--r--tests/net/java/com/android/internal/net/VpnProfileTest.java218
-rw-r--r--tests/net/java/com/android/internal/util/BitUtilsTest.java201
-rw-r--r--tests/net/java/com/android/internal/util/RingBufferTest.java178
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java7751
-rw-r--r--tests/net/java/com/android/server/IpSecServiceParameterizedTest.java838
-rw-r--r--tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java360
-rw-r--r--tests/net/java/com/android/server/IpSecServiceTest.java671
-rw-r--r--tests/net/java/com/android/server/LegacyTypeTrackerTest.kt135
-rw-r--r--tests/net/java/com/android/server/NetIdManagerTest.kt53
-rw-r--r--tests/net/java/com/android/server/NetworkManagementServiceTest.java195
-rw-r--r--tests/net/java/com/android/server/NsdServiceTest.java194
-rw-r--r--tests/net/java/com/android/server/connectivity/DnsManagerTest.java430
-rw-r--r--tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java561
-rw-r--r--tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java618
-rw-r--r--tests/net/java/com/android/server/connectivity/LingerMonitorTest.java381
-rw-r--r--tests/net/java/com/android/server/connectivity/MetricsTestUtil.java81
-rw-r--r--tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java374
-rw-r--r--tests/net/java/com/android/server/connectivity/Nat464XlatTest.java506
-rw-r--r--tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java544
-rw-r--r--tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java269
-rw-r--r--tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt84
-rw-r--r--tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java758
-rw-r--r--tests/net/java/com/android/server/connectivity/VpnTest.java1368
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsAccessTest.java192
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsBaseTest.java122
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java591
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java569
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsObserversTest.java446
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsServiceTest.java1425
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java327
-rw-r--r--tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java67
-rw-r--r--tests/net/jni/Android.bp23
-rw-r--r--tests/net/jni/test_onload.cpp44
-rw-r--r--tests/net/res/raw/history_v1bin144 -> 0 bytes
-rw-r--r--tests/net/res/raw/net_dev_typical8
-rw-r--r--tests/net/res/raw/netstats_uid_v4bin156516 -> 0 bytes
-rw-r--r--tests/net/res/raw/netstats_v1bin18742 -> 0 bytes
-rw-r--r--tests/net/res/raw/xt_qtaguid_iface_fmt_typical4
-rw-r--r--tests/net/res/raw/xt_qtaguid_iface_typical6
-rw-r--r--tests/net/res/raw/xt_qtaguid_typical71
-rw-r--r--tests/net/res/raw/xt_qtaguid_vpn_incorrect_iface3
-rw-r--r--tests/net/res/raw/xt_qtaguid_vpn_one_underlying5
-rw-r--r--tests/net/res/raw/xt_qtaguid_vpn_one_underlying_compression4
-rw-r--r--tests/net/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic6
-rw-r--r--tests/net/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn9
-rw-r--r--tests/net/res/raw/xt_qtaguid_vpn_rewrite_through_self6
-rw-r--r--tests/net/res/raw/xt_qtaguid_vpn_two_underlying_duplication5
-rw-r--r--tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split4
-rw-r--r--tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split_compression4
-rw-r--r--tests/net/res/raw/xt_qtaguid_vpn_with_clat8
-rw-r--r--tests/net/res/raw/xt_qtaguid_with_clat43
-rw-r--r--tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after189
-rw-r--r--tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before187
-rw-r--r--tests/net/res/raw/xt_qtaguid_with_clat_simple4
-rw-r--r--tests/net/smoketest/Android.bp22
-rw-r--r--tests/net/smoketest/java/SmokeTest.java33
-rw-r--r--tests/notification/Android.bp9
-rw-r--r--tests/notification/OWNERS1
-rw-r--r--tests/permission/Android.bp18
-rw-r--r--tests/permission/AndroidManifest.xml5
-rw-r--r--tests/permission/OWNERS1
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java150
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java80
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java49
-rw-r--r--tests/privapp-permissions/Android.bp9
-rw-r--r--tests/testables/Android.bp9
-rw-r--r--tests/testables/tests/Android.bp9
-rw-r--r--tests/utils/DummyIME/OWNERS1
-rw-r--r--tests/utils/StubIME/Android.bp (renamed from tests/utils/DummyIME/Android.bp)11
-rw-r--r--tests/utils/StubIME/AndroidManifest.xml (renamed from tests/utils/DummyIME/AndroidManifest.xml)15
-rw-r--r--tests/utils/StubIME/OWNERS1
-rw-r--r--tests/utils/StubIME/res/xml/method.xml (renamed from tests/utils/DummyIME/res/xml/method.xml)4
-rw-r--r--tests/utils/StubIME/src/com/android/testing/stubime/ImePreferences.java (renamed from tests/utils/DummyIME/src/com/android/testing/dummyime/ImePreferences.java)4
-rw-r--r--tests/utils/StubIME/src/com/android/testing/stubime/StubIme.java (renamed from tests/utils/DummyIME/src/com/android/testing/dummyime/DummyIme.java)6
-rw-r--r--tests/utils/hostutils/Android.bp9
-rw-r--r--tests/utils/hostutils/src/com/android/fsverity/AddFsVerityCertRule.java77
-rw-r--r--tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java94
-rw-r--r--tests/utils/hostutils/src/com/android/tests/rollback/OWNERS1
-rw-r--r--tests/utils/hostutils/src/com/android/tests/rollback/host/AbandonSessionsRule.java8
-rw-r--r--tests/utils/testutils/Android.bp9
-rw-r--r--tests/utils/testutils/java/android/view/test/InsetsModeSession.java37
-rw-r--r--tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java50
-rw-r--r--tests/utils/testutils/java/com/android/internal/util/test/FsUtil.java40
-rw-r--r--tests/utils/testutils/java/com/android/server/accessibility/OWNERS1
-rw-r--r--tests/utils/testutils/java/com/android/server/wm/OWNERS1
-rw-r--r--tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java17
-rw-r--r--tests/vcn/Android.bp37
-rw-r--r--tests/vcn/AndroidManifest.xml (renamed from tests/net/smoketest/AndroidManifest.xml)9
-rw-r--r--tests/vcn/AndroidTest.xml (renamed from tests/net/AndroidTest.xml)10
-rw-r--r--tests/vcn/OWNERS7
-rw-r--r--tests/vcn/TEST_MAPPING7
-rw-r--r--tests/vcn/assets/client-end-cert.pem21
-rw-r--r--tests/vcn/assets/client-private-key.key28
-rw-r--r--tests/vcn/assets/self-signed-ca.pem20
-rw-r--r--tests/vcn/java/android/net/vcn/VcnConfigTest.java118
-rw-r--r--tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java252
-rw-r--r--tests/vcn/java/android/net/vcn/VcnManagerTest.java218
-rw-r--r--tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java129
-rw-r--r--tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java51
-rw-r--r--tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java61
-rw-r--r--tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java113
-rw-r--r--tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java87
-rw-r--r--tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java193
-rw-r--r--tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java66
-rw-r--r--tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java82
-rw-r--r--tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java53
-rw-r--r--tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java118
-rw-r--r--tests/vcn/java/com/android/server/VcnManagementServiceTest.java1349
-rw-r--r--tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java428
-rw-r--r--tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java491
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java597
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java146
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java126
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java106
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java153
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java217
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java324
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java148
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnTest.java461
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnTestUtils.java44
-rw-r--r--tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java92
-rw-r--r--tests/vcn/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java214
693 files changed, 26368 insertions, 41946 deletions
diff --git a/tests/AccessibilityEventsLogger/Android.bp b/tests/AccessibilityEventsLogger/Android.bp
index ead165602254..c403f9bf961e 100644
--- a/tests/AccessibilityEventsLogger/Android.bp
+++ b/tests/AccessibilityEventsLogger/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "AccessibilityEventsLogger",
srcs: ["**/*.java"],
diff --git a/tests/AccessibilityEventsLogger/AndroidManifest.xml b/tests/AccessibilityEventsLogger/AndroidManifest.xml
index d86769f570c5..a5713679786f 100644
--- a/tests/AccessibilityEventsLogger/AndroidManifest.xml
+++ b/tests/AccessibilityEventsLogger/AndroidManifest.xml
@@ -16,25 +16,23 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- package="com.android.tests.accessibilityeventlogger"
- android:versionCode="1"
- android:versionName="0.0" >
-
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="18" />
-
- <application
- android:allowBackup="true"
- android:enabled="true"
- android:label="@string/app_name" >
-
- <service
- android:name=".AELogger"
- android:enabled="true"
- android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
- android:configChanges="locale" >
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.tests.accessibilityeventlogger"
+ android:versionCode="1"
+ android:versionName="0.0">
+
+ <uses-sdk android:minSdkVersion="18"
+ android:targetSdkVersion="18"/>
+
+ <application android:allowBackup="true"
+ android:enabled="true"
+ android:label="@string/app_name">
+
+ <service android:name=".AELogger"
+ android:enabled="true"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+ android:configChanges="locale"
+ android:exported="true">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
@@ -43,9 +41,8 @@
<category android:name="android.accessibilityservice.category.FEEDBACK_AUDIBLE"/>
</intent-filter>
- <meta-data
- android:name="android.accessibilityservice"
- android:resource="@xml/accessibilityservice" />
+ <meta-data android:name="android.accessibilityservice"
+ android:resource="@xml/accessibilityservice"/>
</service>
</application>
</manifest>
diff --git a/tests/AccessoryDisplay/common/Android.bp b/tests/AccessoryDisplay/common/Android.bp
index 3ce4c5718d13..fd3af1ecf1c9 100644
--- a/tests/AccessoryDisplay/common/Android.bp
+++ b/tests/AccessoryDisplay/common/Android.bp
@@ -13,6 +13,15 @@
// limitations under the License.
// Build the application.
+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"],
+}
+
java_library_static {
name: "AccessoryDisplayCommon",
sdk_version: "current",
diff --git a/tests/AccessoryDisplay/sink/Android.bp b/tests/AccessoryDisplay/sink/Android.bp
index 4e50a81d8c24..d825c60b437f 100644
--- a/tests/AccessoryDisplay/sink/Android.bp
+++ b/tests/AccessoryDisplay/sink/Android.bp
@@ -13,6 +13,15 @@
// limitations under the License.
// Build the application.
+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"],
+}
+
android_test {
name: "AccessoryDisplaySink",
sdk_version: "current",
diff --git a/tests/AccessoryDisplay/sink/AndroidManifest.xml b/tests/AccessoryDisplay/sink/AndroidManifest.xml
index 72d498f2d855..2aee9693ff17 100644
--- a/tests/AccessoryDisplay/sink/AndroidManifest.xml
+++ b/tests/AccessoryDisplay/sink/AndroidManifest.xml
@@ -15,26 +15,27 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.accessorydisplay.sink" >
+ package="com.android.accessorydisplay.sink">
<uses-feature android:name="android.hardware.usb.host"/>
- <uses-sdk android:minSdkVersion="18" />
+ <uses-sdk android:minSdkVersion="18"/>
<application android:label="@string/app_name"
- android:icon="@drawable/ic_app"
- android:hardwareAccelerated="true">
+ android:icon="@drawable/ic_app"
+ android:hardwareAccelerated="true">
<activity android:name=".SinkActivity"
- android:label="@string/app_name"
- android:theme="@android:style/Theme.Holo">
+ android:label="@string/app_name"
+ android:theme="@android:style/Theme.Holo"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
- android:resource="@xml/usb_device_filter"/>
+ android:resource="@xml/usb_device_filter"/>
</activity>
</application>
diff --git a/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/SinkActivity.java b/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/SinkActivity.java
index fc1d47bcd20f..65b4bd090c82 100644
--- a/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/SinkActivity.java
+++ b/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/SinkActivity.java
@@ -167,7 +167,7 @@ public class SinkActivity extends Activity {
Intent intent = new Intent(ACTION_USB_DEVICE_PERMISSION);
intent.setPackage(getPackageName());
PendingIntent pendingIntent = PendingIntent.getBroadcast(
- this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
+ this, 0, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE);
mUsbManager.requestPermission(device, pendingIntent);
return;
}
diff --git a/tests/AccessoryDisplay/source/Android.bp b/tests/AccessoryDisplay/source/Android.bp
index 6d8087f5e7dd..6ed752ee2c8f 100644
--- a/tests/AccessoryDisplay/source/Android.bp
+++ b/tests/AccessoryDisplay/source/Android.bp
@@ -13,6 +13,15 @@
// limitations under the License.
// Build the application.
+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"],
+}
+
android_test {
name: "AccessoryDisplaySource",
sdk_version: "current",
diff --git a/tests/AccessoryDisplay/source/AndroidManifest.xml b/tests/AccessoryDisplay/source/AndroidManifest.xml
index d3edcb838877..4611e1de466c 100644
--- a/tests/AccessoryDisplay/source/AndroidManifest.xml
+++ b/tests/AccessoryDisplay/source/AndroidManifest.xml
@@ -15,26 +15,27 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.accessorydisplay.source" >
+ package="com.android.accessorydisplay.source">
<uses-feature android:name="android.hardware.usb.accessory"/>
- <uses-sdk android:minSdkVersion="18" />
+ <uses-sdk android:minSdkVersion="18"/>
<application android:label="@string/app_name"
- android:icon="@drawable/ic_app"
- android:hardwareAccelerated="true">
+ android:icon="@drawable/ic_app"
+ android:hardwareAccelerated="true">
<activity android:name=".SourceActivity"
- android:label="@string/app_name"
- android:theme="@android:style/Theme.Holo">
+ android:label="@string/app_name"
+ android:theme="@android:style/Theme.Holo"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"/>
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
- android:resource="@xml/usb_accessory_filter"/>
+ android:resource="@xml/usb_accessory_filter"/>
</activity>
</application>
diff --git a/tests/ActivityManagerPerfTests/OWNERS b/tests/ActivityManagerPerfTests/OWNERS
new file mode 100644
index 000000000000..72c0a9e6e90c
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/am/OWNERS
diff --git a/tests/ActivityManagerPerfTests/stub-app/Android.bp b/tests/ActivityManagerPerfTests/stub-app/Android.bp
index a3c1f5b2f17d..19225e4c879e 100644
--- a/tests/ActivityManagerPerfTests/stub-app/Android.bp
+++ b/tests/ActivityManagerPerfTests/stub-app/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test_helper_app {
name: "ActivityManagerPerfTestsStubApp1",
static_libs: ["ActivityManagerPerfTestsUtils"],
@@ -65,4 +74,3 @@ android_test_helper_app {
"--auto-add-overlay",
],
}
-
diff --git a/tests/ActivityManagerPerfTests/stub-app/AndroidManifest.xml b/tests/ActivityManagerPerfTests/stub-app/AndroidManifest.xml
index a57f64c320c8..6bdeea06053f 100644
--- a/tests/ActivityManagerPerfTests/stub-app/AndroidManifest.xml
+++ b/tests/ActivityManagerPerfTests/stub-app/AndroidManifest.xml
@@ -16,39 +16,34 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.stubs.am">
+ package="com.android.stubs.am">
<uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
- <application android:label="Android TestCase" >
- <provider
- android:authorities="@string/authority"
- android:name=".TestContentProvider"
- android:exported="true" />
- <receiver
- android:name=".TestBroadcastReceiver"
- android:exported="true">
+ <application android:label="Android TestCase">
+ <provider android:authorities="@string/authority"
+ android:name=".TestContentProvider"
+ android:exported="true"/>
+ <receiver android:name=".TestBroadcastReceiver"
+ android:exported="true">
<intent-filter>
- <action android:name="com.android.stubs.am.ACTION_BROADCAST_TEST" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="com.android.stubs.am.ACTION_BROADCAST_TEST"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
- <service
- android:name=".InitService"
- android:exported="true" />
- <service
- android:name=".TestService"
- android:exported="true" />
- <activity
- android:name=".TestActivity"
- android:excludeFromRecents="true"
- android:turnScreenOn="true"
- android:launchMode="singleTask">
+ <service android:name=".InitService"
+ android:exported="true"/>
+ <service android:name=".TestService"
+ android:exported="true"/>
+ <activity android:name=".TestActivity"
+ android:excludeFromRecents="true"
+ android:turnScreenOn="true"
+ android:launchMode="singleTask"
+ android:exported="true">
<intent-filter>
- <action android:name="com.android.stubs.am.ACTION_START_TEST_ACTIVITY" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="com.android.stubs.am.ACTION_START_TEST_ACTIVITY"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
</manifest>
-
diff --git a/tests/ActivityManagerPerfTests/test-app/Android.bp b/tests/ActivityManagerPerfTests/test-app/Android.bp
index ef9d587581c4..5fd1d5a0ae69 100644
--- a/tests/ActivityManagerPerfTests/test-app/Android.bp
+++ b/tests/ActivityManagerPerfTests/test-app/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "ActivityManagerPerfTestsTestApp",
srcs: ["src/**/*.java"],
diff --git a/tests/ActivityManagerPerfTests/tests/Android.bp b/tests/ActivityManagerPerfTests/tests/Android.bp
index 2ae2cc49bb7a..e5813aec9f43 100644
--- a/tests/ActivityManagerPerfTests/tests/Android.bp
+++ b/tests/ActivityManagerPerfTests/tests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "ActivityManagerPerfTests",
srcs: ["src/**/*.java"],
@@ -19,6 +28,7 @@ android_test {
"androidx.test.rules",
"apct-perftests-utils",
"ActivityManagerPerfTestsUtils",
+ "collector-device-lib-platform",
],
platform_apis: true,
min_sdk_version: "25",
diff --git a/tests/ActivityManagerPerfTests/tests/AndroidTest.xml b/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
index 475bb82a9856..e753b704a3ae 100644
--- a/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
+++ b/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
@@ -28,5 +28,22 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.frameworks.perftests.amtests"/>
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
+
+ <!-- TODO: Add PerfettoListener to automatically capture perfetto traces for each test-->
+ <!-- Listener related args for collecting the traces and waiting for the device
+ to stabilize. -->
+ <option name="device-listeners"
+ value="android.device.collectors.ProcLoadListener" />
+ <!-- Guarantee that user defined RunListeners will be running before any of the default
+ listeners defined in this runner. -->
+ <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+ <!-- ProcLoadListener related arguments -->
+ <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before
+ starting the test run -->
+ <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+ <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+ <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+ <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
</test>
</configuration>
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/OomAdjPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/OomAdjPerfTest.java
index 1d3ff06e6bf1..5d6a4a3541c1 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/OomAdjPerfTest.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/OomAdjPerfTest.java
@@ -22,13 +22,13 @@ import android.content.Context;
import android.net.Uri;
import android.os.HandlerThread;
import android.perftests.utils.ManualBenchmarkState;
-import android.perftests.utils.PerfManualStatusReporter;
import android.perftests.utils.TraceMarkParser;
import android.perftests.utils.TraceMarkParser.TraceMarkLine;
import android.perftests.utils.TraceMarkParser.TraceMarkSlice;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.perftests.am.util.AtraceUtils;
import com.android.frameworks.perftests.am.util.TargetPackageUtils;
@@ -36,10 +36,8 @@ import com.android.frameworks.perftests.am.util.Utils;
import org.junit.After;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import java.util.ArrayList;
import java.util.List;
@@ -53,9 +51,9 @@ import java.util.List;
* into the stats; when there are enough samples in the stats, the test will
* stop and output the mean/stddev time spent on the updateOomAdjLocked.
*/
-@RunWith(JUnit4.class)
+@RunWith(AndroidJUnit4.class)
@LargeTest
-public final class OomAdjPerfTest {
+public final class OomAdjPerfTest extends BasePerfTest {
private static final String TAG = "OomAdjPerfTest";
private static final boolean VERBOSE = true;
@@ -74,8 +72,6 @@ public final class OomAdjPerfTest {
private static final String ATRACE_CATEGORY = "am";
private static final String ATRACE_OOMADJ_PREFIX = "updateOomAdj_";
- @Rule
- public PerfManualStatusReporter mPerfManualStatusReporter = new PerfManualStatusReporter();
private TraceMarkParser mTraceMarkParser = new TraceMarkParser(this::shouldFilterTraceLine);
private final ArrayList<Long> mDurations = new ArrayList<Long>();
private Context mContext;
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java
index ba2064005937..e1b508b424f5 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java
@@ -25,14 +25,30 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.perftests.am.util.Constants;
import com.android.frameworks.perftests.am.util.TargetPackageUtils;
+import com.android.frameworks.perftests.am.util.Utils;
+import org.junit.After;
import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ServiceStartPerfTest extends BasePerfTest {
+ private static final String STUB_PACKAGE_NAME =
+ "com.android.frameworks.perftests.amteststestapp";
+
+ @Before
+ public void setUp() {
+ super.setUp();
+ Utils.runShellCommand("cmd deviceidle whitelist +" + STUB_PACKAGE_NAME);
+ }
+
+ @After
+ public void tearDown() {
+ Utils.runShellCommand("cmd deviceidle whitelist -" + STUB_PACKAGE_NAME);
+ }
/**
* Tries to start the service with the given intent, throwing a RuntimeException with the
diff --git a/tests/ActivityManagerPerfTests/utils/Android.bp b/tests/ActivityManagerPerfTests/utils/Android.bp
index 766c3acf3c09..99c43c8d8fca 100644
--- a/tests/ActivityManagerPerfTests/utils/Android.bp
+++ b/tests/ActivityManagerPerfTests/utils/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
java_test {
name: "ActivityManagerPerfTestsUtils",
sdk_version: "current",
diff --git a/tests/ActivityTests/Android.bp b/tests/ActivityTests/Android.bp
index 01828624fa4a..be6096fb31cf 100644
--- a/tests/ActivityTests/Android.bp
+++ b/tests/ActivityTests/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "ActivityTest",
srcs: ["**/*.java"],
diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml
index 0b3bd70ba5c9..88a5e64a92bd 100644
--- a/tests/ActivityTests/AndroidManifest.xml
+++ b/tests/ActivityTests/AndroidManifest.xml
@@ -15,85 +15,98 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.activity">
- <uses-permission android:name="android.permission.REAL_GET_TASKS" />
- <uses-permission android:name="android.permission.REORDER_TASKS" />
- <uses-permission android:name="android.permission.REMOVE_TASKS" />
- <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
- <uses-permission android:name="android.permission.MANAGE_USERS" />
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
- <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
- <uses-sdk android:targetSdkVersion="22" />
+ package="com.google.android.test.activity">
+ <uses-permission android:name="android.permission.REAL_GET_TASKS"/>
+ <uses-permission android:name="android.permission.REORDER_TASKS"/>
+ <uses-permission android:name="android.permission.REMOVE_TASKS"/>
+ <uses-permission android:name="android.permission.READ_FRAME_BUFFER"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+ <uses-permission android:name="android.permission.MANAGE_USERS"/>
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
+ <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
+ <uses-sdk android:targetSdkVersion="22"/>
<application android:label="ActivityTest">
- <activity android:name="ActivityTestMain">
+ <activity android:name="ActivityTestMain"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="http" android:host="www.angryredplanet.com"
- android:pathPrefix="" />
+ <action android:name="android.intent.action.VIEW"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <data android:scheme="http"
+ android:host="www.angryredplanet.com"
+ android:pathPrefix=""/>
</intent-filter>
<preferred>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="http" android:host="www.angryredplanet.com"
- android:pathPrefix="" />
+ <action android:name="android.intent.action.VIEW"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <data android:scheme="http"
+ android:host="www.angryredplanet.com"
+ android:pathPrefix=""/>
</preferred>
</activity>
- <activity android:name="SpamActivity" android:label="Spam!"
- android:documentLaunchMode="always">
+ <activity android:name="SpamActivity"
+ android:label="Spam!"
+ android:documentLaunchMode="always">
</activity>
- <activity android:name="DocActivity" android:label="Some doc">
+ <activity android:name="DocActivity"
+ android:label="Some doc">
</activity>
<service android:name="SingleUserService"
- android:singleUser="true" android:exported="true">
+ android:singleUser="true"
+ android:exported="true">
</service>
<service android:name="ServiceUserTarget">
</service>
<receiver android:name="UserTarget">
</receiver>
- <service android:name="IsolatedService" android:isolatedProcess="true">
+ <service android:name="IsolatedService"
+ android:isolatedProcess="true">
</service>
- <receiver android:name="StartEmpty" android:exported="true">
+ <receiver android:name="StartEmpty"
+ android:exported="true">
<intent-filter>
- <action android:name="com.example.START_EMPTY" />
+ <action android:name="com.example.START_EMPTY"/>
</intent-filter>
</receiver>
- <service android:name="EmptyService" android:exported="true">
+ <service android:name="EmptyService"
+ android:exported="true">
<intent-filter>
- <action android:name="com.example.START_EMPTY" />
+ <action android:name="com.example.START_EMPTY"/>
</intent-filter>
</service>
<receiver android:name="SingleUserReceiver"
- android:singleUser="true" android:exported="true" >
+ android:singleUser="true"
+ android:exported="true">
</receiver>
<provider android:name="SingleUserProvider"
- android:authorities="com.google.android.test.activity.single_user"
- android:singleUser="true" android:exported="true" />
- <receiver android:name="TrackTimeReceiver" />
- <receiver android:name="AlarmSpamReceiver" />
- <receiver android:name="SlowReceiver" />
+ android:authorities="com.google.android.test.activity.single_user"
+ android:singleUser="true"
+ android:exported="true"/>
+ <receiver android:name="TrackTimeReceiver"/>
+ <receiver android:name="AlarmSpamReceiver"/>
+ <receiver android:name="SlowReceiver"/>
<activity android:name="DisableScreenshotsActivity"
- android:label="DisableScreenshots"
- android:theme="@style/DisableScreenshots">
+ android:label="DisableScreenshots"
+ android:theme="@style/DisableScreenshots"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="CustomSplashscreenActivity"
- android:label="CustomSplashscreen"
- android:theme="@style/CustomSplashscreen">
+ android:label="CustomSplashscreen"
+ android:theme="@style/CustomSplashscreen"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index 768cfaea4898..a8e47b5e6def 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -100,7 +100,7 @@ public class ActivityTestMain extends Activity {
Intent intent = new Intent(ActivityTestMain.this, AlarmSpamReceiver.class);
intent.setAction("com.example.SPAM_ALARM=" + when);
PendingIntent pi = PendingIntent.getBroadcast(ActivityTestMain.this,
- 0, intent, 0);
+ 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
mAlarm.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME, when+(30*1000), pi);
scheduleSpamAlarm(30*1000);
} break;
@@ -134,7 +134,7 @@ public class ActivityTestMain extends Activity {
// Also send a broadcast alarm to evaluate the alarm fast-forward policy
intent.putExtra(SLOW_RECEIVER_EXTRA, 4);
- PendingIntent pi = PendingIntent.getBroadcast(ActivityTestMain.this, 1, intent, 0);
+ PendingIntent pi = PendingIntent.getBroadcast(ActivityTestMain.this, 1, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
long now = SystemClock.elapsedRealtime();
Log.i(TAG, "Setting alarm for now + 5 seconds");
@@ -493,7 +493,7 @@ public class ActivityTestMain extends Activity {
Intent receiveIntent = new Intent(ActivityTestMain.this, TrackTimeReceiver.class);
receiveIntent.putExtra("something", "yeah, this is us!");
options.requestUsageTimeReport(PendingIntent.getBroadcast(ActivityTestMain.this,
- 0, receiveIntent, PendingIntent.FLAG_CANCEL_CURRENT));
+ 0, receiveIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED));
startActivity(Intent.createChooser(intent, "Who do you love?"), options.toBundle());
return true;
}
diff --git a/tests/ActivityViewTest/Android.bp b/tests/ActivityViewTest/Android.bp
deleted file mode 100644
index e7b8c8e1d058..000000000000
--- a/tests/ActivityViewTest/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-android_test {
- name: "ActivityViewTest",
- srcs: ["src/**/*.java"],
- platform_apis: true,
- certificate: "platform",
-}
diff --git a/tests/ActivityViewTest/AndroidManifest.xml b/tests/ActivityViewTest/AndroidManifest.xml
deleted file mode 100644
index 17eb029166f0..000000000000
--- a/tests/ActivityViewTest/AndroidManifest.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.activityview">
- <uses-permission android:name="android.permission.INJECT_EVENTS"/>
- <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"/>
- <uses-permission android:name="android.permission.ACTIVITY_EMBEDDING"/>
- <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
-
- <uses-sdk android:targetSdkVersion="27"/>
- <application android:label="ActivityViewTest">
- <activity android:name=".ActivityViewMainActivity"
- android:label="AV Main"
- android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- <category android:name="android.intent.category.DEFAULT"/>
- </intent-filter>
- </activity>
-
- <activity android:name=".ActivityViewActivity"
- android:label="AV"
- android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"
- android:windowSoftInputMode="stateHidden|adjustResize">
- </activity>
-
- <activity android:name=".ActivityViewResizeActivity"
- android:label="AV Resize"
- android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"
- android:windowSoftInputMode="stateHidden|adjustResize">
- </activity>
-
- <activity android:name=".ActivityViewScrollActivity"
- android:label="AV Scroll"
- android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"
- android:windowSoftInputMode="stateHidden">
- </activity>
-
- <activity android:name=".ActivityViewTestActivity"
- android:resizeableActivity="true"
- android:theme="@*android:style/Theme.NoTitleBar"
- android:exported="true"
- android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
- </activity>
-
- <activity android:name=".ActivityViewVisibilityActivity"
- android:label="AV Visibility"
- android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
- </activity>
- </application>
-</manifest>
diff --git a/tests/ActivityViewTest/res/layout/activity_view_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_activity.xml
deleted file mode 100644
index 67c01f8c78fe..000000000000
--- a/tests/ActivityViewTest/res/layout/activity_view_activity.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#cfd8dc">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <Button
- android:id="@+id/activity_launch_button"
- android:layout_width="200dp"
- android:layout_height="wrap_content"
- android:text="Launch test activity" />
-
- <Button
- android:id="@+id/activity_pick_launch_button"
- android:layout_width="200dp"
- android:layout_height="wrap_content"
- android:text="Launch from picker" />
-
- </LinearLayout>
-
- <ActivityView
- android:id="@+id/activity_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
-</LinearLayout> \ No newline at end of file
diff --git a/tests/ActivityViewTest/res/layout/activity_view_resize_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_resize_activity.xml
deleted file mode 100644
index 18d86e3d5a6f..000000000000
--- a/tests/ActivityViewTest/res/layout/activity_view_resize_activity.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#cfd8dc">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <Button
- android:id="@+id/activity_launch_button"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:text="Launch" />
-
- <Button
- android:id="@+id/activity_resize_button"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:text="Resize" />
- </LinearLayout>
-
- <SeekBar
- android:id="@+id/activity_view_seek_bar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <ActivityView
- android:id="@+id/activity_view"
- android:layout_width="match_parent"
- android:layout_height="600dp" />
-
-</LinearLayout> \ No newline at end of file
diff --git a/tests/ActivityViewTest/res/layout/activity_view_scroll_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_scroll_activity.xml
deleted file mode 100644
index 879c2c20a082..000000000000
--- a/tests/ActivityViewTest/res/layout/activity_view_scroll_activity.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical" android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <Button
- android:id="@+id/activity_launch_button"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:text="Launch" />
-
- <ScrollView
- android:id="@+id/activity_view_host_scroll_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:color="#cfd8dc">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
-
- <View
- android:layout_width="match_parent"
- android:layout_height="300dp"
- android:layout_gravity="center_horizontal"
- android:background="#eeeeee" />
-
- <ActivityView
- android:id="@+id/activity_view"
- android:layout_width="match_parent"
- android:layout_height="300dp"
- android:background="#fce4ec" />
-
- <View
- android:layout_width="match_parent"
- android:layout_height="300dp"
- android:layout_gravity="center_horizontal"
- android:background="#eeeeee" />
- </LinearLayout>
- </ScrollView>
-</LinearLayout> \ No newline at end of file
diff --git a/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml
deleted file mode 100644
index 338d68adfafb..000000000000
--- a/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/test_activity_root"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#ffe0b2">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:orientation="vertical"
- android:background="#00000000" >
- <TextView
- android:id="@+id/test_activity_title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="@android:color/black"
- android:background="#00000000"
- android:gravity="center" />
- <TextView
- android:id="@+id/test_activity_touch_state"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="@android:color/black"
- android:background="#00000000"
- android:gravity="center" />
- </LinearLayout>
-
- <TextView
- android:id="@+id/test_activity_width_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="@android:color/black"
- android:background="#00000000"
- android:gravity="center" />
-
- <TextView
- android:id="@+id/test_activity_height_text"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true"
- android:textColor="@android:color/black"
- android:background="#00000000"
- android:gravity="center" />
-
- <EditText
- android:id="@+id/test_activity_edittext"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_margin="16dp" />
-</RelativeLayout> \ No newline at end of file
diff --git a/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml
deleted file mode 100644
index d29d4dfc0428..000000000000
--- a/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#cfd8dc">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <Button
- android:id="@+id/activity_launch_button"
- android:layout_width="200dp"
- android:layout_height="wrap_content"
- android:text="Launch test activity" />
-
- <Spinner
- android:id="@+id/visibility_spinner"
- android:layout_width="200dp"
- android:layout_height="match_parent"/>
-
- </LinearLayout>
-
- <ActivityView
- android:id="@+id/activity_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
-</LinearLayout>
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java
deleted file mode 100644
index f7c60fc73cb3..000000000000
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * Copyright (c) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.test.activityview;
-
-import android.app.Activity;
-import android.app.ActivityView;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.widget.Button;
-
-public class ActivityViewActivity extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_view_activity);
-
- final ActivityView activityView = findViewById(R.id.activity_view);
- final Button launchButton = findViewById(R.id.activity_launch_button);
- launchButton.setOnClickListener(v -> {
- final Intent intent = new Intent(this, ActivityViewTestActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- activityView.startActivity(intent);
- });
- final Button pickActivityLaunchButton = findViewById(R.id.activity_pick_launch_button);
- pickActivityLaunchButton.setOnClickListener(v -> {
- final Intent intent = Intent.makeMainActivity(null);
- final Intent chooser = Intent.createChooser(intent,
- "Pick an app to launch in ActivityView");
- chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Parcelable[] {
- new Intent(Intent.ACTION_MAIN)
- .addCategory("com.android.internal.category.PLATLOGO")
- });
- if (intent.resolveActivity(getPackageManager()) != null) {
- chooser.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- activityView.startActivity(chooser);
- }
- });
- }
-}
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java
deleted file mode 100644
index 4f09c28fe711..000000000000
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * Copyright (c) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.test.activityview;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-
-public class ActivityViewMainActivity extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_view_main_activity);
-
- findViewById(R.id.activity_view_button).setOnClickListener(
- v -> startActivity(new Intent(this, ActivityViewActivity.class)));
-
- findViewById(R.id.scroll_activity_view_button).setOnClickListener(
- v -> startActivity(new Intent(this, ActivityViewScrollActivity.class)));
-
- findViewById(R.id.resize_activity_view_button).setOnClickListener(
- v -> startActivity(new Intent(this, ActivityViewResizeActivity.class)));
-
- findViewById(R.id.visibility_activity_view_button).setOnClickListener(
- v -> startActivity(new Intent(this, ActivityViewVisibilityActivity.class)));
- }
-}
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewResizeActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewResizeActivity.java
deleted file mode 100644
index 8860a771fd5a..000000000000
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewResizeActivity.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * Copyright (c) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.test.activityview;
-
-import android.app.Activity;
-import android.app.ActivityView;
-import android.content.Intent;
-import android.os.Bundle;
-import android.widget.Button;
-import android.widget.LinearLayout;
-import android.widget.SeekBar;
-
-public class ActivityViewResizeActivity extends Activity {
- private static final int SMALL_SIZE = 600;
- private static final int LARGE_SIZE = 1200;
-
- private ActivityView mActivityView;
-
- private boolean mFlipSize;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_view_resize_activity);
-
- mActivityView = findViewById(R.id.activity_view);
-
- final Button launchButton = findViewById(R.id.activity_launch_button);
- launchButton.setOnClickListener(v -> {
- final Intent intent = new Intent(this, ActivityViewTestActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- mActivityView.startActivity(intent);
- });
- final Button resizeButton = findViewById(R.id.activity_resize_button);
- if (resizeButton != null) {
- resizeButton.setOnClickListener(v -> {
- LinearLayout.LayoutParams params =
- (LinearLayout.LayoutParams) mActivityView.getLayoutParams();
- params.height = mFlipSize ? SMALL_SIZE : LARGE_SIZE;
- mFlipSize = !mFlipSize;
- mActivityView.setLayoutParams(params);
- });
- }
- final SeekBar seekBar = findViewById(R.id.activity_view_seek_bar);
- if (seekBar != null) {
- seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- final LinearLayout.LayoutParams params =
- (LinearLayout.LayoutParams) mActivityView.getLayoutParams();
- params.height = SMALL_SIZE + progress * 10;
- mActivityView.setLayoutParams(params);
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
- });
- }
- }
-}
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewScrollActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewScrollActivity.java
deleted file mode 100644
index 56543662675c..000000000000
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewScrollActivity.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * Copyright (c) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.test.activityview;
-
-import android.app.Activity;
-import android.app.ActivityView;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.Button;
-
-public class ActivityViewScrollActivity extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_view_scroll_activity);
-
- final ActivityView activityView = findViewById(R.id.activity_view);
- final Button launchButton = findViewById(R.id.activity_launch_button);
- launchButton.setOnClickListener(v -> {
- final Intent intent = new Intent(this, ActivityViewTestActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- activityView.startActivity(intent);
- });
- findViewById(R.id.activity_view_host_scroll_view).setOnScrollChangeListener(
- (View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY)
- -> activityView.onLocationChanged());
- }
-}
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java
deleted file mode 100644
index 52aba2b13c42..000000000000
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * Copyright (c) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.test.activityview;
-
-import static android.view.MotionEvent.ACTION_CANCEL;
-import static android.view.MotionEvent.ACTION_DOWN;
-import static android.view.MotionEvent.ACTION_MOVE;
-import static android.view.MotionEvent.ACTION_UP;
-
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewTreeObserver;
-import android.widget.TextView;
-
-public class ActivityViewTestActivity extends Activity {
- private static final String TAG = "ActivityViewTestActivity";
-
- private View mRoot;
- private TextView mTextView;
- private TextView mWidthTextView;
- private TextView mHeightTextView;
- private TextView mTouchStateTextView;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_view_test_activity);
- mRoot = findViewById(R.id.test_activity_root);
- mTextView = findViewById(R.id.test_activity_title);
- mWidthTextView = findViewById(R.id.test_activity_width_text);
- mHeightTextView = findViewById(R.id.test_activity_height_text);
- mTouchStateTextView = findViewById(R.id.test_activity_touch_state);
- ViewTreeObserver viewTreeObserver = mRoot.getViewTreeObserver();
- if (viewTreeObserver.isAlive()) {
- viewTreeObserver.addOnGlobalLayoutListener(this::updateDimensionTexts);
- }
- updateStateText("CREATED");
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- updateStateText("STARTED");
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- updateStateText("RESUMED");
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- updateStateText("PAUSED");
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- updateStateText("STOPPED");
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- updateDimensionTexts();
- }
-
- private void updateStateText(String state) {
- Log.d(TAG, state);
- mTextView.setText(state);
- }
-
- private void updateDimensionTexts() {
- mWidthTextView.setText("" + mRoot.getWidth());
- mHeightTextView.setText("" + mRoot.getHeight());
- }
-
- private void updateTouchState(MotionEvent event) {
- switch (event.getAction()) {
- case ACTION_DOWN:
- case ACTION_MOVE:
- mTouchStateTextView.setText("[" + event.getX() + "," + event.getY() + "]");
- break;
- case ACTION_UP:
- case ACTION_CANCEL:
- mTouchStateTextView.setText("");
- break;
- }
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent event) {
- updateTouchState(event);
- return super.dispatchTouchEvent(event);
- }
-}
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java
deleted file mode 100644
index ecd2cf3c578e..000000000000
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * Copyright (c) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.test.activityview;
-
-import static android.view.View.GONE;
-import static android.view.View.INVISIBLE;
-import static android.view.View.VISIBLE;
-
-import android.app.Activity;
-import android.app.ActivityView;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.Spinner;
-
-public class ActivityViewVisibilityActivity extends Activity {
- private static final String[] sVisibilityOptions = {"VISIBLE", "INVISIBLE", "GONE"};
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_view_visibility_activity);
-
- final ActivityView activityView = findViewById(R.id.activity_view);
- final Button launchButton = findViewById(R.id.activity_launch_button);
- launchButton.setOnClickListener(v -> {
- final Intent intent = new Intent(this, ActivityViewTestActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- activityView.startActivity(intent);
- });
-
- final Spinner visibilitySpinner = findViewById(R.id.visibility_spinner);
- final ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
- android.R.layout.simple_spinner_item, sVisibilityOptions);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- visibilitySpinner.setAdapter(adapter);
- visibilitySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- switch (position) {
- case 0:
- activityView.setVisibility(VISIBLE);
- break;
- case 1:
- activityView.setVisibility(INVISIBLE);
- break;
- case 2:
- activityView.setVisibility(GONE);
- break;
- }
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
- }
-}
diff --git a/tests/AmSlam/Android.bp b/tests/AmSlam/Android.bp
index a8e575a39da4..cc33d88ba363 100644
--- a/tests/AmSlam/Android.bp
+++ b/tests/AmSlam/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "AmSlam",
srcs: ["**/*.java"],
diff --git a/tests/AmSlam/AndroidManifest.xml b/tests/AmSlam/AndroidManifest.xml
index 3d39e850f024..37583a946d1e 100644
--- a/tests/AmSlam/AndroidManifest.xml
+++ b/tests/AmSlam/AndroidManifest.xml
@@ -15,125 +15,324 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="test.amslam">
+ package="test.amslam">
- <application
- android:allowBackup="false"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:theme="@style/AppTheme">
- <activity android:name=".MainActivity">
+ <application android:allowBackup="false"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme">
+ <activity android:name=".MainActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <receiver
- android:name=".PongReceiver"
- android:exported="false" />
+ <receiver android:name=".PongReceiver"
+ android:exported="false"/>
- <service android:name=".subreceivers.PingReceiver000" android:exported="false" android:process=":ping000" />
- <service android:name=".subreceivers.PingReceiver001" android:exported="false" android:process=":ping001" />
- <service android:name=".subreceivers.PingReceiver002" android:exported="false" android:process=":ping002" />
- <service android:name=".subreceivers.PingReceiver003" android:exported="false" android:process=":ping003" />
- <service android:name=".subreceivers.PingReceiver004" android:exported="false" android:process=":ping004" />
- <service android:name=".subreceivers.PingReceiver005" android:exported="false" android:process=":ping005" />
- <service android:name=".subreceivers.PingReceiver006" android:exported="false" android:process=":ping006" />
- <service android:name=".subreceivers.PingReceiver007" android:exported="false" android:process=":ping007" />
- <service android:name=".subreceivers.PingReceiver008" android:exported="false" android:process=":ping008" />
- <service android:name=".subreceivers.PingReceiver009" android:exported="false" android:process=":ping009" />
- <service android:name=".subreceivers.PingReceiver010" android:exported="false" android:process=":ping010" />
- <service android:name=".subreceivers.PingReceiver011" android:exported="false" android:process=":ping011" />
- <service android:name=".subreceivers.PingReceiver012" android:exported="false" android:process=":ping012" />
- <service android:name=".subreceivers.PingReceiver013" android:exported="false" android:process=":ping013" />
- <service android:name=".subreceivers.PingReceiver014" android:exported="false" android:process=":ping014" />
- <service android:name=".subreceivers.PingReceiver015" android:exported="false" android:process=":ping015" />
- <service android:name=".subreceivers.PingReceiver016" android:exported="false" android:process=":ping016" />
- <service android:name=".subreceivers.PingReceiver017" android:exported="false" android:process=":ping017" />
- <service android:name=".subreceivers.PingReceiver018" android:exported="false" android:process=":ping018" />
- <service android:name=".subreceivers.PingReceiver019" android:exported="false" android:process=":ping019" />
- <service android:name=".subreceivers.PingReceiver020" android:exported="false" android:process=":ping020" />
- <service android:name=".subreceivers.PingReceiver021" android:exported="false" android:process=":ping021" />
- <service android:name=".subreceivers.PingReceiver022" android:exported="false" android:process=":ping022" />
- <service android:name=".subreceivers.PingReceiver023" android:exported="false" android:process=":ping023" />
- <service android:name=".subreceivers.PingReceiver024" android:exported="false" android:process=":ping024" />
- <service android:name=".subreceivers.PingReceiver025" android:exported="false" android:process=":ping025" />
- <service android:name=".subreceivers.PingReceiver026" android:exported="false" android:process=":ping026" />
- <service android:name=".subreceivers.PingReceiver027" android:exported="false" android:process=":ping027" />
- <service android:name=".subreceivers.PingReceiver028" android:exported="false" android:process=":ping028" />
- <service android:name=".subreceivers.PingReceiver029" android:exported="false" android:process=":ping029" />
- <service android:name=".subreceivers.PingReceiver030" android:exported="false" android:process=":ping030" />
- <service android:name=".subreceivers.PingReceiver031" android:exported="false" android:process=":ping031" />
- <service android:name=".subreceivers.PingReceiver032" android:exported="false" android:process=":ping032" />
- <service android:name=".subreceivers.PingReceiver033" android:exported="false" android:process=":ping033" />
- <service android:name=".subreceivers.PingReceiver034" android:exported="false" android:process=":ping034" />
- <service android:name=".subreceivers.PingReceiver035" android:exported="false" android:process=":ping035" />
- <service android:name=".subreceivers.PingReceiver036" android:exported="false" android:process=":ping036" />
- <service android:name=".subreceivers.PingReceiver037" android:exported="false" android:process=":ping037" />
- <service android:name=".subreceivers.PingReceiver038" android:exported="false" android:process=":ping038" />
- <service android:name=".subreceivers.PingReceiver039" android:exported="false" android:process=":ping039" />
- <service android:name=".subreceivers.PingReceiver040" android:exported="false" android:process=":ping040" />
- <service android:name=".subreceivers.PingReceiver041" android:exported="false" android:process=":ping041" />
- <service android:name=".subreceivers.PingReceiver042" android:exported="false" android:process=":ping042" />
- <service android:name=".subreceivers.PingReceiver043" android:exported="false" android:process=":ping043" />
- <service android:name=".subreceivers.PingReceiver044" android:exported="false" android:process=":ping044" />
- <service android:name=".subreceivers.PingReceiver045" android:exported="false" android:process=":ping045" />
- <service android:name=".subreceivers.PingReceiver046" android:exported="false" android:process=":ping046" />
- <service android:name=".subreceivers.PingReceiver047" android:exported="false" android:process=":ping047" />
- <service android:name=".subreceivers.PingReceiver048" android:exported="false" android:process=":ping048" />
- <service android:name=".subreceivers.PingReceiver049" android:exported="false" android:process=":ping049" />
- <service android:name=".subreceivers.PingReceiver050" android:exported="false" android:process=":ping050" />
- <service android:name=".subreceivers.PingReceiver051" android:exported="false" android:process=":ping051" />
- <service android:name=".subreceivers.PingReceiver052" android:exported="false" android:process=":ping052" />
- <service android:name=".subreceivers.PingReceiver053" android:exported="false" android:process=":ping053" />
- <service android:name=".subreceivers.PingReceiver054" android:exported="false" android:process=":ping054" />
- <service android:name=".subreceivers.PingReceiver055" android:exported="false" android:process=":ping055" />
- <service android:name=".subreceivers.PingReceiver056" android:exported="false" android:process=":ping056" />
- <service android:name=".subreceivers.PingReceiver057" android:exported="false" android:process=":ping057" />
- <service android:name=".subreceivers.PingReceiver058" android:exported="false" android:process=":ping058" />
- <service android:name=".subreceivers.PingReceiver059" android:exported="false" android:process=":ping059" />
- <service android:name=".subreceivers.PingReceiver060" android:exported="false" android:process=":ping060" />
- <service android:name=".subreceivers.PingReceiver061" android:exported="false" android:process=":ping061" />
- <service android:name=".subreceivers.PingReceiver062" android:exported="false" android:process=":ping062" />
- <service android:name=".subreceivers.PingReceiver063" android:exported="false" android:process=":ping063" />
- <service android:name=".subreceivers.PingReceiver064" android:exported="false" android:process=":ping064" />
- <service android:name=".subreceivers.PingReceiver065" android:exported="false" android:process=":ping065" />
- <service android:name=".subreceivers.PingReceiver066" android:exported="false" android:process=":ping066" />
- <service android:name=".subreceivers.PingReceiver067" android:exported="false" android:process=":ping067" />
- <service android:name=".subreceivers.PingReceiver068" android:exported="false" android:process=":ping068" />
- <service android:name=".subreceivers.PingReceiver069" android:exported="false" android:process=":ping069" />
- <service android:name=".subreceivers.PingReceiver070" android:exported="false" android:process=":ping070" />
- <service android:name=".subreceivers.PingReceiver071" android:exported="false" android:process=":ping071" />
- <service android:name=".subreceivers.PingReceiver072" android:exported="false" android:process=":ping072" />
- <service android:name=".subreceivers.PingReceiver073" android:exported="false" android:process=":ping073" />
- <service android:name=".subreceivers.PingReceiver074" android:exported="false" android:process=":ping074" />
- <service android:name=".subreceivers.PingReceiver075" android:exported="false" android:process=":ping075" />
- <service android:name=".subreceivers.PingReceiver076" android:exported="false" android:process=":ping076" />
- <service android:name=".subreceivers.PingReceiver077" android:exported="false" android:process=":ping077" />
- <service android:name=".subreceivers.PingReceiver078" android:exported="false" android:process=":ping078" />
- <service android:name=".subreceivers.PingReceiver079" android:exported="false" android:process=":ping079" />
- <service android:name=".subreceivers.PingReceiver080" android:exported="false" android:process=":ping080" />
- <service android:name=".subreceivers.PingReceiver081" android:exported="false" android:process=":ping081" />
- <service android:name=".subreceivers.PingReceiver082" android:exported="false" android:process=":ping082" />
- <service android:name=".subreceivers.PingReceiver083" android:exported="false" android:process=":ping083" />
- <service android:name=".subreceivers.PingReceiver084" android:exported="false" android:process=":ping084" />
- <service android:name=".subreceivers.PingReceiver085" android:exported="false" android:process=":ping085" />
- <service android:name=".subreceivers.PingReceiver086" android:exported="false" android:process=":ping086" />
- <service android:name=".subreceivers.PingReceiver087" android:exported="false" android:process=":ping087" />
- <service android:name=".subreceivers.PingReceiver088" android:exported="false" android:process=":ping088" />
- <service android:name=".subreceivers.PingReceiver089" android:exported="false" android:process=":ping089" />
- <service android:name=".subreceivers.PingReceiver090" android:exported="false" android:process=":ping090" />
- <service android:name=".subreceivers.PingReceiver091" android:exported="false" android:process=":ping091" />
- <service android:name=".subreceivers.PingReceiver092" android:exported="false" android:process=":ping092" />
- <service android:name=".subreceivers.PingReceiver093" android:exported="false" android:process=":ping093" />
- <service android:name=".subreceivers.PingReceiver094" android:exported="false" android:process=":ping094" />
- <service android:name=".subreceivers.PingReceiver095" android:exported="false" android:process=":ping095" />
- <service android:name=".subreceivers.PingReceiver096" android:exported="false" android:process=":ping096" />
- <service android:name=".subreceivers.PingReceiver097" android:exported="false" android:process=":ping097" />
- <service android:name=".subreceivers.PingReceiver098" android:exported="false" android:process=":ping098" />
- <service android:name=".subreceivers.PingReceiver099" android:exported="false" android:process=":ping099" />
+ <service android:name=".subreceivers.PingReceiver000"
+ android:exported="false"
+ android:process=":ping000"/>
+ <service android:name=".subreceivers.PingReceiver001"
+ android:exported="false"
+ android:process=":ping001"/>
+ <service android:name=".subreceivers.PingReceiver002"
+ android:exported="false"
+ android:process=":ping002"/>
+ <service android:name=".subreceivers.PingReceiver003"
+ android:exported="false"
+ android:process=":ping003"/>
+ <service android:name=".subreceivers.PingReceiver004"
+ android:exported="false"
+ android:process=":ping004"/>
+ <service android:name=".subreceivers.PingReceiver005"
+ android:exported="false"
+ android:process=":ping005"/>
+ <service android:name=".subreceivers.PingReceiver006"
+ android:exported="false"
+ android:process=":ping006"/>
+ <service android:name=".subreceivers.PingReceiver007"
+ android:exported="false"
+ android:process=":ping007"/>
+ <service android:name=".subreceivers.PingReceiver008"
+ android:exported="false"
+ android:process=":ping008"/>
+ <service android:name=".subreceivers.PingReceiver009"
+ android:exported="false"
+ android:process=":ping009"/>
+ <service android:name=".subreceivers.PingReceiver010"
+ android:exported="false"
+ android:process=":ping010"/>
+ <service android:name=".subreceivers.PingReceiver011"
+ android:exported="false"
+ android:process=":ping011"/>
+ <service android:name=".subreceivers.PingReceiver012"
+ android:exported="false"
+ android:process=":ping012"/>
+ <service android:name=".subreceivers.PingReceiver013"
+ android:exported="false"
+ android:process=":ping013"/>
+ <service android:name=".subreceivers.PingReceiver014"
+ android:exported="false"
+ android:process=":ping014"/>
+ <service android:name=".subreceivers.PingReceiver015"
+ android:exported="false"
+ android:process=":ping015"/>
+ <service android:name=".subreceivers.PingReceiver016"
+ android:exported="false"
+ android:process=":ping016"/>
+ <service android:name=".subreceivers.PingReceiver017"
+ android:exported="false"
+ android:process=":ping017"/>
+ <service android:name=".subreceivers.PingReceiver018"
+ android:exported="false"
+ android:process=":ping018"/>
+ <service android:name=".subreceivers.PingReceiver019"
+ android:exported="false"
+ android:process=":ping019"/>
+ <service android:name=".subreceivers.PingReceiver020"
+ android:exported="false"
+ android:process=":ping020"/>
+ <service android:name=".subreceivers.PingReceiver021"
+ android:exported="false"
+ android:process=":ping021"/>
+ <service android:name=".subreceivers.PingReceiver022"
+ android:exported="false"
+ android:process=":ping022"/>
+ <service android:name=".subreceivers.PingReceiver023"
+ android:exported="false"
+ android:process=":ping023"/>
+ <service android:name=".subreceivers.PingReceiver024"
+ android:exported="false"
+ android:process=":ping024"/>
+ <service android:name=".subreceivers.PingReceiver025"
+ android:exported="false"
+ android:process=":ping025"/>
+ <service android:name=".subreceivers.PingReceiver026"
+ android:exported="false"
+ android:process=":ping026"/>
+ <service android:name=".subreceivers.PingReceiver027"
+ android:exported="false"
+ android:process=":ping027"/>
+ <service android:name=".subreceivers.PingReceiver028"
+ android:exported="false"
+ android:process=":ping028"/>
+ <service android:name=".subreceivers.PingReceiver029"
+ android:exported="false"
+ android:process=":ping029"/>
+ <service android:name=".subreceivers.PingReceiver030"
+ android:exported="false"
+ android:process=":ping030"/>
+ <service android:name=".subreceivers.PingReceiver031"
+ android:exported="false"
+ android:process=":ping031"/>
+ <service android:name=".subreceivers.PingReceiver032"
+ android:exported="false"
+ android:process=":ping032"/>
+ <service android:name=".subreceivers.PingReceiver033"
+ android:exported="false"
+ android:process=":ping033"/>
+ <service android:name=".subreceivers.PingReceiver034"
+ android:exported="false"
+ android:process=":ping034"/>
+ <service android:name=".subreceivers.PingReceiver035"
+ android:exported="false"
+ android:process=":ping035"/>
+ <service android:name=".subreceivers.PingReceiver036"
+ android:exported="false"
+ android:process=":ping036"/>
+ <service android:name=".subreceivers.PingReceiver037"
+ android:exported="false"
+ android:process=":ping037"/>
+ <service android:name=".subreceivers.PingReceiver038"
+ android:exported="false"
+ android:process=":ping038"/>
+ <service android:name=".subreceivers.PingReceiver039"
+ android:exported="false"
+ android:process=":ping039"/>
+ <service android:name=".subreceivers.PingReceiver040"
+ android:exported="false"
+ android:process=":ping040"/>
+ <service android:name=".subreceivers.PingReceiver041"
+ android:exported="false"
+ android:process=":ping041"/>
+ <service android:name=".subreceivers.PingReceiver042"
+ android:exported="false"
+ android:process=":ping042"/>
+ <service android:name=".subreceivers.PingReceiver043"
+ android:exported="false"
+ android:process=":ping043"/>
+ <service android:name=".subreceivers.PingReceiver044"
+ android:exported="false"
+ android:process=":ping044"/>
+ <service android:name=".subreceivers.PingReceiver045"
+ android:exported="false"
+ android:process=":ping045"/>
+ <service android:name=".subreceivers.PingReceiver046"
+ android:exported="false"
+ android:process=":ping046"/>
+ <service android:name=".subreceivers.PingReceiver047"
+ android:exported="false"
+ android:process=":ping047"/>
+ <service android:name=".subreceivers.PingReceiver048"
+ android:exported="false"
+ android:process=":ping048"/>
+ <service android:name=".subreceivers.PingReceiver049"
+ android:exported="false"
+ android:process=":ping049"/>
+ <service android:name=".subreceivers.PingReceiver050"
+ android:exported="false"
+ android:process=":ping050"/>
+ <service android:name=".subreceivers.PingReceiver051"
+ android:exported="false"
+ android:process=":ping051"/>
+ <service android:name=".subreceivers.PingReceiver052"
+ android:exported="false"
+ android:process=":ping052"/>
+ <service android:name=".subreceivers.PingReceiver053"
+ android:exported="false"
+ android:process=":ping053"/>
+ <service android:name=".subreceivers.PingReceiver054"
+ android:exported="false"
+ android:process=":ping054"/>
+ <service android:name=".subreceivers.PingReceiver055"
+ android:exported="false"
+ android:process=":ping055"/>
+ <service android:name=".subreceivers.PingReceiver056"
+ android:exported="false"
+ android:process=":ping056"/>
+ <service android:name=".subreceivers.PingReceiver057"
+ android:exported="false"
+ android:process=":ping057"/>
+ <service android:name=".subreceivers.PingReceiver058"
+ android:exported="false"
+ android:process=":ping058"/>
+ <service android:name=".subreceivers.PingReceiver059"
+ android:exported="false"
+ android:process=":ping059"/>
+ <service android:name=".subreceivers.PingReceiver060"
+ android:exported="false"
+ android:process=":ping060"/>
+ <service android:name=".subreceivers.PingReceiver061"
+ android:exported="false"
+ android:process=":ping061"/>
+ <service android:name=".subreceivers.PingReceiver062"
+ android:exported="false"
+ android:process=":ping062"/>
+ <service android:name=".subreceivers.PingReceiver063"
+ android:exported="false"
+ android:process=":ping063"/>
+ <service android:name=".subreceivers.PingReceiver064"
+ android:exported="false"
+ android:process=":ping064"/>
+ <service android:name=".subreceivers.PingReceiver065"
+ android:exported="false"
+ android:process=":ping065"/>
+ <service android:name=".subreceivers.PingReceiver066"
+ android:exported="false"
+ android:process=":ping066"/>
+ <service android:name=".subreceivers.PingReceiver067"
+ android:exported="false"
+ android:process=":ping067"/>
+ <service android:name=".subreceivers.PingReceiver068"
+ android:exported="false"
+ android:process=":ping068"/>
+ <service android:name=".subreceivers.PingReceiver069"
+ android:exported="false"
+ android:process=":ping069"/>
+ <service android:name=".subreceivers.PingReceiver070"
+ android:exported="false"
+ android:process=":ping070"/>
+ <service android:name=".subreceivers.PingReceiver071"
+ android:exported="false"
+ android:process=":ping071"/>
+ <service android:name=".subreceivers.PingReceiver072"
+ android:exported="false"
+ android:process=":ping072"/>
+ <service android:name=".subreceivers.PingReceiver073"
+ android:exported="false"
+ android:process=":ping073"/>
+ <service android:name=".subreceivers.PingReceiver074"
+ android:exported="false"
+ android:process=":ping074"/>
+ <service android:name=".subreceivers.PingReceiver075"
+ android:exported="false"
+ android:process=":ping075"/>
+ <service android:name=".subreceivers.PingReceiver076"
+ android:exported="false"
+ android:process=":ping076"/>
+ <service android:name=".subreceivers.PingReceiver077"
+ android:exported="false"
+ android:process=":ping077"/>
+ <service android:name=".subreceivers.PingReceiver078"
+ android:exported="false"
+ android:process=":ping078"/>
+ <service android:name=".subreceivers.PingReceiver079"
+ android:exported="false"
+ android:process=":ping079"/>
+ <service android:name=".subreceivers.PingReceiver080"
+ android:exported="false"
+ android:process=":ping080"/>
+ <service android:name=".subreceivers.PingReceiver081"
+ android:exported="false"
+ android:process=":ping081"/>
+ <service android:name=".subreceivers.PingReceiver082"
+ android:exported="false"
+ android:process=":ping082"/>
+ <service android:name=".subreceivers.PingReceiver083"
+ android:exported="false"
+ android:process=":ping083"/>
+ <service android:name=".subreceivers.PingReceiver084"
+ android:exported="false"
+ android:process=":ping084"/>
+ <service android:name=".subreceivers.PingReceiver085"
+ android:exported="false"
+ android:process=":ping085"/>
+ <service android:name=".subreceivers.PingReceiver086"
+ android:exported="false"
+ android:process=":ping086"/>
+ <service android:name=".subreceivers.PingReceiver087"
+ android:exported="false"
+ android:process=":ping087"/>
+ <service android:name=".subreceivers.PingReceiver088"
+ android:exported="false"
+ android:process=":ping088"/>
+ <service android:name=".subreceivers.PingReceiver089"
+ android:exported="false"
+ android:process=":ping089"/>
+ <service android:name=".subreceivers.PingReceiver090"
+ android:exported="false"
+ android:process=":ping090"/>
+ <service android:name=".subreceivers.PingReceiver091"
+ android:exported="false"
+ android:process=":ping091"/>
+ <service android:name=".subreceivers.PingReceiver092"
+ android:exported="false"
+ android:process=":ping092"/>
+ <service android:name=".subreceivers.PingReceiver093"
+ android:exported="false"
+ android:process=":ping093"/>
+ <service android:name=".subreceivers.PingReceiver094"
+ android:exported="false"
+ android:process=":ping094"/>
+ <service android:name=".subreceivers.PingReceiver095"
+ android:exported="false"
+ android:process=":ping095"/>
+ <service android:name=".subreceivers.PingReceiver096"
+ android:exported="false"
+ android:process=":ping096"/>
+ <service android:name=".subreceivers.PingReceiver097"
+ android:exported="false"
+ android:process=":ping097"/>
+ <service android:name=".subreceivers.PingReceiver098"
+ android:exported="false"
+ android:process=":ping098"/>
+ <service android:name=".subreceivers.PingReceiver099"
+ android:exported="false"
+ android:process=":ping099"/>
</application>
</manifest>
diff --git a/tests/AmSlam/OWNERS b/tests/AmSlam/OWNERS
new file mode 100644
index 000000000000..72c0a9e6e90c
--- /dev/null
+++ b/tests/AmSlam/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/am/OWNERS
diff --git a/tests/ApkVerityTest/Android.bp b/tests/ApkVerityTest/Android.bp
index 02c75edafcd5..4e98f4264e11 100644
--- a/tests/ApkVerityTest/Android.bp
+++ b/tests/ApkVerityTest/Android.bp
@@ -12,10 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
java_test_host {
name: "ApkVerityTest",
srcs: ["src/**/*.java"],
libs: ["tradefed", "compatibility-tradefed", "compatibility-host-util"],
+ static_libs: [
+ "block_device_writer_jar",
+ "frameworks-base-hostutils",
+ ],
test_suites: ["general-tests", "vts"],
target_required: [
"block_device_writer_module",
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/Android.bp b/tests/ApkVerityTest/ApkVerityTestApp/Android.bp
index 69632b215822..adf8f9f9d321 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/Android.bp
+++ b/tests/ApkVerityTest/ApkVerityTestApp/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test_helper_app {
name: "ApkVerityTestApp",
manifest: "AndroidManifest.xml",
diff --git a/tests/ApkVerityTest/OWNERS b/tests/ApkVerityTest/OWNERS
new file mode 100644
index 000000000000..d67285ede44a
--- /dev/null
+++ b/tests/ApkVerityTest/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 36824
+
+victorhsieh@google.com
diff --git a/tests/ApkVerityTest/block_device_writer/Android.bp b/tests/ApkVerityTest/block_device_writer/Android.bp
index 37fbc29470f6..0b5f0f611916 100644
--- a/tests/ApkVerityTest/block_device_writer/Android.bp
+++ b/tests/ApkVerityTest/block_device_writer/Android.bp
@@ -14,6 +14,15 @@
// This is a cc_test just because it supports test_suites. This should be converted to something
// like cc_binary_test_helper once supported, thus auto_gen_config:false below.
+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"],
+}
+
cc_test {
// Depending on how the test runs, the executable may be uploaded to different location.
// Before the bug in the file pusher is fixed, workaround by making the name unique.
@@ -51,3 +60,9 @@ cc_test {
test_suites: ["general-tests", "pts", "vts"],
gtest: false,
}
+
+java_library_host {
+ name: "block_device_writer_jar",
+ srcs: ["src/**/*.java"],
+ libs: ["tradefed", "junit"],
+}
diff --git a/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java b/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java
new file mode 100644
index 000000000000..5c2c15b22bb0
--- /dev/null
+++ b/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java
@@ -0,0 +1,100 @@
+/*
+ * 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.blockdevicewriter;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
+
+import java.util.ArrayList;
+
+/**
+ * Wrapper for block_device_writer command.
+ *
+ * <p>To use this class, please push block_device_writer binary to /data/local/tmp.
+ * 1. In Android.bp, add:
+ * <pre>
+ * target_required: ["block_device_writer_module"],
+ * </pre>
+ * 2. In AndroidText.xml, add:
+ * <pre>
+ * <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ * <option name="push" value="block_device_writer->/data/local/tmp/block_device_writer" />
+ * </target_preparer>
+ * </pre>
+ */
+public final class BlockDeviceWriter {
+ private static final String EXECUTABLE = "/data/local/tmp/block_device_writer";
+
+ /**
+ * Modifies a byte of the file directly against the backing block storage.
+ *
+ * The effect can only be observed when the page cache is read from disk again. See
+ * {@link #dropCaches} for details.
+ */
+ public static void damageFileAgainstBlockDevice(ITestDevice device, String path,
+ long offsetOfTargetingByte)
+ throws DeviceNotAvailableException {
+ assertThat(path).startsWith("/data/");
+ ITestDevice.MountPointInfo mountPoint = device.getMountPointInfo("/data");
+ ArrayList<String> args = new ArrayList<>();
+ args.add(EXECUTABLE);
+ if ("f2fs".equals(mountPoint.type)) {
+ args.add("--use-f2fs-pinning");
+ }
+ args.add(mountPoint.filesystem);
+ args.add(path);
+ args.add(Long.toString(offsetOfTargetingByte));
+ CommandResult result = device.executeShellV2Command(String.join(" ", args));
+ assertWithMessage(
+ String.format("stdout=%s\nstderr=%s", result.getStdout(), result.getStderr()))
+ .that(result.getStatus()).isEqualTo(CommandStatus.SUCCESS);
+ }
+
+ /**
+ * Drops file caches so that the result of {@link #damageFileAgainstBlockDevice} can be
+ * observed. If a process has an open FD or memory map of the damaged file, cache eviction won't
+ * happen and the damage cannot be observed.
+ */
+ public static void dropCaches(ITestDevice device) throws DeviceNotAvailableException {
+ CommandResult result = device.executeShellV2Command(
+ "sync && echo 1 > /proc/sys/vm/drop_caches");
+ assertThat(result.getStatus()).isEqualTo(CommandStatus.SUCCESS);
+ }
+
+ public static void assertFileNotOpen(ITestDevice device, String path)
+ throws DeviceNotAvailableException {
+ CommandResult result = device.executeShellV2Command("lsof " + path);
+ assertThat(result.getStatus()).isEqualTo(CommandStatus.SUCCESS);
+ assertThat(result.getStdout()).isEmpty();
+ }
+
+ /**
+ * Checks if the give offset of a file can be read.
+ * This method will return false if the file has fs-verity enabled and is damaged at the offset.
+ */
+ public static boolean canReadByte(ITestDevice device, String filePath, long offset)
+ throws DeviceNotAvailableException {
+ CommandResult result = device.executeShellV2Command(
+ "dd if=" + filePath + " bs=1 count=1 skip=" + Long.toString(offset));
+ return result.getStatus() == CommandStatus.SUCCESS;
+ }
+}
diff --git a/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java b/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
index 629b6c714ae8..d96005b8a71a 100644
--- a/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
+++ b/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
@@ -21,10 +21,11 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
import android.platform.test.annotations.RootPermissionTest;
+import com.android.blockdevicewriter.BlockDeviceWriter;
+import com.android.fsverity.AddFsVerityCertRule;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
@@ -35,6 +36,7 @@ import com.android.tradefed.util.CommandStatus;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -85,29 +87,21 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
private static final String DAMAGING_EXECUTABLE = "/data/local/tmp/block_device_writer";
private static final String CERT_PATH = "/data/local/tmp/ApkVerityTestCert.der";
- private static final String APK_VERITY_STANDARD_MODE = "2";
-
/** Only 4K page is supported by fs-verity currently. */
private static final int FSVERITY_PAGE_SIZE = 4096;
+ @Rule
+ public final AddFsVerityCertRule mAddFsVerityCertRule =
+ new AddFsVerityCertRule(this, CERT_PATH);
+
private ITestDevice mDevice;
- private String mKeyId;
+ private boolean mDmRequireFsVerity;
@Before
public void setUp() throws DeviceNotAvailableException {
mDevice = getDevice();
-
- String apkVerityMode = mDevice.getProperty("ro.apk_verity.mode");
- assumeTrue(mDevice.getLaunchApiLevel() >= 30
- || APK_VERITY_STANDARD_MODE.equals(apkVerityMode));
-
- mKeyId = expectRemoteCommandToSucceed(
- "mini-keyctl padd asymmetric fsv_test .fs-verity < " + CERT_PATH).trim();
- if (!mKeyId.matches("^\\d+$")) {
- String keyId = mKeyId;
- mKeyId = null;
- fail("Key ID is not decimal: " + keyId);
- }
+ mDmRequireFsVerity = "true".equals(
+ mDevice.getProperty("pm.dexopt.dm.require_fsverity"));
uninstallPackage(TARGET_PACKAGE);
}
@@ -115,10 +109,6 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
@After
public void tearDown() throws DeviceNotAvailableException {
uninstallPackage(TARGET_PACKAGE);
-
- if (mKeyId != null) {
- expectRemoteCommandToSucceed("mini-keyctl unlink " + mKeyId + " .fs-verity");
- }
}
@Test
@@ -137,7 +127,7 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
verifyInstalledFiles(
INSTALLED_BASE_APK,
INSTALLED_BASE_APK_FSV_SIG);
- verifyInstalledFilesHaveFsverity();
+ verifyInstalledFilesHaveFsverity(INSTALLED_BASE_APK);
}
@Test
@@ -164,7 +154,9 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
INSTALLED_BASE_APK_FSV_SIG,
INSTALLED_SPLIT_APK,
INSTALLED_SPLIT_APK_FSV_SIG);
- verifyInstalledFilesHaveFsverity();
+ verifyInstalledFilesHaveFsverity(
+ INSTALLED_BASE_APK,
+ INSTALLED_SPLIT_APK);
}
@Test
@@ -180,7 +172,9 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
INSTALLED_BASE_APK_FSV_SIG,
INSTALLED_BASE_DM,
INSTALLED_BASE_DM_FSV_SIG);
- verifyInstalledFilesHaveFsverity();
+ verifyInstalledFilesHaveFsverity(
+ INSTALLED_BASE_APK,
+ INSTALLED_BASE_DM);
}
@Test
@@ -202,7 +196,11 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
INSTALLED_SPLIT_APK_FSV_SIG,
INSTALLED_SPLIT_DM,
INSTALLED_SPLIT_DM_FSV_SIG);
- verifyInstalledFilesHaveFsverity();
+ verifyInstalledFilesHaveFsverity(
+ INSTALLED_BASE_APK,
+ INSTALLED_BASE_DM,
+ INSTALLED_SPLIT_APK,
+ INSTALLED_SPLIT_DM);
}
@Test
@@ -226,7 +224,9 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
INSTALLED_BASE_APK_FSV_SIG,
INSTALLED_SPLIT_APK,
INSTALLED_SPLIT_APK_FSV_SIG);
- verifyInstalledFilesHaveFsverity();
+ verifyInstalledFilesHaveFsverity(
+ INSTALLED_BASE_APK,
+ INSTALLED_SPLIT_APK);
}
@Test
@@ -263,39 +263,92 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
INSTALLED_BASE_APK,
INSTALLED_SPLIT_APK,
INSTALLED_SPLIT_APK_FSV_SIG);
-
}
@Test
- public void testInstallOnlyBaseHasFsvSig()
+ public void testInstallOnlyDmHasFsvSig()
throws DeviceNotAvailableException, FileNotFoundException {
new InstallMultiple()
- .addFileAndSignature(BASE_APK)
+ .addFile(BASE_APK)
+ .addFileAndSignature(BASE_APK_DM)
+ .addFile(SPLIT_APK)
+ .addFileAndSignature(SPLIT_APK_DM)
+ .run();
+ verifyInstalledFiles(
+ INSTALLED_BASE_APK,
+ INSTALLED_BASE_DM,
+ INSTALLED_BASE_DM_FSV_SIG,
+ INSTALLED_SPLIT_APK,
+ INSTALLED_SPLIT_DM,
+ INSTALLED_SPLIT_DM_FSV_SIG);
+ verifyInstalledFilesHaveFsverity(
+ INSTALLED_BASE_DM,
+ INSTALLED_SPLIT_DM);
+ }
+
+ @Test
+ public void testInstallDmWithoutFsvSig_Base()
+ throws DeviceNotAvailableException, FileNotFoundException {
+ InstallMultiple installer = new InstallMultiple()
+ .addFile(BASE_APK)
.addFile(BASE_APK_DM)
.addFile(SPLIT_APK)
- .addFile(SPLIT_APK_DM)
- .runExpectingFailure();
+ .addFileAndSignature(SPLIT_APK_DM);
+ if (mDmRequireFsVerity) {
+ installer.runExpectingFailure();
+ } else {
+ installer.run();
+ verifyInstalledFiles(
+ INSTALLED_BASE_APK,
+ INSTALLED_BASE_DM,
+ INSTALLED_SPLIT_APK,
+ INSTALLED_SPLIT_DM,
+ INSTALLED_SPLIT_DM_FSV_SIG);
+ verifyInstalledFilesHaveFsverity(INSTALLED_SPLIT_DM);
+ }
}
@Test
- public void testInstallOnlyDmHasFsvSig()
+ public void testInstallDmWithoutFsvSig_Split()
throws DeviceNotAvailableException, FileNotFoundException {
- new InstallMultiple()
+ InstallMultiple installer = new InstallMultiple()
.addFile(BASE_APK)
.addFileAndSignature(BASE_APK_DM)
.addFile(SPLIT_APK)
- .addFile(SPLIT_APK_DM)
+ .addFile(SPLIT_APK_DM);
+ if (mDmRequireFsVerity) {
+ installer.runExpectingFailure();
+ } else {
+ installer.run();
+ verifyInstalledFiles(
+ INSTALLED_BASE_APK,
+ INSTALLED_BASE_DM,
+ INSTALLED_BASE_DM_FSV_SIG,
+ INSTALLED_SPLIT_APK,
+ INSTALLED_SPLIT_DM);
+ verifyInstalledFilesHaveFsverity(INSTALLED_BASE_DM);
+ }
+ }
+
+ @Test
+ public void testInstallSomeApkIsMissingFsvSig_Base()
+ throws DeviceNotAvailableException, FileNotFoundException {
+ new InstallMultiple()
+ .addFileAndSignature(BASE_APK)
+ .addFileAndSignature(BASE_APK_DM)
+ .addFile(SPLIT_APK)
+ .addFileAndSignature(SPLIT_APK_DM)
.runExpectingFailure();
}
@Test
- public void testInstallOnlySplitHasFsvSig()
+ public void testInstallSomeApkIsMissingFsvSig_Split()
throws DeviceNotAvailableException, FileNotFoundException {
new InstallMultiple()
.addFile(BASE_APK)
- .addFile(BASE_APK_DM)
+ .addFileAndSignature(BASE_APK_DM)
.addFileAndSignature(SPLIT_APK)
- .addFile(SPLIT_APK_DM)
+ .addFileAndSignature(SPLIT_APK_DM)
.runExpectingFailure();
}
@@ -348,22 +401,23 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
long offsetFirstByte = 0;
// The first two pages should be both readable at first.
- assertTrue(canReadByte(apkPath, offsetFirstByte));
+ assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath, offsetFirstByte));
if (apkSize > offsetFirstByte + FSVERITY_PAGE_SIZE) {
- assertTrue(canReadByte(apkPath, offsetFirstByte + FSVERITY_PAGE_SIZE));
+ assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath,
+ offsetFirstByte + FSVERITY_PAGE_SIZE));
}
// Damage the file directly against the block device.
damageFileAgainstBlockDevice(apkPath, offsetFirstByte);
// Expect actual read from disk to fail but only at damaged page.
- dropCaches();
- assertFalse(canReadByte(apkPath, offsetFirstByte));
+ BlockDeviceWriter.dropCaches(mDevice);
+ assertFalse(BlockDeviceWriter.canReadByte(mDevice, apkPath, offsetFirstByte));
if (apkSize > offsetFirstByte + FSVERITY_PAGE_SIZE) {
long lastByteOfTheSamePage =
offsetFirstByte % FSVERITY_PAGE_SIZE + FSVERITY_PAGE_SIZE - 1;
- assertFalse(canReadByte(apkPath, lastByteOfTheSamePage));
- assertTrue(canReadByte(apkPath, lastByteOfTheSamePage + 1));
+ assertFalse(BlockDeviceWriter.canReadByte(mDevice, apkPath, lastByteOfTheSamePage));
+ assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath, lastByteOfTheSamePage + 1));
}
}
@@ -376,55 +430,55 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
long offsetOfLastByte = apkSize - 1;
// The first two pages should be both readable at first.
- assertTrue(canReadByte(apkPath, offsetOfLastByte));
+ assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath, offsetOfLastByte));
if (offsetOfLastByte - FSVERITY_PAGE_SIZE > 0) {
- assertTrue(canReadByte(apkPath, offsetOfLastByte - FSVERITY_PAGE_SIZE));
+ assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath,
+ offsetOfLastByte - FSVERITY_PAGE_SIZE));
}
// Damage the file directly against the block device.
damageFileAgainstBlockDevice(apkPath, offsetOfLastByte);
// Expect actual read from disk to fail but only at damaged page.
- dropCaches();
- assertFalse(canReadByte(apkPath, offsetOfLastByte));
+ BlockDeviceWriter.dropCaches(mDevice);
+ assertFalse(BlockDeviceWriter.canReadByte(mDevice, apkPath, offsetOfLastByte));
if (offsetOfLastByte - FSVERITY_PAGE_SIZE > 0) {
long firstByteOfTheSamePage = offsetOfLastByte - offsetOfLastByte % FSVERITY_PAGE_SIZE;
- assertFalse(canReadByte(apkPath, firstByteOfTheSamePage));
- assertTrue(canReadByte(apkPath, firstByteOfTheSamePage - 1));
+ assertFalse(BlockDeviceWriter.canReadByte(mDevice, apkPath, firstByteOfTheSamePage));
+ assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath, firstByteOfTheSamePage - 1));
}
}
- private void verifyInstalledFilesHaveFsverity() throws DeviceNotAvailableException {
+ private void verifyInstalledFilesHaveFsverity(String... filenames)
+ throws DeviceNotAvailableException {
// Verify that all files are protected by fs-verity
String apkPath = getApkPath(TARGET_PACKAGE);
String appDir = apkPath.substring(0, apkPath.lastIndexOf("/"));
long kTargetOffset = 0;
- for (String basename : expectRemoteCommandToSucceed("ls " + appDir).split("\n")) {
- if (basename.endsWith(".apk") || basename.endsWith(".dm")) {
- String path = appDir + "/" + basename;
- damageFileAgainstBlockDevice(path, kTargetOffset);
-
- // Retry is sometimes needed to pass the test. Package manager may have FD leaks
- // (see b/122744005 as example) that prevents the file in question to be evicted
- // from filesystem cache. Forcing GC workarounds the problem.
- int retry = 5;
- for (; retry > 0; retry--) {
- dropCaches();
- if (!canReadByte(path, kTargetOffset)) {
- break;
- }
- try {
- CLog.d("lsof: " + expectRemoteCommandToSucceed("lsof " + apkPath));
- Thread.sleep(1000);
- String pid = expectRemoteCommandToSucceed("pidof system_server");
- mDevice.executeShellV2Command("kill -10 " + pid); // force GC
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- return;
- }
+ for (String basename : filenames) {
+ String path = appDir + "/" + basename;
+ damageFileAgainstBlockDevice(path, kTargetOffset);
+
+ // Retry is sometimes needed to pass the test. Package manager may have FD leaks
+ // (see b/122744005 as example) that prevents the file in question to be evicted
+ // from filesystem cache. Forcing GC workarounds the problem.
+ int retry = 5;
+ for (; retry > 0; retry--) {
+ BlockDeviceWriter.dropCaches(mDevice);
+ if (!BlockDeviceWriter.canReadByte(mDevice, path, kTargetOffset)) {
+ break;
+ }
+ try {
+ CLog.d("lsof: " + expectRemoteCommandToSucceed("lsof " + apkPath));
+ Thread.sleep(1000);
+ String pid = expectRemoteCommandToSucceed("pidof system_server");
+ mDevice.executeShellV2Command("kill -10 " + pid); // force GC
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return;
}
- assertTrue("Read from " + path + " should fail", retry > 0);
}
+ assertTrue("Read from " + path + " should fail", retry > 0);
}
}
@@ -465,16 +519,6 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
return Long.parseLong(expectRemoteCommandToSucceed("stat -c '%s' " + packageName).trim());
}
- private void dropCaches() throws DeviceNotAvailableException {
- expectRemoteCommandToSucceed("sync && echo 1 > /proc/sys/vm/drop_caches");
- }
-
- private boolean canReadByte(String filePath, long offset) throws DeviceNotAvailableException {
- CommandResult result = mDevice.executeShellV2Command(
- "dd if=" + filePath + " bs=1 count=1 skip=" + Long.toString(offset));
- return result.getStatus() == CommandStatus.SUCCESS;
- }
-
private String expectRemoteCommandToSucceed(String cmd) throws DeviceNotAvailableException {
CommandResult result = mDevice.executeShellV2Command(cmd);
assertEquals("`" + cmd + "` failed: " + result.getStderr(), CommandStatus.SUCCESS,
diff --git a/tests/ApkVerityTest/testdata/Android.bp b/tests/ApkVerityTest/testdata/Android.bp
index c10b0cef21d7..ccfc4c99a347 100644
--- a/tests/ApkVerityTest/testdata/Android.bp
+++ b/tests/ApkVerityTest/testdata/Android.bp
@@ -12,6 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
filegroup {
name: "ApkVerityTestKeyPem",
srcs: ["ApkVerityTestKey.pem"],
@@ -74,4 +85,3 @@ genrule {
srcs: [":ApkVerityTestAppSplitDm"],
out: ["ApkVerityTestAppSplit.dm.fsv_sig"],
}
-
diff --git a/tests/AppLaunch/Android.bp b/tests/AppLaunch/Android.bp
index 75db55122553..f838c5a80c28 100644
--- a/tests/AppLaunch/Android.bp
+++ b/tests/AppLaunch/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "AppLaunch",
// Only compile source java files in this apk.
diff --git a/tests/AppLaunchWear/Android.bp b/tests/AppLaunchWear/Android.bp
index 8d34b6eb9c0f..e2fc4735a7c2 100644
--- a/tests/AppLaunchWear/Android.bp
+++ b/tests/AppLaunchWear/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "AppLaunchWear",
// Only compile source java files in this apk.
diff --git a/tests/AppResourcesLoaders/Android.bp b/tests/AppResourcesLoaders/Android.bp
index e5739dbf181c..d882db8b18a2 100644
--- a/tests/AppResourcesLoaders/Android.bp
+++ b/tests/AppResourcesLoaders/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "AppResourcesLoaders",
srcs: ["**/*.java"],
diff --git a/tests/AppResourcesLoaders/AndroidManifest.xml b/tests/AppResourcesLoaders/AndroidManifest.xml
index cb403b968abf..61011008d949 100644
--- a/tests/AppResourcesLoaders/AndroidManifest.xml
+++ b/tests/AppResourcesLoaders/AndroidManifest.xml
@@ -16,16 +16,17 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.example.loaders">
+ package="com.android.example.loaders">
<application android:label="AppResourcesLoaders"
- android:name=".LoadersApplication">
- <activity android:name=".LoaderActivity">
+ android:name=".LoadersApplication">
+ <activity android:name=".LoaderActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".LoaderActivityIsolated"
- android:process="com.android.phone" />
+ android:process="com.android.phone"/>
</application>
</manifest>
diff --git a/tests/AppResourcesLoaders/Overlay/Android.bp b/tests/AppResourcesLoaders/Overlay/Android.bp
index 80443f6c3c00..b063023f7d19 100644
--- a/tests/AppResourcesLoaders/Overlay/Android.bp
+++ b/tests/AppResourcesLoaders/Overlay/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test_helper_app {
name: "AppResourcesLoaders_Overlay",
}
diff --git a/tests/Assist/Android.bp b/tests/Assist/Android.bp
index 216e75109dde..033c14017442 100644
--- a/tests/Assist/Android.bp
+++ b/tests/Assist/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "Assist",
srcs: ["**/*.java"],
diff --git a/tests/Assist/AndroidManifest.xml b/tests/Assist/AndroidManifest.xml
index 9d4c4ad17454..2f6f50bd4f48 100644
--- a/tests/Assist/AndroidManifest.xml
+++ b/tests/Assist/AndroidManifest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2015 The Android Open Source Project
~
@@ -15,35 +16,34 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.assist">
+ package="com.android.test.assist">
<application>
<service android:name="AssistInteractionService"
- android:label="Test Assist Interaction Service"
- android:permission="android.permission.BIND_VOICE_INTERACTION"
- android:process=":interactor">
+ android:label="Test Assist Interaction Service"
+ android:permission="android.permission.BIND_VOICE_INTERACTION"
+ android:process=":interactor"
+ android:exported="true">
<meta-data android:name="android.voice_interaction"
- android:resource="@xml/interaction_service" />
+ android:resource="@xml/interaction_service"/>
<intent-filter>
- <action android:name="android.service.voice.VoiceInteractionService" />
+ <action android:name="android.service.voice.VoiceInteractionService"/>
</intent-filter>
- <meta-data
- android:name="com.android.systemui.action_assist_icon"
- android:resource="@drawable/assistant" />
- <meta-data
- android:name="com.android.keyguard.layout"
- android:resource="@layout/keyguard_preview" />
+ <meta-data android:name="com.android.systemui.action_assist_icon"
+ android:resource="@drawable/assistant"/>
+ <meta-data android:name="com.android.keyguard.layout"
+ android:resource="@layout/keyguard_preview"/>
</service>
<service android:name="AssistInteractionSessionService"
- android:permission="android.permission.BIND_VOICE_INTERACTION"
- android:process=":session">
+ android:permission="android.permission.BIND_VOICE_INTERACTION"
+ android:process=":session">
</service>
<activity android:name=".AboveKeyguardActivity"
- android:label="Test Above Keyguard Activity"
- android:theme="@android:style/Theme.NoTitleBar"
- android:excludeFromRecents="true"
- android:launchMode="singleTask"
- android:exported="false" >
+ android:label="Test Above Keyguard Activity"
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:excludeFromRecents="true"
+ android:launchMode="singleTask"
+ android:exported="false">
</activity>
</application>
</manifest>
diff --git a/tests/AutoVerify/app1/Android.bp b/tests/AutoVerify/app1/Android.bp
deleted file mode 100644
index 548519fa653b..000000000000
--- a/tests/AutoVerify/app1/Android.bp
+++ /dev/null
@@ -1,11 +0,0 @@
-android_app {
- name: "AutoVerifyTest",
- srcs: ["src/**/*.java"],
- resource_dirs: ["res"],
- platform_apis: true,
- min_sdk_version: "26",
- target_sdk_version: "26",
- optimize: {
- enabled: false,
- },
-}
diff --git a/tests/AutoVerify/app1/AndroidManifest.xml b/tests/AutoVerify/app1/AndroidManifest.xml
deleted file mode 100644
index d9caad490d82..000000000000
--- a/tests/AutoVerify/app1/AndroidManifest.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.autoverify" >
-
- <uses-sdk android:targetSdkVersion="26" />
-
- <application
- android:label="@string/app_name" >
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
-
- <intent-filter android:autoVerify="true">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:host="explicit.example.com" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/AutoVerify/app1/res/values/strings.xml b/tests/AutoVerify/app1/res/values/strings.xml
deleted file mode 100644
index e234355041c6..000000000000
--- a/tests/AutoVerify/app1/res/values/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-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.
--->
-
-<resources>
- <!-- app icon label, do not translate -->
- <string name="app_name" translatable="false">AutoVerify Test</string>
-</resources>
diff --git a/tests/AutoVerify/app2/Android.bp b/tests/AutoVerify/app2/Android.bp
deleted file mode 100644
index 1c6c97bdf350..000000000000
--- a/tests/AutoVerify/app2/Android.bp
+++ /dev/null
@@ -1,11 +0,0 @@
-android_app {
- name: "AutoVerifyTest2",
- srcs: ["src/**/*.java"],
- resource_dirs: ["res"],
- platform_apis: true,
- min_sdk_version: "26",
- target_sdk_version: "26",
- optimize: {
- enabled: false,
- },
-}
diff --git a/tests/AutoVerify/app2/AndroidManifest.xml b/tests/AutoVerify/app2/AndroidManifest.xml
deleted file mode 100644
index a00807883cfc..000000000000
--- a/tests/AutoVerify/app2/AndroidManifest.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.autoverify" >
-
- <uses-sdk android:targetSdkVersion="26" />
-
- <application
- android:label="@string/app_name" >
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
-
- <intent-filter android:autoVerify="true">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:host="explicit.example.com" />
- <data android:host="*.wildcard.tld" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/AutoVerify/app2/res/values/strings.xml b/tests/AutoVerify/app2/res/values/strings.xml
deleted file mode 100644
index e234355041c6..000000000000
--- a/tests/AutoVerify/app2/res/values/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-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.
--->
-
-<resources>
- <!-- app icon label, do not translate -->
- <string name="app_name" translatable="false">AutoVerify Test</string>
-</resources>
diff --git a/tests/AutoVerify/app3/Android.bp b/tests/AutoVerify/app3/Android.bp
deleted file mode 100644
index 70a2b77d1000..000000000000
--- a/tests/AutoVerify/app3/Android.bp
+++ /dev/null
@@ -1,11 +0,0 @@
-android_app {
- name: "AutoVerifyTest3",
- srcs: ["src/**/*.java"],
- resource_dirs: ["res"],
- platform_apis: true,
- min_sdk_version: "26",
- target_sdk_version: "26",
- optimize: {
- enabled: false,
- },
-}
diff --git a/tests/AutoVerify/app3/AndroidManifest.xml b/tests/AutoVerify/app3/AndroidManifest.xml
deleted file mode 100644
index efaabc9a38d3..000000000000
--- a/tests/AutoVerify/app3/AndroidManifest.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.autoverify" >
-
- <uses-sdk android:targetSdkVersion="26" />
-
- <application
- android:label="@string/app_name" >
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
-
- <!-- does not request autoVerify -->
- <intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:host="explicit.example.com" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/AutoVerify/app3/res/values/strings.xml b/tests/AutoVerify/app3/res/values/strings.xml
deleted file mode 100644
index e234355041c6..000000000000
--- a/tests/AutoVerify/app3/res/values/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-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.
--->
-
-<resources>
- <!-- app icon label, do not translate -->
- <string name="app_name" translatable="false">AutoVerify Test</string>
-</resources>
diff --git a/tests/AutoVerify/app4/Android.bp b/tests/AutoVerify/app4/Android.bp
deleted file mode 100644
index fbdae1181a7a..000000000000
--- a/tests/AutoVerify/app4/Android.bp
+++ /dev/null
@@ -1,11 +0,0 @@
-android_app {
- name: "AutoVerifyTest4",
- srcs: ["src/**/*.java"],
- resource_dirs: ["res"],
- platform_apis: true,
- min_sdk_version: "26",
- target_sdk_version: "26",
- optimize: {
- enabled: false,
- },
-}
diff --git a/tests/AutoVerify/app4/res/values/strings.xml b/tests/AutoVerify/app4/res/values/strings.xml
deleted file mode 100644
index e234355041c6..000000000000
--- a/tests/AutoVerify/app4/res/values/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-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.
--->
-
-<resources>
- <!-- app icon label, do not translate -->
- <string name="app_name" translatable="false">AutoVerify Test</string>
-</resources>
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/Android.bp b/tests/BackgroundDexOptServiceIntegrationTests/Android.bp
index a85d129b013a..0a45d5381f84 100644
--- a/tests/BackgroundDexOptServiceIntegrationTests/Android.bp
+++ b/tests/BackgroundDexOptServiceIntegrationTests/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "BackgroundDexOptServiceIntegrationTests",
srcs: ["src/**/*.java"],
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/OWNERS b/tests/BackgroundDexOptServiceIntegrationTests/OWNERS
new file mode 100644
index 000000000000..3414a7469ac2
--- /dev/null
+++ b/tests/BackgroundDexOptServiceIntegrationTests/OWNERS
@@ -0,0 +1 @@
+include platform/art:/OWNERS
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
index 7d826f7172da..90ddb6ffb34a 100644
--- a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
+++ b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
@@ -20,6 +20,7 @@ import android.app.AlarmManager;
import android.content.Context;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
import android.os.SystemProperties;
import android.os.storage.StorageManager;
import android.util.Log;
@@ -201,11 +202,16 @@ public final class BackgroundDexOptServiceIntegrationTests {
fillUpStorage((long) (getStorageLowBytes() * LOW_STORAGE_MULTIPLIER));
}
- // TODO(aeubanks): figure out how to get scheduled bg-dexopt to run
private static void runBackgroundDexOpt() throws IOException {
+ runBackgroundDexOpt("Success");
+ }
+
+ // TODO(aeubanks): figure out how to get scheduled bg-dexopt to run
+ private static void runBackgroundDexOpt(String expectedStatus) throws IOException {
String result = runShellCommand("cmd package bg-dexopt-job " + PACKAGE_NAME);
- if (!result.trim().equals("Success")) {
- throw new IllegalStateException("Expected command success, received >" + result + "<");
+ if (!result.trim().equals(expectedStatus)) {
+ throw new IllegalStateException("Expected status: " + expectedStatus
+ + "; Received: " + result.trim());
}
}
@@ -242,6 +248,16 @@ public final class BackgroundDexOptServiceIntegrationTests {
runShellCommand(String.format("cmd package compile -f -m %s %s", filter, pkg));
}
+ // Override the thermal status of the device
+ public static void overrideThermalStatus(int status) throws IOException {
+ runShellCommand("cmd thermalservice override-status " + status);
+ }
+
+ // Reset the thermal status of the device
+ public static void resetThermalStatus() throws IOException {
+ runShellCommand("cmd thermalservice reset");
+ }
+
// Test that background dexopt under normal conditions succeeds.
@Test
public void testBackgroundDexOpt() throws IOException {
@@ -264,9 +280,9 @@ public final class BackgroundDexOptServiceIntegrationTests {
// Set time to future.
setTimeFutureDays(deltaDays);
- // Set filter to quicken.
- compilePackageWithFilter(PACKAGE_NAME, "quicken");
- Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
+ // Set filter to verify.
+ compilePackageWithFilter(PACKAGE_NAME, "verify");
+ Assert.assertEquals("verify", getCompilerFilter(PACKAGE_NAME));
// Fill up storage to trigger low storage threshold.
fillUpToLowStorage();
@@ -290,9 +306,9 @@ public final class BackgroundDexOptServiceIntegrationTests {
// Set time to future.
setTimeFutureDays(deltaDays);
- // Set filter to quicken.
- compilePackageWithFilter(PACKAGE_NAME, "quicken");
- Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
+ // Set filter to speed-profile.
+ compilePackageWithFilter(PACKAGE_NAME, "speed-profile");
+ Assert.assertEquals("speed-profile", getCompilerFilter(PACKAGE_NAME));
// Fill up storage to trigger low storage threshold.
fillUpToLowStorage();
@@ -307,4 +323,17 @@ public final class BackgroundDexOptServiceIntegrationTests {
}
}
+ // Test that background dexopt job doesn't trigger if the device is under thermal throttling.
+ @Test
+ public void testBackgroundDexOptThermalThrottling() throws IOException {
+ try {
+ compilePackageWithFilter(PACKAGE_NAME, "verify");
+ overrideThermalStatus(PowerManager.THERMAL_STATUS_MODERATE);
+ // The bgdexopt task should fail when onStartJob is run
+ runBackgroundDexOpt("Failure");
+ Assert.assertEquals("verify", getCompilerFilter(PACKAGE_NAME));
+ } finally {
+ resetThermalStatus();
+ }
+ }
}
diff --git a/tests/BandwidthTests/Android.bp b/tests/BandwidthTests/Android.bp
index 523f5226cd2c..a7fc89db32e1 100644
--- a/tests/BandwidthTests/Android.bp
+++ b/tests/BandwidthTests/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "BandwidthEnforcementTest",
platform_apis: true,
diff --git a/tests/BandwidthTests/AndroidManifest.xml b/tests/BandwidthTests/AndroidManifest.xml
index 19f38cabf23e..72bdd1430cb4 100644
--- a/tests/BandwidthTests/AndroidManifest.xml
+++ b/tests/BandwidthTests/AndroidManifest.xml
@@ -13,19 +13,22 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.bandwidthenforcement">
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ package="com.android.tests.bandwidthenforcement">
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application>
- <activity android:name=".BandwidthEnforcementTestActivity">
+ <activity android:name=".BandwidthEnforcementTestActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- adb shell am startservice -n com.android.tests.bandwidthenforcement/.BandwidthEnforcementTestService -->
- <service android:name=".BandwidthEnforcementTestService" android:exported="true" />
+ <service android:name=".BandwidthEnforcementTestService"
+ android:exported="true"/>
</application>
</manifest>
diff --git a/tests/BatteryStatsPerfTest/Android.bp b/tests/BatteryStatsPerfTest/Android.bp
new file mode 100644
index 000000000000..5233a5b8654e
--- /dev/null
+++ b/tests/BatteryStatsPerfTest/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // 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"],
+}
+
+android_test {
+ name: "BatteryStatsPerfTests",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "apct-perftests-utils",
+ "truth-prebuilt",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/tests/BatteryStatsPerfTest/AndroidManifest.xml b/tests/BatteryStatsPerfTest/AndroidManifest.xml
new file mode 100644
index 000000000000..7633d5283f5e
--- /dev/null
+++ b/tests/BatteryStatsPerfTest/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.perftests.batterystats">
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.BATTERY_STATS"/>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.perftests.batterystats"/>
+</manifest>
diff --git a/tests/net/smoketest/AndroidTest.xml b/tests/BatteryStatsPerfTest/AndroidTest.xml
index ac366e4ac544..2f9e114756d1 100644
--- a/tests/net/smoketest/AndroidTest.xml
+++ b/tests/BatteryStatsPerfTest/AndroidTest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
+<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,16 +13,16 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Runs Frameworks Networking Smoke Tests.">
+<configuration description="Runs BatteryStats service Performance Tests">
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
- <option name="test-file-name" value="FrameworksNetSmokeTests.apk" />
+ <option name="test-file-name" value="BatteryStatsPerfTests.apk"/>
+ <option name="cleanup-apks" value="true"/>
</target_preparer>
- <option name="test-suite-tag" value="apct" />
- <option name="test-tag" value="FrameworksNetSmokeTests" />
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="com.android.frameworks.tests.net.smoketest" />
- <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
- <option name="hidden-api-checks" value="false"/>
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-tag" value="BatteryStatsPerfTests"/>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.frameworks.perftests.batterystats"/>
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
</test>
</configuration>
diff --git a/tests/BatteryStatsPerfTest/OWNERS b/tests/BatteryStatsPerfTest/OWNERS
new file mode 100644
index 000000000000..4068e2bc03b7
--- /dev/null
+++ b/tests/BatteryStatsPerfTest/OWNERS
@@ -0,0 +1 @@
+include /BATTERY_STATS_OWNERS
diff --git a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryStatsHelperPerfTest.java b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryStatsHelperPerfTest.java
new file mode 100644
index 000000000000..6266cda204b0
--- /dev/null
+++ b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryStatsHelperPerfTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.BatteryStats;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class BatteryStatsHelperPerfTest {
+
+ @Rule
+ public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ /**
+ * Measures the performance of {@link BatteryStatsHelper#getStats()}, which triggers
+ * a battery stats sync on every iteration.
+ */
+ @Test
+ public void testGetStats_forceUpdate() {
+ final Context context = InstrumentationRegistry.getContext();
+ final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
+ true /* collectBatteryBroadcast */);
+ statsHelper.create((Bundle) null);
+ statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ statsHelper.clearStats();
+ state.resumeTiming();
+
+ statsHelper.getStats();
+
+ assertThat(statsHelper.getUsageList()).isNotEmpty();
+ }
+ }
+
+ /**
+ * Measures performance of the {@link BatteryStatsHelper#getStats(boolean)}, which does
+ * not trigger a sync and just returns current values.
+ */
+ @Test
+ public void testGetStats_cached() {
+ final Context context = InstrumentationRegistry.getContext();
+ final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
+ true /* collectBatteryBroadcast */);
+ statsHelper.create((Bundle) null);
+ statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ statsHelper.clearStats();
+ state.resumeTiming();
+
+ statsHelper.getStats(false /* forceUpdate */);
+
+ assertThat(statsHelper.getUsageList()).isNotEmpty();
+ }
+ }
+
+ @Test
+ public void testPowerCalculation() {
+ final Context context = InstrumentationRegistry.getContext();
+ final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
+ true /* collectBatteryBroadcast */);
+ statsHelper.create((Bundle) null);
+ statsHelper.getStats();
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ // This will use the cached BatteryStatsObject
+ statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
+
+ assertThat(statsHelper.getUsageList()).isNotEmpty();
+ }
+ }
+
+ @Test
+ public void testEndToEnd() {
+ final Context context = InstrumentationRegistry.getContext();
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context,
+ true /* collectBatteryBroadcast */);
+ statsHelper.create((Bundle) null);
+ statsHelper.clearStats();
+ statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
+
+ state.pauseTiming();
+
+ List<BatterySipper> usageList = statsHelper.getUsageList();
+ double power = 0;
+ for (int i = 0; i < usageList.size(); i++) {
+ BatterySipper sipper = usageList.get(i);
+ power += sipper.sumPower();
+ }
+
+ assertThat(power).isGreaterThan(0.0);
+
+ state.resumeTiming();
+ }
+ }
+}
diff --git a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java
new file mode 100644
index 000000000000..54d70478f762
--- /dev/null
+++ b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.BatteryStatsManager;
+import android.os.BatteryUsageStats;
+import android.os.UidBatteryConsumer;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class BatteryUsageStatsPerfTest {
+
+ @Rule
+ public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ /**
+ * Measures the performance of {@link BatteryStatsManager#getBatteryUsageStats()},
+ * which triggers a battery stats sync on every iteration.
+ */
+ @Test
+ public void testGetBatteryUsageStats() {
+ final Context context = InstrumentationRegistry.getContext();
+ final BatteryStatsManager batteryStatsManager =
+ context.getSystemService(BatteryStatsManager.class);
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ BatteryUsageStats batteryUsageStats = batteryStatsManager.getBatteryUsageStats();
+
+ state.pauseTiming();
+
+ List<UidBatteryConsumer> uidBatteryConsumers =
+ batteryUsageStats.getUidBatteryConsumers();
+ double power = 0;
+ for (int i = 0; i < uidBatteryConsumers.size(); i++) {
+ UidBatteryConsumer uidBatteryConsumer = uidBatteryConsumers.get(i);
+ power += uidBatteryConsumer.getConsumedPower();
+ }
+
+ assertThat(power).isGreaterThan(0.0);
+
+ state.resumeTiming();
+ }
+ }
+}
diff --git a/tests/BatteryWaster/Android.bp b/tests/BatteryWaster/Android.bp
index 4698910adb40..1fa4f82cd9f4 100644
--- a/tests/BatteryWaster/Android.bp
+++ b/tests/BatteryWaster/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "BatteryWaster",
srcs: ["**/*.java"],
diff --git a/tests/BatteryWaster/AndroidManifest.xml b/tests/BatteryWaster/AndroidManifest.xml
index 0d7f007f15fc..5910c187c6eb 100644
--- a/tests/BatteryWaster/AndroidManifest.xml
+++ b/tests/BatteryWaster/AndroidManifest.xml
@@ -1,14 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.batterywaster">
- <uses-permission android:name="android.permission.DEVICE_POWER" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
+ package="com.android.batterywaster">
+ <uses-permission android:name="android.permission.DEVICE_POWER"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
<application>
- <activity android:name="BatteryWaster" android:label="Battery Waster">
+ <activity android:name="BatteryWaster"
+ android:label="Battery Waster"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/BatteryWaster/OWNERS b/tests/BatteryWaster/OWNERS
new file mode 100644
index 000000000000..4068e2bc03b7
--- /dev/null
+++ b/tests/BatteryWaster/OWNERS
@@ -0,0 +1 @@
+include /BATTERY_STATS_OWNERS
diff --git a/tests/BiDiTests/Android.bp b/tests/BiDiTests/Android.bp
index c659e8c1257e..79ae41fb0c82 100644
--- a/tests/BiDiTests/Android.bp
+++ b/tests/BiDiTests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "BiDiTests",
// Only compile source java files in this apk.
diff --git a/tests/BiDiTests/AndroidManifest.xml b/tests/BiDiTests/AndroidManifest.xml
index 4aead814c8a0..cea5d683a2f9 100644
--- a/tests/BiDiTests/AndroidManifest.xml
+++ b/tests/BiDiTests/AndroidManifest.xml
@@ -15,23 +15,24 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.bidi"
- android:versionCode="1"
- android:versionName="1.0">
+ package="com.android.bidi"
+ android:versionCode="1"
+ android:versionName="1.0">
<application android:label="BiDiTests"
- android:hardwareAccelerated="true"
- android:supportsRtl="true" >
+ android:hardwareAccelerated="true"
+ android:supportsRtl="true">
<activity android:name=".BiDiTestActivity"
- android:windowSoftInputMode="stateAlwaysHidden">
+ android:windowSoftInputMode="stateAlwaysHidden"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="10"
- android:targetSdkVersion="10"/>
+ android:targetSdkVersion="10"/>
</manifest>
diff --git a/tests/BlobStoreTestUtils/Android.bp b/tests/BlobStoreTestUtils/Android.bp
index 53d36389a52a..c4faf7f4fb11 100644
--- a/tests/BlobStoreTestUtils/Android.bp
+++ b/tests/BlobStoreTestUtils/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
java_library {
name: "BlobStoreTestUtils",
srcs: ["src/**/*.java"],
@@ -21,4 +30,4 @@ java_library {
"androidx.test.ext.junit",
],
sdk_version: "test_current",
-} \ No newline at end of file
+}
diff --git a/tests/BlobStoreTestUtils/OWNERS b/tests/BlobStoreTestUtils/OWNERS
new file mode 100644
index 000000000000..65bb6b8a5423
--- /dev/null
+++ b/tests/BlobStoreTestUtils/OWNERS
@@ -0,0 +1 @@
+include /apex/blobstore/OWNERS
diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/FakeBlobData.java
index 2df0024bdea9..56db4f98e160 100644
--- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
+++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/FakeBlobData.java
@@ -35,7 +35,7 @@ import java.security.MessageDigest;
import java.util.Random;
import java.util.concurrent.TimeUnit;
-public class DummyBlobData {
+public class FakeBlobData {
private static final long DEFAULT_SIZE_BYTES = 10 * 1024L * 1024L;
private final Random mRandom;
@@ -47,7 +47,7 @@ public class DummyBlobData {
byte[] mFileDigest;
long mExpiryTimeMs;
- private DummyBlobData(Builder builder) {
+ private FakeBlobData(Builder builder) {
mRandom = new Random(builder.getRandomSeed());
mFile = new File(builder.getContext().getFilesDir(), builder.getFileName());
mFileSize = builder.getFileSize();
@@ -116,8 +116,8 @@ public class DummyBlobData {
return mExpiryDurationMs;
}
- public DummyBlobData build() {
- return new DummyBlobData(this);
+ public FakeBlobData build() {
+ return new FakeBlobData(this);
}
}
diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
index ec859955694c..2d230a74a477 100644
--- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
+++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
@@ -23,6 +23,7 @@ import android.app.blob.BlobStoreManager;
import android.app.blob.LeaseInfo;
import android.content.Context;
import android.content.res.Resources;
+import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.util.Log;
@@ -56,6 +57,16 @@ public class Utils {
}
}
+ public static void writeToSession(BlobStoreManager.Session session, ParcelFileDescriptor input)
+ throws IOException {
+ try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(input)) {
+ try (FileOutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(
+ session.openWrite(0, -1))) {
+ FileUtils.copy(in, out);
+ }
+ }
+ }
+
public static void writeToSession(BlobStoreManager.Session session, ParcelFileDescriptor input,
long lengthBytes) throws IOException {
try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(input)) {
diff --git a/tests/BootImageProfileTest/Android.bp b/tests/BootImageProfileTest/Android.bp
index 1b097a8af0f9..9fb5aa21f985 100644
--- a/tests/BootImageProfileTest/Android.bp
+++ b/tests/BootImageProfileTest/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
java_test_host {
name: "BootImageProfileTest",
srcs: ["src/**/*.java"],
diff --git a/tests/BootImageProfileTest/OWNERS b/tests/BootImageProfileTest/OWNERS
index 657b3f2add2e..7ee0d9a5e77e 100644
--- a/tests/BootImageProfileTest/OWNERS
+++ b/tests/BootImageProfileTest/OWNERS
@@ -1,4 +1,4 @@
-mathieuc@google.com
calin@google.com
+mathieuc@google.com
+ngeoffray@google.com
yawanng@google.com
-sehr@google.com
diff --git a/tests/BrowserPowerTest/Android.bp b/tests/BrowserPowerTest/Android.bp
index 1d358cbe6e75..a8a9897c0e86 100644
--- a/tests/BrowserPowerTest/Android.bp
+++ b/tests/BrowserPowerTest/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "BrowserPowerTests",
libs: [
diff --git a/tests/BrowserPowerTest/AndroidManifest.xml b/tests/BrowserPowerTest/AndroidManifest.xml
index 43eeaad23f8b..003e47ef5642 100644
--- a/tests/BrowserPowerTest/AndroidManifest.xml
+++ b/tests/BrowserPowerTest/AndroidManifest.xml
@@ -13,34 +13,35 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.browserpowertest">
+ package="com.android.browserpowertest">
<!-- We add an application tag here just so that we can indicate that
- this package needs to link against the android.test library,
- which is needed when building test cases. -->
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
<application>
- <uses-library android:name="android.test.runner" />
- <activity android:name="PowerTestActivity" android:label="Power">
+ <uses-library android:name="android.test.runner"/>
+ <activity android:name="PowerTestActivity"
+ android:label="Power"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.TEST"/>
</intent-filter>
</activity>
</application>
<!--
- This declares that this app uses the instrumentation test runner targeting
- the package of browserpowertest. To run the tests use the command:
- "adb shell am instrument -w com.android.browserpowertest/.PowerTestRunner"
- -->
+ This declares that this app uses the instrumentation test runner targeting
+ the package of browserpowertest. To run the tests use the command:
+ "adb shell am instrument -w com.android.browserpowertest/.PowerTestRunner"
+ -->
<instrumentation android:name=".PowerTestRunner"
- android:targetPackage="com.android.browserpowertest"
- android:label="Test runner for Browser Power Tests."
- />
+ android:targetPackage="com.android.browserpowertest"
+ android:label="Test runner for Browser Power Tests."/>
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.WRITE_SDCARD" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.WRITE_SDCARD"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>
diff --git a/tests/Camera2Tests/CameraToo/Android.mk b/tests/Camera2Tests/CameraToo/Android.mk
index 7e5911d65bfa..33473143c8cb 100644
--- a/tests/Camera2Tests/CameraToo/Android.mk
+++ b/tests/Camera2Tests/CameraToo/Android.mk
@@ -17,6 +17,9 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := CameraToo
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under,src)
diff --git a/tests/Camera2Tests/CameraToo/AndroidManifest.xml b/tests/Camera2Tests/CameraToo/AndroidManifest.xml
index a92b5d81f660..2c1b4cbbc7d5 100644
--- a/tests/Camera2Tests/CameraToo/AndroidManifest.xml
+++ b/tests/Camera2Tests/CameraToo/AndroidManifest.xml
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
-
<!--
Copyright (C) 2014 The Android Open Source Project
@@ -17,16 +16,16 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.camera2.cameratoo">
- <uses-permission android:name="android.permission.CAMERA" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ package="com.example.android.camera2.cameratoo">
+ <uses-permission android:name="android.permission.CAMERA"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:label="CameraToo">
- <activity
- android:name=".CameraTooActivity"
- android:screenOrientation="portrait">
+ <activity android:name=".CameraTooActivity"
+ android:screenOrientation="portrait"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/Camera2Tests/CameraToo/tests/Android.mk b/tests/Camera2Tests/CameraToo/tests/Android.mk
index fe4dc42aa7d9..dfa64f1feade 100644
--- a/tests/Camera2Tests/CameraToo/tests/Android.mk
+++ b/tests/Camera2Tests/CameraToo/tests/Android.mk
@@ -17,6 +17,9 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := CameraTooTests
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../NOTICE
LOCAL_INSTRUMENTATION_FOR := CameraToo
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under,src)
diff --git a/tests/Camera2Tests/OWNERS b/tests/Camera2Tests/OWNERS
new file mode 100644
index 000000000000..f48a95c5b3a3
--- /dev/null
+++ b/tests/Camera2Tests/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/av:/camera/OWNERS
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/Android.mk b/tests/Camera2Tests/SmartCamera/SimpleCamera/Android.mk
index 4e3675f78edf..6003628ffb0d 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/Android.mk
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/Android.mk
@@ -32,6 +32,9 @@ LOCAL_SRC_FILES := \
$(call all-renderscript-files-under, src)
LOCAL_PACKAGE_NAME := SmartCamera
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../NOTICE
LOCAL_JNI_SHARED_LIBRARIES := libsmartcamera_jni
include $(BUILD_PACKAGE)
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/AndroidManifest.xml b/tests/Camera2Tests/SmartCamera/SimpleCamera/AndroidManifest.xml
index 06818682192f..35a86500b78a 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/AndroidManifest.xml
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/AndroidManifest.xml
@@ -13,24 +13,27 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- android:versionCode="1"
- android:versionName="1.0"
- package="androidx.media.filterfw.samples.simplecamera">
- <uses-sdk android:minSdkVersion="18" android:targetSdkVersion="19"/>
- <uses-permission android:name="android.permission.CAMERA" />
+ android:versionCode="1"
+ android:versionName="1.0"
+ package="androidx.media.filterfw.samples.simplecamera">
+ <uses-sdk android:minSdkVersion="18"
+ android:targetSdkVersion="19"/>
+ <uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:label="Smart Camera"
- android:debuggable="true">
+ android:debuggable="true">
<uses-library android:name="com.google.android.media.effects"
- android:required="false" />
+ android:required="false"/>
<activity android:name=".SmartCamera"
- android:label="Smart Camera"
- android:screenOrientation="portrait">
+ android:label="Smart Camera"
+ android:screenOrientation="portrait"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp
index a23ac38785f6..b889b0d29a8b 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp
@@ -13,6 +13,15 @@
// limitations under the License.
//
+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"],
+}
+
cc_test_library {
name: "libsmartcamera_jni",
sdk_version: "14",
@@ -33,5 +42,6 @@ cc_test_library {
"-Werror",
"-Wno-unused-parameter",
],
+ header_libs: ["jni_headers"],
stl: "c++_static",
}
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk
index a9000774a13a..c23d593d4f86 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk
@@ -22,6 +22,9 @@ LOCAL_MODULE_TAGS := tests
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_PACKAGE_NAME := SmartCamera-tests
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../../../NOTICE
LOCAL_SRC_FILES += $(call all-java-files-under, src)
diff --git a/tests/CameraPrewarmTest/Android.bp b/tests/CameraPrewarmTest/Android.bp
index eaf453b6f3ae..07c49232efc5 100644
--- a/tests/CameraPrewarmTest/Android.bp
+++ b/tests/CameraPrewarmTest/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "CameraPrewarmTest",
srcs: ["**/*.java"],
diff --git a/tests/CameraPrewarmTest/AndroidManifest.xml b/tests/CameraPrewarmTest/AndroidManifest.xml
index 11b2686d2932..7fafd33620b3 100644
--- a/tests/CameraPrewarmTest/AndroidManifest.xml
+++ b/tests/CameraPrewarmTest/AndroidManifest.xml
@@ -16,35 +16,35 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.cameraprewarm">
+ package="com.google.android.test.cameraprewarm">
<application android:label="@string/activity_title">
<activity android:name=".CameraActivity"
- android:theme="@android:style/Theme.NoTitleBar">
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.media.action.STILL_IMAGE_CAMERA" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.media.action.STILL_IMAGE_CAMERA"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
- <meta-data
- android:name="android.media.still_image_camera_preview_service"
- android:value="com.google.android.test.cameraprewarm.PrewarmService">
+ <meta-data android:name="android.media.still_image_camera_preview_service"
+ android:value="com.google.android.test.cameraprewarm.PrewarmService">
</meta-data>
</activity>
<activity android:name=".SecureCameraActivity"
- android:theme="@android:style/Theme.NoTitleBar">
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.media.action.STILL_IMAGE_CAMERA_SECURE" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.media.action.STILL_IMAGE_CAMERA_SECURE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
- <meta-data
- android:name="android.media.still_image_camera_preview_service"
- android:value="com.google.android.test.cameraprewarm.PrewarmService">
+ <meta-data android:name="android.media.still_image_camera_preview_service"
+ android:value="com.google.android.test.cameraprewarm.PrewarmService">
</meta-data>
</activity>
<service android:name=".PrewarmService"
- android:exported="true">
+ android:exported="true">
</service>
</application>
diff --git a/tests/CanvasCompare/Android.mk b/tests/CanvasCompare/Android.mk
index 6a0a93e1bb24..b82ae65b4356 100644
--- a/tests/CanvasCompare/Android.mk
+++ b/tests/CanvasCompare/Android.mk
@@ -20,6 +20,9 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
LOCAL_PACKAGE_NAME := CanvasCompare
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_MODULE_TAGS := tests
diff --git a/tests/CanvasCompare/AndroidManifest.xml b/tests/CanvasCompare/AndroidManifest.xml
index b55e290a52dd..2734e7f07f27 100644
--- a/tests/CanvasCompare/AndroidManifest.xml
+++ b/tests/CanvasCompare/AndroidManifest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2012 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,37 +13,36 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.hwuicompare" >
+ package="com.android.test.hwuicompare">
- <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <application
- android:label="@string/app_name"
- android:theme="@android:style/Theme.Holo.Light.NoActionBar">
- <activity
- android:name="AutomaticActivity"
- android:label="CanvasAutoCompare" >
+ <application android:label="@string/app_name"
+ android:theme="@android:style/Theme.Holo.Light.NoActionBar">
+ <activity android:name="AutomaticActivity"
+ android:label="CanvasAutoCompare"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity
- android:name="ManualActivity"
- android:label="CanvasManualCompare" >
+ <activity android:name="ManualActivity"
+ android:label="CanvasManualCompare"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
</application>
- <instrumentation
- android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.test.hwuicompare"
- android:label="HW/SW Canvas comparison tool."/>
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.test.hwuicompare"
+ android:label="HW/SW Canvas comparison tool."/>
</manifest>
diff --git a/tests/CanvasCompare/OWNERS b/tests/CanvasCompare/OWNERS
new file mode 100644
index 000000000000..c88a9f82c347
--- /dev/null
+++ b/tests/CanvasCompare/OWNERS
@@ -0,0 +1 @@
+include /libs/hwui/OWNERS
diff --git a/tests/Codegen/Android.bp b/tests/Codegen/Android.bp
index 966c5602959c..ddbf16817b94 100644
--- a/tests/Codegen/Android.bp
+++ b/tests/Codegen/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "CodegenTests",
srcs: [
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
index 475305eb83a2..4259a8620727 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
@@ -32,7 +32,7 @@ public class HierrarchicalDataClassBase implements Parcelable {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -51,7 +51,7 @@ public class HierrarchicalDataClassBase implements Parcelable {
}
@DataClass.Generated.Member
- public HierrarchicalDataClassBase setBaseData( int value) {
+ public @android.annotation.NonNull HierrarchicalDataClassBase setBaseData( int value) {
mBaseData = value;
return this;
}
@@ -98,8 +98,8 @@ public class HierrarchicalDataClassBase implements Parcelable {
};
@DataClass.Generated(
- time = 1582685650576L,
- codegenVersion = "1.0.15",
+ time = 1616541542813L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java",
inputSignatures = "private int mBaseData\nclass HierrarchicalDataClassBase extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
index 150b324d1a30..677094b14fd6 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
@@ -46,7 +46,7 @@ public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -65,7 +65,7 @@ public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase {
}
@DataClass.Generated.Member
- public HierrarchicalDataClassChild setChildData(@NonNull String value) {
+ public @NonNull HierrarchicalDataClassChild setChildData(@NonNull String value) {
mChildData = value;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mChildData);
@@ -120,8 +120,8 @@ public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase {
};
@DataClass.Generated(
- time = 1582685651560L,
- codegenVersion = "1.0.15",
+ time = 1616541543730L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java",
inputSignatures = "private @android.annotation.NonNull java.lang.String mChildData\nclass HierrarchicalDataClassChild extends com.android.codegentest.HierrarchicalDataClassBase implements []\n@com.android.internal.util.DataClass(genParcelable=true, genConstructor=false, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
index 30871566c269..eb260ab6d35d 100644
--- a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
@@ -54,7 +54,7 @@ public class ParcelAllTheThingsDataClass implements Parcelable {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -412,10 +412,10 @@ public class ParcelAllTheThingsDataClass implements Parcelable {
}
@DataClass.Generated(
- time = 1582685649678L,
- codegenVersion = "1.0.15",
+ time = 1616541541942L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java",
- inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\n @java.lang.SuppressWarnings({\"WeakerAccess\"}) @android.annotation.Nullable java.lang.Boolean mNullableBoolean\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)")
+ inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\n @java.lang.SuppressWarnings @android.annotation.Nullable java.lang.Boolean mNullableBoolean\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index 8d421bfa492a..158e0656b574 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -23,7 +23,11 @@ import android.annotation.Size;
import android.annotation.StringDef;
import android.annotation.StringRes;
import android.annotation.UserIdInt;
+import android.companion.ICompanionDeviceManager;
+import android.content.pm.PackageManager;
import android.net.LinkAddress;
+import android.os.Binder;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -86,9 +90,10 @@ public final class SampleDataClass implements Parcelable {
* @see #toString()
* @see State
*/
- public static final int STATE_UNDEFINED = -1;
public static final int STATE_ON = 1;
public static final int STATE_OFF = 0;
+ public static final int STATE_UNDEFINED
+ = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
/**
* {@link IntDef}s with values specified in hex("0x...") are considered to be
@@ -280,6 +285,16 @@ public final class SampleDataClass implements Parcelable {
/**
+ * Binder types are also supported
+ */
+ private @NonNull IBinder mToken = new Binder();
+ /**
+ * AIDL interface types are also supported
+ */
+ private @Nullable ICompanionDeviceManager mIPCInterface = null;
+
+
+ /**
* Manually declaring any method that would otherwise be generated suppresses its generation,
* allowing for fine-grained overrides of the generated behavior.
*/
@@ -342,7 +357,7 @@ public final class SampleDataClass implements Parcelable {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -356,9 +371,9 @@ public final class SampleDataClass implements Parcelable {
@IntDef(prefix = "STATE_", value = {
- STATE_UNDEFINED,
STATE_ON,
- STATE_OFF
+ STATE_OFF,
+ STATE_UNDEFINED
})
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
@DataClass.Generated.Member
@@ -367,12 +382,12 @@ public final class SampleDataClass implements Parcelable {
@DataClass.Generated.Member
public static String stateToString(@State int value) {
switch (value) {
- case STATE_UNDEFINED:
- return "STATE_UNDEFINED";
case STATE_ON:
return "STATE_ON";
case STATE_OFF:
return "STATE_OFF";
+ case STATE_UNDEFINED:
+ return "STATE_UNDEFINED";
default: return Integer.toHexString(value);
}
}
@@ -490,6 +505,10 @@ public final class SampleDataClass implements Parcelable {
*
* Validation annotations following {@link Each} annotation, will be applied for each
* array/collection element instead.
+ * @param token
+ * Binder types are also supported
+ * @param iPCInterface
+ * AIDL interface types are also supported
*/
@DataClass.Generated.Member
public SampleDataClass(
@@ -512,7 +531,9 @@ public final class SampleDataClass implements Parcelable {
@Nullable LinkAddress[] linkAddresses5,
@StringRes int stringRes,
@android.annotation.IntRange(from = 0, to = 6) int dayOfWeek,
- @Size(2) @NonNull @FloatRange(from = 0f) float[] coords) {
+ @Size(2) @NonNull @FloatRange(from = 0f) float[] coords,
+ @NonNull IBinder token,
+ @Nullable ICompanionDeviceManager iPCInterface) {
this.mNum = num;
this.mNum2 = num2;
this.mNum4 = num4;
@@ -560,14 +581,14 @@ public final class SampleDataClass implements Parcelable {
| FLAG_AUGMENTED_REQUEST);
this.mState = state;
- if (!(mState == STATE_UNDEFINED)
- && !(mState == STATE_ON)
- && !(mState == STATE_OFF)) {
+ if (!(mState == STATE_ON)
+ && !(mState == STATE_OFF)
+ && !(mState == STATE_UNDEFINED)) {
throw new java.lang.IllegalArgumentException(
"state was " + mState + " but must be one of: "
- + "STATE_UNDEFINED(" + STATE_UNDEFINED + "), "
+ "STATE_ON(" + STATE_ON + "), "
- + "STATE_OFF(" + STATE_OFF + ")");
+ + "STATE_OFF(" + STATE_OFF + "), "
+ + "STATE_UNDEFINED(" + STATE_UNDEFINED + ")");
}
this.charSeq = charSeq;
@@ -595,6 +616,10 @@ public final class SampleDataClass implements Parcelable {
"from", 0f);
}
+ this.mToken = token;
+ AnnotationValidations.validate(
+ NonNull.class, null, mToken);
+ this.mIPCInterface = iPCInterface;
onConstructed();
}
@@ -795,6 +820,22 @@ public final class SampleDataClass implements Parcelable {
}
/**
+ * Binder types are also supported
+ */
+ @DataClass.Generated.Member
+ public @NonNull IBinder getToken() {
+ return mToken;
+ }
+
+ /**
+ * AIDL interface types are also supported
+ */
+ @DataClass.Generated.Member
+ public @Nullable ICompanionDeviceManager getIPCInterface() {
+ return mIPCInterface;
+ }
+
+ /**
* When using transient fields for caching it's often also a good idea to initialize them
* lazily.
*
@@ -820,7 +861,7 @@ public final class SampleDataClass implements Parcelable {
* pieces in multiple places for each field.
*/
@DataClass.Generated.Member
- public SampleDataClass setNum( int value) {
+ public @NonNull SampleDataClass setNum( int value) {
mNum = value;
return this;
}
@@ -832,7 +873,7 @@ public final class SampleDataClass implements Parcelable {
* @see #mNum2 ..and so should blocks at the bottom, e.g. {@code @see} blocks.
*/
@DataClass.Generated.Member
- public SampleDataClass setNum2( int value) {
+ public @NonNull SampleDataClass setNum2( int value) {
mNum2 = value;
return this;
}
@@ -846,7 +887,7 @@ public final class SampleDataClass implements Parcelable {
* @hide
*/
@DataClass.Generated.Member
- public SampleDataClass setNum4( int value) {
+ public @NonNull SampleDataClass setNum4( int value) {
mNum4 = value;
return this;
}
@@ -855,7 +896,7 @@ public final class SampleDataClass implements Parcelable {
* {@link Nullable} or {@link NonNull} annotation is required on all non-primitive fields.
*/
@DataClass.Generated.Member
- public SampleDataClass setName(@NonNull String value) {
+ public @NonNull SampleDataClass setName(@NonNull String value) {
mName = value;
return this;
}
@@ -868,7 +909,7 @@ public final class SampleDataClass implements Parcelable {
* while mandatory fields are passed via {@link Builder#Builder constructor}.
*/
@DataClass.Generated.Member
- public SampleDataClass setName2(@NonNull String value) {
+ public @NonNull SampleDataClass setName2(@NonNull String value) {
mName2 = value;
AnnotationValidations.validate(
NonNull.class, null, mName2);
@@ -880,7 +921,7 @@ public final class SampleDataClass implements Parcelable {
* {@link #defaultName4 defaultFieldName()} can be defined to compute the default value.
*/
@DataClass.Generated.Member
- public SampleDataClass setName4(@NonNull String value) {
+ public @NonNull SampleDataClass setName4(@NonNull String value) {
mName4 = value;
AnnotationValidations.validate(
NonNull.class, null, mName4);
@@ -892,7 +933,7 @@ public final class SampleDataClass implements Parcelable {
* E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
*/
@DataClass.Generated.Member
- public SampleDataClass setOtherParcelable(@NonNull AccessibilityNodeInfo value) {
+ public @NonNull SampleDataClass setOtherParcelable(@NonNull AccessibilityNodeInfo value) {
mOtherParcelable = value;
return this;
}
@@ -904,7 +945,7 @@ public final class SampleDataClass implements Parcelable {
* @see MyDateParcelling an example {@link Parcelling} implementation
*/
@DataClass.Generated.Member
- public SampleDataClass setDate(@NonNull Date value) {
+ public @NonNull SampleDataClass setDate(@NonNull Date value) {
mDate = value;
AnnotationValidations.validate(
NonNull.class, null, mDate);
@@ -916,7 +957,7 @@ public final class SampleDataClass implements Parcelable {
* to encourage its reuse.
*/
@DataClass.Generated.Member
- public SampleDataClass setPattern(@NonNull Pattern value) {
+ public @NonNull SampleDataClass setPattern(@NonNull Pattern value) {
mPattern = value;
AnnotationValidations.validate(
NonNull.class, null, mPattern);
@@ -929,7 +970,7 @@ public final class SampleDataClass implements Parcelable {
* {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience.
*/
@DataClass.Generated.Member
- public SampleDataClass setLinkAddresses2(@NonNull List<LinkAddress> value) {
+ public @NonNull SampleDataClass setLinkAddresses2(@NonNull List<LinkAddress> value) {
mLinkAddresses2 = value;
AnnotationValidations.validate(
NonNull.class, null, mLinkAddresses2);
@@ -943,7 +984,7 @@ public final class SampleDataClass implements Parcelable {
* @see Builder#addLinkAddress(LinkAddress)
*/
@DataClass.Generated.Member
- public SampleDataClass setLinkAddresses(@NonNull ArrayList<LinkAddress> value) {
+ public @NonNull SampleDataClass setLinkAddresses(@NonNull ArrayList<LinkAddress> value) {
mLinkAddresses = value;
AnnotationValidations.validate(
NonNull.class, null, mLinkAddresses);
@@ -957,7 +998,7 @@ public final class SampleDataClass implements Parcelable {
* @see Builder#setLinkAddresses4(LinkAddress...)
*/
@DataClass.Generated.Member
- public SampleDataClass setLinkAddresses4(@NonNull LinkAddress... value) {
+ public @NonNull SampleDataClass setLinkAddresses4(@NonNull LinkAddress... value) {
mLinkAddresses4 = value;
return this;
}
@@ -970,7 +1011,7 @@ public final class SampleDataClass implements Parcelable {
* @see Builder#setStateName
*/
@DataClass.Generated.Member
- public SampleDataClass setStateName(@StateName @NonNull String value) {
+ public @NonNull SampleDataClass setStateName(@StateName @NonNull String value) {
mStateName = value;
if (!(Objects.equals(mStateName, STATE_NAME_UNDEFINED))
@@ -992,7 +1033,7 @@ public final class SampleDataClass implements Parcelable {
* Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value.
*/
@DataClass.Generated.Member
- public SampleDataClass setFlags(@RequestFlags int value) {
+ public @NonNull SampleDataClass setFlags(@RequestFlags int value) {
mFlags = value;
Preconditions.checkFlagsArgument(
@@ -1007,17 +1048,17 @@ public final class SampleDataClass implements Parcelable {
* Above is true for both {@link IntDef#flag flags} and enum-like {@link IntDef}s
*/
@DataClass.Generated.Member
- public SampleDataClass setState(@State int value) {
+ public @NonNull SampleDataClass setState(@State int value) {
mState = value;
- if (!(mState == STATE_UNDEFINED)
- && !(mState == STATE_ON)
- && !(mState == STATE_OFF)) {
+ if (!(mState == STATE_ON)
+ && !(mState == STATE_OFF)
+ && !(mState == STATE_UNDEFINED)) {
throw new java.lang.IllegalArgumentException(
"state was " + mState + " but must be one of: "
- + "STATE_UNDEFINED(" + STATE_UNDEFINED + "), "
+ "STATE_ON(" + STATE_ON + "), "
- + "STATE_OFF(" + STATE_OFF + ")");
+ + "STATE_OFF(" + STATE_OFF + "), "
+ + "STATE_UNDEFINED(" + STATE_UNDEFINED + ")");
}
return this;
@@ -1036,7 +1077,7 @@ public final class SampleDataClass implements Parcelable {
* @see #SampleDataClass
*/
@DataClass.Generated.Member
- public SampleDataClass setStringRes(@StringRes int value) {
+ public @NonNull SampleDataClass setStringRes(@StringRes int value) {
mStringRes = value;
AnnotationValidations.validate(
StringRes.class, null, mStringRes);
@@ -1051,7 +1092,7 @@ public final class SampleDataClass implements Parcelable {
* @see AnnotationValidations#validate(Class, Size, int, String, int, String, int)
*/
@DataClass.Generated.Member
- public SampleDataClass setDayOfWeek(@android.annotation.IntRange(from = 0, to = 6) int value) {
+ public @NonNull SampleDataClass setDayOfWeek(@android.annotation.IntRange(from = 0, to = 6) int value) {
mDayOfWeek = value;
AnnotationValidations.validate(
android.annotation.IntRange.class, null, mDayOfWeek,
@@ -1070,7 +1111,7 @@ public final class SampleDataClass implements Parcelable {
* @see AnnotationValidations#validate(Class, Size, int, String, int)
*/
@DataClass.Generated.Member
- public SampleDataClass setCoords(@Size(2) @NonNull @FloatRange(from = 0f) float... value) {
+ public @NonNull SampleDataClass setCoords(@Size(2) @NonNull @FloatRange(from = 0f) float... value) {
mCoords = value;
AnnotationValidations.validate(
Size.class, null, mCoords.length,
@@ -1087,6 +1128,26 @@ public final class SampleDataClass implements Parcelable {
return this;
}
+ /**
+ * Binder types are also supported
+ */
+ @DataClass.Generated.Member
+ public @NonNull SampleDataClass setToken(@NonNull IBinder value) {
+ mToken = value;
+ AnnotationValidations.validate(
+ NonNull.class, null, mToken);
+ return this;
+ }
+
+ /**
+ * AIDL interface types are also supported
+ */
+ @DataClass.Generated.Member
+ public @NonNull SampleDataClass setIPCInterface(@NonNull ICompanionDeviceManager value) {
+ mIPCInterface = value;
+ return this;
+ }
+
@Override
@DataClass.Generated.Member
public String toString() {
@@ -1113,7 +1174,9 @@ public final class SampleDataClass implements Parcelable {
"linkAddresses5 = " + java.util.Arrays.toString(mLinkAddresses5) + ", " +
"stringRes = " + mStringRes + ", " +
"dayOfWeek = " + mDayOfWeek + ", " +
- "coords = " + java.util.Arrays.toString(mCoords) +
+ "coords = " + java.util.Arrays.toString(mCoords) + ", " +
+ "token = " + mToken + ", " +
+ "iPCInterface = " + mIPCInterface +
" }";
}
@@ -1149,7 +1212,9 @@ public final class SampleDataClass implements Parcelable {
&& java.util.Arrays.equals(mLinkAddresses5, that.mLinkAddresses5)
&& mStringRes == that.mStringRes
&& mDayOfWeek == that.mDayOfWeek
- && java.util.Arrays.equals(mCoords, that.mCoords);
+ && java.util.Arrays.equals(mCoords, that.mCoords)
+ && Objects.equals(mToken, that.mToken)
+ && Objects.equals(mIPCInterface, that.mIPCInterface);
}
@Override
@@ -1179,6 +1244,8 @@ public final class SampleDataClass implements Parcelable {
_hash = 31 * _hash + mStringRes;
_hash = 31 * _hash + mDayOfWeek;
_hash = 31 * _hash + java.util.Arrays.hashCode(mCoords);
+ _hash = 31 * _hash + Objects.hashCode(mToken);
+ _hash = 31 * _hash + Objects.hashCode(mIPCInterface);
return _hash;
}
@@ -1206,6 +1273,8 @@ public final class SampleDataClass implements Parcelable {
actionInt.acceptInt(this, "stringRes", mStringRes);
actionInt.acceptInt(this, "dayOfWeek", mDayOfWeek);
actionObject.acceptObject(this, "coords", mCoords);
+ actionObject.acceptObject(this, "token", mToken);
+ actionObject.acceptObject(this, "iPCInterface", mIPCInterface);
}
/** @deprecated May cause boxing allocations - use with caution! */
@@ -1232,6 +1301,8 @@ public final class SampleDataClass implements Parcelable {
action.acceptObject(this, "stringRes", mStringRes);
action.acceptObject(this, "dayOfWeek", mDayOfWeek);
action.acceptObject(this, "coords", mCoords);
+ action.acceptObject(this, "token", mToken);
+ action.acceptObject(this, "iPCInterface", mIPCInterface);
}
@DataClass.Generated.Member
@@ -1267,6 +1338,7 @@ public final class SampleDataClass implements Parcelable {
if (mOtherParcelable != null) flg |= 0x40;
if (mLinkAddresses4 != null) flg |= 0x800;
if (mLinkAddresses5 != null) flg |= 0x10000;
+ if (mIPCInterface != null) flg |= 0x200000;
dest.writeLong(flg);
dest.writeInt(mNum);
dest.writeInt(mNum2);
@@ -1288,6 +1360,8 @@ public final class SampleDataClass implements Parcelable {
dest.writeInt(mStringRes);
dest.writeInt(mDayOfWeek);
dest.writeFloatArray(mCoords);
+ dest.writeStrongBinder(mToken);
+ if (mIPCInterface != null) dest.writeStrongInterface(mIPCInterface);
}
@Override
@@ -1324,6 +1398,8 @@ public final class SampleDataClass implements Parcelable {
int stringRes = in.readInt();
int dayOfWeek = in.readInt();
float[] coords = in.createFloatArray();
+ IBinder token = (IBinder) in.readStrongBinder();
+ ICompanionDeviceManager iPCInterface = (flg & 0x200000) == 0 ? null : ICompanionDeviceManager.Stub.asInterface(in.readStrongBinder());
this.mNum = num;
this.mNum2 = num2;
@@ -1372,14 +1448,14 @@ public final class SampleDataClass implements Parcelable {
| FLAG_AUGMENTED_REQUEST);
this.mState = state;
- if (!(mState == STATE_UNDEFINED)
- && !(mState == STATE_ON)
- && !(mState == STATE_OFF)) {
+ if (!(mState == STATE_ON)
+ && !(mState == STATE_OFF)
+ && !(mState == STATE_UNDEFINED)) {
throw new java.lang.IllegalArgumentException(
"state was " + mState + " but must be one of: "
- + "STATE_UNDEFINED(" + STATE_UNDEFINED + "), "
+ "STATE_ON(" + STATE_ON + "), "
- + "STATE_OFF(" + STATE_OFF + ")");
+ + "STATE_OFF(" + STATE_OFF + "), "
+ + "STATE_UNDEFINED(" + STATE_UNDEFINED + ")");
}
this.charSeq = _charSeq;
@@ -1407,6 +1483,10 @@ public final class SampleDataClass implements Parcelable {
"from", 0f);
}
+ this.mToken = token;
+ AnnotationValidations.validate(
+ NonNull.class, null, mToken);
+ this.mIPCInterface = iPCInterface;
onConstructed();
}
@@ -1452,6 +1532,8 @@ public final class SampleDataClass implements Parcelable {
private @StringRes int mStringRes;
private @android.annotation.IntRange(from = 0, to = 6) int mDayOfWeek;
private @Size(2) @NonNull @FloatRange(from = 0f) float[] mCoords;
+ private @NonNull IBinder mToken;
+ private @Nullable ICompanionDeviceManager mIPCInterface;
private long mBuilderFieldsSet = 0L;
@@ -1792,10 +1874,32 @@ public final class SampleDataClass implements Parcelable {
return this;
}
+ /**
+ * Binder types are also supported
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setToken(@NonNull IBinder value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x100000;
+ mToken = value;
+ return this;
+ }
+
+ /**
+ * AIDL interface types are also supported
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setIPCInterface(@NonNull ICompanionDeviceManager value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x200000;
+ mIPCInterface = value;
+ return this;
+ }
+
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull SampleDataClass build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x100000; // Mark builder used
+ mBuilderFieldsSet |= 0x400000; // Mark builder used
if ((mBuilderFieldsSet & 0x10) == 0) {
mName2 = "Bob";
@@ -1839,6 +1943,12 @@ public final class SampleDataClass implements Parcelable {
if ((mBuilderFieldsSet & 0x80000) == 0) {
mCoords = new float[] { 0f, 0f };
}
+ if ((mBuilderFieldsSet & 0x100000) == 0) {
+ mToken = new Binder();
+ }
+ if ((mBuilderFieldsSet & 0x200000) == 0) {
+ mIPCInterface = null;
+ }
SampleDataClass o = new SampleDataClass(
mNum,
mNum2,
@@ -1859,12 +1969,14 @@ public final class SampleDataClass implements Parcelable {
mLinkAddresses5,
mStringRes,
mDayOfWeek,
- mCoords);
+ mCoords,
+ mToken,
+ mIPCInterface);
return o;
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x100000) != 0) {
+ if ((mBuilderFieldsSet & 0x400000) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
@@ -1872,10 +1984,10 @@ public final class SampleDataClass implements Parcelable {
}
@DataClass.Generated(
- time = 1582685647656L,
- codegenVersion = "1.0.15",
+ time = 1616541539978L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
- inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_UNDEFINED\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
+ inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final int STATE_UNDEFINED\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange int mDayOfWeek\nprivate @android.annotation.Size @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange float[] mCoords\nprivate @android.annotation.NonNull android.os.IBinder mToken\nprivate @android.annotation.Nullable android.companion.ICompanionDeviceManager mIPCInterface\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
@Deprecated
private void __metadata() {}
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
index d9fe1fd5a465..a535e227cccf 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
@@ -85,7 +85,7 @@ public class SampleWithCustomBuilder implements Parcelable {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -253,10 +253,10 @@ public class SampleWithCustomBuilder implements Parcelable {
}
@DataClass.Generated(
- time = 1582685648622L,
- codegenVersion = "1.0.15",
+ time = 1616541540898L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java",
- inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nprivate static java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []")
+ inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nprivate static java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
private void __metadata() {}
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
index f98d7b05c2d3..d40962456741 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
@@ -36,7 +36,7 @@ public class SampleWithNestedDataClasses {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -135,8 +135,8 @@ public class SampleWithNestedDataClasses {
};
@DataClass.Generated(
- time = 1582685653406L,
- codegenVersion = "1.0.15",
+ time = 1616541545539L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull java.lang.String mBar\nclass NestedDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
@@ -160,7 +160,7 @@ public class SampleWithNestedDataClasses {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -259,8 +259,8 @@ public class SampleWithNestedDataClasses {
};
@DataClass.Generated(
- time = 1582685653415L,
- codegenVersion = "1.0.15",
+ time = 1616541545548L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull long mBaz2\nclass NestedDataClass3 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
@@ -274,7 +274,7 @@ public class SampleWithNestedDataClasses {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -373,8 +373,8 @@ public class SampleWithNestedDataClasses {
};
@DataClass.Generated(
- time = 1582685653420L,
- codegenVersion = "1.0.15",
+ time = 1616541545552L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull java.lang.String mBaz\nclass NestedDataClass2 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
index 6b4fc2fa157f..3583b95fb4ce 100644
--- a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
+++ b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
@@ -15,10 +15,16 @@
*/
package com.android.codegentest;
+import android.annotation.IntRange;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageManager;
import com.android.internal.util.DataClass;
+import java.util.List;
+import java.util.Set;
+
/**
* Test for some false positive pitfalls for
* {@link android.processor.staledataclass.StaleDataclassProcessor}
@@ -46,12 +52,19 @@ public class StaleDataclassDetectorFalsePositivesTest {
/* Initializers should be ignored */
{}
+ /* Wildcard type argument should work correctly */
+ @Nullable
+ private List<Set<?>> mUsesWildcards = null;
+
/** Unrelated methods should be noted, without triggering staleness false positives */
public @NonNull String someMethod(int param) { return null; }
+ /** Inlined constants in annotation args should be fine */
+ private @IntRange(from = PackageManager.PERMISSION_GRANTED) void annotatedWithConstArg() {}
- // Code below generated by codegen v1.0.15.
+
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -64,11 +77,22 @@ public class StaleDataclassDetectorFalsePositivesTest {
//@formatter:off
+ @DataClass.Generated.Member
+ public @Nullable List<Set<?>> getUsesWildcards() {
+ return mUsesWildcards;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull StaleDataclassDetectorFalsePositivesTest setUsesWildcards(@NonNull List<Set<?>> value) {
+ mUsesWildcards = value;
+ return this;
+ }
+
@DataClass.Generated(
- time = 1582685652436L,
- codegenVersion = "1.0.15",
+ time = 1616541544639L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java",
- inputSignatures = "public @android.annotation.NonNull java.lang.String someMethod(int)\nclass StaleDataclassDetectorFalsePositivesTest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)")
+ inputSignatures = "private @android.annotation.Nullable java.util.List<java.util.Set<?>> mUsesWildcards\npublic @android.annotation.NonNull java.lang.String someMethod(int)\nprivate @android.annotation.IntRange void annotatedWithConstArg()\nclass StaleDataclassDetectorFalsePositivesTest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/tests/Compatibility/Android.bp b/tests/Compatibility/Android.bp
index 7dc44fa4a260..c58c99e1c4f0 100644
--- a/tests/Compatibility/Android.bp
+++ b/tests/Compatibility/Android.bp
@@ -12,7 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-android_test {
+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"],
+}
+
+android_test_helper_app {
name: "AppCompatibilityTest",
static_libs: ["androidx.test.rules"],
// Include all test java files.
diff --git a/tests/Compatibility/OWNERS b/tests/Compatibility/OWNERS
new file mode 100644
index 000000000000..f8c3520e9fa8
--- /dev/null
+++ b/tests/Compatibility/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/compat/OWNERS
diff --git a/tests/CoreTests/android/Android.bp b/tests/CoreTests/android/Android.bp
index 24134e8fb7f0..e2f194b04437 100644
--- a/tests/CoreTests/android/Android.bp
+++ b/tests/CoreTests/android/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "LegacyCoreTests",
srcs: ["**/*.java"],
diff --git a/tests/DataIdleTest/Android.bp b/tests/DataIdleTest/Android.bp
index 19656ce32b29..f9509cc9a4bf 100644
--- a/tests/DataIdleTest/Android.bp
+++ b/tests/DataIdleTest/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "DataIdleTest",
platform_apis: true,
diff --git a/tests/DozeTest/Android.bp b/tests/DozeTest/Android.bp
index f1be029f58d5..36ea91a84a0d 100644
--- a/tests/DozeTest/Android.bp
+++ b/tests/DozeTest/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_app {
name: "DozeTest",
// Only compile source java files in this apk.
diff --git a/tests/DozeTest/OWNERS b/tests/DozeTest/OWNERS
new file mode 100644
index 000000000000..2e96c97c8bb3
--- /dev/null
+++ b/tests/DozeTest/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/OWNERS
diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
index fa292bd0d57a..6985702c24e6 100644
--- a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
+++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
@@ -83,7 +83,7 @@ public class DozeTestDream extends DreamService {
filter.addAction(intent.getAction());
registerReceiver(mAlarmReceiver, filter);
mAlarmIntent = PendingIntent.getBroadcast(this, 0, intent,
- PendingIntent.FLAG_CANCEL_CURRENT);
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
setDozeScreenState(DISPLAY_STATE_WHEN_DOZING);
}
diff --git a/tests/DpiTest/Android.bp b/tests/DpiTest/Android.bp
index 7d6a78ba1581..52bb08bbc8ad 100644
--- a/tests/DpiTest/Android.bp
+++ b/tests/DpiTest/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "DensityTest",
srcs: ["**/*.java"],
diff --git a/tests/DpiTest/AndroidManifest.xml b/tests/DpiTest/AndroidManifest.xml
index a4d8c7973141..cf4c21dbe128 100644
--- a/tests/DpiTest/AndroidManifest.xml
+++ b/tests/DpiTest/AndroidManifest.xml
@@ -15,26 +15,34 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.dpi">
- <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="3" />
- <supports-screens android:smallScreens="true" />
+ package="com.google.android.test.dpi">
+ <uses-sdk android:minSdkVersion="3"
+ android:targetSdkVersion="3"/>
+ <supports-screens android:smallScreens="true"/>
<compatible-screens>
- <screen android:screenSize="small" android:screenDensity="ldpi" />
- <screen android:screenSize="small" android:screenDensity="xhdpi" />
- <screen android:screenSize="large" android:screenDensity="hdpi" />
- <screen android:screenSize="xlarge" android:screenDensity="mdpi" />
+ <screen android:screenSize="small"
+ android:screenDensity="ldpi"/>
+ <screen android:screenSize="small"
+ android:screenDensity="xhdpi"/>
+ <screen android:screenSize="large"
+ android:screenDensity="hdpi"/>
+ <screen android:screenSize="xlarge"
+ android:screenDensity="mdpi"/>
</compatible-screens>
<application android:label="DpiTest">
- <activity android:name="DpiTestActivity">
+ <activity android:name="DpiTestActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="DpiTestNoCompatActivity" android:label="DpiTestNoCompat">
+ <activity android:name="DpiTestNoCompatActivity"
+ android:label="DpiTestNoCompat"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
index 01c1c70f3f2a..cf501aed1dd5 100644
--- a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
+++ b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
@@ -19,23 +19,23 @@ package com.google.android.test.dpi;
import android.app.Activity;
import android.app.ActivityThread;
import android.app.Application;
-import android.os.Bundle;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import android.widget.ScrollView;
-import android.view.LayoutInflater;
-import android.view.View;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
public class DpiTestActivity extends Activity {
public DpiTestActivity() {
@@ -64,7 +64,7 @@ public class DpiTestActivity extends Activity {
| ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
app.getResources().setCompatibilityInfo(new CompatibilityInfo(ai,
getResources().getConfiguration().screenLayout,
- getResources().getConfiguration().smallestScreenWidthDp, false));
+ getResources().getConfiguration().smallestScreenWidthDp, false, 1f));
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException("ouch", e);
diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.mk b/tests/DynamicCodeLoggerIntegrationTests/Android.mk
index 62c1ba89653c..dab83046c28f 100644
--- a/tests/DynamicCodeLoggerIntegrationTests/Android.mk
+++ b/tests/DynamicCodeLoggerIntegrationTests/Android.mk
@@ -22,6 +22,9 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := DynamicCodeLoggerTestLibrary
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/dcl)
include $(BUILD_JAVA_LIBRARY)
@@ -35,9 +38,11 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := DynamicCodeLoggerNativeTestLibrary
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
LOCAL_SRC_FILES := src/cpp/com_android_dcl_Jni.cpp
-LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE)
+LOCAL_HEADER_LIBRARIES := jni_headers
LOCAL_SDK_VERSION := 28
LOCAL_NDK_STL_VARIANT := c++_static
@@ -49,6 +54,9 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := DynamicCodeLoggerNativeExecutable
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
LOCAL_SRC_FILES := src/cpp/test_executable.cpp
include $(BUILD_EXECUTABLE)
@@ -81,4 +89,7 @@ LOCAL_JAVA_RESOURCE_FILES := \
$(dynamiccodeloggertest_jar) \
$(dynamiccodeloggertest_executable) \
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
include $(BUILD_PACKAGE)
diff --git a/tests/FeatureSplit/base/Android.bp b/tests/FeatureSplit/base/Android.bp
index ab25464a82fc..89c26d2c2256 100644
--- a/tests/FeatureSplit/base/Android.bp
+++ b/tests/FeatureSplit/base/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test_helper_app {
name: "FeatureSplitBase",
srcs: ["**/*.java"],
diff --git a/tests/FeatureSplit/base/AndroidManifest.xml b/tests/FeatureSplit/base/AndroidManifest.xml
index e82b3b9d45fc..1bc07ef413df 100644
--- a/tests/FeatureSplit/base/AndroidManifest.xml
+++ b/tests/FeatureSplit/base/AndroidManifest.xml
@@ -15,15 +15,17 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.split.feature">
+ package="com.android.test.split.feature">
- <uses-sdk android:minSdkVersion="21" />
+ <uses-sdk android:minSdkVersion="21"/>
<application android:label="@string/app_title">
- <activity android:name=".ActivityMain" android:label="Feature Base">
+ <activity android:name=".ActivityMain"
+ android:label="Feature Base"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/FeatureSplit/feature1/Android.bp b/tests/FeatureSplit/feature1/Android.bp
index 706a4f544393..2f8aa8b6eb28 100644
--- a/tests/FeatureSplit/feature1/Android.bp
+++ b/tests/FeatureSplit/feature1/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "FeatureSplit1",
srcs: ["**/*.java"],
diff --git a/tests/FeatureSplit/feature1/AndroidManifest.xml b/tests/FeatureSplit/feature1/AndroidManifest.xml
index 086c2c33422d..4581a85b3efb 100644
--- a/tests/FeatureSplit/feature1/AndroidManifest.xml
+++ b/tests/FeatureSplit/feature1/AndroidManifest.xml
@@ -15,17 +15,19 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.split.feature"
- featureSplit="feature1">
+ package="com.android.test.split.feature"
+ featureSplit="feature1">
- <uses-sdk android:minSdkVersion="21" />
- <uses-split android:name="feature2" />
+ <uses-sdk android:minSdkVersion="21"/>
+ <uses-split android:name="feature2"/>
<application>
- <activity android:name=".one.One" android:label="Feature One">
+ <activity android:name=".one.One"
+ android:label="Feature One"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/FeatureSplit/feature2/Android.bp b/tests/FeatureSplit/feature2/Android.bp
index a3634821f6fd..2a5c432d1499 100644
--- a/tests/FeatureSplit/feature2/Android.bp
+++ b/tests/FeatureSplit/feature2/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "FeatureSplit2",
srcs: ["**/*.java"],
diff --git a/tests/FixVibrateSetting/Android.bp b/tests/FixVibrateSetting/Android.bp
index 5608a2b5e15d..bd7c701026ba 100644
--- a/tests/FixVibrateSetting/Android.bp
+++ b/tests/FixVibrateSetting/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_app {
name: "FixVibrateSetting",
srcs: ["**/*.java"],
diff --git a/tests/FixVibrateSetting/AndroidManifest.xml b/tests/FixVibrateSetting/AndroidManifest.xml
index 007d6821498b..c2d5918a4681 100644
--- a/tests/FixVibrateSetting/AndroidManifest.xml
+++ b/tests/FixVibrateSetting/AndroidManifest.xml
@@ -1,13 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.fixvibratesetting">
- <uses-permission android:name="android.permission.VIBRATE" />
+ package="com.android.fixvibratesetting">
+ <uses-permission android:name="android.permission.VIBRATE"/>
<application>
- <activity android:name="FixVibrateSetting" android:label="@string/app_label">
+ <activity android:name="FixVibrateSetting"
+ android:label="@string/app_label"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/FixVibrateSetting/OWNERS b/tests/FixVibrateSetting/OWNERS
new file mode 100644
index 000000000000..cc63ceb2c7ad
--- /dev/null
+++ b/tests/FixVibrateSetting/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/vibrator/OWNERS
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 05f0a8e7921d..217a72b90fd4 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -14,17 +14,62 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "FlickerTests",
- srcs: ["src/**/*.java"],
+ srcs: ["src/**/*.java", "src/**/*.kt"],
+ manifest: "AndroidManifest.xml",
+ test_config: "AndroidTest.xml",
platform_apis: true,
certificate: "platform",
test_suites: ["device-tests"],
libs: ["android.test.runner"],
static_libs: [
+ "androidx.test.ext.junit",
"flickertestapplib",
"flickerlib",
"truth-prebuilt",
- "app-helpers-core",
+ "launcher-helper-lib",
+ "launcher-aosp-tapl",
+ "platform-test-annotations",
],
}
+
+java_library {
+ name: "wm-flicker-common-assertions",
+ platform_apis: true,
+ srcs: [
+ "src/**/*Assertions.java",
+ "src/**/*Assertions.kt",
+ ],
+ exclude_srcs: [
+ "**/helpers/*",
+ ],
+ static_libs: [
+ "flickerlib",
+ "truth-prebuilt",
+ "app-helpers-core"
+ ],
+}
+
+java_library {
+ name: "wm-flicker-common-app-helpers",
+ platform_apis: true,
+ srcs: [
+ "**/helpers/*"
+ ],
+ static_libs: [
+ "flickerlib",
+ "flickertestapplib",
+ "truth-prebuilt",
+ "app-helpers-core"
+ ],
+} \ No newline at end of file
diff --git a/tests/FlickerTests/AndroidManifest.xml b/tests/FlickerTests/AndroidManifest.xml
index 91fb7c12b392..fda609196456 100644
--- a/tests/FlickerTests/AndroidManifest.xml
+++ b/tests/FlickerTests/AndroidManifest.xml
@@ -17,19 +17,31 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.wm.flicker">
- <uses-sdk android:minSdkVersion="27" android:targetSdkVersion="27"/>
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <!-- Allow the test to write directly to /sdcard/ -->
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<!-- Write secure settings -->
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<!-- Capture screen contents -->
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
<!-- Enable / Disable tracing !-->
<uses-permission android:name="android.permission.DUMP" />
+ <!-- Force-stop test apps -->
+ <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
<!-- Run layers trace -->
<uses-permission android:name="android.permission.HARDWARE_TEST"/>
- <application>
+ <!-- Capture screen recording -->
+ <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/>
+ <!-- Workaround grant runtime permission exception from b/152733071 -->
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
+ <uses-permission android:name="android.permission.READ_LOGS"/>
+ <!-- ATM.removeRootTasksWithActivityTypes() -->
+ <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
+ <!-- Allow the test to write directly to /sdcard/ -->
+ <application android:requestLegacyExternalStorage="true">
<uses-library android:name="android.test.runner"/>
</application>
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index d1da47f0f9d8..896ec9ae922c 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -9,6 +9,16 @@
<option name="screen-always-on" value="on" />
<!-- prevents the phone from restarting -->
<option name="force-skip-system-props" value="true" />
+ <!-- set WM tracing verbose level to all -->
+ <option name="run-command" value="cmd window tracing level all" />
+ <!-- set WM tracing to frame (avoid incomplete states) -->
+ <option name="run-command" value="cmd window tracing frame" />
+ <!-- restart launcher to activate TAPL -->
+ <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.DeviceCleaner">
+ <!-- reboot the device to teardown any crashed tests -->
+ <option name="cleanup-action" value="REBOOT" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true"/>
@@ -17,9 +27,8 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.server.wm.flicker"/>
- <option name="exclude-annotation" value="org.junit.Ignore" />
<option name="shell-timeout" value="6600s" />
- <option name="test-timeout" value="6000s" />
+ <option name="test-timeout" value="6600s" />
<option name="hidden-api-checks" value="false" />
</test>
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
diff --git a/tests/FlickerTests/OWNERS b/tests/FlickerTests/OWNERS
new file mode 100644
index 000000000000..b5561010e7f9
--- /dev/null
+++ b/tests/FlickerTests/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 909476
+include /services/core/java/com/android/server/wm/OWNERS
+natanieljr@google.com \ No newline at end of file
diff --git a/tests/FlickerTests/README.md b/tests/FlickerTests/README.md
index a7c9e20e0a07..6b28fdf8a8ef 100644
--- a/tests/FlickerTests/README.md
+++ b/tests/FlickerTests/README.md
@@ -1,146 +1,88 @@
# Flicker Test Library
## Motivation
-Detect *flicker* &mdash; any discontinuous, or unpredictable behavior seen during UI transitions that is not due to performance. This is often the result of a logic error in the code and difficult to identify because the issue is transient and at times difficult to reproduce. This library helps create integration tests between `SurfaceFlinger`, `WindowManager` and `SystemUI` to identify flicker.
+This set of tests use the flickerlib from `platform_testing/libraries/flicker` to execute a set of common UI transitions to detect discontinuous or unpredictable behavior.
-## Adding a Test
-The library builds and runs UI transitions, captures Winscope traces and exposes common assertions that can be tested against each trace.
-
-### Building Transitions
-Start by defining common or error prone transitions using `TransitionRunner`.
-```java
-// Example: Build a transition that cold launches an app from launcher
-TransitionRunner transition = TransitionRunner.newBuilder()
- // Specify a tag to identify the transition (optional)
- .withTag("OpenAppCold_" + testApp.getLauncherName())
-
- // Specify preconditions to setup the device
- // Wake up device and go to home screen
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
-
- // Setup transition under test
- // Press the home button and close the app to test a cold start
- .runBefore(device::pressHome)
- .runBefore(testApp::exit)
-
- // Run the transition under test
- // Open the app and wait for UI to be idle
- // This is the part of the transition that will be tested.
- .run(testApp::open)
- .run(device::waitForIdle)
-
- // Perform any tear downs
- // Close the app
- .runAfterAll(testApp::exit)
-
- // Number of times to repeat the transition to catch any flaky issues
- .repeat(5);
-```
-
-
-Run the transition to get a list of `TransitionResult` for each time the transition is repeated.
-```java
- List<TransitionResult> results = transition.run();
-```
-`TransitionResult` contains paths to test artifacts such as Winscope traces and screen recordings.
-
-
-### Checking Assertions
-Each `TransitionResult` can be tested using an extension of the Google Truth library, `LayersTraceSubject` and `WmTraceSubject`. They try to balance test principles set out by Google Truth (not supporting nested assertions, keeping assertions simple) with providing support for common assertion use cases.
-
-Each trace can be represented as a ordered collection of trace entries, with an associated timestamp. Each trace entry has common assertion checks. The trace subjects expose methods to filter the range of entries and test for changing assertions.
-
-```java
- TransitionResult result = results.get(0);
- Rect displayBounds = getDisplayBounds();
+The tests are organized in packages according to the transitions they test (e.g., `rotation`, `splitscreen`).
- // check all trace entries
- assertThat(result).coversRegion(displayBounds).forAllEntries();
-
- // check a range of entries
- assertThat(result).coversRegion(displayBounds).forRange(startTime, endTime);
-
- // check first entry
- assertThat(result).coversRegion(displayBounds).inTheBeginning();
+## Adding a Test
- // check last entry
- assertThat(result).coversRegion(displayBounds).atTheEnd();
+By default tests should inherit from `RotationTestBase` or `NonRotationTestBase` and must override the variable `transitionToRun` (Kotlin) or the function `getTransitionToRun()` (Java).
+Only tests that are not supported by these classes should inherit directly from the `FlickerTestBase` class.
- // check a change in assertions, e.g. wallpaper window is visible,
- // then wallpaper window becomes and stays invisible
- assertThat(result)
- .showsBelowAppWindow("wallpaper")
- .then()
- .hidesBelowAppWindow("wallpaper")
- .forAllEntries();
-```
+### Rotation animations and transitions
-All assertions return `Result` which contains a `success` flag, `assertionName` string identifier, and `reason` string to provide actionable details to the user. The `reason` string is build along the way with all the details as to why the assertions failed and any hints which might help the user determine the root cause. Failed assertion message will also contain a path to the trace that was tested. Example of a failed test:
+Tests that rotate the device should inherit from `RotationTestBase`.
+Tests that inherit from the class automatically receive start and end rotation values.
+Moreover, these tests inherit the following checks:
+* all regions on the screen are covered
+* status bar is always visible
+* status bar rotates
+* nav bar is always visible
+* nav bar is rotates
-```
- java.lang.AssertionError: Not true that <com.android.server.wm.flicker.LayersTrace@65da4cc>
- Layers Trace can be found in: /layers_trace_emptyregion.pb
- Timestamp: 2308008331271
- Assertion: coversRegion
- Reason: Region to test: Rect(0, 0 - 1440, 2880)
- first empty point: 0, 99
- visible regions:
- StatusBar#0Rect(0, 0 - 1440, 98)
- NavigationBar#0Rect(0, 2712 - 1440, 2880)
- ScreenDecorOverlay#0Rect(0, 0 - 1440, 91)
- ...
- at com.google.common.truth.FailureStrategy.fail(FailureStrategy.java:24)
- ...
-```
+The default tests can be disabled by overriding the respective methods and including an `@Ignore` annotation.
----
+### Non-Rotation animations and transitions
-## Running Tests
+`NonRotationTestBase` was created to make it easier to write tests that do not involve rotation (e.g., `Pip`, `split screen` or `IME`).
+Tests that inherit from the class are automatically executed twice: once in portrait and once in landscape mode and the assertions are checked independently.
+Moreover, these tests inherit the following checks:
+* all regions on the screen are covered
+* status bar is always visible
+* nav bar is always visible
-The tests can be run as any other Android JUnit tests. `platform_testing/tests/flicker` uses the library to test common UI transitions. Run `atest FlickerTest` to execute these tests.
+The default tests can be disabled by overriding the respective methods and including an `@Ignore` annotation.
----
+### Exceptional cases
-## Other Topics
-### Monitors
-Monitors capture test artifacts for each transition run. They are started before each iteration of the test transition (after the `runBefore` calls) and stopped after the transition is completed. Each iteration will produce a new test artifact. The following monitors are available:
+Tests that rotate the device should inherit from `RotationTestBase`.
+This class allows the test to be freely configured and does not provide any assertions.
-#### LayersTraceMonitor
-Captures Layers trace. This monitor is started by default. Build a transition with `skipLayersTrace()` to disable this monitor.
-#### WindowManagerTraceMonitor
-Captures Window Manager trace. This monitor is started by default. Build a transition with `skipWindowManagerTrace()` to disable this monitor.
-#### WindowAnimationFrameStatsMonitor
-Captures WindowAnimationFrameStats for the transition. This monitor is started by default and is used to eliminate *janky* runs. If an iteration has skipped frames, as determined by WindowAnimationFrameStats, the results for the iteration is skipped. If the list of results is empty after all iterations are completed, then the test should fail. Build a transition with `includeJankyRuns()` to disable this monitor.
-#### ScreenRecorder
-Captures screen to a video file. This monitor is disabled by default. Build a transition with `recordEachRun()` to capture each transition or build with `recordAllRuns()` to capture every transition including setup and teardown.
----
+### Example
-### Extending Assertions
-
-To add a new assertion, add a function to one of the trace entry classes, `LayersTrace.Entry` or `WindowManagerTrace.Entry`.
+Start by defining common or error prone transitions using `TransitionRunner`.
+```kotlin
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class MyTest(
+ beginRotationName: String,
+ beginRotation: Int
+) : NonRotationTestBase(beginRotationName, beginRotation) {
+ init {
+ mTestApp = MyAppHelper(InstrumentationRegistry.getInstrumentation())
+ }
-```java
- // Example adds an assertion to the check if layer is hidden by parent.
- Result isHiddenByParent(String layerName) {
- // Result should contain a details if assertion fails for any reason
- // such as if layer is not found or layer is not hidden by parent
- // or layer has no parent.
- // ...
+ override val transitionToRun: TransitionRunner
+ get() = TransitionRunner.newBuilder()
+ .withTag("myTest")
+ .recordAllRuns()
+ .runBefore { device.pressHome() }
+ .runBefore { device.waitForIdle() }
+ .run { testApp.open() }
+ .runAfter{ testApp.exit() }
+ .repeat(2)
+ .includeJankyRuns()
+ .build()
+
+ @Test
+ fun myWMTest() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAppWindow(MyTestApp)
+ .forAllEntries()
+ }
}
-```
-Then add a function to the trace subject `LayersTraceSubject` or `WmTraceSubject` which will add the assertion for testing. When the assertion is evaluated, the trace will first be filtered then the assertion will be applied to the remaining entries.
-```java
- public LayersTraceSubject isHiddenByParent(String layerName) {
- mChecker.add(entry -> entry.isHiddenByParent(layerName),
- "isHiddenByParent(" + layerName + ")");
- return this;
+ @Test
+ fun mySFTest() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer(MyTestApp)
+ .forAllEntries()
+ }
}
+}
```
-
-To use the new assertion:
-```java
- // Check if "Chrome" layer is hidden by parent in the first trace entry.
- assertThat(result).isHiddenByParent("Chrome").inTheBeginning();
-``` \ No newline at end of file
diff --git a/tests/FlickerTests/TEST_MAPPING b/tests/FlickerTests/TEST_MAPPING
deleted file mode 100644
index db251b907caa..000000000000
--- a/tests/FlickerTests/TEST_MAPPING
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "postsubmit": [
- // Run tests on real device
- {
- "name": "FlickerTests",
- "keywords": ["primary-device"]
- },
- // Also run the tests in the cloud
- {
- "name": "FlickerTests"
- }
- ]
-} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java
deleted file mode 100644
index 5a66e805c575..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static android.view.Surface.rotationToString;
-
-import static com.android.server.wm.flicker.CommonTransitions.changeAppRotation;
-import static com.android.server.wm.flicker.WindowUtils.getAppPosition;
-import static com.android.server.wm.flicker.WindowUtils.getNavigationBarPosition;
-import static com.android.server.wm.flicker.WindowUtils.getStatusBarPosition;
-import static com.android.server.wm.flicker.WmTraceSubject.assertThat;
-
-import android.graphics.Rect;
-import android.util.Log;
-import android.view.Surface;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-/**
- * Cycle through supported app rotations.
- * To run this test: {@code atest FlickerTest:ChangeAppRotationTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class ChangeAppRotationTest extends FlickerTestBase {
- private int mBeginRotation;
- private int mEndRotation;
-
- public ChangeAppRotationTest(String beginRotationName, String endRotationName,
- int beginRotation, int endRotation) {
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- this.mBeginRotation = beginRotation;
- this.mEndRotation = endRotation;
- }
-
- @Parameters(name = "{0}-{1}")
- public static Collection<Object[]> getParams() {
- int[] supportedRotations =
- {Surface.ROTATION_0, Surface.ROTATION_90};
- Collection<Object[]> params = new ArrayList<>();
- for (int begin : supportedRotations) {
- for (int end : supportedRotations) {
- if (begin != end) {
- params.add(new Object[]{rotationToString(begin), rotationToString(end), begin,
- end});
- }
- }
- }
- return params;
- }
-
- @Before
- public void runTransition() {
- super.runTransition(
- changeAppRotation(mTestApp, mUiDevice, mBeginRotation, mEndRotation)
- .includeJankyRuns().build());
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults(result -> assertThat(result)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults(result -> assertThat(result)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkPosition_navBarLayerRotatesAndScales() {
- Rect startingPos = getNavigationBarPosition(mBeginRotation);
- Rect endingPos = getNavigationBarPosition(mEndRotation);
- checkResults(result -> {
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
- .inTheBeginning();
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, endingPos).atTheEnd();
- }
- );
- }
-
- @Test
- public void checkPosition_appLayerRotates() {
- Rect startingPos = getAppPosition(mBeginRotation);
- Rect endingPos = getAppPosition(mEndRotation);
- Log.e(TAG, "startingPos=" + startingPos + " endingPos=" + endingPos);
- checkResults(result -> {
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(mTestApp.getPackage(), startingPos).inTheBeginning();
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(mTestApp.getPackage(), endingPos).atTheEnd();
- }
- );
- }
-
- @Test
- public void checkPosition_statusBarLayerScales() {
- Rect startingPos = getStatusBarPosition(mBeginRotation);
- Rect endingPos = getStatusBarPosition(mEndRotation);
- checkResults(result -> {
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(STATUS_BAR_WINDOW_TITLE, startingPos)
- .inTheBeginning();
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(STATUS_BAR_WINDOW_TITLE, endingPos).atTheEnd();
- }
- );
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_navBarLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_statusBarLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java
deleted file mode 100644
index 022f798e82f5..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToApp;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test IME window closing back to app window transitions.
- * To run this test: {@code atest FlickerTests:CloseImeWindowToAppTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class CloseImeAutoOpenWindowToAppTest extends CloseImeWindowToAppTest {
-
- public CloseImeAutoOpenWindowToAppTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- mTestApp = new ImeAppAutoFocusHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Before
- public void runTransition() {
- run(editTextLoseFocusToApp((ImeAppAutoFocusHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build());
- }
-
- @FlakyTest(bugId = 141458352)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_imeLayerBecomesInvisible() {
- super.checkVisibility_imeLayerBecomesInvisible();
- }
-
- @FlakyTest(bugId = 141458352)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_imeAppLayerIsAlwaysVisible() {
- super.checkVisibility_imeAppLayerIsAlwaysVisible();
- }
-
- @FlakyTest(bugId = 141458352)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_imeAppWindowIsAlwaysVisible() {
- super.checkVisibility_imeAppWindowIsAlwaysVisible();
- }
-
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java
deleted file mode 100644
index d6f994b5c0d5..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToHome;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test IME window closing back to app window transitions.
- * To run this test: {@code atest FlickerTests:CloseImeWindowToAppTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class CloseImeAutoOpenWindowToHomeTest extends CloseImeWindowToHomeTest {
-
- public CloseImeAutoOpenWindowToHomeTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- mTestApp = new ImeAppAutoFocusHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Before
- public void runTransition() {
- run(editTextLoseFocusToHome((ImeAppAutoFocusHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build());
- }
-
- @FlakyTest(bugId = 141458352)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_imeWindowBecomesInvisible() {
- super.checkVisibility_imeWindowBecomesInvisible();
- }
-
- @FlakyTest(bugId = 141458352)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_imeLayerBecomesInvisible() {
- super.checkVisibility_imeLayerBecomesInvisible();
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java
deleted file mode 100644
index 28da3af2b7c5..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToApp;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test IME window closing back to app window transitions.
- * To run this test: {@code atest FlickerTests:CloseImeWindowToAppTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class CloseImeWindowToAppTest extends NonRotationTestBase {
-
- static final String IME_WINDOW_TITLE = "InputMethod";
-
- public CloseImeWindowToAppTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- mTestApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Before
- public void runTransition() {
- run(editTextLoseFocusToApp((ImeAppHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build());
- }
-
- @Test
- public void checkVisibility_imeLayerBecomesInvisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(IME_WINDOW_TITLE)
- .then()
- .hidesLayer(IME_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_imeAppLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(mTestApp.getPackage())
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_imeAppWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAppWindowOnTop(mTestApp.getPackage())
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java
deleted file mode 100644
index f740af9b89bf..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToHome;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test IME window closing to home transitions.
- * To run this test: {@code atest FlickerTests:CloseImeWindowToHomeTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class CloseImeWindowToHomeTest extends NonRotationTestBase {
-
- static final String IME_WINDOW_TITLE = "InputMethod";
-
- public CloseImeWindowToHomeTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- mTestApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Before
- public void runTransition() {
- run(editTextLoseFocusToHome((ImeAppHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build());
- }
-
- @Test
- public void checkVisibility_imeWindowBecomesInvisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsImeWindow(IME_WINDOW_TITLE)
- .then()
- .hidesImeWindow(IME_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @Ignore("Flaky")
- @Test
- public void checkVisibility_imeLayerBecomesInvisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(IME_WINDOW_TITLE)
- .then()
- .hidesLayer(IME_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @Ignore("Flaky")
- @Test
- public void checkVisibility_imeAppLayerBecomesInvisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(mTestApp.getPackage())
- .then()
- .hidesLayer(mTestApp.getPackage())
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_imeAppWindowBecomesInvisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAppWindowOnTop(mTestApp.getPackage())
- .then()
- .hidesAppWindowOnTop(mTestApp.getPackage())
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
new file mode 100644
index 000000000000..a540dffb3c9c
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker
+
+import android.platform.helpers.IAppHelper
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.NAV_BAR_LAYER_NAME
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.NAV_BAR_WINDOW_NAME
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_LAYER_NAME
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_WINDOW_NAME
+
+val HOME_WINDOW_TITLE = arrayOf("Wallpaper", "Launcher")
+
+fun FlickerTestParameter.statusBarWindowIsAlwaysVisible() {
+ assertWm {
+ this.showsAboveAppWindow(STATUS_BAR_WINDOW_NAME)
+ }
+}
+
+fun FlickerTestParameter.navBarWindowIsAlwaysVisible() {
+ assertWm {
+ this.showsAboveAppWindow(NAV_BAR_WINDOW_NAME)
+ }
+}
+
+fun FlickerTestParameter.launcherReplacesAppWindowAsTopWindow(testApp: IAppHelper) {
+ assertWm {
+ this.showsAppWindowOnTop(testApp.getPackage())
+ .then()
+ .showsAppWindowOnTop(*HOME_WINDOW_TITLE)
+ }
+}
+
+fun FlickerTestParameter.launcherWindowBecomesVisible() {
+ assertWm {
+ this.hidesBelowAppWindow(*HOME_WINDOW_TITLE)
+ .then()
+ .showsBelowAppWindow(*HOME_WINDOW_TITLE)
+ }
+}
+
+fun FlickerTestParameter.launcherWindowBecomesInvisible() {
+ assertWm {
+ this.showsBelowAppWindow(*HOME_WINDOW_TITLE)
+ .then()
+ .hidesBelowAppWindow(*HOME_WINDOW_TITLE)
+ }
+}
+
+fun FlickerTestParameter.appWindowAlwaysVisibleOnTop(packageName: String) {
+ assertWm {
+ this.showsAppWindowOnTop(packageName)
+ }
+}
+
+fun FlickerTestParameter.appWindowBecomesVisible(appName: String) {
+ assertWm {
+ this.hidesAppWindow(appName)
+ .then()
+ .showsAppWindow(appName)
+ }
+}
+
+fun FlickerTestParameter.appWindowBecomesInVisible(appName: String) {
+ assertWm {
+ this.showsAppWindow(appName)
+ .then()
+ .hidesAppWindow(appName)
+ }
+}
+
+@JvmOverloads
+fun FlickerTestParameter.noUncoveredRegions(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ allStates: Boolean = true
+) {
+ val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
+ val endingBounds = WindowUtils.getDisplayBounds(endRotation)
+ if (allStates) {
+ assertLayers {
+ if (startingBounds == endingBounds) {
+ this.coversAtLeast(startingBounds)
+ } else {
+ this.coversAtLeast(startingBounds)
+ .then()
+ .coversAtLeast(endingBounds)
+ }
+ }
+ } else {
+ assertLayersStart {
+ this.visibleRegion().coversAtLeast(startingBounds)
+ }
+ assertLayersEnd {
+ this.visibleRegion().coversAtLeast(endingBounds)
+ }
+ }
+}
+
+@JvmOverloads
+fun FlickerTestParameter.navBarLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
+ if (rotatesScreen) {
+ assertLayers {
+ this.isVisible(NAV_BAR_LAYER_NAME)
+ .then()
+ .isInvisible(NAV_BAR_LAYER_NAME)
+ .then()
+ .isVisible(NAV_BAR_LAYER_NAME)
+ }
+ } else {
+ assertLayers {
+ this.isVisible(NAV_BAR_LAYER_NAME)
+ }
+ }
+}
+
+@JvmOverloads
+fun FlickerTestParameter.statusBarLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
+ if (rotatesScreen) {
+ assertLayers {
+ this.isVisible(STATUS_BAR_LAYER_NAME)
+ .then()
+ .isInvisible(STATUS_BAR_LAYER_NAME)
+ .then()
+ .isVisible(STATUS_BAR_LAYER_NAME)
+ }
+ } else {
+ assertLayers {
+ this.isVisible(STATUS_BAR_LAYER_NAME)
+ }
+ }
+}
+
+@JvmOverloads
+fun FlickerTestParameter.navBarLayerRotatesAndScales(
+ beginRotation: Int,
+ endRotation: Int = beginRotation
+) {
+ val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
+ val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
+
+ assertLayersStart {
+ this.visibleRegion(NAV_BAR_LAYER_NAME).coversExactly(startingPos)
+ }
+ assertLayersEnd {
+ this.visibleRegion(NAV_BAR_LAYER_NAME).coversExactly(endingPos)
+ }
+}
+
+@JvmOverloads
+fun FlickerTestParameter.statusBarLayerRotatesScales(
+ beginRotation: Int,
+ endRotation: Int = beginRotation
+) {
+ val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
+ val endingPos = WindowUtils.getStatusBarPosition(endRotation)
+
+ assertLayersStart {
+ this.visibleRegion(STATUS_BAR_LAYER_NAME).coversExactly(startingPos)
+ }
+ assertLayersEnd {
+ this.visibleRegion(STATUS_BAR_LAYER_NAME).coversExactly(endingPos)
+ }
+}
+
+fun FlickerTestParameter.appLayerReplacesLauncher(appName: String) {
+ assertLayers {
+ this.isVisible(*HOME_WINDOW_TITLE)
+ .then()
+ .isVisible(appName)
+ }
+}
+
+fun FlickerTestParameter.launcherLayerReplacesApp(testApp: IAppHelper) {
+ assertLayers {
+ this.isVisible(testApp.getPackage())
+ .then()
+ .isInvisible(testApp.getPackage())
+ .isVisible(*HOME_WINDOW_TITLE)
+ }
+}
+
+fun FlickerTestParameter.layerBecomesVisible(packageName: String) {
+ assertLayers {
+ this.isInvisible(packageName)
+ .then()
+ .isVisible(packageName)
+ }
+}
+
+fun FlickerTestParameter.layerBecomesInvisible(packageName: String) {
+ assertLayers {
+ this.isVisible(packageName)
+ .then()
+ .isInvisible(packageName)
+ }
+}
+
+fun FlickerTestParameter.focusChanges(vararg windows: String) {
+ assertEventLog {
+ this.focusChanges(windows)
+ }
+}
+
+fun FlickerTestParameter.focusDoesNotChange() {
+ assertEventLog {
+ this.focusDoesNotChange()
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
deleted file mode 100644
index e033d0ab9578..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static android.os.SystemClock.sleep;
-import static android.view.Surface.rotationToString;
-
-import static com.android.server.wm.flicker.helpers.AutomationUtils.clearRecents;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.closePipWindow;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.exitSplitScreen;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.expandPipWindow;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.launchSplitScreen;
-import static com.android.server.wm.flicker.helpers.AutomationUtils.stopPackage;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.RemoteException;
-import android.platform.helpers.IAppHelper;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import android.util.Rational;
-import android.view.Surface;
-
-import com.android.server.wm.flicker.TransitionRunner.TransitionBuilder;
-import com.android.server.wm.flicker.helpers.AutomationUtils;
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-import com.android.server.wm.flicker.helpers.PipAppHelper;
-
-/**
- * Collection of common transitions which can be used to test different apps or scenarios.
- */
-class CommonTransitions {
-
- public static final int ITERATIONS = 1;
- private static final String TAG = "FLICKER";
- private static final long APP_LAUNCH_TIMEOUT = 10000;
-
- private static void setRotation(UiDevice device, int rotation) {
- try {
- switch (rotation) {
- case Surface.ROTATION_270:
- device.setOrientationLeft();
- break;
-
- case Surface.ROTATION_90:
- device.setOrientationRight();
- break;
-
- case Surface.ROTATION_0:
- default:
- device.setOrientationNatural();
- }
- // Wait for animation to complete
- sleep(1000);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- static TransitionBuilder openAppWarm(IAppHelper testApp, UiDevice
- device, int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag("OpenAppWarm_" + testApp.getLauncherName()
- + rotationToString(beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBeforeAll(() -> setRotation(device, beginRotation))
- .runBeforeAll(testApp::open)
- .runBefore(device::pressHome)
- .runBefore(device::waitForIdle)
- .runBefore(() -> setRotation(device, beginRotation))
- .run(testApp::open)
- .runAfterAll(testApp::exit)
- .runAfterAll(AutomationUtils::setDefaultWait)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder closeAppWithBackKey(IAppHelper testApp, UiDevice
- device) {
- return TransitionRunner.newBuilder()
- .withTag("closeAppWithBackKey_" + testApp.getLauncherName())
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(testApp::open)
- .runBefore(device::waitForIdle)
- .run(device::pressBack)
- .run(device::waitForIdle)
- .runAfterAll(testApp::exit)
- .runAfterAll(AutomationUtils::setDefaultWait)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder closeAppWithHomeKey(IAppHelper testApp, UiDevice
- device) {
- return TransitionRunner.newBuilder()
- .withTag("closeAppWithHomeKey_" + testApp.getLauncherName())
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(testApp::open)
- .runBefore(device::waitForIdle)
- .run(device::pressHome)
- .run(device::waitForIdle)
- .runAfterAll(testApp::exit)
- .runAfterAll(AutomationUtils::setDefaultWait)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder openAppCold(IAppHelper testApp,
- UiDevice device, int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag("OpenAppCold_" + testApp.getLauncherName()
- + rotationToString(beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBeforeAll(() -> setRotation(device, beginRotation))
- .runBefore(testApp::exit)
- .runBefore(device::waitForIdle)
- .run(testApp::open)
- .runAfterAll(testApp::exit)
- .runAfterAll(() -> setRotation(device, Surface.ROTATION_0))
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder changeAppRotation(IAppHelper testApp, UiDevice
- device, int beginRotation, int endRotation) {
- return TransitionRunner.newBuilder()
- .withTag("changeAppRotation_" + testApp.getLauncherName()
- + rotationToString(beginRotation) + "_" +
- rotationToString(endRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBeforeAll(testApp::open)
- .runBefore(() -> setRotation(device, beginRotation))
- .run(() -> setRotation(device, endRotation))
- .runAfterAll(testApp::exit)
- .runAfterAll(() -> setRotation(device, Surface.ROTATION_0))
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder changeAppRotation(Intent intent, String intentId, Context context,
- UiDevice
- device, int beginRotation, int endRotation) {
- final String testTag = "changeAppRotation_" + intentId + "_" +
- rotationToString(beginRotation) + "_" + rotationToString(endRotation);
- return TransitionRunner.newBuilder()
- .withTag(testTag)
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBeforeAll(() -> {
- context.startActivity(intent);
- device.wait(Until.hasObject(By.pkg(intent.getComponent()
- .getPackageName()).depth(0)), APP_LAUNCH_TIMEOUT);
- }
- )
- .runBefore(() -> setRotation(device, beginRotation))
- .run(() -> setRotation(device, endRotation))
- .runAfterAll(() -> stopPackage(context, intent.getComponent().getPackageName()))
- .runAfterAll(() -> setRotation(device, Surface.ROTATION_0))
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder appToSplitScreen(IAppHelper testApp, UiDevice device) {
- return TransitionRunner.newBuilder()
- .withTag("appToSplitScreen_" + testApp.getLauncherName())
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(testApp::open)
- .runBefore(device::waitForIdle)
- .runBefore(() -> sleep(500))
- .run(() -> launchSplitScreen(device))
- .runAfter(() -> exitSplitScreen(device))
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder splitScreenToLauncher(IAppHelper testApp, UiDevice device) {
- return TransitionRunner.newBuilder()
- .withTag("splitScreenToLauncher_" + testApp.getLauncherName())
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(testApp::open)
- .runBefore(device::waitForIdle)
- .runBefore(() -> launchSplitScreen(device))
- .run(() -> exitSplitScreen(device))
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder editTextSetFocus(ImeAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag("editTextSetFocus_" + testApp.getLauncherName()
- + rotationToString(beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBefore(() -> setRotation(device, beginRotation))
- .runBefore(testApp::open)
- .run(() -> testApp.clickEditTextWidget(device))
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder resizeSplitScreen(IAppHelper testAppTop, ImeAppHelper testAppBottom,
- UiDevice device, int beginRotation, Rational startRatio, Rational stopRatio) {
- String testTag = "resizeSplitScreen_" + testAppTop.getLauncherName() + "_"
- + testAppBottom.getLauncherName() + "_"
- + startRatio.toString().replace("/", ":") + "_to_"
- + stopRatio.toString().replace("/", ":") + "_"
- + rotationToString(beginRotation);
- return TransitionRunner.newBuilder()
- .withTag(testTag)
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBeforeAll(() -> setRotation(device, beginRotation))
- .runBeforeAll(() -> clearRecents(device))
- .runBefore(testAppBottom::open)
- .runBefore(device::pressHome)
- .runBefore(testAppTop::open)
- .runBefore(device::waitForIdle)
- .runBefore(() -> launchSplitScreen(device))
- .runBefore(() -> {
- UiObject2 snapshot = device.findObject(
- By.res(device.getLauncherPackageName(), "snapshot"));
- snapshot.click();
- })
- .runBefore(() -> testAppBottom.clickEditTextWidget(device))
- .runBefore(() -> AutomationUtils.resizeSplitScreen(device, startRatio))
- .run(() -> AutomationUtils.resizeSplitScreen(device, stopRatio))
- .runAfter(() -> exitSplitScreen(device))
- .runAfter(device::pressHome)
- .runAfterAll(testAppTop::exit)
- .runAfterAll(testAppBottom::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder editTextLoseFocusToHome(ImeAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag("editTextLoseFocusToHome_" + testApp.getLauncherName()
- + rotationToString(beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBefore(() -> setRotation(device, beginRotation))
- .runBefore(testApp::open)
- .runBefore(() -> testApp.clickEditTextWidget(device))
- .run(device::pressHome)
- .run(device::waitForIdle)
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder editTextLoseFocusToApp(ImeAppHelper testApp, UiDevice device,
- int beginRotation) {
- return TransitionRunner.newBuilder()
- .withTag("editTextLoseFocusToApp_" + testApp.getLauncherName()
- + rotationToString(beginRotation))
- .recordAllRuns()
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBefore(() -> setRotation(device, beginRotation))
- .runBefore(testApp::open)
- .runBefore(() -> testApp.clickEditTextWidget(device))
- .run(device::pressBack)
- .run(device::waitForIdle)
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder enterPipMode(PipAppHelper testApp, UiDevice device) {
- return TransitionRunner.newBuilder()
- .withTag("enterPipMode_" + testApp.getLauncherName())
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBefore(testApp::open)
- .run(() -> testApp.clickEnterPipButton(device))
- .runAfter(() -> closePipWindow(device))
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder exitPipModeToHome(PipAppHelper testApp, UiDevice device) {
- return TransitionRunner.newBuilder()
- .withTag("exitPipModeToHome_" + testApp.getLauncherName())
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBefore(testApp::open)
- .runBefore(() -> testApp.clickEnterPipButton(device))
- .run(() -> closePipWindow(device))
- .run(device::waitForIdle)
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-
- static TransitionBuilder exitPipModeToApp(PipAppHelper testApp, UiDevice device) {
- return TransitionRunner.newBuilder()
- .withTag("exitPipModeToApp_" + testApp.getLauncherName())
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
- .runBefore(device::pressHome)
- .runBefore(testApp::open)
- .runBefore(() -> testApp.clickEnterPipButton(device))
- .run(() -> expandPipWindow(device))
- .run(device::waitForIdle)
- .runAfterAll(testApp::exit)
- .repeat(ITERATIONS);
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java
deleted file mode 100644
index 8f0177c7afc5..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import android.platform.helpers.IAppHelper;
-import android.support.test.uiautomator.UiDevice;
-import android.util.Rational;
-import android.view.Surface;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-import com.android.server.wm.flicker.helpers.PipAppHelper;
-
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-
-/**
- * Tests to help debug individual transitions, capture video recordings and create test cases.
- */
-@LargeTest
-@Ignore("Used for debugging transitions used in FlickerTests.")
-@RunWith(AndroidJUnit4.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class DebugTest {
- private IAppHelper testApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- private UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-
- /**
- * atest FlickerTests:DebugTest#openAppCold
- */
- @Test
- public void openAppCold() {
- CommonTransitions.openAppCold(testApp, uiDevice, Surface.ROTATION_0)
- .recordAllRuns().build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#openAppWarm
- */
- @Test
- public void openAppWarm() {
- CommonTransitions.openAppWarm(testApp, uiDevice, Surface.ROTATION_0)
- .recordAllRuns().build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#changeOrientationFromNaturalToLeft
- */
- @Test
- public void changeOrientationFromNaturalToLeft() {
- CommonTransitions.changeAppRotation(testApp, uiDevice, Surface.ROTATION_0,
- Surface.ROTATION_270).recordAllRuns().build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#closeAppWithBackKey
- */
- @Test
- public void closeAppWithBackKey() {
- CommonTransitions.closeAppWithBackKey(testApp, uiDevice).recordAllRuns().build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#closeAppWithHomeKey
- */
- @Test
- public void closeAppWithHomeKey() {
- CommonTransitions.closeAppWithHomeKey(testApp, uiDevice).recordAllRuns().build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#openAppToSplitScreen
- */
- @Test
- public void openAppToSplitScreen() {
- CommonTransitions.appToSplitScreen(testApp, uiDevice).includeJankyRuns().recordAllRuns()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#splitScreenToLauncher
- */
- @Test
- public void splitScreenToLauncher() {
- CommonTransitions.splitScreenToLauncher(testApp,
- uiDevice).includeJankyRuns().recordAllRuns()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#resizeSplitScreen
- */
- @Test
- public void resizeSplitScreen() {
- ImeAppHelper bottomApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.resizeSplitScreen(testApp, bottomApp, uiDevice, Surface.ROTATION_0,
- new Rational(1, 3), new Rational(2, 3))
- .includeJankyRuns().recordEachRun().build().run();
- }
-
- // IME tests
-
- /**
- * atest FlickerTests:DebugTest#editTextSetFocus
- */
- @Test
- public void editTextSetFocus() {
- ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.editTextSetFocus(testApp, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns().recordEachRun()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#editTextLoseFocusToHome
- */
- @Test
- public void editTextLoseFocusToHome() {
- ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.editTextLoseFocusToHome(testApp, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns().recordEachRun()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#editTextLoseFocusToApp
- */
- @Test
- public void editTextLoseFocusToApp() {
- ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.editTextLoseFocusToHome(testApp, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns().recordEachRun()
- .build().run();
- }
-
- // PIP tests
-
- /**
- * atest FlickerTests:DebugTest#enterPipMode
- */
- @Test
- public void enterPipMode() {
- PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.enterPipMode(testApp, uiDevice).includeJankyRuns().recordEachRun()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#exitPipModeToHome
- */
- @Test
- public void exitPipModeToHome() {
- PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.exitPipModeToHome(testApp, uiDevice).includeJankyRuns().recordEachRun()
- .build().run();
- }
-
- /**
- * atest FlickerTests:DebugTest#exitPipModeToApp
- */
- @Test
- public void exitPipModeToApp() {
- PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation());
- CommonTransitions.exitPipModeToApp(testApp, uiDevice).includeJankyRuns().recordEachRun()
- .build().run();
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java
deleted file mode 100644
index 883d59ea8a92..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.server.wm.flicker.helpers.AutomationUtils.setDefaultWait;
-
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import android.os.Bundle;
-import android.platform.helpers.IAppHelper;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.uiautomator.UiDevice;
-import android.util.Log;
-
-import com.android.server.wm.flicker.TransitionRunner.TransitionResult;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.function.Consumer;
-
-/**
- * Base class of all Flicker test that performs common functions for all flicker tests:
- * <p>
- * - Caches transitions so that a transition is run once and the transition results are used by
- * tests multiple times. This is needed for parameterized tests which call the BeforeClass methods
- * multiple times.
- * - Keeps track of all test artifacts and deletes ones which do not need to be reviewed.
- * - Fails tests if results are not available for any test due to jank.
- */
-public class FlickerTestBase {
- public static final String TAG = "FLICKER";
- static final String NAVIGATION_BAR_WINDOW_TITLE = "NavigationBar";
- static final String STATUS_BAR_WINDOW_TITLE = "StatusBar";
- static final String DOCKED_STACK_DIVIDER = "DockedStackDivider";
- private static HashMap<String, List<TransitionResult>> transitionResults =
- new HashMap<>();
- IAppHelper mTestApp;
- UiDevice mUiDevice;
- private List<TransitionResult> mResults;
- private TransitionResult mLastResult = null;
-
- @Before
- public void setUp() {
- InstrumentationRegistry.registerInstance(getInstrumentation(), new Bundle());
- mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- }
-
- /**
- * Teardown any system settings and clean up test artifacts from the file system.
- *
- * Note: test artifacts for failed tests will remain on the device.
- */
- @AfterClass
- public static void teardown() {
- setDefaultWait();
- transitionResults.values().stream()
- .flatMap(List::stream)
- .forEach(result -> {
- if (result.canDelete()) {
- result.delete();
- } else {
- if (result.layersTraceExists()) {
- Log.e(TAG, "Layers trace saved to " + result.getLayersTracePath());
- }
- if (result.windowManagerTraceExists()) {
- Log.e(TAG, "WindowManager trace saved to " + result
- .getWindowManagerTracePath
- ());
- }
- if (result.screenCaptureVideoExists()) {
- Log.e(TAG, "Screen capture video saved to " + result
- .screenCaptureVideo.toString());
- }
- }
- });
- }
-
- /**
- * Runs a transition, returns a cached result if the transition has run before.
- */
- void run(TransitionRunner transition) {
- if (transitionResults.containsKey(transition.getTestTag())) {
- mResults = transitionResults.get(transition.getTestTag());
- return;
- }
- mResults = transition.run().getResults();
- /* Fail if we don't have any results due to jank */
- assertWithMessage("No results to test because all transition runs were invalid because "
- + "of Jank").that(mResults).isNotEmpty();
- transitionResults.put(transition.getTestTag(), mResults);
- }
-
- /**
- * Runs a transition, returns a cached result if the transition has run before.
- */
- void runTransition(TransitionRunner transition) {
- run(transition);
- }
-
- /**
- * Goes through a list of transition results and checks assertions on each result.
- */
- void checkResults(Consumer<TransitionResult> assertion) {
-
- for (TransitionResult result : mResults) {
- mLastResult = result;
- assertion.accept(result);
- }
- mLastResult = null;
- }
-
- /**
- * Kludge to mark a file for saving. If {@code checkResults} fails, the last result is not
- * cleared. This indicates the assertion failed for the result, so mark it for saving.
- */
- @After
- public void markArtifactsForSaving() {
- if (mLastResult != null) {
- mLastResult.flagForSaving();
- }
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java b/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java
deleted file mode 100644
index 54941dc0f585..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static android.view.Surface.rotationToString;
-
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
-
-import android.graphics.Rect;
-import android.view.Surface;
-
-import androidx.test.filters.FlakyTest;
-
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-public abstract class NonRotationTestBase extends FlickerTestBase {
-
- int mBeginRotation;
-
- public NonRotationTestBase(String beginRotationName, int beginRotation) {
- this.mBeginRotation = beginRotation;
- }
-
- @Parameters(name = "{0}")
- public static Collection<Object[]> getParams() {
- int[] supportedRotations =
- {Surface.ROTATION_0, Surface.ROTATION_90};
- Collection<Object[]> params = new ArrayList<>();
-
- for (int begin : supportedRotations) {
- params.add(new Object[]{rotationToString(begin), begin});
- }
-
- return params;
- }
-
- @FlakyTest(bugId = 141361128)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkCoveredRegion_noUncoveredRegions() {
- Rect displayBounds = getDisplayBounds(mBeginRotation);
- checkResults(result -> LayersTraceSubject.assertThat(result).coversRegion(
- displayBounds).forAllEntries());
- }
-
- @FlakyTest(bugId = 141361128)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_navBarLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @FlakyTest(bugId = 141361128)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkVisibility_statusBarLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java
deleted file mode 100644
index efdfaee60e64..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.openAppCold;
-import static com.android.server.wm.flicker.WmTraceSubject.assertThat;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test cold launch app from launcher.
- * To run this test: {@code atest FlickerTests:OpenAppColdTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class OpenAppColdTest extends NonRotationTestBase {
-
- public OpenAppColdTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- }
-
- @Before
- public void runTransition() {
- run(openAppCold(mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build());
- }
-
- @Test
- public void checkVisibility_wallpaperWindowBecomesInvisible() {
- checkResults(result -> assertThat(result)
- .showsBelowAppWindow("Wallpaper")
- .then()
- .hidesBelowAppWindow("Wallpaper")
- .forAllEntries());
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkZOrder_appWindowReplacesLauncherAsTopWindow() {
- checkResults(result -> assertThat(result)
- .showsAppWindowOnTop(
- "com.android.launcher3/.Launcher")
- .then()
- .showsAppWindowOnTop(mTestApp.getPackage())
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_wallpaperLayerBecomesInvisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer("Wallpaper")
- .then()
- .hidesLayer("Wallpaper")
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java
deleted file mode 100644
index f8b7938901a8..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.appToSplitScreen;
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-
-/**
- * Test open app to split screen.
- * To run this test: {@code atest FlickerTests:OpenAppToSplitScreenTest}
- */
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class OpenAppToSplitScreenTest extends FlickerTestBase {
-
- public OpenAppToSplitScreenTest() {
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- }
-
- @Before
- public void runTransition() {
- super.runTransition(appToSplitScreen(mTestApp, mUiDevice).includeJankyRuns().build());
- }
-
- @Test
- public void checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkVisibility_dividerWindowBecomesVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .hidesAboveAppWindow(DOCKED_STACK_DIVIDER)
- .then()
- .showsAboveAppWindow(DOCKED_STACK_DIVIDER)
- .forAllEntries());
- }
-
- @Test
- public void checkCoveredRegion_noUncoveredRegions() {
- checkResults(result ->
- LayersTraceSubject.assertThat(result)
- .coversRegion(getDisplayBounds()).forAllEntries());
- }
-
- @Test
- public void checkVisibility_navBarLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkVisibility_statusBarLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkVisibility_dividerLayerBecomesVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hidesLayer(DOCKED_STACK_DIVIDER)
- .then()
- .showsLayer(DOCKED_STACK_DIVIDER)
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java
deleted file mode 100644
index 7ce6315f529a..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.openAppWarm;
-import static com.android.server.wm.flicker.WmTraceSubject.assertThat;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test warm launch app.
- * To run this test: {@code atest FlickerTests:OpenAppWarmTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class OpenAppWarmTest extends NonRotationTestBase {
-
- public OpenAppWarmTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- }
-
- @Before
- public void runTransition() {
- super.runTransition(openAppWarm(mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build());
- }
-
- @Test
- public void checkVisibility_wallpaperBecomesInvisible() {
- checkResults(result -> assertThat(result)
- .showsBelowAppWindow("Wallpaper")
- .then()
- .hidesBelowAppWindow("Wallpaper")
- .forAllEntries());
- }
-
- @FlakyTest(bugId = 140855415)
- @Ignore("Waiting bug feedback")
- @Test
- public void checkZOrder_appWindowReplacesLauncherAsTopWindow() {
- checkResults(result -> assertThat(result)
- .showsAppWindowOnTop(
- "com.android.launcher3/.Launcher")
- .then()
- .showsAppWindowOnTop(mTestApp.getPackage())
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_wallpaperLayerBecomesInvisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer("Wallpaper")
- .then()
- .hidesLayer("Wallpaper")
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java
deleted file mode 100644
index 91d4a056d8fb..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.editTextSetFocus;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test IME window opening transitions.
- * To run this test: {@code atest FlickerTests:OpenImeWindowTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class OpenImeWindowTest extends NonRotationTestBase {
-
- private static final String IME_WINDOW_TITLE = "InputMethod";
-
- public OpenImeWindowTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- mTestApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- }
-
- @Before
- public void runTransition() {
- run(editTextSetFocus((ImeAppHelper) mTestApp, mUiDevice, mBeginRotation)
- .includeJankyRuns().build());
- }
-
- @Test
- public void checkVisibility_imeWindowBecomesVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .hidesImeWindow(IME_WINDOW_TITLE)
- .then()
- .showsImeWindow(IME_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_imeLayerBecomesVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hidesLayer(IME_WINDOW_TITLE)
- .then()
- .showsLayer(IME_WINDOW_TITLE)
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java
deleted file mode 100644
index 29b624005495..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.resizeSplitScreen;
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
-import static com.android.server.wm.flicker.WindowUtils.getDockedStackDividerInset;
-import static com.android.server.wm.flicker.WindowUtils.getNavigationBarHeight;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.graphics.Rect;
-import android.util.Rational;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import com.android.server.wm.flicker.helpers.ImeAppHelper;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-
-/**
- * Test split screen resizing window transitions.
- * To run this test: {@code atest FlickerTests:ResizeSplitScreenTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 140854698)
-@Ignore("Waiting bug feedback")
-public class ResizeSplitScreenTest extends NonRotationTestBase {
-
- private static String sSimpleActivity = "SimpleActivity";
- private static String sImeActivity = "ImeActivity";
-
- public ResizeSplitScreenTest(String beginRotationName, int beginRotation) {
- super(beginRotationName, beginRotation);
-
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- }
-
- @Before
- public void runTransition() {
- ImeAppHelper bottomApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
- run(resizeSplitScreen(mTestApp, bottomApp, mUiDevice, mBeginRotation,
- new Rational(1, 3), new Rational(2, 3))
- .includeJankyRuns().build());
- }
-
- @Test
- public void checkVisibility_topAppLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(sSimpleActivity)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_bottomAppLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(sImeActivity)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_dividerLayerIsAlwaysVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(DOCKED_STACK_DIVIDER)
- .forAllEntries());
- }
-
- @Test
- public void checkPosition_appsStartingBounds() {
- Rect displayBounds = getDisplayBounds();
- checkResults(result -> {
- LayersTrace entries = LayersTrace.parseFrom(result.getLayersTrace(),
- result.getLayersTracePath());
-
- assertThat(entries.getEntries()).isNotEmpty();
- Rect startingDividerBounds = entries.getEntries().get(0).getVisibleBounds
- (DOCKED_STACK_DIVIDER);
-
- Rect startingTopAppBounds = new Rect(0, 0, startingDividerBounds.right,
- startingDividerBounds.top + getDockedStackDividerInset());
-
- Rect startingBottomAppBounds = new Rect(0,
- startingDividerBounds.bottom - getDockedStackDividerInset(),
- displayBounds.right,
- displayBounds.bottom - getNavigationBarHeight());
-
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion("SimpleActivity", startingTopAppBounds)
- .inTheBeginning();
-
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion("ImeActivity", startingBottomAppBounds)
- .inTheBeginning();
- });
- }
-
- @Test
- public void checkPosition_appsEndingBounds() {
- Rect displayBounds = getDisplayBounds();
- checkResults(result -> {
- LayersTrace entries = LayersTrace.parseFrom(result.getLayersTrace(),
- result.getLayersTracePath());
-
- assertThat(entries.getEntries()).isNotEmpty();
- Rect endingDividerBounds = entries.getEntries().get(
- entries.getEntries().size() - 1).getVisibleBounds(
- DOCKED_STACK_DIVIDER);
-
- Rect startingTopAppBounds = new Rect(0, 0, endingDividerBounds.right,
- endingDividerBounds.top + getDockedStackDividerInset());
-
- Rect startingBottomAppBounds = new Rect(0,
- endingDividerBounds.bottom - getDockedStackDividerInset(),
- displayBounds.right,
- displayBounds.bottom - getNavigationBarHeight());
-
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(sSimpleActivity, startingTopAppBounds)
- .atTheEnd();
-
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(sImeActivity, startingBottomAppBounds)
- .atTheEnd();
- });
- }
-
- @Test
- public void checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_topAppWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAppWindow(sSimpleActivity)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_bottomAppWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAppWindow(sImeActivity)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_dividerWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(DOCKED_STACK_DIVIDER)
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java
deleted file mode 100644
index 37d7c4ca2b46..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static android.view.Surface.rotationToString;
-
-import static com.android.server.wm.flicker.CommonTransitions.changeAppRotation;
-import static com.android.server.wm.flicker.WindowUtils.getAppPosition;
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
-import static com.android.server.wm.flicker.WindowUtils.getNavigationBarPosition;
-import static com.android.server.wm.flicker.testapp.ActivityOptions.EXTRA_STARVE_UI_THREAD;
-import static com.android.server.wm.flicker.testapp.ActivityOptions.SEAMLESS_ACTIVITY_COMPONENT_NAME;
-
-import android.content.Intent;
-import android.graphics.Rect;
-import android.view.Surface;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-/**
- * Cycle through supported app rotations using seamless rotations.
- * To run this test: {@code atest FlickerTests:SeamlessAppRotationTest}
- */
-@LargeTest
-@RunWith(Parameterized.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 147659548)
-@Ignore("Waiting bug feedback")
-public class SeamlessAppRotationTest extends FlickerTestBase {
- private int mBeginRotation;
- private int mEndRotation;
- private Intent mIntent;
-
- public SeamlessAppRotationTest(String testId, Intent intent, int beginRotation,
- int endRotation) {
- this.mIntent = intent;
- this.mBeginRotation = beginRotation;
- this.mEndRotation = endRotation;
- }
-
- @Parameters(name = "{0}")
- public static Collection<Object[]> getParams() {
- int[] supportedRotations =
- {Surface.ROTATION_0, Surface.ROTATION_90};
- Collection<Object[]> params = new ArrayList<>();
-
- ArrayList<Intent> testIntents = new ArrayList<>();
-
- // launch test activity that supports seamless rotation
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.setComponent(SEAMLESS_ACTIVITY_COMPONENT_NAME);
- testIntents.add(intent);
-
- // launch test activity that supports seamless rotation with a busy UI thread to miss frames
- // when the app is asked to redraw
- intent = new Intent(intent);
- intent.putExtra(EXTRA_STARVE_UI_THREAD, true);
- testIntents.add(intent);
-
- for (Intent testIntent : testIntents) {
- for (int begin : supportedRotations) {
- for (int end : supportedRotations) {
- if (begin != end) {
- String testId = rotationToString(begin) + "_" + rotationToString(end);
- if (testIntent.getExtras() != null &&
- testIntent.getExtras().getBoolean(EXTRA_STARVE_UI_THREAD)) {
- testId += "_" + "BUSY_UI_THREAD";
- }
- params.add(new Object[]{testId, testIntent, begin, end});
- }
- }
- }
- }
- return params;
- }
-
- @Before
- public void runTransition() {
- String intentId = "";
- if (mIntent.getExtras() != null &&
- mIntent.getExtras().getBoolean(EXTRA_STARVE_UI_THREAD)) {
- intentId = "BUSY_UI_THREAD";
- }
-
- super.runTransition(
- changeAppRotation(mIntent, intentId, InstrumentationRegistry.getContext(),
- mUiDevice, mBeginRotation, mEndRotation).build());
- }
-
- @Test
- public void checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkPosition_navBarLayerRotatesAndScales() {
- Rect startingPos = getNavigationBarPosition(mBeginRotation);
- Rect endingPos = getNavigationBarPosition(mEndRotation);
- if (startingPos.equals(endingPos)) {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
- .forAllEntries());
- } else {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
- .inTheBeginning());
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, endingPos)
- .atTheEnd());
- }
- }
-
- @Test
- public void checkPosition_appLayerRotates() {
- Rect startingPos = getAppPosition(mBeginRotation);
- Rect endingPos = getAppPosition(mEndRotation);
- if (startingPos.equals(endingPos)) {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(mIntent.getComponent().getPackageName(), startingPos)
- .forAllEntries());
- } else {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(mIntent.getComponent().getPackageName(), startingPos)
- .then()
- .hasVisibleRegion(mIntent.getComponent().getPackageName(), endingPos)
- .forAllEntries());
- }
- }
-
- @Test
- public void checkCoveredRegion_noUncoveredRegions() {
- Rect startingBounds = getDisplayBounds(mBeginRotation);
- Rect endingBounds = getDisplayBounds(mEndRotation);
- if (startingBounds.equals(endingBounds)) {
- checkResults(result ->
- LayersTraceSubject.assertThat(result)
- .coversRegion(startingBounds)
- .forAllEntries());
- } else {
- checkResults(result ->
- LayersTraceSubject.assertThat(result)
- .coversRegion(startingBounds)
- .then()
- .coversRegion(endingBounds)
- .forAllEntries());
- }
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/SplitScreenToLauncherTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/SplitScreenToLauncherTest.java
deleted file mode 100644
index 85a14941a7fd..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/SplitScreenToLauncherTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker;
-
-import static com.android.server.wm.flicker.CommonTransitions.splitScreenToLauncher;
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-
-/**
- * Test open app to split screen.
- * To run this test: {@code atest FlickerTests:SplitScreenToLauncherTest}
- */
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 140856143)
-@Ignore("Waiting bug feedback")
-public class SplitScreenToLauncherTest extends FlickerTestBase {
-
- public SplitScreenToLauncherTest() {
- this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp");
- }
-
- @Before
- public void runTransition() {
- super.runTransition(splitScreenToLauncher(mTestApp, mUiDevice).includeJankyRuns().build());
- }
-
- @Test
- public void checkCoveredRegion_noUncoveredRegions() {
- checkResults(result ->
- LayersTraceSubject.assertThat(result)
- .coversRegion(getDisplayBounds()).forAllEntries());
- }
-
- @Test
- public void checkVisibility_dividerLayerBecomesInVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(DOCKED_STACK_DIVIDER)
- .then()
- .hidesLayer(DOCKED_STACK_DIVIDER)
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_appLayerBecomesInVisible() {
- checkResults(result -> LayersTraceSubject.assertThat(result)
- .showsLayer(mTestApp.getPackage())
- .then()
- .hidesLayer(mTestApp.getPackage())
- .forAllEntries());
- }
-
- @Test
- public void checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries());
- }
-
- @Test
- public void checkVisibility_dividerWindowBecomesInVisible() {
- checkResults(result -> WmTraceSubject.assertThat(result)
- .showsAboveAppWindow(DOCKED_STACK_DIVIDER)
- .then()
- .hidesAboveAppWindow(DOCKED_STACK_DIVIDER)
- .forAllEntries());
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
new file mode 100644
index 000000000000..71184c2e0aa2
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.close
+
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test app closes by pressing back button
+ * To run this test: `atest FlickerTests:CloseAppBackButtonTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ transitions {
+ device.pressBack()
+ wmHelper.waitForHomeActivityVisible()
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
new file mode 100644
index 000000000000..6786279ae107
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.close
+
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test app closes by pressing home button.
+ * To run this test: `atest FlickerTests:CloseAppHomeButtonTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ transitions {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
new file mode 100644
index 000000000000..f7f977d7bd0a
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -0,0 +1,142 @@
+/*
+ * 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.wm.flicker.close
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import androidx.test.filters.FlakyTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.launcherReplacesAppWindowAsTopWindow
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.launcherLayerReplacesApp
+import com.android.server.wm.flicker.launcherWindowBecomesVisible
+import org.junit.Test
+
+abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter) {
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ protected open val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
+ protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
+ setup {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ teardown {
+ test {
+ testApp.exit()
+ }
+ }
+ }
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ transition(testSpec.config)
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun navBarWindowIsAlwaysVisible() {
+ testSpec.navBarWindowIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarWindowIsAlwaysVisible() {
+ testSpec.statusBarWindowIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ open fun navBarLayerIsAlwaysVisible() {
+ testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarLayerIsAlwaysVisible() {
+ testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
+ }
+
+ @FlakyTest
+ @Test
+ open fun navBarLayerRotatesAndScales() {
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun noUncoveredRegions() {
+ testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ open fun launcherReplacesAppWindowAsTopWindow() {
+ testSpec.launcherReplacesAppWindowAsTopWindow(testApp)
+ }
+
+ @Presubmit
+ @Test
+ open fun launcherWindowBecomesVisible() {
+ testSpec.launcherWindowBecomesVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun launcherLayerReplacesApp() {
+ testSpec.launcherLayerReplacesApp(testApp)
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java
deleted file mode 100644
index 42977f549162..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.helpers;
-
-import android.app.Instrumentation;
-
-import com.android.server.wm.flicker.StandardAppHelper;
-
-public abstract class FlickerAppHelper extends StandardAppHelper {
-
- static int sFindTimeout = 10000;
- static String sFlickerPackage = "com.android.server.wm.flicker.testapp";
-
- public FlickerAppHelper(Instrumentation instr, String launcherName) {
- super(instr, sFlickerPackage, launcherName);
- }
-}
diff --git a/tests/AutoVerify/app4/src/com/android/test/autoverify/MainActivity.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
index 09ef47212622..fad25b4fa0b9 100644
--- a/tests/AutoVerify/app4/src/com/android/test/autoverify/MainActivity.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
@@ -13,3 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+package com.android.server.wm.flicker.helpers
+
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.rules.ChangeDisplayOrientationRule
+
+/**
+ * Changes the device [rotation] and wait for the rotation animation to complete
+ *
+ * @param rotation New device rotation
+ */
+fun Flicker.setRotation(rotation: Int) =
+ ChangeDisplayOrientationRule.setRotation(rotation, instrumentation, wmHelper)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java
deleted file mode 100644
index 56e1118590ea..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.helpers;
-
-import android.app.Instrumentation;
-import android.support.test.uiautomator.UiDevice;
-
-public class ImeAppAutoFocusHelper extends ImeAppHelper {
-
- public ImeAppAutoFocusHelper(Instrumentation instr) {
- super(instr, "ImeAppAutoFocus");
- }
-
- public void clickEditTextWidget(UiDevice device) {
- // do nothing (the app is focused automatically)
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
new file mode 100644
index 000000000000..bd7c1855fea9
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import androidx.test.uiautomator.UiDevice
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+
+class ImeAppAutoFocusHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ private val rotation: Int,
+ private val imePackageName: String = IME_PACKAGE,
+ launcherName: String = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_LAUNCHER_NAME,
+ component: ComponentName = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME
+) : ImeAppHelper(instr, launcherName, component) {
+ override fun openIME(
+ device: UiDevice,
+ wmHelper: WindowManagerStateHelper?
+ ) {
+ // do nothing (the app is focused automatically)
+ waitIMEShown(device, wmHelper)
+ }
+
+ override fun open() {
+ val expectedPackage = if (rotation.isRotated()) {
+ imePackageName
+ } else {
+ getPackage()
+ }
+ launcherStrategy.launch(appName, expectedPackage)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java
deleted file mode 100644
index 098fd6d4250b..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.helpers;
-
-import static android.os.SystemClock.sleep;
-
-import android.app.Instrumentation;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-
-public class ImeAppHelper extends FlickerAppHelper {
-
- ImeAppHelper(Instrumentation instr, String launcherName) {
- super(instr, launcherName);
- }
-
- public ImeAppHelper(Instrumentation instr) {
- this(instr, "ImeApp");
- }
-
- public void clickEditTextWidget(UiDevice device) {
- UiObject2 editText = device.findObject(By.res(getPackage(), "plain_text_input"));
- editText.click();
- sleep(500);
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
new file mode 100644
index 000000000000..83fddae5b1a7
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+
+open class ImeAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.IME_ACTIVITY_LAUNCHER_NAME,
+ component: ComponentName = ActivityOptions.IME_ACTIVITY_COMPONENT_NAME,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+ /**
+ * Opens the IME and wait for it to be displayed
+ *
+ * @param device UIDevice instance to interact with the device
+ * @param wmHelper Helper used to wait for WindowManager states
+ */
+ @JvmOverloads
+ open fun openIME(device: UiDevice, wmHelper: WindowManagerStateHelper? = null) {
+ val editText = device.wait(
+ Until.findObject(By.res(getPackage(), "plain_text_input")),
+ FIND_TIMEOUT)
+
+ require(editText != null) {
+ "Text field not found, this usually happens when the device " +
+ "was left in an unknown state (e.g. in split screen)"
+ }
+ editText.click()
+ waitIMEShown(device, wmHelper)
+ }
+
+ protected fun waitIMEShown(
+ device: UiDevice,
+ wmHelper: WindowManagerStateHelper? = null
+ ) {
+ if (wmHelper == null) {
+ device.waitForIdle()
+ } else {
+ wmHelper.waitImeWindowShown()
+ }
+ }
+
+ /**
+ * Opens the IME and wait for it to be gone
+ *
+ * @param device UIDevice instance to interact with the device
+ * @param wmHelper Helper used to wait for WindowManager states
+ */
+ @JvmOverloads
+ open fun closeIME(device: UiDevice, wmHelper: WindowManagerStateHelper? = null) {
+ device.pressBack()
+ // Using only the AccessibilityInfo it is not possible to identify if the IME is active
+ if (wmHelper == null) {
+ device.waitForIdle()
+ } else {
+ wmHelper.waitImeWindowGone()
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java
deleted file mode 100644
index d00e11b2994d..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.helpers;
-
-import static com.android.server.wm.flicker.helpers.AutomationUtils.getPipWindowSelector;
-
-import android.app.Instrumentation;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-
-public class PipAppHelper extends FlickerAppHelper {
-
- public PipAppHelper(Instrumentation instr) {
- super(instr, "PipApp");
- }
-
- public void clickEnterPipButton(UiDevice device) {
- UiObject2 enterPipButton = device.findObject(By.res(getPackage(), "enter_pip"));
- enterPipButton.click();
- UiObject2 pipWindow = device.wait(Until.findObject(getPipWindowSelector()), sFindTimeout);
-
- if (pipWindow == null) {
- throw new RuntimeException("Unable to find PIP window");
- }
- }
-
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
new file mode 100644
index 000000000000..02be3cf0a8a3
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import com.android.server.wm.flicker.testapp.ActivityOptions
+
+class SeamlessRotationAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.SEAMLESS_ACTIVITY_LAUNCHER_NAME,
+ component: ComponentName = ActivityOptions.SEAMLESS_ACTIVITY_COMPONENT_NAME,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
new file mode 100644
index 000000000000..d7cbaaee2627
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import com.android.server.wm.flicker.testapp.ActivityOptions
+
+class SimpleAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.SIMPLE_ACTIVITY_LAUNCHER_NAME,
+ component: ComponentName = ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
new file mode 100644
index 000000000000..b5757fd21ee0
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window closing back to app window transitions.
+ * To run this test: `atest FlickerTests:CloseImeAutoOpenWindowToAppTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ testApp.openIME(device, wmHelper)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ testApp.closeIME(device, wmHelper)
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE,
+ WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+ WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME))
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp)
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @FlakyTest
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
+
+ @Presubmit
+ @Test
+ fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun imeAppLayerIsAlwaysVisible() = testSpec.imeAppLayerIsAlwaysVisible(testApp)
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ }
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
+ }
+
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5,
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY)
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
new file mode 100644
index 000000000000..549e44c511b9
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window closing back to app window transitions.
+ * To run this test: `atest FlickerTests:CloseImeAutoOpenWindowToHomeTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ testApp.openIME(device, wmHelper)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ wmHelper.waitImeWindowGone()
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE,
+ WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+ WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME))
+ }
+ }
+
+ @FlakyTest
+ @Test
+ fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
+
+ @FlakyTest
+ @Test
+ fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp)
+
+ @Presubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ Surface.ROTATION_0)
+
+ @FlakyTest
+ @Test
+ fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp)
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(IME_WINDOW_TITLE, WindowManagerStateHelper.SPLASH_SCREEN_NAME))
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 1,
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY)
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
new file mode 100644
index 000000000000..82ca074b5ef2
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import org.junit.Assume
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window closing back to app window transitions.
+ * To run this test: `atest FlickerTests:CloseImeWindowToAppTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ test {
+ testApp.launchViaIntent()
+ }
+ eachRun {
+ testApp.openIME(device, wmHelper)
+ }
+ }
+ teardown {
+ test {
+ testApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ testApp.closeIME(device, wmHelper)
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE,
+ WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+ WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME))
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp)
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ }
+
+ @FlakyTest
+ @Test
+ fun navBarLayerRotatesAndScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
+ }
+
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun imeAppLayerIsAlwaysVisible() = testSpec.imeAppLayerIsAlwaysVisible(testApp)
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
new file mode 100644
index 000000000000..703e4a125440
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+/**
+ * Test IME window closing to home transitions.
+ * To run this test: `atest FlickerTests:CloseImeWindowToHomeTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ testApp.openIME(device, wmHelper)
+ }
+ }
+ transitions {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ wmHelper.waitImeWindowGone()
+ }
+ teardown {
+ eachRun {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ }
+ test {
+ testApp.exit()
+ }
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE,
+ WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+ WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME))
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
+
+ @FlakyTest
+ @Test
+ fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp)
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ Surface.ROTATION_0)
+
+ @Presubmit
+ @Test
+ fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp)
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() =
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(IME_WINDOW_TITLE, WindowManagerStateHelper.SPLASH_SCREEN_NAME))
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(
+ repetitions = 5,
+ supportedRotations = listOf(Surface.ROTATION_0),
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+ )
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
new file mode 100644
index 000000000000..7e34469b8188
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.ime
+
+import android.platform.helpers.IAppHelper
+import com.android.server.wm.flicker.FlickerTestParameter
+
+const val IME_WINDOW_TITLE = "InputMethod"
+
+fun FlickerTestParameter.imeLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
+ if (rotatesScreen) {
+ assertLayers {
+ this.isVisible(IME_WINDOW_TITLE)
+ .then()
+ .isInvisible(IME_WINDOW_TITLE)
+ .then()
+ .isVisible(IME_WINDOW_TITLE)
+ }
+ } else {
+ assertLayers {
+ this.isVisible(IME_WINDOW_TITLE)
+ }
+ }
+}
+
+fun FlickerTestParameter.imeLayerBecomesVisible() {
+ assertLayers {
+ this.isInvisible(IME_WINDOW_TITLE)
+ .then()
+ .isVisible(IME_WINDOW_TITLE)
+ }
+}
+
+fun FlickerTestParameter.imeLayerBecomesInvisible() {
+ assertLayers {
+ this.isVisible(IME_WINDOW_TITLE)
+ .then()
+ .isInvisible(IME_WINDOW_TITLE)
+ }
+}
+
+fun FlickerTestParameter.imeAppLayerIsAlwaysVisible(testApp: IAppHelper) {
+ assertLayers {
+ this.isVisible(testApp.getPackage())
+ }
+}
+
+fun FlickerTestParameter.imeAppWindowIsAlwaysVisible(testApp: IAppHelper) {
+ assertWm {
+ this.showsAppWindowOnTop(testApp.getPackage())
+ }
+}
+
+fun FlickerTestParameter.imeWindowIsAlwaysVisible(rotatesScreen: Boolean = false) {
+ if (rotatesScreen) {
+ assertWm {
+ this.showsNonAppWindow(IME_WINDOW_TITLE)
+ .then()
+ .hidesNonAppWindow(IME_WINDOW_TITLE)
+ .then()
+ .showsNonAppWindow(IME_WINDOW_TITLE)
+ }
+ } else {
+ assertWm {
+ this.showsNonAppWindow(IME_WINDOW_TITLE)
+ }
+ }
+}
+
+fun FlickerTestParameter.imeWindowBecomesVisible() {
+ assertWm {
+ this.hidesNonAppWindow(IME_WINDOW_TITLE)
+ .then()
+ .showsNonAppWindow(IME_WINDOW_TITLE)
+ }
+}
+
+fun FlickerTestParameter.imeWindowBecomesInvisible() {
+ assertWm {
+ this.showsNonAppWindow(IME_WINDOW_TITLE)
+ .then()
+ .hidesNonAppWindow(IME_WINDOW_TITLE)
+ }
+}
+
+fun FlickerTestParameter.imeAppWindowIsAlwaysVisible(
+ testApp: IAppHelper,
+ rotatesScreen: Boolean = false
+) {
+ if (rotatesScreen) {
+ assertWm {
+ this.showsAppWindow(testApp.getPackage())
+ .then()
+ .hidesAppWindow(testApp.getPackage())
+ .then()
+ .showsAppWindow(testApp.getPackage())
+ }
+ } else {
+ assertWm {
+ this.showsAppWindow(testApp.getPackage())
+ }
+ }
+}
+
+fun FlickerTestParameter.imeAppWindowBecomesVisible(windowName: String) {
+ assertWm {
+ this.hidesAppWindow(windowName)
+ .then()
+ .showsAppWindow(windowName)
+ }
+}
+
+fun FlickerTestParameter.imeAppWindowBecomesInvisible(testApp: IAppHelper) {
+ assertWm {
+ this.showsAppWindowOnTop(testApp.getPackage())
+ .then()
+ .appWindowNotOnTop(testApp.getPackage())
+ }
+}
+
+fun FlickerTestParameter.imeAppLayerBecomesInvisible(testApp: IAppHelper) {
+ assertLayers {
+ this.isVisible(testApp.getPackage())
+ .then()
+ .isInvisible(testApp.getPackage())
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
new file mode 100644
index 000000000000..cae1b16c1c8c
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window opening transitions.
+ * To run this test: `atest FlickerTests:OpenImeWindowTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class OpenImeWindowTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ test {
+ testApp.launchViaIntent(wmHelper)
+ }
+ }
+ transitions {
+ testApp.openIME(device, wmHelper)
+ }
+ teardown {
+ eachRun {
+ testApp.closeIME(device, wmHelper)
+ }
+ test {
+ testApp.exit()
+ }
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun imeWindowBecomesVisible() = testSpec.imeWindowBecomesVisible()
+
+ @Presubmit
+ @Test
+ fun appWindowAlwaysVisibleOnTop() = testSpec.appWindowAlwaysVisibleOnTop(testApp.`package`)
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
+
+ @Presubmit
+ @Test
+ fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible()
+
+ @Presubmit
+ @Test
+ fun layerAlwaysVisible() {
+ testSpec.assertLayers {
+ this.isVisible(testApp.`package`)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
+ }
+
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(
+ repetitions = 5,
+ supportedRotations = listOf(Surface.ROTATION_0),
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+ )
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
new file mode 100644
index 000000000000..b7673d5b0107
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
+import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.flicker.helpers.reopenAppFromOverview
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.launcherWindowBecomesInvisible
+import com.android.server.wm.flicker.appLayerReplacesLauncher
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window opening transitions.
+ * To run this test: `atest FlickerTests:ReOpenImeWindowTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
+ private val testAppComponentName = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ test {
+ testApp.launchViaIntent(wmHelper)
+ testApp.openIME(device, wmHelper)
+ }
+ eachRun {
+ device.pressRecentApps()
+ wmHelper.waitImeWindowGone()
+ wmHelper.waitForAppTransitionIdle()
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ transitions {
+ device.reopenAppFromOverview(wmHelper)
+ wmHelper.waitImeWindowShown()
+ }
+ teardown {
+ test {
+ testApp.exit()
+ }
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun launcherWindowBecomesInvisible() = testSpec.launcherWindowBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun imeWindowIsAlwaysVisible() = testSpec.imeWindowIsAlwaysVisible(true)
+
+ @Presubmit
+ @Test
+ fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp, true)
+
+ @Presubmit
+ @Test
+ // During testing the launcher is always in portrait mode
+ fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ testSpec.config.endRotation)
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun imeLayerIsAlwaysVisible() = testSpec.imeLayerIsAlwaysVisible(true)
+
+ @Presubmit
+ @Test
+ fun appLayerReplacesLauncher() =
+ testSpec.appLayerReplacesLauncher(testAppComponentName.className)
+
+ @Presubmit
+ @Test
+ fun navBarLayerRotatesAndScales() {
+ testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(
+ repetitions = 1,
+ supportedRotations = listOf(Surface.ROTATION_0),
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+ )
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
new file mode 100644
index 000000000000..0cae37c8d5ab
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
@@ -0,0 +1,143 @@
+/*
+ * 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.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME windows switching with 2-Buttons or gestural navigation.
+ * To run this test: `atest FlickerTests:SwitchImeWindowsFromGestureNavTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = SimpleAppHelper(instrumentation)
+ private val imeTestApp = ImeAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ eachRun {
+ this.setRotation(testSpec.config.startRotation)
+ testApp.launchViaIntent(wmHelper)
+ imeTestApp.launchViaIntent(wmHelper)
+ imeTestApp.openIME(device, wmHelper)
+ }
+ }
+ teardown {
+ eachRun {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ }
+ test {
+ imeTestApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ // [Step1]: Swipe right from imeTestApp to testApp task
+ val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+ val displayCenterX = displayBounds.bounds.width() / 2
+ device.swipe(displayCenterX, displayBounds.bounds.height(),
+ displayBounds.bounds.width(), displayBounds.bounds.height(), 20)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ transitions {
+ // [Step2]: Swipe left to back to imeTestApp task
+ val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+ val displayCenterX = displayBounds.bounds.width() / 2
+ device.swipe(displayBounds.bounds.width(), displayBounds.bounds.height(),
+ displayCenterX, displayBounds.bounds.height(), 20)
+ wmHelper.waitForFullScreenApp(imeTestApp.component)
+ }
+ }
+ }
+
+ @FlakyTest
+ @Test
+ fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(imeTestApp)
+
+ @FlakyTest
+ @Test
+ fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible()
+
+ @FlakyTest
+ @Test
+ fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @FlakyTest
+ @Test
+ fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(
+ repetitions = 3,
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+ )
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
new file mode 100644
index 000000000000..01e34d9f8f97
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.platform.helpers.IAppHelper
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.HOME_WINDOW_TITLE
+
+fun FlickerTestParameter.appWindowReplacesLauncherAsTopWindow(testApp: IAppHelper) {
+ assertWm {
+ this.showsAppWindowOnTop(*HOME_WINDOW_TITLE)
+ .then()
+ .showsAppWindowOnTop("Snapshot", testApp.getPackage())
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
new file mode 100644
index 000000000000..9ff0bdfe66ba
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test cold launch app from launcher.
+ * To run this test: `atest FlickerTests:OpenAppColdTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ setup {
+ eachRun {
+ removeAllTasksButHome()
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ testApp.launchViaIntent(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ }
+
+ @FlakyTest
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerIsAlwaysVisible() {
+ super.navBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() {
+ super.navBarLayerRotatesAndScales()
+ }
+
+ @FlakyTest
+ @Test
+ override fun statusBarLayerIsAlwaysVisible() {
+ super.statusBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun appLayerReplacesLauncher() {
+ super.appLayerReplacesLauncher()
+ }
+
+ @FlakyTest
+ @Test
+ override fun appWindowReplacesLauncherAsTopWindow() {
+ super.appWindowReplacesLauncherAsTopWindow()
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests()
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
new file mode 100644
index 000000000000..b073a7ca1495
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.reopenAppFromOverview
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Launch an app from the recents app view (the overview)
+ * To run this test: `atest FlickerTests:OpenAppFromOverviewTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ setup {
+ test {
+ testApp.launchViaIntent(wmHelper)
+ }
+ eachRun {
+ device.pressHome()
+ wmHelper.waitForAppTransitionIdle()
+ device.pressRecentApps()
+ wmHelper.waitForAppTransitionIdle()
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ transitions {
+ device.reopenAppFromOverview(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ }
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerIsAlwaysVisible() {
+ super.navBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun statusBarLayerIsAlwaysVisible() {
+ super.statusBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() {
+ super.navBarLayerRotatesAndScales()
+ }
+
+ @FlakyTest
+ @Test
+ override fun statusBarLayerRotatesScales() {
+ super.statusBarLayerRotatesScales()
+ }
+
+ @FlakyTest
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
new file mode 100644
index 000000000000..b304d5f999df
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -0,0 +1,154 @@
+/*
+ * 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.wm.flicker.launch
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.appLayerReplacesLauncher
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.launcherWindowBecomesInvisible
+import org.junit.Test
+
+abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ protected val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
+
+ protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ teardown {
+ test {
+ testApp.exit()
+ }
+ }
+ }
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ transition(testSpec.config)
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun navBarWindowIsAlwaysVisible() {
+ testSpec.navBarWindowIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun navBarLayerIsAlwaysVisible() {
+ testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
+ }
+
+ @Presubmit
+ @Test
+ open fun navBarLayerRotatesAndScales() {
+ testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarWindowIsAlwaysVisible() {
+ testSpec.statusBarWindowIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarLayerIsAlwaysVisible() {
+ testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Presubmit
+ @Test
+ // During testing the launcher is always in portrait mode
+ open fun noUncoveredRegions() {
+ testSpec.noUncoveredRegions(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ open fun focusChanges() {
+ testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
+ }
+
+ @Presubmit
+ @Test
+ open fun appLayerReplacesLauncher() {
+ testSpec.appLayerReplacesLauncher(testApp.`package`)
+ }
+
+ @Presubmit
+ @Test
+ open fun appWindowReplacesLauncherAsTopWindow() {
+ testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
+ }
+
+ @Presubmit
+ @Test
+ open fun launcherWindowBecomesInvisible() {
+ testSpec.launcherWindowBecomesInvisible()
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
new file mode 100644
index 000000000000..e2705c764917
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test warm launch app.
+ * To run this test: `atest FlickerTests:OpenAppWarmTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class OpenAppWarmTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ setup {
+ test {
+ testApp.launchViaIntent(wmHelper)
+ }
+ eachRun {
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ testApp.launchViaIntent(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ }
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerIsAlwaysVisible() {
+ super.navBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() {
+ super.navBarLayerRotatesAndScales()
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests()
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
new file mode 100644
index 000000000000..69e8a8d08e58
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.rotation
+
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Cycle through supported app rotations.
+ * To run this test: `atest FlickerTests:ChangeAppRotationTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class ChangeAppRotationTest(
+ testSpec: FlickerTestParameter
+) : RotationTransition(testSpec) {
+ override val testApp = SimpleAppHelper(instrumentation)
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ setup {
+ test {
+ testApp.launchViaIntent(wmHelper)
+ }
+ }
+ }
+
+ @FlakyTest(bugId = 190185577)
+ @Test
+ override fun focusDoesNotChange() {
+ super.focusDoesNotChange()
+ }
+
+ @Postsubmit
+ @Test
+ fun screenshotLayerBecomesInvisible() {
+ testSpec.assertLayers {
+ this.isVisible(testApp.getPackage())
+ .then()
+ .isVisible(SCREENSHOT_LAYER)
+ .then()
+ .isVisible(testApp.getPackage())
+ }
+ }
+
+ @Postsubmit
+ @Test
+ override fun statusBarLayerRotatesScales() {
+ super.statusBarLayerRotatesScales()
+ }
+
+ @Presubmit
+ @Test
+ override fun navBarWindowIsAlwaysVisible() {
+ super.navBarWindowIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun statusBarLayerIsAlwaysVisible() {
+ super.statusBarLayerIsAlwaysVisible()
+ }
+
+ companion object {
+ private const val SCREENSHOT_LAYER = "RotationLayer"
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigRotationTests(repetitions = 5)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
new file mode 100644
index 000000000000..4b888cd5aad0
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -0,0 +1,159 @@
+/*
+ * 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.wm.flicker.rotation
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.FlakyTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.focusDoesNotChange
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import org.junit.Test
+
+abstract class RotationTransition(protected val testSpec: FlickerTestParameter) {
+ protected abstract val testApp: StandardAppHelper
+
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ protected val startingPos get() = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+ protected val endingPos get() = WindowUtils.getDisplayBounds(testSpec.config.endRotation)
+
+ protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
+ setup {
+ eachRun {
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ teardown {
+ test {
+ testApp.exit()
+ }
+ }
+ transitions {
+ this.setRotation(testSpec.config.endRotation)
+ }
+ }
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ transition(testSpec.config)
+ }
+ }
+
+ @FlakyTest
+ @Test
+ open fun navBarWindowIsAlwaysVisible() {
+ testSpec.navBarWindowIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ open fun navBarLayerIsAlwaysVisible() {
+ testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = true)
+ }
+
+ @FlakyTest
+ @Test
+ open fun navBarLayerRotatesAndScales() {
+ testSpec.navBarLayerRotatesAndScales(
+ testSpec.config.startRotation, testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarWindowIsAlwaysVisible() {
+ testSpec.statusBarWindowIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ open fun statusBarLayerIsAlwaysVisible() {
+ testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = true)
+ }
+
+ @FlakyTest
+ @Test
+ open fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(
+ testSpec.config.startRotation, testSpec.config.endRotation)
+ }
+
+ @FlakyTest
+ @Test
+ open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(
+ ignoreLayers = listOf(WindowManagerStateHelper.SPLASH_SCREEN_NAME,
+ WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME,
+ "SecondaryHomeHandle"
+ )
+ )
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun noUncoveredRegions() {
+ testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ testSpec.config.endRotation, allStates = false)
+ }
+
+ @Presubmit
+ @Test
+ open fun focusDoesNotChange() {
+ testSpec.focusDoesNotChange()
+ }
+
+ @Presubmit
+ @Test
+ open fun appLayerRotates_StartingPos() {
+ testSpec.assertLayersStart {
+ this.visibleRegion(testApp.getPackage()).coversExactly(startingPos)
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun appLayerRotates_EndingPos() {
+ testSpec.assertLayersEnd {
+ this.visibleRegion(testApp.getPackage()).coversExactly(endingPos)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
new file mode 100644
index 000000000000..b153bece1133
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.rotation
+
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Cycle through supported app rotations using seamless rotations.
+ * To run this test: `atest FlickerTests:SeamlessAppRotationTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class SeamlessAppRotationTest(
+ testSpec: FlickerTestParameter
+) : RotationTransition(testSpec) {
+ override val testApp = SeamlessRotationAppHelper(instrumentation)
+
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ setup {
+ test {
+ testApp.launchViaIntent(wmHelper,
+ stringExtras = mapOf(
+ ActivityOptions.EXTRA_STARVE_UI_THREAD to it.starveUiThread.toString())
+ )
+ }
+ }
+ }
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ override fun statusBarWindowIsAlwaysVisible() {
+ super.statusBarWindowIsAlwaysVisible()
+ }
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ override fun statusBarLayerIsAlwaysVisible() {
+ super.statusBarLayerIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ fun appLayerAlwaysVisible() {
+ testSpec.assertLayers {
+ isVisible(testApp.`package`)
+ }
+ }
+
+ @FlakyTest(bugId = 185400889)
+ @Test
+ fun appLayerRotates() {
+ testSpec.assertLayers {
+ this.coversExactly(startingPos, testApp.`package`)
+ .then()
+ .coversExactly(endingPos, testApp.`package`)
+ }
+ }
+
+ @Postsubmit
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
+ companion object {
+ private val testFactory = FlickerTestParameterFactory.getInstance()
+
+ private val Map<String, Any?>.starveUiThread
+ get() = this.getOrDefault(ActivityOptions.EXTRA_STARVE_UI_THREAD, false) as Boolean
+
+ private fun FlickerTestParameter.createConfig(
+ starveUiThread: Boolean
+ ): MutableMap<String, Any?> {
+ val config = this.config.toMutableMap()
+ config[ActivityOptions.EXTRA_STARVE_UI_THREAD] = starveUiThread
+ return config
+ }
+
+ @JvmStatic
+ private fun getConfigurations(): List<FlickerTestParameter> {
+ return testFactory.getConfigRotationTests(repetitions = 2).flatMap {
+ val defaultRun = it.createConfig(starveUiThread = false)
+ val busyUiRun = it.createConfig(starveUiThread = true)
+ listOf(
+ FlickerTestParameter(defaultRun),
+ FlickerTestParameter(busyUiRun,
+ name = "${FlickerTestParameter.defaultName(busyUiRun)}_BUSY_UI_THREAD"
+ )
+ )
+ }
+ }
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return getConfigurations()
+ }
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/Android.bp b/tests/FlickerTests/test-apps/flickerapp/Android.bp
index 0bea209a757a..78660c04d8d4 100644
--- a/tests/FlickerTests/test-apps/flickerapp/Android.bp
+++ b/tests/FlickerTests/test-apps/flickerapp/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "FlickerTestApp",
srcs: ["**/*.java"],
@@ -19,7 +28,7 @@ android_test {
test_suites: ["device-tests"],
}
-java_test {
+java_library {
name: "flickertestapplib",
sdk_version: "current",
srcs: ["src/com/android/server/wm/flicker/testapp/ActivityOptions.java"],
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 0fe968273567..1599ed4b280f 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -14,60 +14,50 @@
limitations under the License.
-->
-<manifest
- xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.testapp">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.wm.flicker.testapp">
- <uses-sdk android:minSdkVersion="17" android:targetSdkVersion="27"/>
- <application
- android:allowBackup="false"
- android:supportsRtl="true">
+ <uses-sdk android:minSdkVersion="29"
+ android:targetSdkVersion="29"/>
+ <application android:allowBackup="false"
+ android:supportsRtl="true">
<activity android:name=".SimpleActivity"
- android:taskAffinity="com.android.server.wm.flicker.testapp.SimpleActivity"
- android:label="SimpleApp">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.SimpleActivity"
+ android:label="SimpleApp"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".ImeActivity"
- android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivity"
- android:label="ImeApp">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivity"
+ android:label="ImeApp"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".ImeActivityAutoFocus"
- android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivityAutoFocus"
- android:windowSoftInputMode="stateVisible"
- android:label="ImeAppAutoFocus">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- <activity android:name=".PipActivity"
- android:resizeableActivity="true"
- android:supportsPictureInPicture="true"
- android:configChanges=
- "screenSize|smallestScreenSize|screenLayout|orientation"
- android:taskAffinity="com.android.server.wm.flicker.testapp.PipActivity"
- android:label="PipApp">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivityAutoFocus"
+ android:windowSoftInputMode="stateVisible"
+ android:label="ImeAppAutoFocus"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".SeamlessRotationActivity"
- android:taskAffinity=
- "com.android.server.wm.flicker.testapp.SeamlessRotationActivity"
- android:configChanges="orientation|screenSize"
- android:label="SeamlessApp">
+ android:taskAffinity="com.android.server.wm.flicker.testapp.SeamlessRotationActivity"
+ android:configChanges="orientation|screenSize"
+ android:label="SeamlessApp"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
-</manifest> \ No newline at end of file
+</manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 18994111324e..0ccc49897202 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -20,7 +20,25 @@ import android.content.ComponentName;
public class ActivityOptions {
public static final String EXTRA_STARVE_UI_THREAD = "StarveUiThread";
+ public static final String FLICKER_APP_PACKAGE = "com.android.server.wm.flicker.testapp";
+
+ public static final String SEAMLESS_ACTIVITY_LAUNCHER_NAME = "SeamlessApp";
public static final ComponentName SEAMLESS_ACTIVITY_COMPONENT_NAME =
- new ComponentName("com.android.server.wm.flicker.testapp",
- "com.android.server.wm.flicker.testapp.SeamlessRotationActivity");
+ new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".SeamlessRotationActivity");
+
+ public static final String IME_ACTIVITY_AUTO_FOCUS_LAUNCHER_NAME = "ImeAppAutoFocus";
+ public static final ComponentName IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME =
+ new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ImeActivityAutoFocus");
+
+ public static final String IME_ACTIVITY_LAUNCHER_NAME = "ImeActivity";
+ public static final ComponentName IME_ACTIVITY_COMPONENT_NAME =
+ new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ImeActivity");
+
+ public static final String SIMPLE_ACTIVITY_LAUNCHER_NAME = "SimpleApp";
+ public static final ComponentName SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME =
+ new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".SimpleActivity");
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
deleted file mode 100644
index 9a8f39907877..000000000000
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.testapp;
-
-import android.app.Activity;
-import android.app.PictureInPictureParams;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.util.Rational;
-import android.view.WindowManager;
-import android.widget.Button;
-
-public class PipActivity extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- WindowManager.LayoutParams p = getWindow().getAttributes();
- p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
- .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
- getWindow().setAttributes(p);
- setContentView(R.layout.activity_pip);
- Button enterPip = (Button) findViewById(R.id.enter_pip);
-
- PictureInPictureParams params = new PictureInPictureParams.Builder()
- .setAspectRatio(new Rational(1, 1))
- .setSourceRectHint(new Rect(0, 0, 100, 100))
- .build();
-
- enterPip.setOnClickListener((v) -> enterPictureInPictureMode(params));
- }
-}
diff --git a/tests/FrameworkPerf/Android.bp b/tests/FrameworkPerf/Android.bp
index a259ebd05fa8..9be3ab795b86 100644
--- a/tests/FrameworkPerf/Android.bp
+++ b/tests/FrameworkPerf/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "FrameworkPerf",
srcs: ["**/*.java"],
diff --git a/tests/FrameworkPerf/AndroidManifest.xml b/tests/FrameworkPerf/AndroidManifest.xml
index 4fd2043ce938..07e775aeb838 100644
--- a/tests/FrameworkPerf/AndroidManifest.xml
+++ b/tests/FrameworkPerf/AndroidManifest.xml
@@ -1,30 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.frameworkperf">
+ package="com.android.frameworkperf">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-sdk android:minSdkVersion="5" />
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
+ <uses-sdk android:minSdkVersion="5"/>
<application android:hardwareAccelerated="false">
- <uses-library android:name="android.test.runner" />
- <activity android:name="FrameworkPerfActivity" android:label="Framework Perf">
+ <uses-library android:name="android.test.runner"/>
+ <activity android:name="FrameworkPerfActivity"
+ android:label="Framework Perf"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service android:name="SchedulerService"
- android:foregroundServiceType="dataSync|mediaPlayback|phoneCall|location|connectedDevice">
+ android:foregroundServiceType="dataSync|mediaPlayback|phoneCall|location|connectedDevice">
</service>
- <service android:name="TestService" android:process=":test">
+ <service android:name="TestService"
+ android:process=":test">
</service>
<service android:name="LocalTestService">
</service>
- <receiver android:name="Receiver" android:exported="true">
+ <receiver android:name="Receiver"
+ android:exported="true">
</receiver>
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.frameworkperf"
- android:label="Framework Perf Runner"
- />
+ android:targetPackage="com.android.frameworkperf"
+ android:label="Framework Perf Runner"/>
</manifest>
diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java b/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java
index d4cbbf9c8271..11a26d6c727a 100644
--- a/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java
+++ b/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java
@@ -41,7 +41,7 @@ public class SchedulerService extends Service {
new Intent(this, FrameworkPerfActivity.class)
.setAction(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0))
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), PendingIntent.FLAG_MUTABLE_UNAUDITED))
.setOngoing(true)
.build();
startForeground(1, status);
diff --git a/tests/GamePerformance/Android.bp b/tests/GamePerformance/Android.bp
new file mode 100644
index 000000000000..f250a1bbdaca
--- /dev/null
+++ b/tests/GamePerformance/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // 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"],
+}
+
+android_test_helper_app {
+ name: "GamePerformance",
+ // Don't include this package in any target
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+ srcs: ["src/**/*.java"],
+ static_libs: ["androidx.test.rules"],
+ libs: [
+ "android.test.base",
+ "android.test.runner",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/tests/GamePerformance/Android.mk b/tests/GamePerformance/Android.mk
deleted file mode 100644
index 58654de34029..000000000000
--- a/tests/GamePerformance/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
-
-LOCAL_JAVA_LIBRARIES := android.test.base android.test.runner
-
-LOCAL_PACKAGE_NAME := GamePerformance
-
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-
-
-include $(BUILD_PACKAGE)
diff --git a/tests/GamePerformance/AndroidManifest.xml b/tests/GamePerformance/AndroidManifest.xml
index 2ff7fa65664e..8e6054bca0d8 100644
--- a/tests/GamePerformance/AndroidManifest.xml
+++ b/tests/GamePerformance/AndroidManifest.xml
@@ -16,28 +16,30 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.gameperformance"
- android:versionCode="3"
- android:versionName="3.0" >
+ package="android.gameperformance"
+ android:versionCode="3"
+ android:versionName="3.0">
<uses-sdk android:minSdkVersion="25"/>
- <uses-feature android:glEsVersion="0x00020000" android:required="true" />
+ <uses-feature android:glEsVersion="0x00020000"
+ android:required="true"/>
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:theme="@style/noeffects">
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
<activity android:name="android.gameperformance.GamePerformanceActivity"
- android:screenOrientation="landscape" >
+ android:screenOrientation="landscape"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
</application>
<!-- self-instrumenting test package. -->
<instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="android.gameperformance">
+ android:targetPackage="android.gameperformance">
</instrumentation>
</manifest>
diff --git a/tests/GridLayoutTest/Android.bp b/tests/GridLayoutTest/Android.bp
index b4b5ba561c3f..71d884c4111f 100644
--- a/tests/GridLayoutTest/Android.bp
+++ b/tests/GridLayoutTest/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "GridLayoutTest",
srcs: ["**/*.java"],
diff --git a/tests/GridLayoutTest/AndroidManifest.xml b/tests/GridLayoutTest/AndroidManifest.xml
index 677220db8a53..6fdcda3e6ce7 100644
--- a/tests/GridLayoutTest/AndroidManifest.xml
+++ b/tests/GridLayoutTest/AndroidManifest.xml
@@ -15,76 +15,96 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.layout">
+ package="com.android.test.layout">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-sdk android:minSdkVersion="11"/>
<application>
- <activity android:name="Activity0" android:label="Activity0">
+ <activity android:name="Activity0"
+ android:label="Activity0"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="Activity1" android:label="Activity1">
+ <activity android:name="Activity1"
+ android:label="Activity1"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="Activity4" android:label="Activity4">
+ <activity android:name="Activity4"
+ android:label="Activity4"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="Activity5" android:label="Activity5">
+ <activity android:name="Activity5"
+ android:label="Activity5"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="Activity6" android:label="Activity6">
+ <activity android:name="Activity6"
+ android:label="Activity6"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="Activity7" android:label="Activity7">
+ <activity android:name="Activity7"
+ android:label="Activity7"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="AlignmentTest" android:label="AlignmentTest">
+ <activity android:name="AlignmentTest"
+ android:label="AlignmentTest"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="LinearLayoutTest" android:label="LinearLayoutTest">
+ <activity android:name="LinearLayoutTest"
+ android:label="LinearLayoutTest"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="GridLayoutTest" android:label="GridLayoutTest">
+ <activity android:name="GridLayoutTest"
+ android:label="GridLayoutTest"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="LayoutInsetsTest" android:label="LayoutInsetsTest">
+ <activity android:name="LayoutInsetsTest"
+ android:label="LayoutInsetsTest"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
diff --git a/tests/HierarchyViewerTest/Android.bp b/tests/HierarchyViewerTest/Android.bp
index 814c88328118..9c5d1c09cedd 100644
--- a/tests/HierarchyViewerTest/Android.bp
+++ b/tests/HierarchyViewerTest/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "HierarchyViewerTest",
srcs: ["**/*.java"],
diff --git a/tests/HierarchyViewerTest/AndroidManifest.xml b/tests/HierarchyViewerTest/AndroidManifest.xml
index 65f2fd3e1a9c..f4414b0c4d00 100644
--- a/tests/HierarchyViewerTest/AndroidManifest.xml
+++ b/tests/HierarchyViewerTest/AndroidManifest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2015 The Android Open Source Project
~
@@ -15,22 +16,21 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.hierarchyviewer">
+ package="com.android.test.hierarchyviewer">
<application>
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
- <activity
- android:name=".MainActivity"
- android:label="HvTest" >
+ <activity android:name=".MainActivity"
+ android:label="HvTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
- <instrumentation
- android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.test.hierarchyviewer" />
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.test.hierarchyviewer"/>
</manifest>
diff --git a/tests/HugeBackup/Android.bp b/tests/HugeBackup/Android.bp
index b44c4578a853..7d4e52acb9b2 100644
--- a/tests/HugeBackup/Android.bp
+++ b/tests/HugeBackup/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "HugeBackup",
// Only compile source java files in this apk.
diff --git a/tests/HugeBackup/AndroidManifest.xml b/tests/HugeBackup/AndroidManifest.xml
index 923881b9b0b0..945e59bd36ed 100644
--- a/tests/HugeBackup/AndroidManifest.xml
+++ b/tests/HugeBackup/AndroidManifest.xml
@@ -13,30 +13,32 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
<!-- Declare the contents of this Android application. The namespace
attribute brings in the Android platform namespace, and the package
supplies a unique name for the application. When writing your
own application, the package name must be changed from "com.example.*"
to come from a domain that you own or have control over. -->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.hugebackup"
- android:versionCode="1"
- android:versionName="1.0">
+ package="com.android.hugebackup"
+ android:versionCode="1"
+ android:versionName="1.0">
<!-- The backup/restore mechanism was introduced in API version 8 -->
- <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8" />
+ <uses-sdk android:minSdkVersion="8"
+ android:targetSdkVersion="8"/>
<application android:label="Huge Backup"
- android:backupAgent="HugeAgent">
+ android:backupAgent="HugeAgent">
<meta-data android:name="com.google.android.backup.api_key"
- android:value="AEdPqrEAAAAINyoagzQOEEpIH3yw7LYCFN7CRX4FMd6TGIGVaA" />
+ android:value="AEdPqrEAAAAINyoagzQOEEpIH3yw7LYCFN7CRX4FMd6TGIGVaA"/>
- <activity android:name="HugeBackupActivity">
+ <activity android:name="HugeBackupActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
diff --git a/tests/HugeBackup/OWNERS b/tests/HugeBackup/OWNERS
new file mode 100644
index 000000000000..d99779e3d9da
--- /dev/null
+++ b/tests/HugeBackup/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/tests/HwAccelerationTest/Android.bp b/tests/HwAccelerationTest/Android.bp
index 37d3f5d4d97f..76063227eac1 100644
--- a/tests/HwAccelerationTest/Android.bp
+++ b/tests/HwAccelerationTest/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "HwAccelerationTest",
srcs: ["**/*.java"],
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 7b8c154dea1e..04a55d6038b0 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -15,1045 +15,1107 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.hwui">
+ package="com.android.test.hwui">
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.CAMERA" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.CAMERA"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <uses-feature android:name="android.hardware.camera" />
- <uses-feature android:name="android.hardware.camera.autofocus" />
+ <uses-feature android:name="android.hardware.camera"/>
+ <uses-feature android:name="android.hardware.camera.autofocus"/>
- <uses-sdk android:minSdkVersion="21" />
+ <uses-sdk android:minSdkVersion="21"/>
- <application
- android:label="HwUi"
- android:theme="@android:style/Theme.Material.Light">
+ <application android:label="HwUi"
+ android:theme="@android:style/Theme.Material.Light">
- <activity
- android:name="HwTests"
- android:label="OpenGL Renderer Tests">
+ <activity android:name="HwTests"
+ android:label="OpenGL Renderer Tests"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity
- android:name="PathOpsActivity"
- android:label="Path/Ops">
+ <activity android:name="PathOpsActivity"
+ android:label="Path/Ops"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="AssetsAtlasActivity"
- android:label="Atlas/Framework">
+ <activity android:name="AssetsAtlasActivity"
+ android:label="Atlas/Framework"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ScaledTextActivity"
- android:label="Text/Scaled">
+ <activity android:name="ScaledTextActivity"
+ android:label="Text/Scaled"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="Rotate3dTextActivity"
- android:label="Text/3D Rotation">
+ <activity android:name="Rotate3dTextActivity"
+ android:label="Text/3D Rotation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="NoAATextActivity"
- android:label="Text/Aliased">
+ <activity android:name="NoAATextActivity"
+ android:label="Text/Aliased"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ScaledPathsActivity"
- android:label="Path/Scaled">
+ <activity android:name="ScaledPathsActivity"
+ android:label="Path/Scaled"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="Alpha8BitmapActivity"
- android:label="Bitmaps/Alpha8">
+ <activity android:name="Alpha8BitmapActivity"
+ android:label="Bitmaps/Alpha8"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="MipMapActivity"
- android:label="Bitmaps/MipMap">
+ <activity android:name="MipMapActivity"
+ android:label="Bitmaps/MipMap"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="DrawIntoHwBitmapActivity"
- android:label="Bitmaps/DrawIntoHwBitmap">
+ <activity android:name="DrawIntoHwBitmapActivity"
+ android:label="Bitmaps/DrawIntoHwBitmap"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PathOffsetActivity"
- android:label="Path/Offset">
+ <activity android:name="PathOffsetActivity"
+ android:label="Path/Offset"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="MultiLayersActivity"
- android:label="Layers/Multiple">
+ <activity android:name="MultiLayersActivity"
+ android:label="Layers/Multiple"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="TJunctionActivity"
- android:label="Layers/T-Junction">
+ <activity android:name="TJunctionActivity"
+ android:label="Layers/T-Junction"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="TextPathActivity"
- android:label="Text/As Path">
+ <activity android:name="TextPathActivity"
+ android:label="Text/As Path"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="GradientStopsActivity"
- android:label="Gradients/Multi-stops">
+ <activity android:name="GradientStopsActivity"
+ android:label="Gradients/Multi-stops"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PaintDrawFilterActivity"
- android:label="Paint/Draw Filter">
+ <activity android:name="PaintDrawFilterActivity"
+ android:label="Paint/Draw Filter"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="BigGradientActivity"
- android:label="Gradients/Large">
+ <activity android:name="BigGradientActivity"
+ android:label="Gradients/Large"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="DatePickerActivity"
- android:label="View/DatePicker">
+
+ <activity android:name="DatePickerActivity"
+ android:label="View/DatePicker"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="ClipRegionActivity"
+ android:label="Clip/Region 1"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="ClipRegion2Activity"
+ android:label="Clip/Region 2"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="ClipRegion3Activity"
+ android:label="Clip/Region 3"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="ClipOutlineActivity"
+ android:label="Clip/Outline"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="DisplayListLayersActivity"
+ android:label="Layers/Display Lists"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="MatrixActivity"
+ android:label="Misc/Matrix"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="LooperAcceleration"
+ android:label="Misc/LooperAcceleration"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ClipRegionActivity"
- android:label="Clip/Region 1">
+ <activity android:name="TextFadeActivity"
+ android:label="Text/Fade"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ClipRegion2Activity"
- android:label="Clip/Region 2">
+ <activity android:name="MaxBitmapSizeActivity"
+ android:label="Bitmaps/Max Size"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ClipRegion3Activity"
- android:label="Clip/Region 3">
+ <activity android:name="TimeDialogActivity"
+ android:label="View/TimeDialog"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ClipOutlineActivity"
- android:label="Clip/Outline">
+ <activity android:name="ColoredShadowsActivity"
+ android:label="View/ColoredShadows"
+ android:theme="@style/ThemeColoredShadows"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="DisplayListLayersActivity"
- android:label="Layers/Display Lists">
+ <activity android:name="OpaqueActivity"
+ android:label="Window/Opaque"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="MatrixActivity"
- android:label="Misc/Matrix">
+ <activity android:name="GetBitmapActivity"
+ android:label="TextureView/Get Bitmap"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="LooperAcceleration"
- android:label="Misc/LooperAcceleration">
+ <activity android:name="PictureCaptureDemo"
+ android:label="Debug/Picture Capture"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="TextFadeActivity"
- android:label="Text/Fade">
+
+ <activity android:name="SmallCircleActivity"
+ android:label="Draw/Small Circle"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="MaxBitmapSizeActivity"
- android:label="Bitmaps/Max Size">
+ <activity android:name="ClearActivity"
+ android:label="Window/Clear"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="TimeDialogActivity"
- android:label="View/TimeDialog">
+ <activity android:name="TextureViewActivity"
+ android:label="TextureView/Camera"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ColoredShadowsActivity"
- android:label="View/ColoredShadows"
- android:theme="@style/ThemeColoredShadows">
+ <activity android:name="GlyphCacheActivity"
+ android:label="Text/Glyph Cache"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="OpaqueActivity"
- android:label="Window/Opaque">
+
+ <activity android:name="CanvasTextureViewActivity"
+ android:label="TextureView/Canvas"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="GetBitmapActivity"
- android:label="TextureView/Get Bitmap">
+ <activity android:name="HardwareCanvasTextureViewActivity"
+ android:label="TextureView/HardwareCanvas"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PictureCaptureDemo"
- android:label="Debug/Picture Capture">
+ <activity android:name="SingleFrameTextureViewTestActivity"
+ android:label="TextureView/SingleFrameTextureViewTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="SmallCircleActivity"
- android:label="Draw/Small Circle">
+
+ <activity android:name="HardwareCanvasSurfaceViewActivity"
+ android:label="SurfaceView/HardwareCanvas"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ClearActivity"
- android:label="Window/Clear">
+ <activity android:name="MovingSurfaceViewActivity"
+ android:label="SurfaceView/Animated Movement"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="TextureViewActivity"
- android:label="TextureView/Camera">
+ <activity android:name="StretchySurfaceViewActivity"
+ android:label="SurfaceView/Stretchy Movement"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="GlyphCacheActivity"
- android:label="Text/Glyph Cache">
+ <activity android:name="ScrollingStretchSurfaceViewActivity"
+ android:label="SurfaceView/Scrolling Stretched SurfaceView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="CanvasTextureViewActivity"
- android:label="TextureView/Canvas">
+ <activity android:name="GetBitmapSurfaceViewActivity"
+ android:label="SurfaceView/GetBitmap with Camera source"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="HardwareCanvasTextureViewActivity"
- android:label="TextureView/HardwareCanvas">
+ <activity android:name="VideoViewCaptureActivity"
+ android:label="SurfaceView/GetBitmap with Video source"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="SingleFrameTextureViewTestActivity"
- android:label="TextureView/SingleFrameTextureViewTest">
+ <activity android:name="GLTextureViewActivity"
+ android:label="TextureView/OpenGL"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="HardwareCanvasSurfaceViewActivity"
- android:label="SurfaceView/HardwareCanvas">
+ <activity android:name="BitmapMeshActivity"
+ android:label="Bitmaps/Mesh"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="MovingSurfaceViewActivity"
- android:label="SurfaceView/Animated Movement">
+ <activity android:name="BitmapMutateActivity"
+ android:label="Bitmaps/Mutate"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="GetBitmapSurfaceViewActivity"
- android:label="SurfaceView/GetBitmap with Camera source">
+ <activity android:name="BitmapMeshLayerActivity"
+ android:label="Bitmaps/Mesh in Layer"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="VideoViewCaptureActivity"
- android:label="SurfaceView/GetBitmap with Video source">
+ <activity android:name="MarqueeActivity"
+ android:label="Text/Marquee"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="GLTextureViewActivity"
- android:label="TextureView/OpenGL">
+ <activity android:name="ShapesActivity"
+ android:label="Path/Shapes"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="BitmapMeshActivity"
- android:label="Bitmaps/Mesh">
+ <activity android:name="ColoredRectsActivity"
+ android:label="Draw/Rects"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="BitmapMutateActivity"
- android:label="Bitmaps/Mutate">
+ <activity android:name="SimplePatchActivity"
+ android:label="Draw/9-Patch"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="BitmapMeshLayerActivity"
- android:label="Bitmaps/Mesh in Layer">
+ <activity android:name="ViewLayersActivity"
+ android:label="Layers/Views 1"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="MarqueeActivity"
- android:label="Text/Marquee">
+
+ <activity android:name="ViewLayersActivity2"
+ android:label="Layers/Views 2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ShapesActivity"
- android:label="Path/Shapes">
+ <activity android:name="ViewLayersActivity3"
+ android:label="Layers/Views 3"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="ColoredRectsActivity"
- android:label="Draw/Rects">
+
+ <activity android:name="ViewLayersActivity4"
+ android:label="Layers/Views 4"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="SimplePatchActivity"
- android:label="Draw/9-Patch"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+ <activity android:name="ViewLayersActivity5"
+ android:label="Layers/Views 5"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ViewLayersActivity"
- android:label="Layers/Views 1">
+ <activity android:name="AlphaLayersActivity"
+ android:label="Layers/Alpha"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="ViewLayersActivity2"
- android:label="Layers/Views 2">
+
+ <activity android:name="AdvancedGradientsActivity"
+ android:label="Gradients/Advanced"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="ViewLayersActivity3"
- android:label="Layers/Views 3">
+
+ <activity android:name="Bitmaps3dActivity"
+ android:label="Bitmaps/3D Rotation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ViewLayersActivity4"
- android:label="Layers/Views 4">
+ <activity android:name="LabelsActivity"
+ android:label="View/TextView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="ViewLayersActivity5"
- android:label="Layers/Views 5">
+
+ <activity android:name="ViewFlipperActivity"
+ android:label="View/ViewFlipper"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="AlphaLayersActivity"
- android:label="Layers/Alpha">
+ <activity android:name="ResizeActivity"
+ android:label="Window/Resize"
+ android:windowSoftInputMode="adjustResize"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="AdvancedGradientsActivity"
- android:label="Gradients/Advanced">
+
+ <activity android:name="TextGammaActivity"
+ android:label="Text/Gamma"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="Bitmaps3dActivity"
- android:label="Bitmaps/3D Rotation">
+
+ <activity android:name="TextGammaActivity$SubGammaActivity"
+ android:label="Text/Sub Gamma"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:hardwareAccelerated="false"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity>
-
- <activity
- android:name="LabelsActivity"
- android:label="View/TextView">
+
+ <activity android:name="LayersActivity"
+ android:label="Layers/Canvas Layers"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ViewFlipperActivity"
- android:label="View/ViewFlipper"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+ <activity android:name="NewLayersActivity"
+ android:label="Layers/Overlapping Layers"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ResizeActivity"
- android:label="Window/Resize"
- android:windowSoftInputMode="adjustResize">
+ <activity android:name="XfermodeActivity"
+ android:label="Draw/Xfermodes"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="TextGammaActivity"
- android:label="Text/Gamma"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+
+ <activity android:name="BitmapsActivity"
+ android:label="Bitmaps/Draw Bitmaps"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="TextGammaActivity$SubGammaActivity"
- android:label="Text/Sub Gamma"
- android:theme="@android:style/Theme.Translucent.NoTitleBar"
- android:hardwareAccelerated="false">
+ <activity android:name="BitmapsSkewActivity"
+ android:label="Bitmaps/Skew"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="LayersActivity"
- android:label="Layers/Canvas Layers"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+
+ <activity android:name="BitmapsAlphaActivity"
+ android:label="Bitmaps/Alpha"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="NewLayersActivity"
- android:label="Layers/Overlapping Layers">
+ <activity android:name="BitmapsRectActivity"
+ android:label="Bitmaps/Rect"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="XfermodeActivity"
- android:label="Draw/Xfermodes"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+
+ <activity android:name="ThinPatchesActivity"
+ android:label="Draw/9-Patch Thin Drawable"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="BitmapsActivity"
- android:label="Bitmaps/Draw Bitmaps"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+
+ <activity android:name="NinePatchesActivity"
+ android:label="Draw/9-Patch Drawable"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="BitmapsSkewActivity"
- android:label="Bitmaps/Skew">
+
+ <activity android:name="MoreNinePatchesActivity"
+ android:label="Draw/9-Patch Vertical Drawable"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="BitmapsAlphaActivity"
- android:label="Bitmaps/Alpha"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+ <activity android:name="QuickRejectActivity"
+ android:label="Clip/QuickReject"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="BitmapsRectActivity"
- android:label="Bitmaps/Rect"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+
+ <activity android:name="RotationActivity"
+ android:label="View/Rotation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ThinPatchesActivity"
- android:label="Draw/9-Patch Thin Drawable"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+ <activity android:name="GradientsActivity"
+ android:label="Gradients/Gradients"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="NinePatchesActivity"
- android:label="Draw/9-Patch Drawable">
+
+ <activity android:name="ShadersActivity"
+ android:label="Shaders/Shaders"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="MoreNinePatchesActivity"
- android:label="Draw/9-Patch Vertical Drawable">
+ <activity android:name="BlurActivity"
+ android:label="RenderEffect/Blur"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="QuickRejectActivity"
- android:label="Clip/QuickReject">
+
+ <activity android:name="RenderEffectShaderActivity"
+ android:label="RenderEffect/Shader"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="RotationActivity"
- android:label="View/Rotation">
+
+ <activity android:name="StretchShaderActivity"
+ android:label="RenderEffect/Stretch"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="GradientsActivity"
- android:label="Gradients/Gradients">
+
+ <activity android:name="EdgeEffectStretchActivity"
+ android:label="RenderEffect/EdgeEffect stretch"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ShadersActivity"
- android:label="Shaders/Shaders">
+ <activity android:name="TextActivity"
+ android:label="Text/Simple Text"
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="TextActivity"
- android:label="Text/Simple Text"
- android:theme="@android:style/Theme.NoTitleBar">
+
+ <activity android:name="PosTextActivity"
+ android:label="Text/Pos Text"
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PosTextActivity"
- android:label="Text/Pos Text"
- android:theme="@android:style/Theme.NoTitleBar">
+ <activity android:name="ListActivity"
+ android:label="View/List"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ListActivity"
- android:label="View/List">
+ <activity android:name="TransparentListActivity"
+ android:label="View/Transparent List"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="TransparentListActivity"
- android:label="View/Transparent List">
+ <activity android:name="MoreShadersActivity"
+ android:label="Shaders/Compose Shaders"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
-
- <activity
- android:name="MoreShadersActivity"
- android:label="Shaders/Compose Shaders">
+
+ <activity android:name="ColorFiltersActivity"
+ android:label="ColorFilters/Filters"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ColorFiltersActivity"
- android:label="ColorFilters/Filters">
+ <activity android:name="ColorFiltersMutateActivity"
+ android:label="ColorFilters/Mutate Filters"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ColorFiltersMutateActivity"
- android:label="ColorFilters/Mutate Filters">
+ <activity android:name="LinesActivity"
+ android:label="Draw/Lines"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="LinesActivity"
- android:label="Draw/Lines">
+ <activity android:name="Lines2Activity"
+ android:label="Draw/Lines 2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="Lines2Activity"
- android:label="Draw/Lines 2">
+ <activity android:name="PathsActivity"
+ android:label="Path/Paths"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PathsActivity"
- android:label="Path/Paths">
+ <activity android:name="TextOnPathActivity"
+ android:label="Text/Text on Path"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="TextOnPathActivity"
- android:label="Text/Text on Path">
+ <activity android:name="PathsCacheActivity"
+ android:label="Path/Cache"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>`
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PathsCacheActivity"
- android:label="Path/Cache">
+ <activity android:name="PointsActivity"
+ android:label="Draw/Points"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />`
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PointsActivity"
- android:label="Draw/Points">
+ <activity android:name="Transform3dActivity"
+ android:label="Draw/3D Transform"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="Transform3dActivity"
- android:label="Draw/3D Transform">
+ <activity android:name="Animated3dActivity"
+ android:label="Draw/Animated 3D Transform"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="Animated3dActivity"
- android:label="Draw/Animated 3D Transform">
+ <activity android:name="SimplePathsActivity"
+ android:label="Path/Simple Paths"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="SimplePathsActivity"
- android:label="Path/Simple Paths">
+ <activity android:name="AdvancedBlendActivity"
+ android:label="Draw/Advanced Blend"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="AdvancedBlendActivity"
- android:label="Draw/Advanced Blend">
+ <activity android:name="FramebufferBlendActivity"
+ android:label="Draw/Framebuffer Blend"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="FramebufferBlendActivity"
- android:label="Draw/Framebuffer Blend">
+ <activity android:name="StackActivity"
+ android:label="View/Stacks"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="StackActivity"
- android:label="View/Stacks">
+ <activity android:name="PathDestructionActivity"
+ android:label="Path/Path Destruction"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PathDestructionActivity"
- android:label="Path/Path Destruction">
+ <activity android:name="TransformsAndAnimationsActivity"
+ android:label="Draw/Transforms and Animations"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="TransformsAndAnimationsActivity"
- android:label="Draw/Transforms and Animations">
+ <activity android:name="ViewPropertyAlphaActivity"
+ android:label="View/Alpha Property"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ViewPropertyAlphaActivity"
- android:label="View/Alpha Property">
+ <activity android:name="ViewLayerInvalidationActivity"
+ android:label="Layers/Invalidation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ViewLayerInvalidationActivity"
- android:label="Layers/Invalidation">
+ <activity android:name="ProjectionActivity"
+ android:label="Reordering/Projection"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ProjectionActivity"
- android:label="Reordering/Projection">
+ <activity android:name=".ProjectionClippingActivity"
+ android:label="Reordering/Projection Clipping"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".ProjectionClippingActivity"
- android:label="Reordering/Projection Clipping">
+ <activity android:name=".ZOrderingActivity"
+ android:label="Reordering/Z Ordering"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".ZOrderingActivity"
- android:label="Reordering/Z Ordering">
+ <activity android:name="GLDepthTestActivity"
+ android:label="Reordering/OpenGL Depth Test"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="GLDepthTestActivity"
- android:label="Reordering/OpenGL Depth Test">
+ <activity android:name="CirclePropActivity"
+ android:label="Animation/Circle Props"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="CirclePropActivity"
- android:label="Animation/Circle Props">
+ <activity android:name="RevealActivity"
+ android:label="Animation/Reveal Animation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="RevealActivity"
- android:label="Animation/Reveal Animation">
+ <activity android:name="RippleActivity"
+ android:label="Animation/Ripple Animation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="MultiProducerActivity"
- android:label="Threads/Multiple Producers">
+ <activity android:name="MultiProducerActivity"
+ android:label="Threads/Multiple Producers"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PixelCopyWindow"
- android:label="Readback/Window"
- android:screenOrientation="fullSensor">
+ <activity android:name="PixelCopyWindow"
+ android:label="Readback/Window"
+ android:screenOrientation="fullSensor"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="PositionListenerActivity"
- android:label="RenderNode/PositionListener"
- android:screenOrientation="fullSensor">
+ <activity android:name="PositionListenerActivity"
+ android:label="RenderNode/PositionListener"
+ android:screenOrientation="fullSensor"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="CustomRenderer"
- android:label="HardwareRenderer/HelloTakeSurface"
- android:screenOrientation="fullSensor">
+ <activity android:name="CustomRenderer"
+ android:label="HardwareRenderer/HelloTakeSurface"
+ android:screenOrientation="fullSensor"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="MyLittleTextureView"
- android:label="HardwareRenderer/MyLittleTextureView"
- android:screenOrientation="fullSensor">
+ <activity android:name="MyLittleTextureView"
+ android:label="HardwareRenderer/MyLittleTextureView"
+ android:screenOrientation="fullSensor"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.hwui.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
</intent-filter>
</activity>
diff --git a/tests/HwAccelerationTest/OWNERS b/tests/HwAccelerationTest/OWNERS
new file mode 100644
index 000000000000..c88a9f82c347
--- /dev/null
+++ b/tests/HwAccelerationTest/OWNERS
@@ -0,0 +1 @@
+include /libs/hwui/OWNERS
diff --git a/tests/HwAccelerationTest/res/layout/image_filter_activity.xml b/tests/HwAccelerationTest/res/layout/image_filter_activity.xml
new file mode 100644
index 000000000000..a0ee67ae0bef
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/image_filter_activity.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center">
+
+ <ImageView
+ android:id="@+id/image_filter_test_view"
+ android:background="#FF0000"
+ android:layout_width="200dp"
+ android:layout_height="200dp" />
+</FrameLayout> \ No newline at end of file
diff --git a/tests/HwAccelerationTest/res/layout/scrolling_stretch_surfaceview.xml b/tests/HwAccelerationTest/res/layout/scrolling_stretch_surfaceview.xml
new file mode 100644
index 000000000000..77f5e60dc091
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/scrolling_stretch_surfaceview.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:overScrollMode="always"
+ android:fillViewport="true"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ >
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="100dp"
+ android:layout_marginTop="100dp"
+ android:orientation="horizontal"
+ >
+
+ <ImageView
+ android:id="@+id/vertical_imageview"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent"/>
+ <FrameLayout
+ android:id="@+id/vertical_surfaceview_container"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"/>
+ </LinearLayout>
+
+ <HorizontalScrollView
+ android:overScrollMode="always"
+ android:layout_width="400dp"
+ android:layout_height="0dp"
+ android:background="#FF0000"
+ android:layout_weight="1"
+ >
+ <LinearLayout
+ android:layout_width="400dp"
+ android:layout_height="400dp"
+ android:layout_marginLeft="100dp"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/horizontal_imageview"
+ android:layout_width="100dp"
+ android:layout_weight="1"
+ android:layout_height="0dp"/>
+
+ <FrameLayout
+ android:id="@+id/horizontal_surfaceview_container"
+ android:layout_width="100dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ </LinearLayout>
+ </HorizontalScrollView>
+ </LinearLayout>
+</ScrollView> \ No newline at end of file
diff --git a/tests/HwAccelerationTest/res/layout/stretch_layout.xml b/tests/HwAccelerationTest/res/layout/stretch_layout.xml
new file mode 100644
index 000000000000..81e0c019490f
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/stretch_layout.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/scroll_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <HorizontalScrollView
+ android:id="@+id/horizontal_scroll_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ </LinearLayout>
+ </HorizontalScrollView>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+
+ </LinearLayout>
+</ScrollView>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
new file mode 100644
index 000000000000..e4ca7881f796
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.RenderEffect;
+import android.graphics.RenderNode;
+import android.graphics.Shader;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class BlurActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setClipChildren(false);
+ layout.setGravity(Gravity.CENTER);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(500, 500);
+ params.bottomMargin = 100;
+
+ layout.addView(new BlurGradientView(this), params);
+ layout.addView(new BlurView(this), params);
+
+ setContentView(layout);
+ }
+
+ public static class BlurGradientView extends View {
+ private final float mBlurRadius = 25f;
+ private final Paint mPaint;
+ private final RenderNode mRenderNode;
+
+ public BlurGradientView(Context c) {
+ super(c);
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mRenderNode = new RenderNode("BlurGradientView");
+ mRenderNode.setRenderEffect(
+ RenderEffect.createBlurEffect(
+ mBlurRadius,
+ mBlurRadius,
+ null,
+ Shader.TileMode.DECAL
+ )
+ );
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (changed) {
+ LinearGradient gradient = new LinearGradient(
+ 0f,
+ 0f,
+ right - left,
+ bottom - top,
+ Color.CYAN,
+ Color.YELLOW,
+ Shader.TileMode.CLAMP
+ );
+
+ mPaint.setShader(gradient);
+
+ final int width = right - left;
+ final int height = bottom - top;
+ mRenderNode.setPosition(0, 0, width, height);
+
+ Canvas canvas = mRenderNode.beginRecording();
+ canvas.drawRect(
+ mBlurRadius * 2,
+ mBlurRadius * 2,
+ width - mBlurRadius * 2,
+ height - mBlurRadius * 2,
+ mPaint
+ );
+ mRenderNode.endRecording();
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawRenderNode(mRenderNode);
+ }
+ }
+
+ public static class BlurView extends View {
+
+ private final Paint mPaint;
+ private final RenderNode mRenderNode;
+ private final float mBlurRadius = 20f;
+
+ public BlurView(Context c) {
+ super(c);
+
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mRenderNode = new RenderNode("blurNode");
+ mRenderNode.setRenderEffect(
+ RenderEffect.createBlurEffect(
+ mBlurRadius,
+ mBlurRadius,
+ null,
+ Shader.TileMode.DECAL
+ )
+ );
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (changed) {
+ int width = right - left;
+ int height = bottom - top;
+ mRenderNode.setPosition(0, 0, width, height);
+ Canvas canvas = mRenderNode.beginRecording(width, height);
+ mPaint.setColor(Color.BLUE);
+
+ canvas.drawRect(
+ mBlurRadius * 2,
+ mBlurRadius * 2,
+ width - mBlurRadius * 2,
+ height - mBlurRadius * 2,
+ mPaint
+ );
+
+ mPaint.setColor(Color.RED);
+ canvas.drawCircle((right - left) / 2f, (bottom - top) / 2f, 50f, mPaint);
+
+ mRenderNode.endRecording();
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawRenderNode(mRenderNode);
+ }
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
index 51bae3af3e9c..c06f8fd44c03 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
@@ -22,6 +22,7 @@ import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
@@ -30,12 +31,10 @@ import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.RuntimeShader;
+import android.graphics.Shader;
import android.os.Bundle;
import android.view.View;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
@SuppressWarnings({"UnusedDeclaration"})
public class ColorFiltersMutateActivity extends Activity {
@Override
@@ -52,20 +51,21 @@ public class ColorFiltersMutateActivity extends Activity {
private final Paint mLightingPaint;
private final Paint mBlendPaint;
private final Paint mShaderPaint;
+ private final RuntimeShader mRuntimeShader;
private float mSaturation = 0.0f;
private int mLightAdd = 0;
private int mLightMul = 0;
private int mPorterDuffColor = 0;
+ private float mShaderParam1 = 0.0f;
static final String sSkSL =
- "uniform float param1;\n"
- + "void main(float x, float y, inout half4 color) {\n"
- + "color = half4(color.r, half(param1), color.b, 1.0);\n"
+ "uniform shader bitmapShader;\n"
+ + "uniform float param1;\n"
+ + "half4 main(float2 xy) {\n"
+ + " return half4(sample(bitmapShader, xy).rgb, param1);\n"
+ "}\n";
- private byte[] mUniforms = new byte[4];
-
BitmapsView(Context c) {
super(c);
@@ -83,9 +83,13 @@ public class ColorFiltersMutateActivity extends Activity {
mBlendPaint = new Paint();
mBlendPaint.setColorFilter(new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_OVER));
+ mRuntimeShader = new RuntimeShader(sSkSL, false);
+ mRuntimeShader.setUniform("param1", mShaderParam1);
+ mRuntimeShader.setInputShader("bitmapShader", new BitmapShader(mBitmap1,
+ Shader.TileMode.CLAMP,
+ Shader.TileMode.CLAMP));
mShaderPaint = new Paint();
- mShaderPaint.setShader(new RuntimeShader(sSkSL, mUniforms, true));
- setShaderParam1(0.0f);
+ mShaderPaint.setShader(mRuntimeShader);
ObjectAnimator sat = ObjectAnimator.ofFloat(this, "saturation", 1.0f);
sat.setDuration(1000);
@@ -172,20 +176,15 @@ public class ColorFiltersMutateActivity extends Activity {
}
public void setShaderParam1(float value) {
- RuntimeShader shader = (RuntimeShader) mShaderPaint.getShader();
- ByteBuffer buffer = ByteBuffer.wrap(mUniforms);
- buffer.order(ByteOrder.LITTLE_ENDIAN);
- buffer.putFloat(value);
- shader.updateUniforms(mUniforms);
+ mShaderParam1 = value;
+ mRuntimeShader.setUniform("param1", mShaderParam1);
invalidate();
}
// If either valueFrom or valueTo is null, then a getter function will also be derived
// and called by the animator class.
public float getShaderParam1() {
- ByteBuffer buffer = ByteBuffer.wrap(mUniforms);
- buffer.order(ByteOrder.LITTLE_ENDIAN);
- return buffer.getFloat();
+ return mShaderParam1;
}
@Override
diff --git a/tests/AutoVerify/app1/src/com/android/test/autoverify/MainActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java
index 09ef47212622..c4b0072eaff8 100644
--- a/tests/AutoVerify/app1/src/com/android/test/autoverify/MainActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 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.
@@ -13,3 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class EdgeEffectStretchActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.stretch_layout);
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java
index 029e302d0382..15568ac72227 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java
@@ -34,13 +34,14 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ProgressBar;
+import android.widget.TextView;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
import java.util.Random;
-import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
public class PictureCaptureDemo extends Activity {
@Override
@@ -77,6 +78,12 @@ public class PictureCaptureDemo extends Activity {
iv2.setImageBitmap(Bitmap.createBitmap(picture, 100, 100, Bitmap.Config.HARDWARE));
inner.addView(iv2, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+ TextView hello = new TextView(this);
+ hello.setText("I'm on a layer!");
+ hello.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ inner.addView(hello,
+ new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+
layout.addView(inner,
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
// For testing with a functor in the tree
@@ -84,11 +91,13 @@ public class PictureCaptureDemo extends Activity {
wv.setWebViewClient(new WebViewClient());
wv.setWebChromeClient(new WebChromeClient());
wv.loadUrl("https://google.com");
- layout.addView(wv, new LayoutParams(LayoutParams.MATCH_PARENT, 400));
+ LayoutParams wvParams = new LayoutParams(LayoutParams.MATCH_PARENT, 400);
+ wvParams.bottomMargin = 50;
+ layout.addView(wv, wvParams);
SurfaceView mySurfaceView = new SurfaceView(this);
layout.addView(mySurfaceView,
- new LayoutParams(LayoutParams.MATCH_PARENT, 600));
+ new LayoutParams(LayoutParams.MATCH_PARENT, 600, 1f));
setContentView(layout);
@@ -98,22 +107,29 @@ public class PictureCaptureDemo extends Activity {
@Override
public void surfaceCreated(SurfaceHolder holder) {
final Random rand = new Random();
+ OutputStream renderingStream = new ByteArrayOutputStream() {
+ @Override
+ public void flush() throws IOException {
+ Picture picture = Picture.createFromStream(
+ new ByteArrayInputStream(buf, 0, count));
+ Canvas canvas = holder.lockCanvas();
+ if (canvas != null && picture != null) {
+ canvas.drawPicture(picture);
+ holder.unlockCanvasAndPost(canvas);
+ }
+ reset();
+ }
+ };
+
mStopCapture = ViewDebug.startRenderingCommandsCapture(mySurfaceView,
- mCaptureThread, (picture) -> {
+ Executors.newSingleThreadExecutor(), () -> {
if (rand.nextInt(20) == 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
- Canvas canvas = holder.lockCanvas();
- if (canvas == null) {
- return false;
- }
- canvas.drawPicture(picture);
- holder.unlockCanvasAndPost(canvas);
- picture.close();
- return true;
+ return renderingStream;
});
}
@@ -134,20 +150,4 @@ public class PictureCaptureDemo extends Activity {
}
});
}
-
- ExecutorService mCaptureThread = Executors.newSingleThreadExecutor();
- ExecutorService mExecutor = Executors.newSingleThreadExecutor();
-
- Picture deepCopy(Picture src) {
- try {
- PipedInputStream inputStream = new PipedInputStream();
- PipedOutputStream outputStream = new PipedOutputStream(inputStream);
- Future<Picture> future = mExecutor.submit(() -> Picture.createFromStream(inputStream));
- src.writeToStream(outputStream);
- outputStream.close();
- return future.get();
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- }
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java
index 818d899413de..2ad034cd143e 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PositionListenerActivity.java
@@ -19,8 +19,13 @@ package com.android.test.hwui;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.PointF;
+import android.graphics.RecordingCanvas;
+import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.RenderNode;
import android.os.Bundle;
+import android.view.MotionEvent;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.ScrollView;
@@ -38,7 +43,44 @@ public class PositionListenerActivity extends Activity {
ProgressBar spinner = new ProgressBar(this, null, android.R.attr.progressBarStyleLarge);
layout.addView(spinner);
- ScrollView scrollingThing = new ScrollView(this);
+ ScrollView scrollingThing = new ScrollView(this) {
+ int setting = 0;
+ PointF opts[] = new PointF[] {
+ new PointF(0, 0),
+ new PointF(0, -1f),
+ new PointF(1f, 0),
+ new PointF(0, 1f),
+ new PointF(-1f, 0),
+ new PointF(-1f, 1f),
+ };
+ {
+ setWillNotDraw(false);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
+ setting = (setting + 1) % opts.length;
+ invalidate();
+ }
+ return super.onTouchEvent(ev);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ RenderNode node = ((RecordingCanvas) canvas).mNode;
+ PointF dir = opts[setting];
+ float maxStretchAmount = 100f;
+ // Although we could do this in a single call, the real one won't be - so mimic that
+ if (dir.x != 0f) {
+ node.stretch(dir.x, 0f, maxStretchAmount, maxStretchAmount);
+ }
+ if (dir.y != 0f) {
+ node.stretch(0f, dir.y, maxStretchAmount, maxStretchAmount);
+ }
+ }
+ };
scrollingThing.addView(new MyPositionReporter(this));
layout.addView(scrollingThing);
@@ -49,6 +91,14 @@ public class PositionListenerActivity extends Activity {
RenderNode mNode;
int mCurrentCount = 0;
int mTranslateY = 0;
+ Rect mPosition = new Rect();
+ float mWidth = 0f;
+ float mHeight = 0f;
+ RectF mMappedBounds = new RectF();
+ float mStretchX = 0.0f;
+ float mStretchY = 0.0f;
+ float mStretchMaxX = 0.0f;
+ float mStretchMaxY = 0.0f;
MyPositionReporter(Context c) {
super(c);
@@ -78,18 +128,45 @@ public class PositionListenerActivity extends Activity {
canvas.drawRenderNode(mNode);
}
+ void updateText() {
+ String posText =
+ "%d: Position %s, stretch width %f, height %f, vec %f,%f, amountX %f amountY %f mappedBounds %s";
+ setText(String.format(posText,
+ mCurrentCount, mPosition.toShortString(), mWidth, mHeight,
+ mStretchX, mStretchY, mStretchMaxX, mStretchMaxY,
+ mMappedBounds.toShortString()));
+ }
+
@Override
public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
- post(() -> {
+ getHandler().postAtFrontOfQueue(() -> {
mCurrentCount++;
- setText(String.format("%d: Position [%d, %d, %d, %d]", mCurrentCount,
- left, top, right, bottom));
+ mPosition.set(left, top, right, bottom);
+ updateText();
+ });
+ }
+
+ @Override
+ public void applyStretch(long frameNumber, float width, float height,
+ float vecX, float vecY,
+ float maxStretchX, float maxStretchY, float childRelativeLeft,
+ float childRelativeTop, float childRelativeRight, float childRelativeBottom) {
+ getHandler().postAtFrontOfQueue(() -> {
+ mWidth = width;
+ mHeight = height;
+ mStretchX = vecX;
+ mStretchY = vecY;
+ mStretchMaxX = maxStretchX;
+ mStretchMaxY = maxStretchY;
+ mMappedBounds.set(childRelativeLeft, childRelativeTop, childRelativeRight,
+ childRelativeBottom);
+ updateText();
});
}
@Override
public void positionLost(long frameNumber) {
- post(() -> {
+ getHandler().postAtFrontOfQueue(() -> {
mCurrentCount++;
setText(mCurrentCount + " No position");
});
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectShaderActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectShaderActivity.java
new file mode 100644
index 000000000000..661d48a84768
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectShaderActivity.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.RenderEffect;
+import android.graphics.RenderNode;
+import android.graphics.Shader;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class RenderEffectShaderActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setClipChildren(false);
+ layout.setGravity(Gravity.CENTER);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(500, 500);
+ params.bottomMargin = 100;
+
+ layout.addView(new ShaderRenderEffectView(this), params);
+
+ setContentView(layout);
+ }
+
+ public static class ShaderRenderEffectView extends View {
+
+ private final Paint mPaint;
+ private final RenderNode mRenderNode;
+
+ public ShaderRenderEffectView(Context c) {
+ super(c);
+
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mRenderNode = new RenderNode("blurNode");
+
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (changed) {
+ LinearGradient gradient = new LinearGradient(
+ 0f, 0f,
+ 0f, bottom - top,
+ new int[]{Color.CYAN, Color.MAGENTA},
+ null,
+ Shader.TileMode.CLAMP
+ );
+ mRenderNode.setRenderEffect(
+ RenderEffect.createShaderEffect(gradient)
+ );
+
+ int width = right - left;
+ int height = bottom - top;
+ mRenderNode.setPosition(0, 0, width, height);
+ Canvas canvas = mRenderNode.beginRecording(width, height);
+ mPaint.setColor(Color.BLUE);
+
+ canvas.drawRect(
+ 0,
+ 0,
+ width,
+ height,
+ mPaint
+ );
+
+ mPaint.setColor(Color.RED);
+ canvas.drawCircle((right - left) / 2f, (bottom - top) / 2f, 50f, mPaint);
+
+ mRenderNode.endRecording();
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawRenderNode(mRenderNode);
+ }
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
new file mode 100644
index 000000000000..d925541c76d6
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
@@ -0,0 +1,186 @@
+/*
+ * 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.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RecordingCanvas;
+import android.graphics.RuntimeShader;
+import android.os.Bundle;
+import android.os.Trace;
+import android.view.RenderNodeAnimator;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+
+import java.util.ArrayList;
+
+public class RippleActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ layout.addView(new RippleView(this),
+ new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+
+ setContentView(layout);
+ }
+
+ static class RippleView extends View {
+ static final int DURATION = 1000;
+ static final int MAX_RADIUS = 250;
+ private final int mColor = Color.RED;
+
+ private boolean mToggle = false;
+ ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<RenderNodeAnimator>();
+
+ CanvasProperty<Float> mX;
+ CanvasProperty<Float> mY;
+ CanvasProperty<Float> mRadius;
+ CanvasProperty<Float> mProgress;
+ CanvasProperty<Float> mNoisePhase;
+ CanvasProperty<Paint> mPaint;
+ RuntimeShader mRuntimeShader;
+
+ static final String sSkSL = ""
+ + "uniform float2 in_origin;"
+ + "uniform float in_progress;\n"
+ + "uniform float in_maxRadius;\n"
+ + "uniform shader in_paintColor;\n"
+ + "float dist2(float2 p0, float2 pf) { return sqrt((pf.x - p0.x) * (pf.x - p0.x) + "
+ + "(pf.y - p0.y) * (pf.y - p0.y)); }\n"
+ + "float mod2(float a, float b) { return a - (b * floor(a / b)); }\n"
+ + "float rand(float2 src) { return fract(sin(dot(src.xy, float2(12.9898, 78.233)))"
+ + " * 43758.5453123); }\n"
+ + "float4 main(float2 p)\n"
+ + "{\n"
+ + " float fraction = in_progress;\n"
+ + " float2 fragCoord = p;//sk_FragCoord.xy;\n"
+ + " float maxDist = in_maxRadius;\n"
+ + " float fragDist = dist2(in_origin, fragCoord.xy);\n"
+ + " float circleRadius = maxDist * fraction;\n"
+ + " float colorVal = (fragDist - circleRadius) / maxDist;\n"
+ + " float d = fragDist < circleRadius \n"
+ + " ? 1. - abs(colorVal * 2. * smoothstep(0., 1., fraction)) \n"
+ + " : 1. - abs(colorVal * 3.);\n"
+ + " d = smoothstep(0., 1., d);\n"
+ + " float divider = 2.;\n"
+ + " float x = floor(fragCoord.x / divider);\n"
+ + " float y = floor(fragCoord.y / divider);\n"
+ + " float density = .95;\n"
+ + " d = rand(float2(x, y)) > density ? d : d * .2;\n"
+ + " d = d * rand(float2(fraction, x * y));\n"
+ + " float alpha = 1. - pow(fraction, 3.);\n"
+ + " return float4(sample(in_paintColor, p).rgb, d * alpha);\n"
+ + "}";
+
+ RippleView(Context c) {
+ super(c);
+ setClickable(true);
+
+ mX = CanvasProperty.createFloat(200.0f);
+ mY = CanvasProperty.createFloat(200.0f);
+ mRadius = CanvasProperty.createFloat(150.0f);
+ mProgress = CanvasProperty.createFloat(0.0f);
+ mNoisePhase = CanvasProperty.createFloat(0.0f);
+
+ Paint p = new Paint();
+ p.setAntiAlias(true);
+ p.setColor(mColor);
+ mPaint = CanvasProperty.createPaint(p);
+
+ mRuntimeShader = new RuntimeShader(sSkSL, false);
+ mRuntimeShader.setUniform("in_maxRadius", MAX_RADIUS);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (canvas.isHardwareAccelerated()) {
+ RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
+ recordingCanvas.drawRipple(mX, mY, mRadius, mPaint, mProgress, mNoisePhase,
+ mColor, mRuntimeShader);
+ }
+ }
+
+ @Override
+ public boolean performClick() {
+ for (int i = 0; i < mRunningAnimations.size(); i++) {
+ mRunningAnimations.get(i).cancel();
+ }
+ mRunningAnimations.clear();
+
+ mToggle = !mToggle;
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mX, mToggle ? 400.0f : 200.0f));
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mY, mToggle ? 600.0f : 200.0f));
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mRadius, mToggle ? MAX_RADIUS : 150.0f));
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mProgress, mToggle ? 1.0f : 0.0f));
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mNoisePhase, DURATION));
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mPaint, RenderNodeAnimator.PAINT_ALPHA, 64.0f));
+
+ // Will be "chained" to run after the above
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mPaint, RenderNodeAnimator.PAINT_ALPHA, 255.0f));
+
+ for (int i = 0; i < mRunningAnimations.size(); i++) {
+ RenderNodeAnimator anim = mRunningAnimations.get(i);
+ anim.setDuration(DURATION);
+ anim.setTarget(this);
+ if (i == (mRunningAnimations.size() - 1)) {
+ // "chain" test
+ anim.setStartValue(64.0f);
+ anim.setStartDelay(anim.getDuration());
+ }
+ anim.start();
+ }
+
+ if (mToggle) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "pretendBusy");
+ try {
+ Thread.sleep(DURATION);
+ } catch (InterruptedException e) {
+ }
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ });
+ }
+ return true;
+ }
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ScrollingStretchSurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ScrollingStretchSurfaceViewActivity.java
new file mode 100644
index 000000000000..040bff5d74d8
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ScrollingStretchSurfaceViewActivity.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.SurfaceHolder;
+import android.view.SurfaceHolder.Callback;
+import android.view.SurfaceView;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+public class ScrollingStretchSurfaceViewActivity extends Activity implements Callback {
+
+ SurfaceView mVerticalSurfaceView;
+ SurfaceView mHorizontalSurfaceView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.scrolling_stretch_surfaceview);
+
+ mVerticalSurfaceView = new SurfaceView(this);
+ mVerticalSurfaceView.getHolder().addCallback(this);
+
+ mHorizontalSurfaceView = new SurfaceView(this);
+ mHorizontalSurfaceView.getHolder().addCallback(this);
+
+ FrameLayout verticalContainer = findViewById(R.id.vertical_surfaceview_container);
+ verticalContainer.addView(mVerticalSurfaceView,
+ new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT));
+
+ FrameLayout horizontalContainer = findViewById(R.id.horizontal_surfaceview_container);
+ horizontalContainer.addView(mHorizontalSurfaceView,
+ new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT));
+
+ ImageView verticalImageView = findViewById(R.id.vertical_imageview);
+ verticalImageView.setImageDrawable(new LineDrawable());
+
+ ImageView horizontalImageView = findViewById(R.id.horizontal_imageview);
+ horizontalImageView.setImageDrawable(new LineDrawable());
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Canvas canvas = holder.lockCanvas();
+
+ drawLine(canvas, width, height);
+ holder.unlockCanvasAndPost(canvas);
+ }
+
+ private static void drawLine(Canvas canvas, int width, int height) {
+ canvas.drawColor(Color.GRAY);
+
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setColor(Color.GREEN);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeWidth(10f);
+ canvas.drawLine(0, 0, width, height, paint);
+ }
+
+ private static class LineDrawable extends Drawable {
+ @Override
+ public void draw(Canvas canvas) {
+ drawLine(canvas, getBounds().width(), getBounds().height());
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ // NO-OP
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ // NO-OP
+ }
+
+ @Override
+ public int getOpacity() {
+ return 0;
+ }
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
new file mode 100644
index 000000000000..3307c36d9d1a
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
@@ -0,0 +1,537 @@
+/*
+ * 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.test.hwui;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.RecordingCanvas;
+import android.graphics.Rect;
+import android.graphics.RenderEffect;
+import android.graphics.RuntimeShader;
+import android.graphics.Shader;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+public class StretchShaderActivity extends Activity {
+
+ private static final float MAX_STRETCH_INTENSITY = 1.5f;
+ private static final float STRETCH_AFFECTED_DISTANCE = 1.0f;
+
+ private float mScrollX = 0f;
+ private float mScrollY = 0f;
+
+ private float mMaxStretchIntensity = MAX_STRETCH_INTENSITY;
+ private float mStretchAffectedDistance = STRETCH_AFFECTED_DISTANCE;
+
+ private float mOverscrollX = 25f;
+ private float mOverscrollY = 25f;
+
+ private RuntimeShader mRuntimeShader;
+ private ImageView mImageView;
+ private ImageView mTestImageView;
+
+ private Bitmap mBitmap;
+
+ private StretchDrawable mStretchDrawable = new StretchDrawable();
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout linearLayout = new LinearLayout(this);
+ linearLayout.setOrientation(LinearLayout.VERTICAL);
+
+ mBitmap = ((BitmapDrawable) getDrawable(R.drawable.sunset1)).getBitmap();
+ mRuntimeShader = new RuntimeShader(SKSL, false);
+
+ BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP,
+ Shader.TileMode.CLAMP);
+ mRuntimeShader.setInputShader("uContentTexture", bitmapShader);
+
+ mImageView = new ImageView(this);
+
+ mImageView.setRenderEffect(RenderEffect.createShaderEffect(mRuntimeShader));
+ mImageView.setImageDrawable(new ColorDrawable(Color.CYAN));
+
+ TextView overscrollXText = new TextView(this);
+ overscrollXText.setText("Overscroll X");
+
+ SeekBar overscrollXBar = new SeekBar(this);
+ overscrollXBar.setProgress(0);
+ overscrollXBar.setMin(-50);
+ overscrollXBar.setMax(50);
+ overscrollXBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mOverscrollX = progress;
+ overscrollXText.setText("Overscroll X: " + mOverscrollX);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+ TextView overscrollYText = new TextView(this);
+ overscrollYText.setText("Overscroll Y");
+
+ SeekBar overscrollYBar = new SeekBar(this);
+ overscrollYBar.setProgress(0);
+ overscrollYBar.setMin(-50);
+ overscrollYBar.setMax(50);
+ overscrollYBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mOverscrollY = progress;
+ overscrollYText.setText("Overscroll Y: " + mOverscrollY);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+ TextView scrollXText = new TextView(this);
+ scrollXText.setText("Scroll X");
+ SeekBar scrollXSeekBar = new SeekBar(this);
+ scrollXSeekBar.setMin(0);
+ scrollXSeekBar.setMax(100);
+ scrollXSeekBar.setProgress(0);
+ scrollXSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mScrollX = (progress / 100f);
+ scrollXText.setText("Scroll X: " + mScrollY);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+ TextView scrollYText = new TextView(this);
+ scrollYText.setText("Scroll Y");
+ SeekBar scrollYSeekBar = new SeekBar(this);
+ scrollYSeekBar.setMin(0);
+ scrollYSeekBar.setMax(100);
+ scrollYSeekBar.setProgress(0);
+ scrollYSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mScrollY = (progress / 100f);
+ scrollYText.setText("Scroll Y: " + mScrollY);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+ TextView stretchIntensityText = new TextView(this);
+ int stretchProgress = (int) (mMaxStretchIntensity * 100);
+ stretchIntensityText.setText("StretchIntensity: " + mMaxStretchIntensity);
+ SeekBar stretchIntensitySeekbar = new SeekBar(this);
+ stretchIntensitySeekbar.setProgress(stretchProgress);
+ stretchIntensitySeekbar.setMin(1);
+ stretchIntensitySeekbar.setMax((int) (MAX_STRETCH_INTENSITY * 100));
+ stretchIntensitySeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mMaxStretchIntensity = progress / 100f;
+ stretchIntensityText.setText("StretchIntensity: " + mMaxStretchIntensity);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+ TextView stretchDistanceText = new TextView(this);
+ stretchDistanceText.setText("StretchDistance");
+ SeekBar stretchDistanceSeekbar = new SeekBar(this);
+ stretchDistanceSeekbar.setMin(0);
+ stretchDistanceSeekbar.setProgress((int) (mStretchAffectedDistance * 100));
+ stretchDistanceSeekbar.setMax(100);
+ stretchDistanceSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mStretchAffectedDistance = progress / 100f;
+ stretchDistanceText.setText("StretchDistance: " + mStretchAffectedDistance);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+
+ linearLayout.addView(mImageView,
+ new LinearLayout.LayoutParams(
+ mBitmap.getWidth(),
+ mBitmap.getHeight())
+ );
+
+ linearLayout.addView(overscrollXText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+ linearLayout.addView(overscrollXBar,
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ );
+
+ linearLayout.addView(overscrollYText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+ linearLayout.addView(overscrollYBar,
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ );
+
+ linearLayout.addView(scrollXText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+
+ linearLayout.addView(scrollXSeekBar,
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ ));
+
+ linearLayout.addView(scrollYText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+
+ linearLayout.addView(scrollYSeekBar,
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ ));
+
+ linearLayout.addView(stretchIntensityText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ )
+ );
+
+ linearLayout.addView(stretchIntensitySeekbar,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ )
+ );
+
+ linearLayout.addView(stretchDistanceText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+
+ linearLayout.addView(stretchDistanceSeekbar,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+
+ ImageView test = new ImageView(this);
+ mStretchDrawable.setBitmap(mBitmap);
+ test.setImageDrawable(mStretchDrawable);
+
+ mTestImageView = test;
+ linearLayout.addView(test,
+ new LinearLayout.LayoutParams(mBitmap.getWidth(), mBitmap.getHeight()));
+
+ setContentView(linearLayout);
+
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mImageView.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ updateShader();
+ mImageView.getViewTreeObserver().removeOnPreDrawListener(this);
+ return false;
+ }
+ });
+ }
+
+ private void updateShader() {
+ final float width = mImageView.getWidth();
+ final float height = mImageView.getHeight();
+ final float distanceNotStretched = mStretchAffectedDistance;
+ final float normOverScrollDistX = mOverscrollX / width;
+ final float normOverScrollDistY = mOverscrollY / height;
+ final float distanceStretchedX =
+ mStretchAffectedDistance
+ / (1 + Math.abs(normOverScrollDistX) * mMaxStretchIntensity);
+ final float distanceStretchedY =
+ mStretchAffectedDistance
+ / (1 + Math.abs(normOverScrollDistY) * mMaxStretchIntensity);
+ final float diffX = distanceStretchedX - distanceNotStretched;
+ final float diffY = distanceStretchedY - distanceNotStretched;
+ float uScrollX = mScrollX;
+ float uScrollY = mScrollY;
+
+ mRuntimeShader.setUniform("uMaxStretchIntensity", mMaxStretchIntensity);
+ mRuntimeShader.setUniform("uStretchAffectedDist", mStretchAffectedDistance);
+ mRuntimeShader.setUniform("uDistanceStretchedX", distanceStretchedX);
+ mRuntimeShader.setUniform("uDistanceStretchedY", distanceStretchedY);
+ mRuntimeShader.setUniform("uDistDiffX", diffX);
+ mRuntimeShader.setUniform("uDistDiffY", diffY);
+ mRuntimeShader.setUniform("uOverscrollX", normOverScrollDistX);
+ mRuntimeShader.setUniform("uOverscrollY", normOverScrollDistY);
+ mRuntimeShader.setUniform("uScrollX", uScrollX);
+ mRuntimeShader.setUniform("uScrollY", uScrollY);
+ mRuntimeShader.setUniform("viewportWidth", width);
+ mRuntimeShader.setUniform("viewportHeight", height);
+
+ mImageView.setRenderEffect(RenderEffect.createShaderEffect(mRuntimeShader));
+
+ mStretchDrawable.setStretchDistance(mStretchAffectedDistance);
+ mStretchDrawable.setOverscrollX(normOverScrollDistX);
+ mStretchDrawable.setOverscrollY(normOverScrollDistY);
+ }
+
+ private static class StretchDrawable extends Drawable {
+
+ private float mStretchDistance = 0;
+ private float mOverScrollX = 0f;
+ private float mOverScrollY = 0f;
+ private Bitmap mBitmap = null;
+
+ public void setStretchDistance(float stretchDistance) {
+ mStretchDistance = stretchDistance;
+ invalidateSelf();
+ }
+
+ public void setOverscrollX(float overscrollX) {
+ mOverScrollX = overscrollX;
+ invalidateSelf();
+ }
+
+ public void setOverscrollY(float overscrollY) {
+ mOverScrollY = overscrollY;
+ invalidateSelf();
+ }
+
+ public void setBitmap(Bitmap bitmap) {
+ mBitmap = bitmap;
+ invalidateSelf();
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mStretchDistance > 0 && canvas instanceof RecordingCanvas) {
+ Rect bounds = getBounds();
+ ((RecordingCanvas) canvas).mNode.stretch(
+ mOverScrollX,
+ mOverScrollY,
+ mStretchDistance,
+ mStretchDistance
+ );
+ }
+ if (mBitmap != null) {
+ canvas.drawBitmap(mBitmap, 0f, 0f, null);
+ }
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+
+ }
+
+ @Override
+ public int getOpacity() {
+ return 0;
+ }
+ }
+
+ private static final String SKSL = "uniform shader uContentTexture;\n"
+ + "uniform float uMaxStretchIntensity; // multiplier to apply to scale effect\n"
+ + "uniform float uStretchAffectedDist; // Maximum percentage to stretch beyond bounds"
+ + " of target\n"
+ + "\n"
+ + "// Distance stretched as a function of the normalized overscroll times scale "
+ + "intensity\n"
+ + "uniform float uDistanceStretchedX;\n"
+ + "uniform float uDistanceStretchedY;\n"
+ + "uniform float uDistDiffX;\n"
+ + "uniform float uDistDiffY; // Difference between the peak stretch amount and "
+ + "overscroll amount normalized\n"
+ + "uniform float uScrollX; // Horizontal offset represented as a ratio of pixels "
+ + "divided by the target width\n"
+ + "uniform float uScrollY; // Vertical offset represented as a ratio of pixels "
+ + "divided by the target height\n"
+ + "uniform float uOverscrollX; // Normalized overscroll amount in the horizontal "
+ + "direction\n"
+ + "uniform float uOverscrollY; // Normalized overscroll amount in the vertical "
+ + "direction\n"
+ + "\n"
+ + "uniform float viewportWidth; // target height in pixels\n"
+ + "uniform float viewportHeight; // target width in pixels\n"
+ + "\n"
+ + "vec4 main(vec2 coord) {\n"
+ + "\n"
+ + " // Normalize SKSL pixel coordinate into a unit vector\n"
+ + " vec2 uv = vec2(coord.x / viewportWidth, coord.y / viewportHeight);\n"
+ + " float inU = uv.x;\n"
+ + " float inV = uv.y;\n"
+ + " float outU;\n"
+ + " float outV;\n"
+ + " float stretchIntensity;\n"
+ + "\n"
+ + " // Add the normalized scroll position within scrolling list\n"
+ + " inU += uScrollX;\n"
+ + " inV += uScrollY;\n"
+ + "\n"
+ + " outU = inU;\n"
+ + " outV = inV;\n"
+ + " if (uOverscrollX > 0) {\n"
+ + " if (inU <= uStretchAffectedDist) {\n"
+ + " inU = uStretchAffectedDist - inU;\n"
+ + " float posBasedVariation = smoothstep(0., uStretchAffectedDist, inU);\n"
+ + " stretchIntensity = uMaxStretchIntensity * uOverscrollX * "
+ + "posBasedVariation;\n"
+ + " outU = uDistanceStretchedX - (inU / (1. + stretchIntensity));\n"
+ + " } else {\n"
+ + " outU = uDistDiffX + inU;\n"
+ + " }\n"
+ + " }\n"
+ + "\n"
+ + " if (uOverscrollX < 0) {\n"
+ + " float stretchAffectedDist = 1. - uStretchAffectedDist;\n"
+ + " if (inU >= stretchAffectedDist) {\n"
+ + " inU = inU - stretchAffectedDist;\n"
+ + " float posBasedVariation = (smoothstep(0., uStretchAffectedDist, "
+ + "inU));\n"
+ + " stretchIntensity = uMaxStretchIntensity * (-uOverscrollX) * "
+ + "posBasedVariation;\n"
+ + " outU = 1 - (uDistanceStretchedX - (inU / (1. + stretchIntensity)))"
+ + ";\n"
+ + " } else if (inU < stretchAffectedDist) {\n"
+ + " outU = -uDistDiffX + inU;\n"
+ + " }\n"
+ + " }\n"
+ + "\n"
+ + " if (uOverscrollY > 0) {\n"
+ + " if (inV <= uStretchAffectedDist) {\n"
+ + " inV = uStretchAffectedDist - inV;\n"
+ + " float posBasedVariation = smoothstep(0., uStretchAffectedDist, inV);\n"
+ + " stretchIntensity = uMaxStretchIntensity * uOverscrollY * "
+ + "posBasedVariation;\n"
+ + " outV = uDistanceStretchedY - (inV / (1. + stretchIntensity));\n"
+ + " } else if (inV >= uStretchAffectedDist) {\n"
+ + " outV = uDistDiffY + inV;\n"
+ + " }\n"
+ + " }\n"
+ + "\n"
+ + " if (uOverscrollY < 0) {\n"
+ + " float stretchAffectedDist = 1. - uStretchAffectedDist;\n"
+ + " if (inV >= stretchAffectedDist) {\n"
+ + " inV = inV - stretchAffectedDist;\n"
+ + " float posBasedVariation = (smoothstep(0., uStretchAffectedDist, inV));\n"
+ + " stretchIntensity = uMaxStretchIntensity * (-uOverscrollY) * "
+ + "posBasedVariation;\n"
+ + " outV = 1 - (uDistanceStretchedY - (inV / (1. + stretchIntensity)));\n"
+ + " } else if (inV < stretchAffectedDist) {\n"
+ + " outV = -uDistDiffY + inV;\n"
+ + " }\n"
+ + " }\n"
+ + "\n"
+ + " uv.x = outU;\n"
+ + " uv.y = outV;\n"
+ + " coord.x = uv.x * viewportWidth;\n"
+ + " coord.y = uv.y * viewportHeight;\n"
+ + " return sample(uContentTexture, coord);\n"
+ + "}";
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java
new file mode 100644
index 000000000000..acb872cd23b8
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchySurfaceViewActivity.java
@@ -0,0 +1,158 @@
+/*
+ * 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.test.hwui;
+
+import android.animation.ObjectAnimator;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.SurfaceHolder;
+import android.view.SurfaceHolder.Callback;
+import android.view.SurfaceView;
+import android.view.animation.LinearInterpolator;
+import android.widget.FrameLayout;
+
+public class StretchySurfaceViewActivity extends Activity implements Callback {
+ SurfaceView mSurfaceView;
+ ObjectAnimator mAnimator;
+
+ class MySurfaceView extends SurfaceView {
+ boolean mSlow;
+ boolean mScaled;
+ int mToggle = 0;
+
+ public MySurfaceView(Context context) {
+ super(context);
+ setOnClickListener(v -> {
+ mToggle = (mToggle + 1) % 4;
+ mSlow = (mToggle & 0x2) != 0;
+ mScaled = (mToggle & 0x1) != 0;
+
+ mSurfaceView.setScaleX(mScaled ? 1.6f : 1f);
+ mSurfaceView.setScaleY(mScaled ? 0.8f : 1f);
+
+ setTitle("Slow=" + mSlow + ", scaled=" + mScaled);
+ invalidate();
+ });
+ setWillNotDraw(false);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
+ if (mSlow) {
+ try {
+ Thread.sleep(16);
+ } catch (InterruptedException e) {}
+ }
+ }
+
+ public void setMyTranslationY(float ty) {
+ setTranslationY(ty);
+ if (mSlow) {
+ invalidate();
+ }
+ }
+
+ public float getMyTranslationY() {
+ return getTranslationY();
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ FrameLayout content = new FrameLayout(this) {
+ {
+ setWillNotDraw(false);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setColor(Color.RED);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeWidth(10f);
+ canvas.drawLine(0f, 0f, getWidth(), getHeight(), paint);
+ super.onDraw(canvas);
+
+ RenderNode node = ((RecordingCanvas) canvas).mNode;
+ node.stretch(0f,
+ 1f, 400f, 400f);
+ }
+ };
+
+ mSurfaceView = new MySurfaceView(this);
+ mSurfaceView.getHolder().addCallback(this);
+
+ final float density = getResources().getDisplayMetrics().density;
+ int size = (int) (200 * density);
+
+ content.addView(mSurfaceView, new FrameLayout.LayoutParams(
+ size, size, Gravity.CENTER_HORIZONTAL | Gravity.TOP));
+ mAnimator = ObjectAnimator.ofFloat(mSurfaceView, "myTranslationY",
+ 0, size);
+ mAnimator.setRepeatMode(ObjectAnimator.REVERSE);
+ mAnimator.setRepeatCount(ObjectAnimator.INFINITE);
+ mAnimator.setDuration(1000);
+ mAnimator.setInterpolator(new LinearInterpolator());
+ setContentView(content);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Canvas canvas = holder.lockCanvas();
+ canvas.drawColor(Color.WHITE);
+
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setColor(Color.GREEN);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeWidth(10f);
+ canvas.drawLine(0, 0, width, height, paint);
+
+ holder.unlockCanvasAndPost(canvas);
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mAnimator.start();
+ }
+
+ @Override
+ protected void onPause() {
+ mAnimator.pause();
+ super.onPause();
+ }
+}
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
new file mode 100644
index 000000000000..eacf5b287a2e
--- /dev/null
+++ b/tests/Input/Android.bp
@@ -0,0 +1,25 @@
+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"],
+}
+
+android_test {
+ name: "InputTests",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+ static_libs: [
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "truth-prebuilt",
+ "ub-uiautomator",
+ ],
+ test_suites: ["device-tests"],
+}
diff --git a/tests/Input/AndroidManifest.xml b/tests/Input/AndroidManifest.xml
new file mode 100644
index 000000000000..20f564e80b3d
--- /dev/null
+++ b/tests/Input/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.input">
+ <uses-permission android:name="android.permission.MONITOR_INPUT"/>
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+ <uses-permission android:name="android.permission.INJECT_EVENTS"/>
+
+ <application android:label="InputTest">
+
+ <activity android:name=".UnresponsiveGestureMonitorActivity"
+ android:label="Unresponsive gesture monitor"
+ android:process=":externalProcess">
+ </activity>
+
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.test.input"
+ android:label="Input Tests"/>
+</manifest>
diff --git a/tests/Input/AndroidTest.xml b/tests/Input/AndroidTest.xml
new file mode 100644
index 000000000000..c62db1ea5ca9
--- /dev/null
+++ b/tests/Input/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright 2020 Google Inc. All Rights Reserved.
+ -->
+<configuration description="Runs Input Tests">
+ <option name="test-tag" value="InputTests" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on" />
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="InputTests.apk"/>
+
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.test.input"/>
+ <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+ <option name="shell-timeout" value="660s" />
+ <option name="test-timeout" value="600s" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/tests/Input/OWNERS b/tests/Input/OWNERS
new file mode 100644
index 000000000000..d701f23cb9b8
--- /dev/null
+++ b/tests/Input/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/hardware/input/OWNERS
diff --git a/tests/Input/TEST_MAPPING b/tests/Input/TEST_MAPPING
new file mode 100644
index 000000000000..15b2bfa9fdc1
--- /dev/null
+++ b/tests/Input/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "InputTests"
+ }
+ ]
+}
diff --git a/tests/Input/src/com/android/test/input/AnrTest.kt b/tests/Input/src/com/android/test/input/AnrTest.kt
new file mode 100644
index 000000000000..4da3eca25ea0
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/AnrTest.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.input
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.filters.MediumTest
+
+import android.graphics.Rect
+import android.os.SystemClock
+import android.provider.Settings
+import android.provider.Settings.Global.HIDE_ERROR_DIALOGS
+import android.support.test.uiautomator.By
+import android.support.test.uiautomator.UiDevice
+import android.support.test.uiautomator.UiObject2
+import android.support.test.uiautomator.Until
+import android.view.InputDevice
+import android.view.MotionEvent
+
+import org.junit.After
+import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * This test makes sure that an unresponsive gesture monitor gets an ANR.
+ *
+ * The gesture monitor must be registered from a different process than the instrumented process.
+ * Otherwise, when the test runs, you will get:
+ * Test failed to run to completion.
+ * Reason: 'Instrumentation run failed due to 'keyDispatchingTimedOut''.
+ * Check device logcat for details
+ * RUNNER ERROR: Instrumentation run failed due to 'keyDispatchingTimedOut'
+ */
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class AnrTest {
+ companion object {
+ private const val TAG = "AnrTest"
+ }
+
+ val mInstrumentation = InstrumentationRegistry.getInstrumentation()
+ var mHideErrorDialogs = 0
+
+ @Before
+ fun setUp() {
+ val contentResolver = mInstrumentation.targetContext.contentResolver
+ mHideErrorDialogs = Settings.Global.getInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
+ Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
+ }
+
+ @After
+ fun tearDown() {
+ val contentResolver = mInstrumentation.targetContext.contentResolver
+ Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, mHideErrorDialogs)
+ }
+
+ @Test
+ fun testGestureMonitorAnr() {
+ startUnresponsiveActivity()
+ val uiDevice: UiDevice = UiDevice.getInstance(mInstrumentation)
+ val obj: UiObject2? = uiDevice.wait(Until.findObject(
+ By.text("Unresponsive gesture monitor")), 10000)
+
+ if (obj == null) {
+ fail("Could not find unresponsive activity")
+ return
+ }
+
+ val rect: Rect = obj.visibleBounds
+ val downTime = SystemClock.uptimeMillis()
+ val downEvent = MotionEvent.obtain(downTime, downTime,
+ MotionEvent.ACTION_DOWN, rect.left.toFloat(), rect.top.toFloat(), 0 /* metaState */)
+ downEvent.source = InputDevice.SOURCE_TOUCHSCREEN
+
+ mInstrumentation.uiAutomation.injectInputEvent(downEvent, false /* sync*/)
+
+ // Todo: replace using timeout from android.hardware.input.IInputManager
+ SystemClock.sleep(5000) // default ANR timeout for gesture monitors
+
+ clickCloseAppOnAnrDialog()
+ }
+
+ private fun clickCloseAppOnAnrDialog() {
+ // Find anr dialog and kill app
+ val uiDevice: UiDevice = UiDevice.getInstance(mInstrumentation)
+ val closeAppButton: UiObject2? =
+ uiDevice.wait(Until.findObject(By.res("android:id/aerr_close")), 20000)
+ if (closeAppButton == null) {
+ fail("Could not find anr dialog")
+ return
+ }
+ closeAppButton.click()
+ }
+
+ private fun startUnresponsiveActivity() {
+ val flags = " -W -n "
+ val startCmd = "am start $flags com.android.test.input/.UnresponsiveGestureMonitorActivity"
+ mInstrumentation.uiAutomation.executeShellCommand(startCmd)
+ }
+} \ No newline at end of file
diff --git a/tests/Input/src/com/android/test/input/InputDeviceTest.java b/tests/Input/src/com/android/test/input/InputDeviceTest.java
new file mode 100644
index 000000000000..63500774816a
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/InputDeviceTest.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 android.view;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputDeviceTest {
+ private static final float DELTA = 0.01f;
+ private static final int DEVICE_ID = 1000;
+
+ private void assertMotionRangeEquals(InputDevice.MotionRange range,
+ InputDevice.MotionRange outRange) {
+ assertEquals(range.getAxis(), outRange.getAxis());
+ assertEquals(range.getSource(), outRange.getSource());
+ assertEquals(range.getMin(), outRange.getMin(), DELTA);
+ assertEquals(range.getMax(), outRange.getMax(), DELTA);
+ assertEquals(range.getFlat(), outRange.getFlat(), DELTA);
+ assertEquals(range.getFuzz(), outRange.getFuzz(), DELTA);
+ assertEquals(range.getResolution(), outRange.getResolution(), DELTA);
+ }
+
+ private void assertDeviceEquals(InputDevice device, InputDevice outDevice) {
+ assertEquals(device.getId(), outDevice.getId());
+ assertEquals(device.getGeneration(), outDevice.getGeneration());
+ assertEquals(device.getControllerNumber(), outDevice.getControllerNumber());
+ assertEquals(device.getName(), outDevice.getName());
+ assertEquals(device.getVendorId(), outDevice.getVendorId());
+ assertEquals(device.getProductId(), outDevice.getProductId());
+ assertEquals(device.getDescriptor(), outDevice.getDescriptor());
+ assertEquals(device.isExternal(), outDevice.isExternal());
+ assertEquals(device.getSources(), outDevice.getSources());
+ assertEquals(device.getKeyboardType(), outDevice.getKeyboardType());
+ assertEquals(device.getMotionRanges().size(), outDevice.getMotionRanges().size());
+
+ KeyCharacterMap keyCharacterMap = device.getKeyCharacterMap();
+ KeyCharacterMap outKeyCharacterMap = outDevice.getKeyCharacterMap();
+ assertTrue("keyCharacterMap not equal", keyCharacterMap.equals(outKeyCharacterMap));
+
+ for (int j = 0; j < device.getMotionRanges().size(); j++) {
+ assertMotionRangeEquals(device.getMotionRanges().get(j),
+ outDevice.getMotionRanges().get(j));
+ }
+ }
+
+ private void assertInputDeviceParcelUnparcel(KeyCharacterMap keyCharacterMap) {
+ final InputDevice device =
+ new InputDevice(DEVICE_ID, 0 /* generation */, 0 /* controllerNumber */, "name",
+ 0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */,
+ 0 /* sources */, 0 /* keyboardType */, keyCharacterMap,
+ false /* hasVibrator */, false /* hasMicrophone */, false /* hasButtonUnderpad */,
+ true /* hasSensor */, false /* hasBattery */);
+
+ Parcel parcel = Parcel.obtain();
+ device.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ InputDevice outDevice = InputDevice.CREATOR.createFromParcel(parcel);
+ assertDeviceEquals(device, outDevice);
+ }
+
+ @Test
+ public void testParcelUnparcelInputDevice_VirtualCharacterMap() {
+ final KeyCharacterMap keyCharacterMap =
+ KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+ assertInputDeviceParcelUnparcel(keyCharacterMap);
+ }
+
+ @Test
+ public void testParcelUnparcelInputDevice_EmptyCharacterMap() {
+ final KeyCharacterMap keyCharacterMap = KeyCharacterMap.obtainEmptyMap(DEVICE_ID);
+ assertInputDeviceParcelUnparcel(keyCharacterMap);
+ }
+}
diff --git a/tests/Input/src/com/android/test/input/InputEventAssignerTest.kt b/tests/Input/src/com/android/test/input/InputEventAssignerTest.kt
new file mode 100644
index 000000000000..c1a86b3a2dac
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/InputEventAssignerTest.kt
@@ -0,0 +1,130 @@
+/*
+ * 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.test.input
+
+import android.view.InputDevice.SOURCE_MOUSE
+import android.view.InputDevice.SOURCE_TOUCHSCREEN
+import android.view.InputEventAssigner
+import android.view.KeyEvent
+import android.view.MotionEvent
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+/**
+ * Create a MotionEvent with the provided action, eventTime, and source
+ */
+fun createMotionEvent(action: Int, eventTime: Long, source: Int): MotionEvent {
+ val downTime: Long = 10
+ val x = 1f
+ val y = 2f
+ val pressure = 3f
+ val size = 1f
+ val metaState = 0
+ val xPrecision = 0f
+ val yPrecision = 0f
+ val deviceId = 1
+ val edgeFlags = 0
+ val displayId = 0
+ return MotionEvent.obtain(downTime, eventTime, action, x, y, pressure, size, metaState,
+ xPrecision, yPrecision, deviceId, edgeFlags, source, displayId)
+}
+
+private fun createKeyEvent(action: Int, eventTime: Long): KeyEvent {
+ val code = KeyEvent.KEYCODE_A
+ val repeat = 0
+ return KeyEvent(eventTime, eventTime, action, code, repeat)
+}
+
+class InputEventAssignerTest {
+ companion object {
+ private const val TAG = "InputEventAssignerTest"
+ }
+
+ /**
+ * A single MOVE event should be assigned to the next available frame.
+ */
+ @Test
+ fun testTouchGesture() {
+ val assigner = InputEventAssigner()
+ val event = createMotionEvent(MotionEvent.ACTION_MOVE, 10, SOURCE_TOUCHSCREEN)
+ val eventId = assigner.processEvent(event)
+ assertEquals(event.id, eventId)
+ }
+
+ /**
+ * DOWN event should be used until a vsync comes in. After vsync, the latest event should be
+ * produced.
+ */
+ @Test
+ fun testTouchDownWithMove() {
+ val assigner = InputEventAssigner()
+ val down = createMotionEvent(MotionEvent.ACTION_DOWN, 10, SOURCE_TOUCHSCREEN)
+ val move1 = createMotionEvent(MotionEvent.ACTION_MOVE, 12, SOURCE_TOUCHSCREEN)
+ val move2 = createMotionEvent(MotionEvent.ACTION_MOVE, 13, SOURCE_TOUCHSCREEN)
+ val move3 = createMotionEvent(MotionEvent.ACTION_MOVE, 14, SOURCE_TOUCHSCREEN)
+ val move4 = createMotionEvent(MotionEvent.ACTION_MOVE, 15, SOURCE_TOUCHSCREEN)
+ var eventId = assigner.processEvent(down)
+ assertEquals(down.id, eventId)
+ eventId = assigner.processEvent(move1)
+ assertEquals(down.id, eventId)
+ eventId = assigner.processEvent(move2)
+ // Even though we already had 2 move events, there was no choreographer callback yet.
+ // Therefore, we should still get the id of the down event
+ assertEquals(down.id, eventId)
+
+ // Now send CALLBACK_INPUT to the assigner. It should provide the latest motion event
+ assigner.notifyFrameProcessed()
+ eventId = assigner.processEvent(move3)
+ assertEquals(move3.id, eventId)
+ eventId = assigner.processEvent(move4)
+ assertEquals(move4.id, eventId)
+ }
+
+ /**
+ * Similar to the above test, but with SOURCE_MOUSE. Since we don't have down latency
+ * concept for non-touchscreens, the latest input event will be used.
+ */
+ @Test
+ fun testMouseDownWithMove() {
+ val assigner = InputEventAssigner()
+ val down = createMotionEvent(MotionEvent.ACTION_DOWN, 10, SOURCE_MOUSE)
+ val move1 = createMotionEvent(MotionEvent.ACTION_MOVE, 12, SOURCE_MOUSE)
+ var eventId = assigner.processEvent(down)
+ assertEquals(down.id, eventId)
+ eventId = assigner.processEvent(move1)
+ assertEquals(move1.id, eventId)
+ }
+
+ /**
+ * KeyEvents are processed immediately, so the latest event should be returned.
+ */
+ @Test
+ fun testKeyEvent() {
+ val assigner = InputEventAssigner()
+ val down = createKeyEvent(KeyEvent.ACTION_DOWN, 20)
+ var eventId = assigner.processEvent(down)
+ assertEquals(down.id, eventId)
+ val up = createKeyEvent(KeyEvent.ACTION_UP, 21)
+ eventId = assigner.processEvent(up)
+ // DOWN is only sticky for Motions, not for keys
+ assertEquals(up.id, eventId)
+ assigner.notifyFrameProcessed()
+ val down2 = createKeyEvent(KeyEvent.ACTION_DOWN, 22)
+ eventId = assigner.processEvent(down2)
+ assertEquals(down2.id, eventId)
+ }
+}
diff --git a/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt b/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt
new file mode 100644
index 000000000000..014efc2b954c
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/InputEventSenderAndReceiverTest.kt
@@ -0,0 +1,165 @@
+/*
+ * 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.test.input
+
+import android.os.HandlerThread
+import android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS
+import android.os.Looper
+import android.view.InputChannel
+import android.view.InputEvent
+import android.view.InputEventReceiver
+import android.view.InputEventSender
+import android.view.KeyEvent
+import android.view.MotionEvent
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.concurrent.TimeUnit
+import org.junit.Assert.assertEquals
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+
+private fun assertKeyEvent(expected: KeyEvent, received: KeyEvent) {
+ assertEquals(expected.action, received.action)
+ assertEquals(expected.deviceId, received.deviceId)
+ assertEquals(expected.downTime, received.downTime)
+ assertEquals(expected.eventTime, received.eventTime)
+ assertEquals(expected.keyCode, received.keyCode)
+ assertEquals(expected.scanCode, received.scanCode)
+ assertEquals(expected.repeatCount, received.repeatCount)
+ assertEquals(expected.metaState, received.metaState)
+ assertEquals(expected.flags, received.flags)
+ assertEquals(expected.source, received.source)
+ assertEquals(expected.displayId, received.displayId)
+}
+
+private fun <T> getEvent(queue: LinkedBlockingQueue<T>): T {
+ try {
+ return queue.poll(DEFAULT_DISPATCHING_TIMEOUT_MILLIS.toLong(), TimeUnit.MILLISECONDS)
+ } catch (e: InterruptedException) {
+ throw RuntimeException("Unexpectedly interrupted while waiting for event")
+ }
+}
+
+class TestInputEventReceiver(channel: InputChannel, looper: Looper) :
+ InputEventReceiver(channel, looper) {
+ private val mInputEvents = LinkedBlockingQueue<InputEvent>()
+
+ override fun onInputEvent(event: InputEvent) {
+ when (event) {
+ is KeyEvent -> mInputEvents.put(KeyEvent.obtain(event))
+ is MotionEvent -> mInputEvents.put(MotionEvent.obtain(event))
+ else -> throw Exception("Received $event is neither a key nor a motion")
+ }
+ finishInputEvent(event, true /*handled*/)
+ }
+
+ fun getInputEvent(): InputEvent {
+ return getEvent(mInputEvents)
+ }
+}
+
+class TestInputEventSender(channel: InputChannel, looper: Looper) :
+ InputEventSender(channel, looper) {
+ data class FinishedSignal(val seq: Int, val handled: Boolean)
+ data class Timeline(val inputEventId: Int, val gpuCompletedTime: Long, val presentTime: Long)
+
+ private val mFinishedSignals = LinkedBlockingQueue<FinishedSignal>()
+ private val mTimelines = LinkedBlockingQueue<Timeline>()
+
+ override fun onInputEventFinished(seq: Int, handled: Boolean) {
+ mFinishedSignals.put(FinishedSignal(seq, handled))
+ }
+
+ override fun onTimelineReported(inputEventId: Int, gpuCompletedTime: Long, presentTime: Long) {
+ mTimelines.put(Timeline(inputEventId, gpuCompletedTime, presentTime))
+ }
+
+ fun getFinishedSignal(): FinishedSignal {
+ return getEvent(mFinishedSignals)
+ }
+
+ fun getTimeline(): Timeline {
+ return getEvent(mTimelines)
+ }
+}
+
+class InputEventSenderAndReceiverTest {
+ companion object {
+ private const val TAG = "InputEventSenderAndReceiverTest"
+ }
+ private val mHandlerThread = HandlerThread("Process input events")
+ private lateinit var mReceiver: TestInputEventReceiver
+ private lateinit var mSender: TestInputEventSender
+
+ @Before
+ fun setUp() {
+ val channels = InputChannel.openInputChannelPair("TestChannel")
+ mHandlerThread.start()
+
+ val looper = mHandlerThread.getLooper()
+ mSender = TestInputEventSender(channels[0], looper)
+ mReceiver = TestInputEventReceiver(channels[1], looper)
+ }
+
+ @After
+ fun tearDown() {
+ mHandlerThread.quitSafely()
+ }
+
+ @Test
+ fun testSendAndReceiveKey() {
+ val key = KeyEvent(1 /*downTime*/, 1 /*eventTime*/, KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_A, 0 /*repeat*/)
+ val seq = 10
+ mSender.sendInputEvent(seq, key)
+ val receivedKey = mReceiver.getInputEvent() as KeyEvent
+ val finishedSignal = mSender.getFinishedSignal()
+
+ // Check receiver
+ assertKeyEvent(key, receivedKey)
+
+ // Check sender
+ assertEquals(TestInputEventSender.FinishedSignal(seq, handled = true), finishedSignal)
+ }
+
+ // The timeline case is slightly unusual because it goes from InputConsumer to InputPublisher.
+ @Test
+ fun testSendAndReceiveTimeline() {
+ val sent = TestInputEventSender.Timeline(
+ inputEventId = 1, gpuCompletedTime = 2, presentTime = 3)
+ mReceiver.reportTimeline(sent.inputEventId, sent.gpuCompletedTime, sent.presentTime)
+ val received = mSender.getTimeline()
+ assertEquals(sent, received)
+ }
+
+ // If an invalid timeline is sent, the channel should get closed. This helps surface any
+ // app-originating bugs early, and forces the work-around to happen in the early stages of the
+ // event processing.
+ @Test
+ fun testSendAndReceiveInvalidTimeline() {
+ val sent = TestInputEventSender.Timeline(
+ inputEventId = 1, gpuCompletedTime = 3, presentTime = 2)
+ mReceiver.reportTimeline(sent.inputEventId, sent.gpuCompletedTime, sent.presentTime)
+ val received = mSender.getTimeline()
+ assertEquals(null, received)
+ // Sender will no longer receive callbacks for this fd, even if receiver sends a valid
+ // timeline later
+ mReceiver.reportTimeline(2 /*inputEventId*/, 3 /*gpuCompletedTime*/, 4 /*presentTime*/)
+ val receivedSecondTimeline = mSender.getTimeline()
+ assertEquals(null, receivedSecondTimeline)
+ }
+}
diff --git a/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
new file mode 100644
index 000000000000..d83a4570fedc
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.input
+
+import android.app.Activity
+import android.hardware.input.InputManager
+import android.os.Bundle
+import android.os.Looper
+import android.util.Log
+import android.view.InputChannel
+import android.view.InputEvent
+import android.view.InputEventReceiver
+import android.view.InputMonitor
+
+class UnresponsiveReceiver(channel: InputChannel, looper: Looper) :
+ InputEventReceiver(channel, looper) {
+ companion object {
+ const val TAG = "UnresponsiveReceiver"
+ }
+ override fun onInputEvent(event: InputEvent) {
+ Log.i(TAG, "Received $event")
+ // Not calling 'finishInputEvent' in order to trigger the ANR
+ }
+}
+
+class UnresponsiveGestureMonitorActivity : Activity() {
+ companion object {
+ const val MONITOR_NAME = "unresponsive gesture monitor"
+ }
+ private lateinit var mInputEventReceiver: InputEventReceiver
+ private lateinit var mInputMonitor: InputMonitor
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ mInputMonitor = InputManager.getInstance().monitorGestureInput(MONITOR_NAME, displayId)
+ mInputEventReceiver = UnresponsiveReceiver(
+ mInputMonitor.getInputChannel(), Looper.myLooper())
+ }
+}
diff --git a/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
new file mode 100644
index 000000000000..6ef1ecdae59b
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.input
+
+import android.graphics.FrameInfo
+import android.os.IInputConstants.INVALID_INPUT_EVENT_ID
+import android.os.SystemClock
+import android.view.ViewFrameInfo
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+
+class ViewFrameInfoTest {
+ companion object {
+ private const val TAG = "ViewFrameInfoTest"
+ }
+ private val mViewFrameInfo = ViewFrameInfo()
+ private var mTimeStarted: Long = 0
+
+ @Before
+ fun setUp() {
+ mViewFrameInfo.reset()
+ mViewFrameInfo.setInputEvent(139)
+ mViewFrameInfo.flags = mViewFrameInfo.flags or FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED
+ mTimeStarted = SystemClock.uptimeNanos()
+ mViewFrameInfo.markDrawStart()
+ }
+
+ @Test
+ fun testPopulateFields() {
+ assertThat(mViewFrameInfo.drawStart).isGreaterThan(mTimeStarted)
+ assertThat(mViewFrameInfo.flags).isEqualTo(FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED)
+ }
+
+ @Test
+ fun testReset() {
+ mViewFrameInfo.reset()
+ // Ensure that the original object is reset correctly
+ assertThat(mViewFrameInfo.drawStart).isEqualTo(0)
+ assertThat(mViewFrameInfo.flags).isEqualTo(0)
+ }
+
+ @Test
+ fun testUpdateFrameInfoFromViewFrameInfo() {
+ val frameInfo = FrameInfo()
+ // By default, all values should be zero
+ assertThat(frameInfo.frameInfo[FrameInfo.INPUT_EVENT_ID]).isEqualTo(INVALID_INPUT_EVENT_ID)
+ assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo(0)
+ assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isEqualTo(0)
+
+ // The values inside FrameInfo should match those from ViewFrameInfo after we update them
+ mViewFrameInfo.populateFrameInfo(frameInfo)
+ assertThat(frameInfo.frameInfo[FrameInfo.INPUT_EVENT_ID]).isEqualTo(139)
+ assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo(
+ FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED)
+ assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isGreaterThan(mTimeStarted)
+ }
+} \ No newline at end of file
diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp
index e233fed7e785..ef45864dd93b 100644
--- a/tests/Internal/Android.bp
+++ b/tests/Internal/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "InternalTests",
proto: {
@@ -11,6 +20,7 @@ android_test {
"androidx.test.rules",
"mockito-target-minus-junit4",
"truth-prebuilt",
+ "platform-test-annotations",
],
java_resource_dirs: ["res"],
certificate: "platform",
diff --git a/tests/Internal/AndroidManifest.xml b/tests/Internal/AndroidManifest.xml
index c85c3b12504a..dbba24531769 100644
--- a/tests/Internal/AndroidManifest.xml
+++ b/tests/Internal/AndroidManifest.xml
@@ -16,29 +16,30 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.internal.tests">
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.BIND_WALLPAPER" />
+ package="com.android.internal.tests">
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.BIND_WALLPAPER"/>
<application>
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
<service android:name="stub.DummyWallpaperService"
- android:enabled="true"
- android:directBootAware="true"
- android:label="Dummy wallpaper"
- android:permission="android.permission.BIND_WALLPAPER">
+ android:enabled="true"
+ android:directBootAware="true"
+ android:label="Dummy wallpaper"
+ android:permission="android.permission.BIND_WALLPAPER"
+ android:exported="true">
<intent-filter>
- <action android:name="android.service.wallpaper.WallpaperService" />
+ <action android:name="android.service.wallpaper.WallpaperService"/>
</intent-filter>
<!-- Link to XML that defines the wallpaper info. -->
<meta-data android:name="android.service.wallpaper"
- android:resource="@xml/livewallpaper" />
+ android:resource="@xml/livewallpaper"/>
</service>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.internal.tests"
- android:label="Internal Tests" />
+ android:targetPackage="com.android.internal.tests"
+ android:label="Internal Tests"/>
</manifest>
diff --git a/tests/Internal/src/android/app/WallpaperColorsTest.java b/tests/Internal/src/android/app/WallpaperColorsTest.java
index e9bac717daa1..9ffb236d3f59 100644
--- a/tests/Internal/src/android/app/WallpaperColorsTest.java
+++ b/tests/Internal/src/android/app/WallpaperColorsTest.java
@@ -20,6 +20,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
+import android.os.Parcel;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -47,7 +48,7 @@ public class WallpaperColorsTest {
}
/**
- * Sanity check to guarantee that white supports dark text and black doesn't
+ * Check that white supports dark text and black doesn't
*/
@Test
public void colorHintsTest() {
@@ -106,4 +107,26 @@ public class WallpaperColorsTest {
// This would crash:
canvas.drawBitmap(image, 0, 0, new Paint());
}
+
+ /**
+ * Parcelled WallpaperColors object should equal the original.
+ */
+ @Test
+ public void testParcelUnparcel() {
+ Bitmap image = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888);
+ WallpaperColors colors = WallpaperColors.fromBitmap(image);
+ Parcel parcel = Parcel.obtain();
+ colors.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ WallpaperColors reconstructed = new WallpaperColors(parcel);
+ parcel.recycle();
+ Assert.assertEquals("WallpaperColors recreated from Parcel should equal original",
+ colors, reconstructed);
+ Assert.assertEquals("getAllColors() on WallpaperColors recreated from Parcel should"
+ + "return the same as the original",
+ colors.getAllColors(), reconstructed.getAllColors());
+ Assert.assertEquals("getMainColors() on WallpaperColors recreated from Parcel should"
+ + "return the same as the original",
+ colors.getMainColors(), reconstructed.getMainColors());
+ }
}
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
new file mode 100644
index 000000000000..3db011683a86
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.protolog;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.internal.protolog.ProtoLogImpl.PROTOLOG_VERSION;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
+import android.util.proto.ProtoInputStream;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.protolog.common.IProtoLogGroup;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.LinkedList;
+
+/**
+ * Test class for {@link ProtoLogImpl}.
+ */
+@SuppressWarnings("ConstantConditions")
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class ProtoLogImplTest {
+
+ private static final byte[] MAGIC_HEADER = new byte[]{
+ 0x9, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47
+ };
+
+ private ProtoLogImpl mProtoLog;
+ private File mFile;
+
+ @Mock
+ private ProtoLogViewerConfigReader mReader;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ final Context testContext = getInstrumentation().getContext();
+ mFile = testContext.getFileStreamPath("tracing_test.dat");
+ //noinspection ResultOfMethodCallIgnored
+ mFile.delete();
+ mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader);
+ }
+
+ @After
+ public void tearDown() {
+ if (mFile != null) {
+ //noinspection ResultOfMethodCallIgnored
+ mFile.delete();
+ }
+ ProtoLogImpl.setSingleInstance(null);
+ }
+
+ @Test
+ public void isEnabled_returnsFalseByDefault() {
+ assertFalse(mProtoLog.isProtoEnabled());
+ }
+
+ @Test
+ public void isEnabled_returnsTrueAfterStart() {
+ mProtoLog.startProtoLog(mock(PrintWriter.class));
+ assertTrue(mProtoLog.isProtoEnabled());
+ }
+
+ @Test
+ public void isEnabled_returnsFalseAfterStop() {
+ mProtoLog.startProtoLog(mock(PrintWriter.class));
+ mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+ assertFalse(mProtoLog.isProtoEnabled());
+ }
+
+ @Test
+ public void logFile_startsWithMagicHeader() throws Exception {
+ mProtoLog.startProtoLog(mock(PrintWriter.class));
+ mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+
+ assertTrue("Log file should exist", mFile.exists());
+
+ byte[] header = new byte[MAGIC_HEADER.length];
+ try (InputStream is = new FileInputStream(mFile)) {
+ assertEquals(MAGIC_HEADER.length, is.read(header));
+ assertArrayEquals(MAGIC_HEADER, header);
+ }
+ }
+
+ @Test
+ public void getSingleInstance() {
+ ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+ ProtoLogImpl.setSingleInstance(mockedProtoLog);
+ assertSame(mockedProtoLog, ProtoLogImpl.getSingleInstance());
+ }
+
+ @Test
+ public void d_logCalled() {
+ ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+ ProtoLogImpl.setSingleInstance(mockedProtoLog);
+ ProtoLogImpl.d(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d");
+ verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.DEBUG), eq(
+ TestProtoLogGroup.TEST_GROUP),
+ eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+ }
+
+ @Test
+ public void v_logCalled() {
+ ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+ ProtoLogImpl.setSingleInstance(mockedProtoLog);
+ ProtoLogImpl.v(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d");
+ verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.VERBOSE), eq(
+ TestProtoLogGroup.TEST_GROUP),
+ eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+ }
+
+ @Test
+ public void i_logCalled() {
+ ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+ ProtoLogImpl.setSingleInstance(mockedProtoLog);
+ ProtoLogImpl.i(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d");
+ verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.INFO), eq(
+ TestProtoLogGroup.TEST_GROUP),
+ eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+ }
+
+ @Test
+ public void w_logCalled() {
+ ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+ ProtoLogImpl.setSingleInstance(mockedProtoLog);
+ ProtoLogImpl.w(TestProtoLogGroup.TEST_GROUP, 1234,
+ 4321, "test %d");
+ verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.WARN), eq(
+ TestProtoLogGroup.TEST_GROUP),
+ eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+ }
+
+ @Test
+ public void e_logCalled() {
+ ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+ ProtoLogImpl.setSingleInstance(mockedProtoLog);
+ ProtoLogImpl.e(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d");
+ verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.ERROR), eq(
+ TestProtoLogGroup.TEST_GROUP),
+ eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+ }
+
+ @Test
+ public void wtf_logCalled() {
+ ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+ ProtoLogImpl.setSingleInstance(mockedProtoLog);
+ ProtoLogImpl.wtf(TestProtoLogGroup.TEST_GROUP,
+ 1234, 4321, "test %d");
+ verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.WTF), eq(
+ TestProtoLogGroup.TEST_GROUP),
+ eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+ }
+
+ @Test
+ public void log_logcatEnabledExternalMessage() {
+ when(mReader.getViewerString(anyInt())).thenReturn("test %b %d %% %o %x %e %g %s %f");
+ ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+ implSpy.log(
+ ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+ new Object[]{true, 10000, 20000, 30000, 0.0001, 0.00002, "test", 0.000003});
+
+ verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+ ProtoLogImpl.LogLevel.INFO),
+ eq("test true 10000 % 47040 7530 1.000000e-04 2.00000e-05 test 0.000003"));
+ verify(mReader).getViewerString(eq(1234));
+ }
+
+ @Test
+ public void log_logcatEnabledInvalidMessage() {
+ when(mReader.getViewerString(anyInt())).thenReturn("test %b %d %% %o %x %e %g %s %f");
+ ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+ implSpy.log(
+ ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+ new Object[]{true, 10000, 0.0001, 0.00002, "test"});
+
+ verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+ ProtoLogImpl.LogLevel.INFO),
+ eq("UNKNOWN MESSAGE (1234) true 10000 1.0E-4 2.0E-5 test"));
+ verify(mReader).getViewerString(eq(1234));
+ }
+
+ @Test
+ public void log_logcatEnabledInlineMessage() {
+ when(mReader.getViewerString(anyInt())).thenReturn("test %d");
+ ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+ implSpy.log(
+ ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d",
+ new Object[]{5});
+
+ verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+ ProtoLogImpl.LogLevel.INFO), eq("test 5"));
+ verify(mReader, never()).getViewerString(anyInt());
+ }
+
+ @Test
+ public void log_logcatEnabledNoMessage() {
+ when(mReader.getViewerString(anyInt())).thenReturn(null);
+ ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+ implSpy.log(
+ ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+ new Object[]{5});
+
+ verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+ ProtoLogImpl.LogLevel.INFO), eq("UNKNOWN MESSAGE (1234) 5"));
+ verify(mReader).getViewerString(eq(1234));
+ }
+
+ @Test
+ public void log_logcatDisabled() {
+ when(mReader.getViewerString(anyInt())).thenReturn("test %d");
+ ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+ implSpy.log(
+ ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d",
+ new Object[]{5});
+
+ verify(implSpy, never()).passToLogcat(any(), any(), any());
+ verify(mReader, never()).getViewerString(anyInt());
+ }
+
+ private static class ProtoLogData {
+ Integer mMessageHash = null;
+ Long mElapsedTime = null;
+ LinkedList<String> mStrParams = new LinkedList<>();
+ LinkedList<Long> mSint64Params = new LinkedList<>();
+ LinkedList<Double> mDoubleParams = new LinkedList<>();
+ LinkedList<Boolean> mBooleanParams = new LinkedList<>();
+ }
+
+ private ProtoLogData readProtoLogSingle(ProtoInputStream ip) throws IOException {
+ while (ip.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ if (ip.getFieldNumber() == (int) ProtoLogFileProto.VERSION) {
+ assertEquals(PROTOLOG_VERSION, ip.readString(ProtoLogFileProto.VERSION));
+ continue;
+ }
+ if (ip.getFieldNumber() != (int) ProtoLogFileProto.LOG) {
+ continue;
+ }
+ long token = ip.start(ProtoLogFileProto.LOG);
+ ProtoLogData data = new ProtoLogData();
+ while (ip.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (ip.getFieldNumber()) {
+ case (int) ProtoLogMessage.MESSAGE_HASH: {
+ data.mMessageHash = ip.readInt(ProtoLogMessage.MESSAGE_HASH);
+ break;
+ }
+ case (int) ProtoLogMessage.ELAPSED_REALTIME_NANOS: {
+ data.mElapsedTime = ip.readLong(ProtoLogMessage.ELAPSED_REALTIME_NANOS);
+ break;
+ }
+ case (int) ProtoLogMessage.STR_PARAMS: {
+ data.mStrParams.add(ip.readString(ProtoLogMessage.STR_PARAMS));
+ break;
+ }
+ case (int) ProtoLogMessage.SINT64_PARAMS: {
+ data.mSint64Params.add(ip.readLong(ProtoLogMessage.SINT64_PARAMS));
+ break;
+ }
+ case (int) ProtoLogMessage.DOUBLE_PARAMS: {
+ data.mDoubleParams.add(ip.readDouble(ProtoLogMessage.DOUBLE_PARAMS));
+ break;
+ }
+ case (int) ProtoLogMessage.BOOLEAN_PARAMS: {
+ data.mBooleanParams.add(ip.readBoolean(ProtoLogMessage.BOOLEAN_PARAMS));
+ break;
+ }
+ }
+ }
+ ip.end(token);
+ return data;
+ }
+ return null;
+ }
+
+ @Test
+ public void log_protoEnabled() throws Exception {
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(true);
+ mProtoLog.startProtoLog(mock(PrintWriter.class));
+ long before = SystemClock.elapsedRealtimeNanos();
+ mProtoLog.log(
+ ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
+ 0b1110101001010100, null,
+ new Object[]{"test", 1, 2, 3, 0.4, 0.5, 0.6, true});
+ long after = SystemClock.elapsedRealtimeNanos();
+ mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+ try (InputStream is = new FileInputStream(mFile)) {
+ ProtoInputStream ip = new ProtoInputStream(is);
+ ProtoLogData data = readProtoLogSingle(ip);
+ assertNotNull(data);
+ assertEquals(1234, data.mMessageHash.longValue());
+ assertTrue(before <= data.mElapsedTime && data.mElapsedTime <= after);
+ assertArrayEquals(new String[]{"test"}, data.mStrParams.toArray());
+ assertArrayEquals(new Long[]{1L, 2L, 3L}, data.mSint64Params.toArray());
+ assertArrayEquals(new Double[]{0.4, 0.5, 0.6}, data.mDoubleParams.toArray());
+ assertArrayEquals(new Boolean[]{true}, data.mBooleanParams.toArray());
+ }
+ }
+
+ @Test
+ public void log_invalidParamsMask() throws Exception {
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(true);
+ mProtoLog.startProtoLog(mock(PrintWriter.class));
+ long before = SystemClock.elapsedRealtimeNanos();
+ mProtoLog.log(
+ ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
+ 0b01100100, null,
+ new Object[]{"test", 1, 0.1, true});
+ long after = SystemClock.elapsedRealtimeNanos();
+ mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+ try (InputStream is = new FileInputStream(mFile)) {
+ ProtoInputStream ip = new ProtoInputStream(is);
+ ProtoLogData data = readProtoLogSingle(ip);
+ assertNotNull(data);
+ assertEquals(1234, data.mMessageHash.longValue());
+ assertTrue(before <= data.mElapsedTime && data.mElapsedTime <= after);
+ assertArrayEquals(new String[]{"test", "(INVALID PARAMS_MASK) true"},
+ data.mStrParams.toArray());
+ assertArrayEquals(new Long[]{1L}, data.mSint64Params.toArray());
+ assertArrayEquals(new Double[]{0.1}, data.mDoubleParams.toArray());
+ assertArrayEquals(new Boolean[]{}, data.mBooleanParams.toArray());
+ }
+ }
+
+ @Test
+ public void log_protoDisabled() throws Exception {
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+ mProtoLog.startProtoLog(mock(PrintWriter.class));
+ mProtoLog.log(ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
+ 0b11, null, new Object[]{true});
+ mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+ try (InputStream is = new FileInputStream(mFile)) {
+ ProtoInputStream ip = new ProtoInputStream(is);
+ ProtoLogData data = readProtoLogSingle(ip);
+ assertNull(data);
+ }
+ }
+
+ private enum TestProtoLogGroup implements IProtoLogGroup {
+ TEST_GROUP(true, true, false, "WindowManagetProtoLogTest");
+
+ private final boolean mEnabled;
+ private volatile boolean mLogToProto;
+ private volatile boolean mLogToLogcat;
+ private final String mTag;
+
+ /**
+ * @param enabled set to false to exclude all log statements for this group from
+ * compilation,
+ * they will not be available in runtime.
+ * @param logToProto enable binary logging for the group
+ * @param logToLogcat enable text logging for the group
+ * @param tag name of the source of the logged message
+ */
+ TestProtoLogGroup(boolean enabled, boolean logToProto, boolean logToLogcat, String tag) {
+ this.mEnabled = enabled;
+ this.mLogToProto = logToProto;
+ this.mLogToLogcat = logToLogcat;
+ this.mTag = tag;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+
+ @Override
+ public boolean isLogToProto() {
+ return mLogToProto;
+ }
+
+ @Override
+ public boolean isLogToLogcat() {
+ return mLogToLogcat;
+ }
+
+ @Override
+ public boolean isLogToAny() {
+ return mLogToLogcat || mLogToProto;
+ }
+
+ @Override
+ public String getTag() {
+ return mTag;
+ }
+
+ @Override
+ public void setLogToProto(boolean logToProto) {
+ this.mLogToProto = logToProto;
+ }
+
+ @Override
+ public void setLogToLogcat(boolean logToLogcat) {
+ this.mLogToLogcat = logToLogcat;
+ }
+
+ }
+}
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
new file mode 100644
index 000000000000..ae5021638745
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.protolog;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.zip.GZIPOutputStream;
+
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class ProtoLogViewerConfigReaderTest {
+ private static final String TEST_VIEWER_CONFIG = "{\n"
+ + " \"version\": \"1.0.0\",\n"
+ + " \"messages\": {\n"
+ + " \"70933285\": {\n"
+ + " \"message\": \"Test completed successfully: %b\",\n"
+ + " \"level\": \"ERROR\",\n"
+ + " \"group\": \"GENERIC_WM\"\n"
+ + " },\n"
+ + " \"1792430067\": {\n"
+ + " \"message\": \"Attempted to add window to a display that does not exist: %d."
+ + " Aborting.\",\n"
+ + " \"level\": \"WARN\",\n"
+ + " \"group\": \"GENERIC_WM\"\n"
+ + " },\n"
+ + " \"1352021864\": {\n"
+ + " \"message\": \"Test 2\",\n"
+ + " \"level\": \"WARN\",\n"
+ + " \"group\": \"GENERIC_WM\"\n"
+ + " },\n"
+ + " \"409412266\": {\n"
+ + " \"message\": \"Window %s is already added\",\n"
+ + " \"level\": \"WARN\",\n"
+ + " \"group\": \"GENERIC_WM\"\n"
+ + " }\n"
+ + " },\n"
+ + " \"groups\": {\n"
+ + " \"GENERIC_WM\": {\n"
+ + " \"tag\": \"WindowManager\"\n"
+ + " }\n"
+ + " }\n"
+ + "}\n";
+
+
+ private ProtoLogViewerConfigReader
+ mConfig = new ProtoLogViewerConfigReader();
+ private File mTestViewerConfig;
+
+ @Before
+ public void setUp() throws IOException {
+ mTestViewerConfig = File.createTempFile("testConfig", ".json.gz");
+ OutputStreamWriter writer = new OutputStreamWriter(
+ new GZIPOutputStream(new FileOutputStream(mTestViewerConfig)));
+ writer.write(TEST_VIEWER_CONFIG);
+ writer.close();
+ }
+
+ @After
+ public void tearDown() {
+ //noinspection ResultOfMethodCallIgnored
+ mTestViewerConfig.delete();
+ }
+
+ @Test
+ public void getViewerString_notLoaded() {
+ assertNull(mConfig.getViewerString(1));
+ }
+
+ @Test
+ public void loadViewerConfig() {
+ mConfig.loadViewerConfig(null, mTestViewerConfig.getAbsolutePath());
+ assertEquals("Test completed successfully: %b", mConfig.getViewerString(70933285));
+ assertEquals("Test 2", mConfig.getViewerString(1352021864));
+ assertEquals("Window %s is already added", mConfig.getViewerString(409412266));
+ assertNull(mConfig.getViewerString(1));
+ }
+
+ @Test
+ public void loadViewerConfig_invalidFile() {
+ mConfig.loadViewerConfig(null, "/tmp/unknown/file/does/not/exist");
+ // No exception is thrown.
+ assertNull(mConfig.getViewerString(1));
+ }
+}
diff --git a/tests/Internal/src/com/android/internal/protolog/common/LogDataTypeTest.java b/tests/Internal/src/com/android/internal/protolog/common/LogDataTypeTest.java
new file mode 100644
index 000000000000..e20ca3df57c7
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/protolog/common/LogDataTypeTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.protolog.common;
+
+import static org.junit.Assert.assertEquals;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class LogDataTypeTest {
+ @Test
+ public void parseFormatString() {
+ String str = "%b %d %o %x %f %e %g %s %%";
+ List<Integer> out = LogDataType.parseFormatString(str);
+ assertEquals(Arrays.asList(
+ LogDataType.BOOLEAN,
+ LogDataType.LONG,
+ LogDataType.LONG,
+ LogDataType.LONG,
+ LogDataType.DOUBLE,
+ LogDataType.DOUBLE,
+ LogDataType.DOUBLE,
+ LogDataType.STRING
+ ), out);
+ }
+
+ @Test(expected = InvalidFormatStringException.class)
+ public void parseFormatString_invalid() {
+ String str = "%q";
+ LogDataType.parseFormatString(str);
+ }
+
+ @Test
+ public void logDataTypesToBitMask() {
+ List<Integer> types = Arrays.asList(LogDataType.STRING, LogDataType.DOUBLE,
+ LogDataType.LONG, LogDataType.BOOLEAN);
+ int mask = LogDataType.logDataTypesToBitMask(types);
+ assertEquals(0b11011000, mask);
+ }
+
+ @Test(expected = BitmaskConversionException.class)
+ public void logDataTypesToBitMask_toManyParams() {
+ ArrayList<Integer> types = new ArrayList<>();
+ for (int i = 0; i <= 16; i++) {
+ types.add(LogDataType.STRING);
+ }
+ LogDataType.logDataTypesToBitMask(types);
+ }
+
+ @Test
+ public void bitmaskToLogDataTypes() {
+ int bitmask = 0b11011000;
+ List<Integer> types = Arrays.asList(LogDataType.STRING, LogDataType.DOUBLE,
+ LogDataType.LONG, LogDataType.BOOLEAN);
+ for (int i = 0; i < types.size(); i++) {
+ assertEquals(types.get(i).intValue(), LogDataType.bitmaskToLogDataType(bitmask, i));
+ }
+ }
+}
diff --git a/tests/JankBench/Android.bp b/tests/JankBench/Android.bp
index 166639d2e7db..39dd197bf681 100644
--- a/tests/JankBench/Android.bp
+++ b/tests/JankBench/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "JankBench",
manifest: "app/src/main/AndroidManifest.xml",
diff --git a/tests/JankBench/app/src/main/AndroidManifest.xml b/tests/JankBench/app/src/main/AndroidManifest.xml
index 58aa66fcd05d..fe431fda48cd 100644
--- a/tests/JankBench/app/src/main/AndroidManifest.xml
+++ b/tests/JankBench/app/src/main/AndroidManifest.xml
@@ -1,4 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?><!--
+<?xml version="1.0" encoding="utf-8"?>
+<!--
~ Copyright (C) 2015 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,50 +14,48 @@
~ License.
~
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.benchmark">
+ package="com.android.benchmark">
- <uses-sdk android:minSdkVersion="24" />
+ <uses-sdk android:minSdkVersion="24"/>
- <android:uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <android:uses-permission android:name="android.permission.READ_PHONE_STATE" />
- <android:uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <android:uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <android:uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+ <android:uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
- <application
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:theme="@style/AppTheme">
- <activity
- android:name=".app.HomeActivity"
- android:label="@string/app_name"
- android:theme="@style/AppTheme.NoActionBar">
+ <application android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme">
+ <activity android:name=".app.HomeActivity"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme.NoActionBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity
- android:name=".app.RunLocalBenchmarksActivity"
- android:exported="true">
+ <activity android:name=".app.RunLocalBenchmarksActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="com.android.benchmark.ACTION_BENCHMARK" />
+ <action android:name="com.android.benchmark.ACTION_BENCHMARK"/>
</intent-filter>
- <meta-data
- android:name="com.android.benchmark.benchmark_group"
- android:resource="@xml/benchmark" />
+ <meta-data android:name="com.android.benchmark.benchmark_group"
+ android:resource="@xml/benchmark"/>
</activity>
- <activity android:name=".ui.ListViewScrollActivity" />
- <activity android:name=".ui.ImageListViewScrollActivity" />
- <activity android:name=".ui.ShadowGridActivity" />
- <activity android:name=".ui.TextScrollActivity" />
- <activity android:name=".ui.EditTextInputActivity" />
- <activity android:name=".synthetic.MemoryActivity" />
- <activity android:name=".ui.FullScreenOverdrawActivity"></activity>
- <activity android:name=".ui.BitmapUploadActivity"></activity>
+ <activity android:name=".ui.ListViewScrollActivity"/>
+ <activity android:name=".ui.ImageListViewScrollActivity"/>
+ <activity android:name=".ui.ShadowGridActivity"/>
+ <activity android:name=".ui.TextScrollActivity"/>
+ <activity android:name=".ui.EditTextInputActivity"/>
+ <activity android:name=".synthetic.MemoryActivity"/>
+ <activity android:name=".ui.FullScreenOverdrawActivity"/>
+ <activity android:name=".ui.BitmapUploadActivity"/>
</application>
-</manifest> \ No newline at end of file
+</manifest>
diff --git a/tests/JobSchedulerPerfTests/Android.bp b/tests/JobSchedulerPerfTests/Android.bp
index 2ae8c33b60a7..eb9b2f636191 100644
--- a/tests/JobSchedulerPerfTests/Android.bp
+++ b/tests/JobSchedulerPerfTests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "JobSchedulerPerfTests",
srcs: ["src/**/*.java"],
diff --git a/tests/JobSchedulerPerfTests/OWNERS b/tests/JobSchedulerPerfTests/OWNERS
new file mode 100644
index 000000000000..6f207fb1a00e
--- /dev/null
+++ b/tests/JobSchedulerPerfTests/OWNERS
@@ -0,0 +1 @@
+include /apex/jobscheduler/OWNERS
diff --git a/tests/JobSchedulerTestApp/Android.bp b/tests/JobSchedulerTestApp/Android.bp
index bac0220e5591..893a983ca9d9 100644
--- a/tests/JobSchedulerTestApp/Android.bp
+++ b/tests/JobSchedulerTestApp/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_app {
name: "JobSchedulerTestApp",
srcs: ["src/**/*.java"],
diff --git a/tests/JobSchedulerTestApp/AndroidManifest.xml b/tests/JobSchedulerTestApp/AndroidManifest.xml
index 96541972b9b8..aeeaba469a2a 100644
--- a/tests/JobSchedulerTestApp/AndroidManifest.xml
+++ b/tests/JobSchedulerTestApp/AndroidManifest.xml
@@ -1,32 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.demo.jobSchedulerApp" >
+ package="com.android.demo.jobSchedulerApp">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="18" />
+ <uses-sdk android:minSdkVersion="18"
+ android:targetSdkVersion="18"/>
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
- <application
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- <activity
- android:name="com.android.demo.jobSchedulerApp.MainActivity"
- android:label="@string/app_name"
- android:windowSoftInputMode="stateHidden" >
+ <application android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
+ <activity android:name="com.android.demo.jobSchedulerApp.MainActivity"
+ android:label="@string/app_name"
+ android:windowSoftInputMode="stateHidden"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <service
- android:name=".service.TestJobService"
- android:permission="android.permission.BIND_JOB_SERVICE"
- android:exported="true"/>
+ <service android:name=".service.TestJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE"
+ android:exported="true"/>
</application>
</manifest>
diff --git a/tests/JobSchedulerTestApp/OWNERS b/tests/JobSchedulerTestApp/OWNERS
new file mode 100644
index 000000000000..6f207fb1a00e
--- /dev/null
+++ b/tests/JobSchedulerTestApp/OWNERS
@@ -0,0 +1 @@
+include /apex/jobscheduler/OWNERS
diff --git a/tests/LargeAssetTest/Android.bp b/tests/LargeAssetTest/Android.bp
index 499e6a0721a1..2a6de77fb170 100644
--- a/tests/LargeAssetTest/Android.bp
+++ b/tests/LargeAssetTest/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_app {
name: "LargeAssetTest",
srcs: ["**/*.java"],
diff --git a/tests/LargeAssetTest/AndroidManifest.xml b/tests/LargeAssetTest/AndroidManifest.xml
index c86118e492e5..ac55dcb66be8 100644
--- a/tests/LargeAssetTest/AndroidManifest.xml
+++ b/tests/LargeAssetTest/AndroidManifest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,15 +13,18 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.largeassettest">
+ package="com.android.largeassettest">
<application>
- <activity android:name="LargeAssetTest" android:label="Large Asset Test">
+ <activity android:name="LargeAssetTest"
+ android:label="Large Asset Test"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/LegacyAssistant/Android.bp b/tests/LegacyAssistant/Android.bp
index fef924d1cd89..ab8ef8885c45 100644
--- a/tests/LegacyAssistant/Android.bp
+++ b/tests/LegacyAssistant/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "LegacyAssistant",
srcs: ["**/*.java"],
diff --git a/tests/LegacyAssistant/AndroidManifest.xml b/tests/LegacyAssistant/AndroidManifest.xml
index 7ae510379980..942eafa06f35 100644
--- a/tests/LegacyAssistant/AndroidManifest.xml
+++ b/tests/LegacyAssistant/AndroidManifest.xml
@@ -15,22 +15,23 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.legacyassistant">
+ package="com.google.android.test.legacyassistant">
<application android:label="@string/activity_title">
<activity android:name=".AssistActivity"
- android:theme="@android:style/Theme.NoTitleBar">
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:exported="true">
<!-- Handle assist intent -->
<intent-filter>
- <action android:name="android.intent.action.ASSIST" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.intent.action.ASSIST"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<!-- Provide icon for search -->
<meta-data android:name="com.android.systemui.action_assist_icon"
- android:resource="@drawable/ic_action_assist" />
+ android:resource="@drawable/ic_action_assist"/>
</activity>
diff --git a/tests/LocalizationTest/Android.bp b/tests/LocalizationTest/Android.bp
new file mode 100644
index 000000000000..4e0b0a89d972
--- /dev/null
+++ b/tests/LocalizationTest/Android.bp
@@ -0,0 +1,50 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // 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"],
+}
+
+android_test {
+ name: "LocalizationTest",
+ srcs: ["java/**/*.kt"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "mockito-target-extended-minus-junit4",
+ "truth-prebuilt",
+ ],
+ jni_libs: [
+ // For mockito extended
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ ],
+ certificate: "platform",
+ platform_apis: true,
+ test_suites: ["device-tests"],
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/tests/LocalizationTest/AndroidManifest.xml b/tests/LocalizationTest/AndroidManifest.xml
new file mode 100644
index 000000000000..b135443960f5
--- /dev/null
+++ b/tests/LocalizationTest/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.android.internal.app">
+
+ <application android:debuggable="true" android:testOnly="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.android.internal.app"
+ android:label="Localization Tests" />
+
+</manifest>
diff --git a/tests/LocalizationTest/AndroidTest.xml b/tests/LocalizationTest/AndroidTest.xml
new file mode 100644
index 000000000000..8309b4f611f8
--- /dev/null
+++ b/tests/LocalizationTest/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<configuration description="Localization Tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-t" />
+ <option name="test-file-name" value="LocalizationTest.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="LocalizationTest" />
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.android.internal.app" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration> \ No newline at end of file
diff --git a/tests/LocalizationTest/java/com/android/internal/app/LocalizationTest.kt b/tests/LocalizationTest/java/com/android/internal/app/LocalizationTest.kt
new file mode 100644
index 000000000000..22ea97167326
--- /dev/null
+++ b/tests/LocalizationTest/java/com/android/internal/app/LocalizationTest.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.android.internal.app
+
+import android.os.SystemProperties
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.internal.R
+import com.android.internal.app.LocalePicker
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.After
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.MockitoSession
+
+@RunWith(AndroidJUnit4::class)
+class LocalizationTest {
+ private val mContext = InstrumentationRegistry.getInstrumentation().context
+ private val mUnfilteredLocales =
+ mContext.getResources().getStringArray(R.array.supported_locales)
+
+ private lateinit var mMockitoSession: MockitoSession
+
+ @Before
+ fun setUp() {
+ mMockitoSession = mockitoSession()
+ .initMocks(this)
+ .spyStatic(SystemProperties::class.java)
+ .startMocking()
+ }
+
+ @After
+ fun tearDown() {
+ mMockitoSession.finishMocking()
+ }
+
+ @Test
+ fun testGetSupportedLocales_noFilter() {
+ // Filter not set.
+ setTestLocaleFilter(null)
+
+ val locales1 = LocalePicker.getSupportedLocales(mContext)
+
+ assertThat(locales1).isEqualTo(mUnfilteredLocales)
+
+ // Empty filter.
+ setTestLocaleFilter("")
+
+ val locales2 = LocalePicker.getSupportedLocales(mContext)
+
+ assertThat(locales2).isEqualTo(mUnfilteredLocales)
+ }
+
+ @Test
+ fun testGetSupportedLocales_invalidFilter() {
+ setTestLocaleFilter("**")
+
+ val locales = LocalePicker.getSupportedLocales(mContext)
+
+ assertThat(locales).isEqualTo(mUnfilteredLocales)
+ }
+
+ @Test
+ fun testGetSupportedLocales_inclusiveFilter() {
+ setTestLocaleFilter("^(de-AT|de-DE|en|ru).*")
+
+ val locales = LocalePicker.getSupportedLocales(mContext)
+
+ assertThat(locales).isEqualTo(
+ mUnfilteredLocales
+ .filter { it.startsWithAnyOf("de-AT", "de-DE", "en", "ru") }
+ .toTypedArray()
+ )
+ }
+
+ @Test
+ fun testGetSupportedLocales_exclusiveFilter() {
+ setTestLocaleFilter("^(?!de-IT|es|fr).*")
+
+ val locales = LocalePicker.getSupportedLocales(mContext)
+
+ assertThat(locales).isEqualTo(
+ mUnfilteredLocales
+ .filter { !it.startsWithAnyOf("de-IT", "es", "fr") }
+ .toTypedArray()
+ )
+ }
+
+ private fun setTestLocaleFilter(localeFilter: String?) {
+ doReturn(localeFilter).`when` { SystemProperties.get(eq("ro.localization.locale_filter")) }
+ }
+
+ private fun String.startsWithAnyOf(vararg prefixes: String): Boolean {
+ prefixes.forEach {
+ if (startsWith(it)) return true
+ }
+
+ return false
+ }
+}
diff --git a/tests/LocationTracker/Android.bp b/tests/LocationTracker/Android.bp
index f0075a9c37bd..538687c7db45 100644
--- a/tests/LocationTracker/Android.bp
+++ b/tests/LocationTracker/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "LocationTracker",
srcs: ["**/*.java"],
diff --git a/tests/LocationTracker/AndroidManifest.xml b/tests/LocationTracker/AndroidManifest.xml
index dc7ea99849e0..0940ee31db1f 100644
--- a/tests/LocationTracker/AndroidManifest.xml
+++ b/tests/LocationTracker/AndroidManifest.xml
@@ -1,30 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.locationtracker">
+ package="com.android.locationtracker">
<!-- Permissions for the Location Service -->
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- Permission for wifi -->
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!-- give the location tracker ability to induce device insomnia -->
- <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
<!-- Permission for SD card -->
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:label="@string/app_label">
- <activity android:name="TrackerActivity" android:label="Location Tracker">
+ <activity android:name="TrackerActivity"
+ android:label="Location Tracker"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <service android:name=".TrackerService" />
- <activity android:label="@string/settings_menu" android:name="SettingsActivity" />
+ <service android:name=".TrackerService"/>
+ <activity android:label="@string/settings_menu"
+ android:name="SettingsActivity"/>
<provider android:name=".data.TrackerProvider"
- android:authorities="com.android.locationtracker" />
+ android:authorities="com.android.locationtracker"/>
</application>
</manifest>
diff --git a/tests/LocationTracker/OWNERS b/tests/LocationTracker/OWNERS
new file mode 100644
index 000000000000..5ac6028411f0
--- /dev/null
+++ b/tests/LocationTracker/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/location/OWNERS
diff --git a/tests/LockTaskTests/Android.mk b/tests/LockTaskTests/Android.mk
index a693eaa4da04..5406ee19041b 100644
--- a/tests/LockTaskTests/Android.mk
+++ b/tests/LockTaskTests/Android.mk
@@ -5,6 +5,9 @@ LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/priv-app
LOCAL_PACKAGE_NAME := LockTaskTests
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
diff --git a/tests/LockTaskTests/AndroidManifest.xml b/tests/LockTaskTests/AndroidManifest.xml
index e349c9248263..3ffdc4712b0e 100644
--- a/tests/LockTaskTests/AndroidManifest.xml
+++ b/tests/LockTaskTests/AndroidManifest.xml
@@ -1,56 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.example.locktasktests"
- android:versionCode="1"
- android:versionName="1.0" >
+ package="com.google.android.example.locktasktests"
+ android:versionCode="1"
+ android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="22"
- android:targetSdkVersion="22" />
+ <uses-sdk android:minSdkVersion="22"
+ android:targetSdkVersion="22"/>
<uses-permission android:name="android.permission.INTERNET"/>
- <application
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme"
- android:allowBackup="true" >
- <activity
- android:name="com.google.android.example.locktasktests.MainActivity"
- android:label="@string/app_name"
- android:screenOrientation="portrait"
- android:theme="@style/AppTheme" >
+ <application android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme"
+ android:allowBackup="true">
+ <activity android:name="com.google.android.example.locktasktests.MainActivity"
+ android:label="@string/app_name"
+ android:screenOrientation="portrait"
+ android:theme="@style/AppTheme"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity
- android:name="com.google.android.example.locktasktests.LockDefaultActivity"
- android:label="@string/title_activity_default"
- android:taskAffinity=""
- android:documentLaunchMode="always"
- android:lockTaskMode="normal" >
+ <activity android:name="com.google.android.example.locktasktests.LockDefaultActivity"
+ android:label="@string/title_activity_default"
+ android:taskAffinity=""
+ android:documentLaunchMode="always"
+ android:lockTaskMode="normal">
</activity>
- <activity
- android:name="com.google.android.example.locktasktests.LockTaskNeverActivity"
- android:label="@string/title_activity_never"
- android:taskAffinity=""
- android:documentLaunchMode="always"
- android:lockTaskMode="never" >
+ <activity android:name="com.google.android.example.locktasktests.LockTaskNeverActivity"
+ android:label="@string/title_activity_never"
+ android:taskAffinity=""
+ android:documentLaunchMode="always"
+ android:lockTaskMode="never">
</activity>
- <activity
- android:name="com.google.android.example.locktasktests.LockWhitelistedActivity"
- android:label="@string/title_activity_whitelist"
- android:taskAffinity=""
- android:documentLaunchMode="always"
- android:lockTaskMode="if_whitelisted" >
+ <activity android:name="com.google.android.example.locktasktests.LockWhitelistedActivity"
+ android:label="@string/title_activity_whitelist"
+ android:taskAffinity=""
+ android:documentLaunchMode="always"
+ android:lockTaskMode="if_whitelisted">
</activity>
- <activity
- android:name="com.google.android.example.locktasktests.LockAtLaunchActivity"
- android:label="@string/title_activity_always"
- android:taskAffinity=""
- android:documentLaunchMode="always"
- android:lockTaskMode="always" >
+ <activity android:name="com.google.android.example.locktasktests.LockAtLaunchActivity"
+ android:label="@string/title_activity_always"
+ android:taskAffinity=""
+ android:documentLaunchMode="always"
+ android:lockTaskMode="always">
</activity>
</application>
diff --git a/tests/LotsOfApps/Android.bp b/tests/LotsOfApps/Android.bp
index 68b9f88ecfd7..5f6c089188c7 100644
--- a/tests/LotsOfApps/Android.bp
+++ b/tests/LotsOfApps/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_app {
name: "LotsOfApps",
srcs: ["**/*.java"],
diff --git a/tests/LotsOfApps/AndroidManifest.xml b/tests/LotsOfApps/AndroidManifest.xml
index 585ddccf8450..3aed04391103 100644
--- a/tests/LotsOfApps/AndroidManifest.xml
+++ b/tests/LotsOfApps/AndroidManifest.xml
@@ -1,710 +1,912 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.lotsofapps">
- <uses-permission android:name="android.permission.DEVICE_POWER" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-permission android:name="android.permission.STATUS_BAR" />
- <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
- <uses-permission android:name="android.permission.VIBRATE" />
+ package="com.android.lotsofapps">
+ <uses-permission android:name="android.permission.DEVICE_POWER"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
+ <uses-permission android:name="android.permission.STATUS_BAR"/>
+ <uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>
+ <uses-permission android:name="android.permission.VIBRATE"/>
<application>
- <activity android:name="com.android.lotsofapps.activity00" android:icon="@drawable/ic_launcher_add_folder">
+ <activity android:name="com.android.lotsofapps.activity00"
+ android:icon="@drawable/ic_launcher_add_folder"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity01" android:icon="@drawable/ic_launcher_alarmclock">
+ <activity android:name="com.android.lotsofapps.activity01"
+ android:icon="@drawable/ic_launcher_alarmclock"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity02" android:icon="@drawable/ic_launcher_application">
+ <activity android:name="com.android.lotsofapps.activity02"
+ android:icon="@drawable/ic_launcher_application"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity03" android:icon="@drawable/ic_launcher_browser">
+ <activity android:name="com.android.lotsofapps.activity03"
+ android:icon="@drawable/ic_launcher_browser"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity04" android:icon="@drawable/ic_launcher_camera">
+ <activity android:name="com.android.lotsofapps.activity04"
+ android:icon="@drawable/ic_launcher_camera"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity05" android:icon="@drawable/ic_launcher_camera_record">
+ <activity android:name="com.android.lotsofapps.activity05"
+ android:icon="@drawable/ic_launcher_camera_record"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity06" android:icon="@drawable/ic_launcher_contacts">
+ <activity android:name="com.android.lotsofapps.activity06"
+ android:icon="@drawable/ic_launcher_contacts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity07" android:icon="@drawable/ic_launcher_drm_file">
+ <activity android:name="com.android.lotsofapps.activity07"
+ android:icon="@drawable/ic_launcher_drm_file"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity08" android:icon="@drawable/ic_launcher_folder">
+ <activity android:name="com.android.lotsofapps.activity08"
+ android:icon="@drawable/ic_launcher_folder"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity09" android:icon="@drawable/ic_launcher_folder_bluetooth">
+ <activity android:name="com.android.lotsofapps.activity09"
+ android:icon="@drawable/ic_launcher_folder_bluetooth"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity10" android:icon="@drawable/ic_launcher_folder_live">
+ <activity android:name="com.android.lotsofapps.activity10"
+ android:icon="@drawable/ic_launcher_folder_live"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity11" android:icon="@drawable/ic_launcher_folder_live_contacts">
+ <activity android:name="com.android.lotsofapps.activity11"
+ android:icon="@drawable/ic_launcher_folder_live_contacts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity12" android:icon="@drawable/ic_launcher_folder_live_contacts_phone">
+ <activity android:name="com.android.lotsofapps.activity12"
+ android:icon="@drawable/ic_launcher_folder_live_contacts_phone"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity13" android:icon="@drawable/ic_launcher_folder_live_contacts_starred">
+ <activity android:name="com.android.lotsofapps.activity13"
+ android:icon="@drawable/ic_launcher_folder_live_contacts_starred"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity14" android:icon="@drawable/ic_launcher_folder_open">
+ <activity android:name="com.android.lotsofapps.activity14"
+ android:icon="@drawable/ic_launcher_folder_open"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity15" android:icon="@drawable/ic_launcher_gallery">
+ <activity android:name="com.android.lotsofapps.activity15"
+ android:icon="@drawable/ic_launcher_gallery"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity16" android:icon="@drawable/ic_launcher_home">
+ <activity android:name="com.android.lotsofapps.activity16"
+ android:icon="@drawable/ic_launcher_home"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity17" android:icon="@drawable/ic_launcher_im">
+ <activity android:name="com.android.lotsofapps.activity17"
+ android:icon="@drawable/ic_launcher_im"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity18" android:icon="@drawable/ic_launcher_musicplayer_2">
+ <activity android:name="com.android.lotsofapps.activity18"
+ android:icon="@drawable/ic_launcher_musicplayer_2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity19" android:icon="@drawable/ic_launcher_phone">
+ <activity android:name="com.android.lotsofapps.activity19"
+ android:icon="@drawable/ic_launcher_phone"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity20" android:icon="@drawable/ic_launcher_record_audio">
+ <activity android:name="com.android.lotsofapps.activity20"
+ android:icon="@drawable/ic_launcher_record_audio"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity21" android:icon="@drawable/ic_launcher_settings">
+ <activity android:name="com.android.lotsofapps.activity21"
+ android:icon="@drawable/ic_launcher_settings"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity22" android:icon="@drawable/ic_launcher_shortcut">
+ <activity android:name="com.android.lotsofapps.activity22"
+ android:icon="@drawable/ic_launcher_shortcut"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity23" android:icon="@drawable/ic_launcher_shortcut_browser_bookmark">
+ <activity android:name="com.android.lotsofapps.activity23"
+ android:icon="@drawable/ic_launcher_shortcut_browser_bookmark"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity24" android:icon="@drawable/ic_launcher_contacts">
+ <activity android:name="com.android.lotsofapps.activity24"
+ android:icon="@drawable/ic_launcher_contacts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity25" android:icon="@drawable/ic_launcher_shortcut_directdial">
+ <activity android:name="com.android.lotsofapps.activity25"
+ android:icon="@drawable/ic_launcher_shortcut_directdial"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity26" android:icon="@drawable/ic_launcher_shortcut_directmessage">
+ <activity android:name="com.android.lotsofapps.activity26"
+ android:icon="@drawable/ic_launcher_shortcut_directmessage"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity27" android:icon="@drawable/ic_launcher_browser">
+ <activity android:name="com.android.lotsofapps.activity27"
+ android:icon="@drawable/ic_launcher_browser"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity28" android:icon="@drawable/ic_launcher_sim_toolkit">
+ <activity android:name="com.android.lotsofapps.activity28"
+ android:icon="@drawable/ic_launcher_sim_toolkit"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity29" android:icon="@drawable/ic_launcher_slideshow_add_sms">
+ <activity android:name="com.android.lotsofapps.activity29"
+ android:icon="@drawable/ic_launcher_slideshow_add_sms"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity20" android:icon="@drawable/ic_launcher_slideshow_default_sms">
+ <activity android:name="com.android.lotsofapps.activity20"
+ android:icon="@drawable/ic_launcher_slideshow_default_sms"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity31" android:icon="@drawable/ic_launcher_smsmms">
+ <activity android:name="com.android.lotsofapps.activity31"
+ android:icon="@drawable/ic_launcher_smsmms"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity32" android:icon="@drawable/ic_launcher_soundrecorder">
+ <activity android:name="com.android.lotsofapps.activity32"
+ android:icon="@drawable/ic_launcher_soundrecorder"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity33" android:icon="@drawable/ic_launcher_video_camera">
+ <activity android:name="com.android.lotsofapps.activity33"
+ android:icon="@drawable/ic_launcher_video_camera"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity34" android:icon="@drawable/ic_launcher_video_player">
+ <activity android:name="com.android.lotsofapps.activity34"
+ android:icon="@drawable/ic_launcher_video_player"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity35" android:icon="@drawable/ic_launcher_wallpaper">
+ <activity android:name="com.android.lotsofapps.activity35"
+ android:icon="@drawable/ic_launcher_wallpaper"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity36" android:icon="@drawable/ic_launcher_im">
+ <activity android:name="com.android.lotsofapps.activity36"
+ android:icon="@drawable/ic_launcher_im"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity37" android:icon="@drawable/ic_launcher_musicplayer_2">
+ <activity android:name="com.android.lotsofapps.activity37"
+ android:icon="@drawable/ic_launcher_musicplayer_2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity38" android:icon="@drawable/ic_launcher_phone">
+ <activity android:name="com.android.lotsofapps.activity38"
+ android:icon="@drawable/ic_launcher_phone"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity39" android:icon="@drawable/ic_launcher_record_audio">
+ <activity android:name="com.android.lotsofapps.activity39"
+ android:icon="@drawable/ic_launcher_record_audio"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity40" android:icon="@drawable/ic_launcher_settings">
+ <activity android:name="com.android.lotsofapps.activity40"
+ android:icon="@drawable/ic_launcher_settings"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity41" android:icon="@drawable/ic_launcher_shortcut">
+ <activity android:name="com.android.lotsofapps.activity41"
+ android:icon="@drawable/ic_launcher_shortcut"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity42" android:icon="@drawable/ic_launcher_sim_toolkit">
+ <activity android:name="com.android.lotsofapps.activity42"
+ android:icon="@drawable/ic_launcher_sim_toolkit"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity43" android:icon="@drawable/ic_launcher_smsmms">
+ <activity android:name="com.android.lotsofapps.activity43"
+ android:icon="@drawable/ic_launcher_smsmms"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity44" android:icon="@drawable/ic_launcher_soundrecorder">
+ <activity android:name="com.android.lotsofapps.activity44"
+ android:icon="@drawable/ic_launcher_soundrecorder"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity45" android:icon="@drawable/ic_launcher_video_camera">
+ <activity android:name="com.android.lotsofapps.activity45"
+ android:icon="@drawable/ic_launcher_video_camera"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity46" android:icon="@drawable/ic_launcher_wallpaper">
+ <activity android:name="com.android.lotsofapps.activity46"
+ android:icon="@drawable/ic_launcher_wallpaper"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity47" android:icon="@drawable/ic_launcher_drm_file">
+ <activity android:name="com.android.lotsofapps.activity47"
+ android:icon="@drawable/ic_launcher_drm_file"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity48" android:icon="@drawable/ic_launcher_contacts">
+ <activity android:name="com.android.lotsofapps.activity48"
+ android:icon="@drawable/ic_launcher_contacts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity49" android:icon="@drawable/ic_launcher_drm_file">
+ <activity android:name="com.android.lotsofapps.activity49"
+ android:icon="@drawable/ic_launcher_drm_file"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity50" android:icon="@drawable/ic_launcher_add_folder">
+ <activity android:name="com.android.lotsofapps.activity50"
+ android:icon="@drawable/ic_launcher_add_folder"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity51" android:icon="@drawable/ic_launcher_alarmclock">
+ <activity android:name="com.android.lotsofapps.activity51"
+ android:icon="@drawable/ic_launcher_alarmclock"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity52" android:icon="@drawable/ic_launcher_application">
+ <activity android:name="com.android.lotsofapps.activity52"
+ android:icon="@drawable/ic_launcher_application"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity53" android:icon="@drawable/ic_launcher_browser">
+ <activity android:name="com.android.lotsofapps.activity53"
+ android:icon="@drawable/ic_launcher_browser"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity54" android:icon="@drawable/ic_launcher_camera">
+ <activity android:name="com.android.lotsofapps.activity54"
+ android:icon="@drawable/ic_launcher_camera"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity55" android:icon="@drawable/ic_launcher_camera_record">
+ <activity android:name="com.android.lotsofapps.activity55"
+ android:icon="@drawable/ic_launcher_camera_record"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity56" android:icon="@drawable/ic_launcher_contacts">
+ <activity android:name="com.android.lotsofapps.activity56"
+ android:icon="@drawable/ic_launcher_contacts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity57" android:icon="@drawable/ic_launcher_drm_file">
+ <activity android:name="com.android.lotsofapps.activity57"
+ android:icon="@drawable/ic_launcher_drm_file"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity58" android:icon="@drawable/ic_launcher_folder">
+ <activity android:name="com.android.lotsofapps.activity58"
+ android:icon="@drawable/ic_launcher_folder"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity59" android:icon="@drawable/ic_launcher_folder_bluetooth">
+ <activity android:name="com.android.lotsofapps.activity59"
+ android:icon="@drawable/ic_launcher_folder_bluetooth"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity60" android:icon="@drawable/ic_launcher_folder_live">
+ <activity android:name="com.android.lotsofapps.activity60"
+ android:icon="@drawable/ic_launcher_folder_live"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity61" android:icon="@drawable/ic_launcher_folder_live_contacts">
+ <activity android:name="com.android.lotsofapps.activity61"
+ android:icon="@drawable/ic_launcher_folder_live_contacts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity62" android:icon="@drawable/ic_launcher_folder_live_contacts_phone">
+ <activity android:name="com.android.lotsofapps.activity62"
+ android:icon="@drawable/ic_launcher_folder_live_contacts_phone"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity63" android:icon="@drawable/ic_launcher_folder_live_contacts_starred">
+ <activity android:name="com.android.lotsofapps.activity63"
+ android:icon="@drawable/ic_launcher_folder_live_contacts_starred"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity64" android:icon="@drawable/ic_launcher_folder_open">
+ <activity android:name="com.android.lotsofapps.activity64"
+ android:icon="@drawable/ic_launcher_folder_open"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity65" android:icon="@drawable/ic_launcher_gallery">
+ <activity android:name="com.android.lotsofapps.activity65"
+ android:icon="@drawable/ic_launcher_gallery"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity66" android:icon="@drawable/ic_launcher_home">
+ <activity android:name="com.android.lotsofapps.activity66"
+ android:icon="@drawable/ic_launcher_home"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity67" android:icon="@drawable/ic_launcher_im">
+ <activity android:name="com.android.lotsofapps.activity67"
+ android:icon="@drawable/ic_launcher_im"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity68" android:icon="@drawable/ic_launcher_musicplayer_2">
+ <activity android:name="com.android.lotsofapps.activity68"
+ android:icon="@drawable/ic_launcher_musicplayer_2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity69" android:icon="@drawable/ic_launcher_phone">
+ <activity android:name="com.android.lotsofapps.activity69"
+ android:icon="@drawable/ic_launcher_phone"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity70" android:icon="@drawable/ic_launcher_record_audio">
+ <activity android:name="com.android.lotsofapps.activity70"
+ android:icon="@drawable/ic_launcher_record_audio"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity71" android:icon="@drawable/ic_launcher_settings">
+ <activity android:name="com.android.lotsofapps.activity71"
+ android:icon="@drawable/ic_launcher_settings"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity72" android:icon="@drawable/ic_launcher_shortcut">
+ <activity android:name="com.android.lotsofapps.activity72"
+ android:icon="@drawable/ic_launcher_shortcut"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity73" android:icon="@drawable/ic_launcher_shortcut_browser_bookmark">
+ <activity android:name="com.android.lotsofapps.activity73"
+ android:icon="@drawable/ic_launcher_shortcut_browser_bookmark"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity74" android:icon="@drawable/ic_launcher_contacts">
+ <activity android:name="com.android.lotsofapps.activity74"
+ android:icon="@drawable/ic_launcher_contacts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity75" android:icon="@drawable/ic_launcher_shortcut_directdial">
+ <activity android:name="com.android.lotsofapps.activity75"
+ android:icon="@drawable/ic_launcher_shortcut_directdial"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity76" android:icon="@drawable/ic_launcher_shortcut_directmessage">
+ <activity android:name="com.android.lotsofapps.activity76"
+ android:icon="@drawable/ic_launcher_shortcut_directmessage"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity77" android:icon="@drawable/ic_launcher_browser">
+ <activity android:name="com.android.lotsofapps.activity77"
+ android:icon="@drawable/ic_launcher_browser"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity78" android:icon="@drawable/ic_launcher_sim_toolkit">
+ <activity android:name="com.android.lotsofapps.activity78"
+ android:icon="@drawable/ic_launcher_sim_toolkit"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity79" android:icon="@drawable/ic_launcher_slideshow_add_sms">
+ <activity android:name="com.android.lotsofapps.activity79"
+ android:icon="@drawable/ic_launcher_slideshow_add_sms"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity80" android:icon="@drawable/ic_launcher_slideshow_default_sms">
+ <activity android:name="com.android.lotsofapps.activity80"
+ android:icon="@drawable/ic_launcher_slideshow_default_sms"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity81" android:icon="@drawable/ic_launcher_smsmms">
+ <activity android:name="com.android.lotsofapps.activity81"
+ android:icon="@drawable/ic_launcher_smsmms"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity82" android:icon="@drawable/ic_launcher_soundrecorder">
+ <activity android:name="com.android.lotsofapps.activity82"
+ android:icon="@drawable/ic_launcher_soundrecorder"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity83" android:icon="@drawable/ic_launcher_video_camera">
+ <activity android:name="com.android.lotsofapps.activity83"
+ android:icon="@drawable/ic_launcher_video_camera"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity84" android:icon="@drawable/ic_launcher_video_player">
+ <activity android:name="com.android.lotsofapps.activity84"
+ android:icon="@drawable/ic_launcher_video_player"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity85" android:icon="@drawable/ic_launcher_wallpaper">
+ <activity android:name="com.android.lotsofapps.activity85"
+ android:icon="@drawable/ic_launcher_wallpaper"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity86" android:icon="@drawable/ic_launcher_im">
+ <activity android:name="com.android.lotsofapps.activity86"
+ android:icon="@drawable/ic_launcher_im"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity87" android:icon="@drawable/ic_launcher_musicplayer_2">
+ <activity android:name="com.android.lotsofapps.activity87"
+ android:icon="@drawable/ic_launcher_musicplayer_2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity88" android:icon="@drawable/ic_launcher_phone">
+ <activity android:name="com.android.lotsofapps.activity88"
+ android:icon="@drawable/ic_launcher_phone"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity89" android:icon="@drawable/ic_launcher_record_audio">
+ <activity android:name="com.android.lotsofapps.activity89"
+ android:icon="@drawable/ic_launcher_record_audio"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity90" android:icon="@drawable/ic_launcher_settings">
+ <activity android:name="com.android.lotsofapps.activity90"
+ android:icon="@drawable/ic_launcher_settings"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity91" android:icon="@drawable/ic_launcher_shortcut">
+ <activity android:name="com.android.lotsofapps.activity91"
+ android:icon="@drawable/ic_launcher_shortcut"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity92" android:icon="@drawable/ic_launcher_sim_toolkit">
+ <activity android:name="com.android.lotsofapps.activity92"
+ android:icon="@drawable/ic_launcher_sim_toolkit"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity93" android:icon="@drawable/ic_launcher_smsmms">
+ <activity android:name="com.android.lotsofapps.activity93"
+ android:icon="@drawable/ic_launcher_smsmms"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity94" android:icon="@drawable/ic_launcher_soundrecorder">
+ <activity android:name="com.android.lotsofapps.activity94"
+ android:icon="@drawable/ic_launcher_soundrecorder"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity95" android:icon="@drawable/ic_launcher_video_camera">
+ <activity android:name="com.android.lotsofapps.activity95"
+ android:icon="@drawable/ic_launcher_video_camera"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity96" android:icon="@drawable/ic_launcher_wallpaper">
+ <activity android:name="com.android.lotsofapps.activity96"
+ android:icon="@drawable/ic_launcher_wallpaper"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity97" android:icon="@drawable/ic_launcher_drm_file">
+ <activity android:name="com.android.lotsofapps.activity97"
+ android:icon="@drawable/ic_launcher_drm_file"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity98" android:icon="@drawable/ic_launcher_contacts">
+ <activity android:name="com.android.lotsofapps.activity98"
+ android:icon="@drawable/ic_launcher_contacts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="com.android.lotsofapps.activity99" android:icon="@drawable/ic_launcher_drm_file">
+ <activity android:name="com.android.lotsofapps.activity99"
+ android:icon="@drawable/ic_launcher_drm_file"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/LowStorageTest/Android.bp b/tests/LowStorageTest/Android.bp
index e72e4a5e2559..6dcf39d606dd 100644
--- a/tests/LowStorageTest/Android.bp
+++ b/tests/LowStorageTest/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "lowstoragetest",
certificate: "platform",
diff --git a/tests/LowStorageTest/AndroidManifest.xml b/tests/LowStorageTest/AndroidManifest.xml
index 9d4a63ac330f..5b496562ab27 100644
--- a/tests/LowStorageTest/AndroidManifest.xml
+++ b/tests/LowStorageTest/AndroidManifest.xml
@@ -1,13 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.lowstoragetest">
+ package="com.android.lowstoragetest">
<application android:label="LowStorageTest">
<activity android:name="LowStorageTest"
- android:theme="@android:style/Theme.Black.NoTitleBar">
+ android:theme="@android:style/Theme.Black.NoTitleBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
-</manifest> \ No newline at end of file
+</manifest>
diff --git a/tests/LowStorageTest/OWNERS b/tests/LowStorageTest/OWNERS
new file mode 100644
index 000000000000..6f9dbea36b06
--- /dev/null
+++ b/tests/LowStorageTest/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/os/storage/OWNERS
diff --git a/tests/ManagedProfileLifecycleStressTest/Android.bp b/tests/ManagedProfileLifecycleStressTest/Android.bp
index 639ce3cfe935..3ef6322a2984 100644
--- a/tests/ManagedProfileLifecycleStressTest/Android.bp
+++ b/tests/ManagedProfileLifecycleStressTest/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
java_test_host {
name: "ManagedProfileLifecycleStressTest",
srcs: ["src/**/*.java"],
diff --git a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp
index 1f47b03d0074..7a9b6cfb134f 100644
--- a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp
+++ b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "DummyDPC",
defaults: ["cts_defaults"],
diff --git a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/AndroidManifest.xml b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/AndroidManifest.xml
index 860940d4e025..aefb07661f7e 100644
--- a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/AndroidManifest.xml
+++ b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/AndroidManifest.xml
@@ -15,17 +15,16 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.dummydpc">
+ package="com.android.dummydpc">
- <application
- android:testOnly="true">
- <receiver
- android:name="com.android.dummydpc.DummyDeviceAdminReceiver"
- android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <application android:testOnly="true">
+ <receiver android:name="com.android.dummydpc.DummyDeviceAdminReceiver"
+ android:permission="android.permission.BIND_DEVICE_ADMIN"
+ android:exported="true">
<meta-data android:name="android.app.device_admin"
- android:resource="@xml/device_admin" />
+ android:resource="@xml/device_admin"/>
<intent-filter>
- <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
</intent-filter>
</receiver>
</application>
diff --git a/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java b/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java
index 026677e09bed..99dde859028a 100644
--- a/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java
+++ b/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java
@@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import com.android.tradefed.device.CollectingOutputReceiver;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
@@ -62,13 +63,62 @@ public class ManagedProfileLifecycleStressTest extends BaseHostJUnit4Test {
CLog.w("Iteration N" + iteration);
final int userId = createManagedProfile();
startUser(userId);
- installPackageAsUser(DUMMY_DPC_APK, true /* grantPermissions */, userId, "-t");
+ installPackageAsUser(
+ DUMMY_DPC_APK, /* grantPermissions= */true, userId, /* options= */"-t");
setProfileOwner(DUMMY_DPC_COMPONENT, userId);
removeUser(userId);
}
CLog.w("Completed " + iteration + " iterations.");
}
+ /**
+ * Create, start, and kill managed profiles in a loop with waitForBroadcastIdle after each user
+ * operation.
+ */
+ @Test
+ public void testCreateStartDeleteStable() throws Exception {
+ // Disable package verifier for ADB installs.
+ getDevice().executeShellCommand("settings put global verifier_verify_adb_installs 0");
+ int iteration = 0;
+ final long deadline = System.nanoTime() + TimeUnit.MINUTES.toNanos(TIME_LIMIT_MINUTES);
+ while (System.nanoTime() < deadline) {
+ iteration++;
+ CLog.w("Iteration N" + iteration);
+ final int userId = createManagedProfile();
+ waitForBroadcastIdle();
+
+ startUser(userId);
+ waitForBroadcastIdle();
+
+ installPackageAsUser(
+ DUMMY_DPC_APK, /* grantPermissions= */true, userId, /* options= */"-t");
+
+ setProfileOwner(DUMMY_DPC_COMPONENT, userId);
+
+ removeUser(userId);
+ waitForBroadcastIdle();
+ }
+ CLog.w("Completed " + iteration + " iterations.");
+ }
+
+ private void waitForBroadcastIdle() throws Exception {
+ final CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+ // We allow 8min for the command to complete and 4min for the command to start to
+ // output something.
+ getDevice().executeShellCommand(
+ "am wait-for-broadcast-idle",
+ receiver,
+ /* maxTimeoutForCommand= */8,
+ /* maxTimeoutToOutputShellResponse= */4,
+ TimeUnit.MINUTES,
+ /* retryAttempts= */0);
+ final String output = receiver.getOutput();
+ if (!output.contains("All broadcast queues are idle!")) {
+ CLog.e("Output from 'am wait-for-broadcast-idle': %s", output);
+ fail("'am wait-for-broadcase-idle' did not complete.");
+ }
+ }
+
private int createManagedProfile() throws Exception {
final String output = getDevice().executeShellCommand(
"pm create-user --profileOf 0 --managed TestProfile");
diff --git a/tests/MemoryUsage/Android.bp b/tests/MemoryUsage/Android.bp
index aeb533882d4f..e30a0a7cd8b5 100644
--- a/tests/MemoryUsage/Android.bp
+++ b/tests/MemoryUsage/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "MemoryUsage",
// Only compile source java files in this apk.
diff --git a/tests/MirrorSurfaceTest/Android.bp b/tests/MirrorSurfaceTest/Android.bp
index e359c64cc982..1368f260725f 100644
--- a/tests/MirrorSurfaceTest/Android.bp
+++ b/tests/MirrorSurfaceTest/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "MirrorSurfaceTest",
srcs: ["src/**/*.java"],
diff --git a/tests/MirrorSurfaceTest/AndroidManifest.xml b/tests/MirrorSurfaceTest/AndroidManifest.xml
index 123cd0f26ff3..6385cc8a9d22 100644
--- a/tests/MirrorSurfaceTest/AndroidManifest.xml
+++ b/tests/MirrorSurfaceTest/AndroidManifest.xml
@@ -16,14 +16,15 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.mirrorsurface">
+ package="com.google.android.test.mirrorsurface">
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER"/>
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application android:label="MirrorSurfaceTest">
<activity android:name=".MirrorSurfaceActivity"
- android:label="Mirror Surface"
- android:configChanges="orientation|screenSize">
+ android:label="Mirror Surface"
+ android:configChanges="orientation|screenSize"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
diff --git a/tests/NativeProcessesMemoryTest/Android.bp b/tests/NativeProcessesMemoryTest/Android.bp
index f2625bf2db11..b7160e95dbb6 100644
--- a/tests/NativeProcessesMemoryTest/Android.bp
+++ b/tests/NativeProcessesMemoryTest/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
java_test_host {
name: "native-processes-memory-test",
srcs: ["src/**/*.java"],
diff --git a/tests/NetworkSecurityConfigTest/Android.bp b/tests/NetworkSecurityConfigTest/Android.bp
index cf8ca57862b4..473eadbcad73 100644
--- a/tests/NetworkSecurityConfigTest/Android.bp
+++ b/tests/NetworkSecurityConfigTest/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "NetworkSecurityConfigTests",
certificate: "platform",
diff --git a/tests/NetworkSecurityConfigTest/OWNERS b/tests/NetworkSecurityConfigTest/OWNERS
new file mode 100644
index 000000000000..aa87958f1d53
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/tests/NullHomeTest/Android.bp b/tests/NullHomeTest/Android.bp
index 99248bfe1da1..d8799a87e8c9 100644
--- a/tests/NullHomeTest/Android.bp
+++ b/tests/NullHomeTest/Android.bp
@@ -12,11 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "NullHomeTest",
srcs: ["src/**/*.java"],
certificate: "platform",
platform_apis: true,
- static_libs: ["android-support-test"],
+ static_libs: ["androidx.test.rules"],
test_suites: ["device-tests"],
}
diff --git a/tests/NullHomeTest/AndroidManifest.xml b/tests/NullHomeTest/AndroidManifest.xml
index dc6402e03b5a..6f77781c7a29 100644
--- a/tests/NullHomeTest/AndroidManifest.xml
+++ b/tests/NullHomeTest/AndroidManifest.xml
@@ -21,7 +21,7 @@
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
<instrumentation
- android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.test.nullhome"
android:label="Check if no null Home exists/is enabled" />
diff --git a/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java b/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java
index 1d77cdc51187..3ec3ef2f8fea 100644
--- a/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java
+++ b/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java
@@ -18,9 +18,10 @@ package com.android.test.nullhome;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.support.test.InstrumentationRegistry;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
diff --git a/tests/OdmApps/Android.bp b/tests/OdmApps/Android.bp
index d86f9cc81a5f..de86498afd27 100644
--- a/tests/OdmApps/Android.bp
+++ b/tests/OdmApps/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
java_test_host {
name: "OdmAppsTest",
srcs: ["src/**/*.java"],
diff --git a/tests/OdmApps/app/Android.bp b/tests/OdmApps/app/Android.bp
index 5eb8590b6e06..a33a1cf4690e 100644
--- a/tests/OdmApps/app/Android.bp
+++ b/tests/OdmApps/app/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "TestOdmApp",
test_suites: ["device-tests"],
diff --git a/tests/OdmApps/priv-app/Android.bp b/tests/OdmApps/priv-app/Android.bp
index 9dd477cf6ad3..7527729c8267 100644
--- a/tests/OdmApps/priv-app/Android.bp
+++ b/tests/OdmApps/priv-app/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "TestOdmPrivApp",
test_suites: ["device-tests"],
diff --git a/tests/OneMedia/Android.bp b/tests/OneMedia/Android.bp
index 11e12f35741c..5c7317735bc7 100644
--- a/tests/OneMedia/Android.bp
+++ b/tests/OneMedia/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_app {
name: "OneMedia",
srcs: [
diff --git a/tests/OneMedia/AndroidManifest.xml b/tests/OneMedia/AndroidManifest.xml
index 8697f1b085bf..7fc352405212 100644
--- a/tests/OneMedia/AndroidManifest.xml
+++ b/tests/OneMedia/AndroidManifest.xml
@@ -1,33 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.onemedia"
- android:versionCode="1"
- android:versionName="1.0" >
+ package="com.android.onemedia"
+ android:versionCode="1"
+ android:versionName="1.0">
<uses-sdk android:minSdkVersion="19"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
+ <application android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
- <uses-library android:name="org.apache.http.legacy" android:required="false" />
- <activity
- android:name="com.android.onemedia.OnePlayerActivity"
- android:label="@string/app_name" >
+ <uses-library android:name="org.apache.http.legacy"
+ android:required="false"/>
+ <activity android:name="com.android.onemedia.OnePlayerActivity"
+ android:label="@string/app_name"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <service
- android:name="com.android.onemedia.OnePlayerService"
- android:exported="true"
- android:process="com.android.onemedia.service" />
+ <service android:name="com.android.onemedia.OnePlayerService"
+ android:exported="true"
+ android:process="com.android.onemedia.service"/>
</application>
</manifest>
diff --git a/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java b/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java
index ceb0937b9165..6483c924cd67 100644
--- a/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java
+++ b/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java
@@ -52,22 +52,22 @@ public class NotificationHelper extends BroadcastReceiver {
mIntents.put(R.drawable.ic_pause, PendingIntent.getBroadcast(mService, 100, new Intent(
com.android.onemedia.playback.RequestUtils.ACTION_PAUSE).setPackage(pkg),
- PendingIntent.FLAG_CANCEL_CURRENT));
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED));
mIntents.put(R.drawable.ic_play_arrow, PendingIntent.getBroadcast(mService, 100,
new Intent(com.android.onemedia.playback.RequestUtils.ACTION_PLAY).setPackage(pkg),
- PendingIntent.FLAG_CANCEL_CURRENT));
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED));
mIntents.put(R.drawable.ic_skip_previous, PendingIntent.getBroadcast(mService, 100,
new Intent(com.android.onemedia.playback.RequestUtils.ACTION_PREV).setPackage(pkg),
- PendingIntent.FLAG_CANCEL_CURRENT));
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED));
mIntents.put(R.drawable.ic_skip_next, PendingIntent.getBroadcast(mService, 100,
new Intent(com.android.onemedia.playback.RequestUtils.ACTION_NEXT).setPackage(pkg),
- PendingIntent.FLAG_CANCEL_CURRENT));
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED));
mIntents.put(R.drawable.ic_fast_rewind, PendingIntent.getBroadcast(mService, 100,
new Intent(com.android.onemedia.playback.RequestUtils.ACTION_REW).setPackage(pkg),
- PendingIntent.FLAG_CANCEL_CURRENT));
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED));
mIntents.put(R.drawable.ic_fast_forward, PendingIntent.getBroadcast(mService, 100,
new Intent(com.android.onemedia.playback.RequestUtils.ACTION_FFWD).setPackage(pkg),
- PendingIntent.FLAG_CANCEL_CURRENT));
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED));
}
/**
diff --git a/tests/PackageWatchdog/Android.bp b/tests/PackageWatchdog/Android.bp
index 0b75039cf69f..1e1dc8458560 100644
--- a/tests/PackageWatchdog/Android.bp
+++ b/tests/PackageWatchdog/Android.bp
@@ -13,6 +13,15 @@
// limitations under the License.
// PackageWatchdogTest
+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"],
+}
+
android_test {
name: "PackageWatchdogTest",
srcs: ["src/**/*.java"],
diff --git a/tests/PackageWatchdog/OWNERS b/tests/PackageWatchdog/OWNERS
new file mode 100644
index 000000000000..d04a70619caa
--- /dev/null
+++ b/tests/PackageWatchdog/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/rollback/OWNERS
diff --git a/tests/PackageWatchdog/TEST_MAPPING b/tests/PackageWatchdog/TEST_MAPPING
new file mode 100644
index 000000000000..6494a273eced
--- /dev/null
+++ b/tests/PackageWatchdog/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "PackageWatchdogTest"
+ }
+ ]
+}
diff --git a/tests/PackageWatchdog/src/com/android/server/OWNERS b/tests/PackageWatchdog/src/com/android/server/OWNERS
new file mode 100644
index 000000000000..5cf4dcf92048
--- /dev/null
+++ b/tests/PackageWatchdog/src/com/android/server/OWNERS
@@ -0,0 +1 @@
+per-file PackageWatchdogTest.java = file:/services/core/java/com/android/server/rollback/OWNERS
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index ae93a81f274e..96bbf82cfba7 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -22,7 +22,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
@@ -43,10 +43,15 @@ import android.os.SystemProperties;
import android.os.test.TestLooper;
import android.provider.DeviceConfig;
import android.util.AtomicFile;
+import android.util.LongArrayQueue;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
import androidx.test.InstrumentationRegistry;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.util.XmlUtils;
import com.android.server.PackageWatchdog.HealthCheckState;
import com.android.server.PackageWatchdog.MonitoredPackage;
import com.android.server.PackageWatchdog.PackageHealthObserver;
@@ -64,6 +69,7 @@ import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;
import java.io.File;
+import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -72,11 +78,15 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
+import java.util.function.Supplier;
/**
* Test PackageWatchdog.
*/
public class PackageWatchdogTest {
+ private static final long RETRY_MAX_COUNT = 30;
+ private static final long RETRY_TIMEOUT_MILLIS = 500;
+
private static final String APP_A = "com.package.a";
private static final String APP_B = "com.package.b";
private static final String APP_C = "com.package.c";
@@ -91,6 +101,8 @@ public class PackageWatchdogTest {
private final TestClock mTestClock = new TestClock();
private TestLooper mTestLooper;
private Context mSpyContext;
+ // Keep track of all created watchdogs to apply device config changes
+ private List<PackageWatchdog> mAllocatedWatchdogs;
@Mock
private ConnectivityModuleConnector mConnectivityModuleConnector;
@Mock
@@ -100,12 +112,23 @@ public class PackageWatchdogTest {
private MockitoSession mSession;
private HashMap<String, String> mSystemSettingsMap;
+ private boolean retry(Supplier<Boolean> supplier) throws Exception {
+ for (int i = 0; i < RETRY_MAX_COUNT; ++i) {
+ if (supplier.get()) {
+ return true;
+ }
+ Thread.sleep(RETRY_TIMEOUT_MILLIS);
+ }
+ return false;
+ }
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
new File(InstrumentationRegistry.getContext().getFilesDir(),
"package-watchdog.xml").delete();
- adoptShellPermissions(Manifest.permission.READ_DEVICE_CONFIG);
+ adoptShellPermissions(Manifest.permission.READ_DEVICE_CONFIG,
+ Manifest.permission.WRITE_DEVICE_CONFIG);
mTestLooper = new TestLooper();
mSpyContext = spy(InstrumentationRegistry.getContext());
when(mSpyContext.getPackageManager()).thenReturn(mMockPackageManager);
@@ -150,12 +173,27 @@ public class PackageWatchdogTest {
return storedValue == null ? defaultValue : Long.parseLong(storedValue);
}
).when(() -> SystemProperties.getLong(anyString(), anyLong()));
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED,
+ Boolean.toString(true), false);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
+ Integer.toString(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT), false);
+
+ mAllocatedWatchdogs = new ArrayList<>();
}
@After
public void tearDown() throws Exception {
dropShellPermissions();
mSession.finishMocking();
+ // Clean up listeners since too many listeners will delay notifications significantly
+ for (PackageWatchdog watchdog : mAllocatedWatchdogs) {
+ watchdog.removePropertyChangedListener();
+ }
+ mAllocatedWatchdogs.clear();
}
@Test
@@ -376,7 +414,7 @@ public class PackageWatchdogTest {
TestObserver observer = new TestObserver(OBSERVER_NAME_1) {
@Override
public int onHealthCheckFailed(VersionedPackage versionedPackage,
- int failureReason) {
+ int failureReason, int mitigationCount) {
if (versionedPackage.getVersionCode() == VERSION_CODE) {
// Only rollback for specific versionCode
return PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
@@ -604,10 +642,6 @@ public class PackageWatchdogTest {
*/
@Test
public void testExplicitHealthCheckStateChanges() throws Exception {
- adoptShellPermissions(
- Manifest.permission.WRITE_DEVICE_CONFIG,
- Manifest.permission.READ_DEVICE_CONFIG);
-
TestController controller = new TestController();
PackageWatchdog watchdog = createWatchdog(controller, true /* withPackagesReady */);
TestObserver observer = new TestObserver(OBSERVER_NAME_1,
@@ -739,7 +773,8 @@ public class PackageWatchdogTest {
false /* hasPassedHealthCheck */);
MonitoredPackage m2 = wd.newMonitoredPackage(APP_B, LONG_DURATION, false);
MonitoredPackage m3 = wd.newMonitoredPackage(APP_C, LONG_DURATION, false);
- MonitoredPackage m4 = wd.newMonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true);
+ MonitoredPackage m4 = wd.newMonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true,
+ new LongArrayQueue());
// Verify transition: inactive -> active -> passed
// Verify initially inactive
@@ -799,9 +834,6 @@ public class PackageWatchdogTest {
/** Test default values are used when device property is invalid. */
@Test
public void testInvalidConfig_watchdogTriggerFailureCount() {
- adoptShellPermissions(
- Manifest.permission.WRITE_DEVICE_CONFIG,
- Manifest.permission.READ_DEVICE_CONFIG);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
Integer.toString(-1), /*makeDefault*/false);
@@ -827,9 +859,6 @@ public class PackageWatchdogTest {
/** Test default values are used when device property is invalid. */
@Test
public void testInvalidConfig_watchdogTriggerDurationMillis() {
- adoptShellPermissions(
- Manifest.permission.WRITE_DEVICE_CONFIG,
- Manifest.permission.READ_DEVICE_CONFIG);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
Integer.toString(2), /*makeDefault*/false);
@@ -842,7 +871,6 @@ public class PackageWatchdogTest {
watchdog.startObservingHealth(observer, Arrays.asList(APP_A, APP_B), Long.MAX_VALUE);
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
- mTestLooper.dispatchAll();
moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS + 1);
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
@@ -854,7 +882,6 @@ public class PackageWatchdogTest {
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
- mTestLooper.dispatchAll();
moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS - 1);
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
@@ -909,9 +936,6 @@ public class PackageWatchdogTest {
/** Test we are notified when enough failures are triggered within any window. */
@Test
public void testFailureTriggerWindow() {
- adoptShellPermissions(
- Manifest.permission.WRITE_DEVICE_CONFIG,
- Manifest.permission.READ_DEVICE_CONFIG);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
Integer.toString(3), /*makeDefault*/false);
@@ -925,11 +949,9 @@ public class PackageWatchdogTest {
// Raise 2 failures at t=0 and t=900 respectively
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
- mTestLooper.dispatchAll();
moveTimeForwardAndDispatch(900);
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
PackageWatchdog.FAILURE_REASON_UNKNOWN);
- mTestLooper.dispatchAll();
// Raise 2 failures at t=1100
moveTimeForwardAndDispatch(200);
@@ -1064,6 +1086,31 @@ public class PackageWatchdogTest {
}
/**
+ * Ensure that the correct mitigation counts are sent to the boot loop observer.
+ */
+ @Test
+ public void testMultipleBootLoopMitigation() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1);
+ watchdog.registerHealthObserver(bootObserver);
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; j++) {
+ watchdog.noteBoot();
+ }
+ }
+
+ moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS + 1);
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; j++) {
+ watchdog.noteBoot();
+ }
+ }
+
+ assertThat(bootObserver.mBootMitigationCounts).isEqualTo(List.of(1, 2, 3, 4, 1, 2, 3, 4));
+ }
+
+ /**
* Ensure that passing a null list of failed packages does not cause any mitigation logic to
* execute.
*/
@@ -1146,6 +1193,172 @@ public class PackageWatchdogTest {
assertThat(observer.mMitigatedPackages).isEqualTo(List.of(APP_A));
}
+ /**
+ * Ensure that the sliding window logic results in the correct mitigation count being sent to
+ * an observer.
+ */
+ @Test
+ public void testMitigationSlidingWindow() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver observer = new TestObserver(OBSERVER_NAME_1);
+ watchdog.startObservingHealth(observer, List.of(APP_A),
+ PackageWatchdog.DEFAULT_OBSERVING_DURATION_MS * 2);
+
+
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ moveTimeForwardAndDispatch(TimeUnit.MINUTES.toMillis(10));
+
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS);
+
+ // The first failure will be outside the threshold.
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ moveTimeForwardAndDispatch(TimeUnit.MINUTES.toMillis(20));
+
+ // The next 2 failures will also be outside the threshold.
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ assertThat(observer.mMitigationCounts).isEqualTo(List.of(1, 2, 3, 3, 2, 3));
+ }
+
+ @Test
+ public void testNormalizingMitigationCalls() {
+ PackageWatchdog watchdog = createWatchdog();
+
+ LongArrayQueue mitigationCalls = new LongArrayQueue();
+ mitigationCalls.addLast(1000);
+ mitigationCalls.addLast(2000);
+ mitigationCalls.addLast(3000);
+
+ MonitoredPackage pkg = watchdog.newMonitoredPackage(
+ "test", 123, 456, true, mitigationCalls);
+
+ // Make current system uptime 10000ms.
+ moveTimeForwardAndDispatch(9999);
+
+ LongArrayQueue expectedCalls = pkg.normalizeMitigationCalls();
+
+ assertThat(expectedCalls.size()).isEqualTo(mitigationCalls.size());
+
+ for (int i = 0; i < mitigationCalls.size(); i++) {
+ assertThat(expectedCalls.get(i)).isEqualTo(mitigationCalls.get(i) - 10000);
+ }
+ }
+
+ /**
+ * Ensure that a {@link MonitoredPackage} may be correctly written and read in order to persist
+ * across reboots.
+ */
+ @Test
+ public void testWritingAndReadingMonitoredPackage() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+
+ LongArrayQueue mitigationCalls = new LongArrayQueue();
+ mitigationCalls.addLast(1000);
+ mitigationCalls.addLast(2000);
+ mitigationCalls.addLast(3000);
+ MonitoredPackage writePkg = watchdog.newMonitoredPackage(
+ "test.package", 1000, 2000, true, mitigationCalls);
+
+ // Move time forward so that the current uptime is 4000ms. Therefore, the written mitigation
+ // calls will each be reduced by 4000.
+ moveTimeForwardAndDispatch(3999);
+ LongArrayQueue expectedCalls = new LongArrayQueue();
+ expectedCalls.addLast(-3000);
+ expectedCalls.addLast(-2000);
+ expectedCalls.addLast(-1000);
+ MonitoredPackage expectedPkg = watchdog.newMonitoredPackage(
+ "test.package", 1000, 2000, true, expectedCalls);
+
+ // Write the package
+ File tmpFile = File.createTempFile("package-watchdog-test", ".xml");
+ AtomicFile testFile = new AtomicFile(tmpFile);
+ FileOutputStream stream = testFile.startWrite();
+ TypedXmlSerializer outputSerializer = Xml.resolveSerializer(stream);
+ outputSerializer.startDocument(null, true);
+ writePkg.writeLocked(outputSerializer);
+ outputSerializer.endDocument();
+ testFile.finishWrite(stream);
+
+ // Read the package
+ TypedXmlPullParser parser = Xml.resolvePullParser(testFile.openRead());
+ XmlUtils.beginDocument(parser, "package");
+ MonitoredPackage readPkg = watchdog.parseMonitoredPackage(parser);
+
+ assertTrue(readPkg.isEqualTo(expectedPkg));
+ }
+
+ /**
+ * Tests device config changes are propagated correctly.
+ */
+ @Test
+ public void testDeviceConfigChange_explicitHealthCheckEnabled() throws Exception {
+ TestController controller = new TestController();
+ PackageWatchdog watchdog = createWatchdog(controller, true /* withPackagesReady */);
+ assertThat(controller.mIsEnabled).isTrue();
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED,
+ Boolean.toString(false), /*makeDefault*/false);
+ retry(() -> !controller.mIsEnabled);
+ assertThat(controller.mIsEnabled).isFalse();
+ }
+
+ /**
+ * Tests device config changes are propagated correctly.
+ */
+ @Test
+ public void testDeviceConfigChange_triggerFailureCount() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
+ Integer.toString(777), false);
+ retry(() -> watchdog.getTriggerFailureCount() == 777);
+ assertThat(watchdog.getTriggerFailureCount()).isEqualTo(777);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
+ Integer.toString(0), false);
+ retry(() -> watchdog.getTriggerFailureCount()
+ == PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT);
+ assertThat(watchdog.getTriggerFailureCount()).isEqualTo(
+ PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT);
+ }
+
+ /**
+ * Tests device config changes are propagated correctly.
+ */
+ @Test
+ public void testDeviceConfigChange_triggerFailureDurationMs() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS,
+ Integer.toString(888), false);
+ retry(() -> watchdog.getTriggerFailureDurationMs() == 888);
+ assertThat(watchdog.getTriggerFailureDurationMs()).isEqualTo(888);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS,
+ Integer.toString(0), false);
+ retry(() -> watchdog.getTriggerFailureDurationMs()
+ == PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS);
+ assertThat(watchdog.getTriggerFailureDurationMs()).isEqualTo(
+ PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS);
+ }
+
private void adoptShellPermissions(String... permissions) {
InstrumentationRegistry
.getInstrumentation()
@@ -1164,15 +1377,15 @@ public class PackageWatchdogTest {
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
PackageWatchdog.PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED,
Boolean.toString(enabled), /*makeDefault*/false);
- //give time for DeviceConfig to broadcast the property value change
- try {
- Thread.sleep(SHORT_DURATION);
- } catch (InterruptedException e) {
- fail("Thread.sleep unexpectedly failed!");
+ // Call updateConfigs() so device config changes take effect immediately
+ for (PackageWatchdog watchdog : mAllocatedWatchdogs) {
+ watchdog.updateConfigs();
}
}
private void moveTimeForwardAndDispatch(long milliSeconds) {
+ // Exhaust all due runnables now which shouldn't be executed after time-leap
+ mTestLooper.dispatchAll();
mTestClock.moveTimeForward(milliSeconds);
mTestLooper.moveTimeForward(milliSeconds);
mTestLooper.dispatchAll();
@@ -1215,6 +1428,7 @@ public class PackageWatchdogTest {
verify(mConnectivityModuleConnector).registerHealthListener(
mConnectivityModuleCallbackCaptor.capture());
}
+ mAllocatedWatchdogs.add(watchdog);
return watchdog;
}
@@ -1227,6 +1441,8 @@ public class PackageWatchdogTest {
private boolean mMitigatedBootLoop = false;
final List<String> mHealthCheckFailedPackages = new ArrayList<>();
final List<String> mMitigatedPackages = new ArrayList<>();
+ final List<Integer> mMitigationCounts = new ArrayList<>();
+ final List<Integer> mBootMitigationCounts = new ArrayList<>();
TestObserver(String name) {
mName = name;
@@ -1238,13 +1454,16 @@ public class PackageWatchdogTest {
mImpact = impact;
}
- public int onHealthCheckFailed(VersionedPackage versionedPackage, int failureReason) {
+ public int onHealthCheckFailed(VersionedPackage versionedPackage, int failureReason,
+ int mitigationCount) {
mHealthCheckFailedPackages.add(versionedPackage.getPackageName());
return mImpact;
}
- public boolean execute(VersionedPackage versionedPackage, int failureReason) {
+ public boolean execute(VersionedPackage versionedPackage, int failureReason,
+ int mitigationCount) {
mMitigatedPackages.add(versionedPackage.getPackageName());
+ mMitigationCounts.add(mitigationCount);
mLastFailureReason = failureReason;
return true;
}
@@ -1261,12 +1480,13 @@ public class PackageWatchdogTest {
return mMayObservePackages;
}
- public int onBootLoop() {
+ public int onBootLoop(int level) {
return mImpact;
}
- public boolean executeBootLoopMitigation() {
+ public boolean executeBootLoopMitigation(int level) {
mMitigatedBootLoop = true;
+ mBootMitigationCounts.add(level);
return true;
}
diff --git a/tests/PlatformCompatGating/Android.bp b/tests/PlatformCompatGating/Android.bp
index 7d918cc4c18b..f0f9c4bdd721 100644
--- a/tests/PlatformCompatGating/Android.bp
+++ b/tests/PlatformCompatGating/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "PlatformCompatGating",
// Only compile source java files in this apk.
diff --git a/tests/PlatformCompatGating/OWNERS b/tests/PlatformCompatGating/OWNERS
new file mode 100644
index 000000000000..f8c3520e9fa8
--- /dev/null
+++ b/tests/PlatformCompatGating/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/compat/OWNERS
diff --git a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
index 0f62c4fa66a3..ac9e6817a230 100644
--- a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
+++ b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
@@ -76,11 +76,11 @@ class PlatformCompatCommandNotInstalledTest {
Params(enableDisable = null, targetSdk = 29, result = false),
Params(enableDisable = null, targetSdk = 30, result = true),
- Params(enableDisable = true, targetSdk = 29, result = true),
+ Params(enableDisable = true, targetSdk = 29, result = false),
Params(enableDisable = true, targetSdk = 30, result = true),
Params(enableDisable = false, targetSdk = 29, result = false),
- Params(enableDisable = false, targetSdk = 30, result = false)
+ Params(enableDisable = false, targetSdk = 30, result = true)
)
}
@@ -107,7 +107,10 @@ class PlatformCompatCommandNotInstalledTest {
fun ParcelFileDescriptor.text() = FileReader(fileDescriptor).readText()
@After
- fun resetIdentity() = uiAutomation.dropShellPermissionIdentity()
+ fun resetChangeIdAndIdentity() {
+ command("am compat reset $TEST_CHANGE_ID $TEST_PKG")
+ uiAutomation.dropShellPermissionIdentity()
+ }
@Test
fun execute() {
@@ -128,6 +131,10 @@ class PlatformCompatCommandNotInstalledTest {
assertThat(platformCompat.isChangeEnabled(TEST_CHANGE_ID, appInfo)).isEqualTo(params.result)
}
- private fun command(command: String) =
- FileReader(uiAutomation.executeShellCommand(command).fileDescriptor).readText()
+ private fun command(command: String): String {
+ val fileDescriptor = uiAutomation.executeShellCommand(command)
+ return String(ParcelFileDescriptor.AutoCloseInputStream(fileDescriptor).use {
+ inputStream -> inputStream.readBytes()
+ })
+ }
}
diff --git a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatPermissionsTest.java b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatPermissionsTest.java
index 9b9e5815a588..060133df0a40 100644
--- a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatPermissionsTest.java
+++ b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatPermissionsTest.java
@@ -16,6 +16,7 @@
package com.android.tests.gating;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.LOG_COMPAT_CHANGE;
import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG;
import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
@@ -261,13 +262,15 @@ public final class PlatformCompatPermissionsTest {
public void clearOverrides_noOverridesPermission_throwsSecurityException()
throws Throwable {
thrown.expect(SecurityException.class);
+ mUiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_FULL);
mPlatformCompat.clearOverrides("foo.bar");
}
@Test
public void clearOverrides_overridesPermission_noThrow()
throws Throwable {
- mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG);
+ mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG,
+ INTERACT_ACROSS_USERS_FULL);
mPlatformCompat.clearOverrides("foo.bar");
}
@@ -276,13 +279,15 @@ public final class PlatformCompatPermissionsTest {
public void clearOverridesForTest_noOverridesPermission_throwsSecurityException()
throws Throwable {
thrown.expect(SecurityException.class);
+ mUiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_FULL);
mPlatformCompat.clearOverridesForTest("foo.bar");
}
@Test
public void clearOverridesForTest_overridesPermission_noThrow()
throws Throwable {
- mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG);
+ mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG,
+ INTERACT_ACROSS_USERS_FULL);
mPlatformCompat.clearOverridesForTest("foo.bar");
}
@@ -291,13 +296,15 @@ public final class PlatformCompatPermissionsTest {
public void clearOverride_noOverridesPermission_throwsSecurityException()
throws Throwable {
thrown.expect(SecurityException.class);
+ mUiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_FULL);
mPlatformCompat.clearOverride(1, "foo.bar");
}
@Test
public void clearOverride_overridesPermission_noThrow()
throws Throwable {
- mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG);
+ mUiAutomation.adoptShellPermissionIdentity(OVERRIDE_COMPAT_CHANGE_CONFIG,
+ INTERACT_ACROSS_USERS_FULL);
mPlatformCompat.clearOverride(1, "foo.bar");
}
diff --git a/tests/PlatformCompatGating/test-rules/Android.bp b/tests/PlatformCompatGating/test-rules/Android.bp
index 10fa2dc0d7c6..5f91f9d0e505 100644
--- a/tests/PlatformCompatGating/test-rules/Android.bp
+++ b/tests/PlatformCompatGating/test-rules/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
java_library {
name: "platform-compat-test-rules",
srcs: ["src/**/*.java"],
@@ -23,4 +32,4 @@ java_library {
"truth-prebuilt",
"core-compat-test-rules"
],
-} \ No newline at end of file
+}
diff --git a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
index d6846faa5c00..0c5205c848da 100644
--- a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
+++ b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
@@ -94,10 +94,7 @@ public class PlatformCompatChangeRule extends CoreCompatChangeRule {
if (platformCompat == null) {
throw new IllegalStateException("Could not get IPlatformCompat service!");
}
- uiAutomation.adoptShellPermissionIdentity(
- Manifest.permission.LOG_COMPAT_CHANGE,
- Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG,
- Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
+ adoptShellPermissions(uiAutomation);
Compatibility.setOverrides(mConfig);
try {
platformCompat.setOverridesForTest(new CompatibilityChangeConfig(mConfig),
@@ -105,6 +102,7 @@ public class PlatformCompatChangeRule extends CoreCompatChangeRule {
try {
mTestStatement.evaluate();
} finally {
+ adoptShellPermissions(uiAutomation);
platformCompat.clearOverridesForTest(packageName);
}
} catch (RemoteException e) {
@@ -114,5 +112,14 @@ public class PlatformCompatChangeRule extends CoreCompatChangeRule {
Compatibility.clearOverrides();
}
}
+
+ private static void adoptShellPermissions(UiAutomation uiAutomation) {
+ uiAutomation.adoptShellPermissionIdentity(
+ Manifest.permission.LOG_COMPAT_CHANGE,
+ Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG,
+ Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD,
+ Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ }
}
}
diff --git a/tests/net/common/Android.bp b/tests/ProtoInputStreamTests/Android.bp
index 46d680fc4511..0029080b5a89 100644
--- a/tests/net/common/Android.bp
+++ b/tests/ProtoInputStreamTests/Android.bp
@@ -1,4 +1,3 @@
-//
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,22 +11,32 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
-// Tests in this folder are included both in unit tests and CTS.
-// They must be fast and stable, and exercise public or test APIs.
-java_library {
- name: "FrameworksNetCommonTests",
- srcs: ["java/**/*.java", "java/**/*.kt"],
+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"],
+}
+
+android_test {
+ name: "ProtoInputStreamTests",
+ proto: {
+ type: "nano",
+ },
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.proto",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: ["device-tests"],
+ libs: ["android.test.runner"],
static_libs: [
- "androidx.core_core",
"androidx.test.rules",
- "junit",
+ "frameworks-base-testutils",
"mockito-target-minus-junit4",
- "net-tests-utils",
- "platform-test-annotations",
- ],
- libs: [
- "android.test.base.stubs",
],
}
diff --git a/tests/ProtoInputStreamTests/Android.mk b/tests/ProtoInputStreamTests/Android.mk
deleted file mode 100644
index eb747cc2cdcc..000000000000
--- a/tests/ProtoInputStreamTests/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := ProtoInputStreamTests
-LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_MODULE_TAGS := tests optional
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src) \
- $(call all-proto-files-under, src)
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := \
- androidx.test.rules \
- frameworks-base-testutils \
- mockito-target-minus-junit4
-
-include $(BUILD_PACKAGE) \ No newline at end of file
diff --git a/tests/RemoteDisplayProvider/Android.bp b/tests/RemoteDisplayProvider/Android.bp
index 6c7798fb3faf..55732d14af46 100644
--- a/tests/RemoteDisplayProvider/Android.bp
+++ b/tests/RemoteDisplayProvider/Android.bp
@@ -13,6 +13,15 @@
// limitations under the License.
// Build the application.
+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"],
+}
+
android_test {
name: "RemoteDisplayProviderTest",
sdk_version: "system_current",
diff --git a/tests/RenderThreadTest/Android.bp b/tests/RenderThreadTest/Android.bp
index 165977607219..b18b04edb4c4 100644
--- a/tests/RenderThreadTest/Android.bp
+++ b/tests/RenderThreadTest/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "RenderThreadTest",
// Only compile source java files in this apk.
diff --git a/tests/RenderThreadTest/AndroidManifest.xml b/tests/RenderThreadTest/AndroidManifest.xml
index a7f4f6e9c5c8..22a4e43c988c 100644
--- a/tests/RenderThreadTest/AndroidManifest.xml
+++ b/tests/RenderThreadTest/AndroidManifest.xml
@@ -1,25 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.renderthread"
- android:versionCode="1"
- android:versionName="1.0" >
+ package="com.example.renderthread"
+ android:versionCode="1"
+ android:versionName="1.0">
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name" >
+ <application android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
+ <activity android:name=".MainActivity"
+ android:label="@string/app_name"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".SubActivity"
- android:theme="@style/AppTheme.Transparent" />
+ android:theme="@style/AppTheme.Transparent"/>
</application>
</manifest>
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index 3ccbad84f2e0..6e1cef496f40 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -12,9 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "RollbackTest",
manifest: "RollbackTest/AndroidManifest.xml",
+ platform_apis: true,
srcs: ["RollbackTest/src/**/*.java"],
static_libs: ["androidx.test.rules", "cts-rollback-lib", "cts-install-lib"],
test_suites: ["general-tests"],
@@ -29,7 +39,12 @@ java_test_host {
name: "StagedRollbackTest",
srcs: ["StagedRollbackTest/src/**/*.java"],
libs: ["tradefed"],
- static_libs: ["testng", "compatibility-tradefed", "RollbackTestLib"],
+ static_libs: [
+ "compatibility-tradefed",
+ "frameworks-base-hostutils",
+ "RollbackTestLib",
+ "testng",
+ ],
test_suites: ["general-tests"],
test_config: "StagedRollbackTest.xml",
data: [":com.android.apex.apkrollback.test_v1"],
@@ -39,7 +54,7 @@ java_test_host {
name: "NetworkStagedRollbackTest",
srcs: ["NetworkStagedRollbackTest/src/**/*.java"],
libs: ["tradefed"],
- static_libs: ["RollbackTestLib"],
+ static_libs: ["RollbackTestLib", "frameworks-base-hostutils"],
test_suites: ["general-tests"],
test_config: "NetworkStagedRollbackTest.xml",
}
@@ -90,6 +105,7 @@ apex {
key: "com.android.apex.apkrollback.test.key",
apps: ["TestAppAv1"],
installable: false,
+ updatable: false,
}
apex {
@@ -100,6 +116,7 @@ apex {
key: "com.android.apex.apkrollback.test.key",
apps: ["TestAppAv2"],
installable: false,
+ updatable: false,
}
apex {
@@ -110,4 +127,5 @@ apex {
key: "com.android.apex.apkrollback.test.key",
apps: ["TestAppACrashingV2"],
installable: false,
-} \ No newline at end of file
+ updatable: false,
+}
diff --git a/tests/RollbackTest/MultiUserRollbackTest.xml b/tests/RollbackTest/MultiUserRollbackTest.xml
index 2f62af1856da..8fa0510d9e71 100644
--- a/tests/RollbackTest/MultiUserRollbackTest.xml
+++ b/tests/RollbackTest/MultiUserRollbackTest.xml
@@ -20,6 +20,8 @@
<option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ <option name="run-command" value="setprop persist.rollback.is_test 1" />
+ <option name="teardown-command" value="setprop persist.rollback.is_test 0" />
</target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.tests.rollback.host.MultiUserRollbackTest" />
diff --git a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
index f16084744853..35859fe1472e 100644
--- a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
+++ b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
@@ -48,6 +48,8 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
public void tearDown() throws Exception {
removeSecondaryUserIfNecessary();
runPhaseForUsers("cleanUp", mOriginalUserId);
+ uninstallPackage("com.android.cts.install.lib.testapp.A");
+ uninstallPackage("com.android.cts.install.lib.testapp.B");
}
@Before
@@ -88,6 +90,13 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
}
@Test
+ public void testBadUpdateRollback() throws Exception {
+ // Need to switch user in order to send broadcasts in device tests
+ assertTrue(getDevice().switchUser(mSecondaryUserId));
+ runPhaseForUsers("testBadUpdateRollback", mSecondaryUserId);
+ }
+
+ @Test
public void testMultipleUsers() throws Exception {
runPhaseForUsers("testMultipleUsersInstallV1", mOriginalUserId, mSecondaryUserId);
runPhaseForUsers("testMultipleUsersUpgradeToV2", mOriginalUserId);
@@ -111,6 +120,8 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
private void removeSecondaryUserIfNecessary() throws Exception {
if (mSecondaryUserId != -1) {
+ // Can't remove the 2nd user without switching out of it
+ assertTrue(getDevice().switchUser(mOriginalUserId));
getDevice().removeUser(mSecondaryUserId);
mSecondaryUserId = -1;
}
diff --git a/tests/RollbackTest/NetworkStagedRollbackTest.xml b/tests/RollbackTest/NetworkStagedRollbackTest.xml
index 2ab907a59298..13f603140aee 100644
--- a/tests/RollbackTest/NetworkStagedRollbackTest.xml
+++ b/tests/RollbackTest/NetworkStagedRollbackTest.xml
@@ -24,6 +24,8 @@
<option name="run-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es package &quot;com.google.android.gms.platformconfigurator&quot; --es user '\\*' --esa flags &quot;ModuleConfig__versioned_immediate_commit_packages&quot; --esa types &quot;bytes&quot; --esa values &quot;Cm5vdGFwYWNrYWdlOgA=&quot; com.google.android.gms" />
<option name="teardown-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es action delete --es package &quot;com.google.android.gms.platformconfigurator&quot; --es user '\*' --esa flag &quot;ModuleConfig__immediate_commit_packages&quot; com.google.android.gms" />
<option name="teardown-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es action delete --es package &quot;com.google.android.gms.platformconfigurator&quot; --es user '\*' --esa flag &quot;ModuleConfig__versioned_immediate_commit_packages&quot; com.google.android.gms" />
+ <option name="run-command" value="setprop persist.rollback.is_test 1" />
+ <option name="teardown-command" value="setprop persist.rollback.is_test 0" />
</target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.tests.rollback.host.NetworkStagedRollbackTest" />
diff --git a/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
index e3c7cfaf3bef..c769a6f8c018 100644
--- a/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
+++ b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
@@ -16,8 +16,6 @@
package com.android.tests.rollback.host;
-import static com.android.tests.rollback.host.WatchdogEventLogger.watchdogEventOccurred;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -27,10 +25,10 @@ import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.List;
import java.util.concurrent.TimeUnit;
/**
@@ -58,6 +56,9 @@ public class NetworkStagedRollbackTest extends BaseHostJUnit4Test {
private WatchdogEventLogger mLogger = new WatchdogEventLogger();
+ @Rule
+ public AbandonSessionsRule mHostTestRule = new AbandonSessionsRule(this);
+
@Before
public void setUp() throws Exception {
runPhase("cleanUp");
@@ -94,12 +95,11 @@ public class NetworkStagedRollbackTest extends BaseHostJUnit4Test {
// Verify rollback was executed after health check deadline
runPhase("testNetworkFailedRollback_Phase3");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_INITIATE, null,
REASON_EXPLICIT_HEALTH_CHECK, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_BOOT_TRIGGERED, null,
null, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_SUCCESS, null, null, null));
+ assertTrue(mLogger.watchdogEventOccurred(ROLLBACK_SUCCESS, null, null, null));
} finally {
// Reconnect internet again so we won't break tests which assume internet available
getDevice().executeShellCommand("svc wifi enable");
@@ -130,8 +130,7 @@ public class NetworkStagedRollbackTest extends BaseHostJUnit4Test {
// Verify rollback was not executed after health check deadline
runPhase("testNetworkPassedDoesNotRollback_Phase3");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertEquals(watchdogEventOccurred(watchdogEvents, null, null,
+ assertEquals(mLogger.watchdogEventOccurred(null, null,
REASON_EXPLICIT_HEALTH_CHECK, null), false);
}
}
diff --git a/tests/RollbackTest/OWNERS b/tests/RollbackTest/OWNERS
new file mode 100644
index 000000000000..d04a70619caa
--- /dev/null
+++ b/tests/RollbackTest/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/rollback/OWNERS
diff --git a/tests/RollbackTest/README.txt b/tests/RollbackTest/README.txt
index c0b718a3e2c1..bc3b3bc3a1ee 100644
--- a/tests/RollbackTest/README.txt
+++ b/tests/RollbackTest/README.txt
@@ -9,10 +9,10 @@ StagedRollbackTest
- device driven test for staged rollbacks.
TestApp
- - source for dummy apks used in testing.
+ - source for fake apks used in testing.
TestApex
- - source for dummy apex modules used in testing.
+ - source for fake apex modules used in testing.
Running the tests
=================
diff --git a/tests/RollbackTest/RollbackTest.xml b/tests/RollbackTest/RollbackTest.xml
index 7b85cc84f1f5..fbb6e46e1721 100644
--- a/tests/RollbackTest/RollbackTest.xml
+++ b/tests/RollbackTest/RollbackTest.xml
@@ -27,6 +27,8 @@
<option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ <option name="run-command" value="setprop persist.rollback.is_test 1" />
+ <option name="teardown-command" value="setprop persist.rollback.is_test 0" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.tests.rollback" />
diff --git a/tests/RollbackTest/RollbackTest/AndroidManifest.xml b/tests/RollbackTest/RollbackTest/AndroidManifest.xml
index 9274da268735..590105b3209f 100644
--- a/tests/RollbackTest/RollbackTest/AndroidManifest.xml
+++ b/tests/RollbackTest/RollbackTest/AndroidManifest.xml
@@ -19,8 +19,6 @@
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<application>
- <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
- android:exported="true" />
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
index 5d133a4de13d..d37dd7b9ceab 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
@@ -70,6 +70,11 @@ public class MultiUserRollbackTest {
new RollbackTest().testBasic();
}
+ @Test
+ public void testBadUpdateRollback() throws Exception {
+ new RollbackTest().testBadUpdateRollback();
+ }
+
/**
* Install version 1 of the test app. This method is run for both users.
*/
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index dd08771b220d..7b2a07fd80f8 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -175,7 +175,7 @@ public class RollbackTest {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
UserManager um = (UserManager) context.getSystemService(context.USER_SERVICE);
- List<Integer> userIds = um.getUsers(true)
+ List<Integer> userIds = um.getAliveUsers()
.stream().map(user -> user.id).collect(Collectors.toList());
assertThat(InstallUtils.isOnlyInstalledForUser(TestApp.A,
context.getUserId(), userIds)).isTrue();
@@ -1193,28 +1193,74 @@ public class RollbackTest {
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS);
- Uninstall.packages(TestApp.A, TestApp.B);
- Install.multi(TestApp.A1, TestApp.B1).commit();
+ Uninstall.packages(TestApp.A, TestApp.B, TestApp.C);
+ Install.multi(TestApp.A1, TestApp.B1, TestApp.C1).commit();
// Write user data version = 1
InstallUtils.processUserData(TestApp.A);
InstallUtils.processUserData(TestApp.B);
+ InstallUtils.processUserData(TestApp.C);
Install a2 = Install.single(TestApp.A2)
.setEnableRollback(PackageManager.RollbackDataPolicy.WIPE);
Install b2 = Install.single(TestApp.B2)
.setEnableRollback(PackageManager.RollbackDataPolicy.RESTORE);
- Install.multi(a2, b2).setEnableRollback().commit();
+ // The rollback data policy of C2 is specified in the manifest
+ Install c2 = Install.single(TestApp.C2).setEnableRollback();
+ Install.multi(a2, b2, c2).setEnableRollback().commit();
// Write user data version = 2
InstallUtils.processUserData(TestApp.A);
InstallUtils.processUserData(TestApp.B);
+ InstallUtils.processUserData(TestApp.C);
RollbackInfo info = RollbackUtils.getAvailableRollback(TestApp.A);
RollbackUtils.rollback(info.getRollbackId());
// Read user data version from userdata.txt
// A's user data version is -1 for user data is wiped.
// B's user data version is 1 as rollback committed.
+ // C's user data version is -1 for user data is wiped.
assertThat(InstallUtils.getUserDataVersion(TestApp.A)).isEqualTo(-1);
assertThat(InstallUtils.getUserDataVersion(TestApp.B)).isEqualTo(1);
+ assertThat(InstallUtils.getUserDataVersion(TestApp.C)).isEqualTo(-1);
+ } finally {
+ InstallUtils.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
+ * Tests an app can be rolled back to the previous signing key.
+ *
+ * <p>The rollback capability in the signing lineage allows an app to be updated to an APK
+ * signed with a previous signing key in the lineage; however this often defeats the purpose
+ * of key rotation as a compromised key could then be used to roll an app back to the previous
+ * key. To avoid requiring the rollback capability to support app rollbacks the PackageManager
+ * allows an app to be rolled back to the previous signing key if the rollback install reason
+ * is set.
+ */
+ @Test
+ public void testRollbackAfterKeyRotation() throws Exception {
+ try {
+ InstallUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
+ Manifest.permission.MANAGE_ROLLBACKS);
+
+ // Uninstall TestApp.A
+ Uninstall.packages(TestApp.A);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+
+ // Install v1 of the app with the original signing key (without rollbacks enabled).
+ Install.single(TestApp.AOriginal1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+
+ // Upgrade from v1 to v2 with the rotated signing key, with rollbacks enabled.
+ Install.single(TestApp.ARotated2).setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+
+ // Roll back the app.
+ RollbackInfo available = waitForAvailableRollback(TestApp.A);
+ RollbackUtils.rollback(available.getRollbackId());
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
} finally {
InstallUtils.dropShellPermissionIdentity();
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 00bd4cf388ce..642b19e6d961 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -34,9 +34,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.cts.install.lib.Install;
import com.android.cts.install.lib.InstallUtils;
-import com.android.cts.install.lib.LocalIntentSender;
import com.android.cts.install.lib.TestApp;
-import com.android.cts.install.lib.Uninstall;
import com.android.cts.rollback.lib.Rollback;
import com.android.cts.rollback.lib.RollbackUtils;
import com.android.internal.R;
@@ -89,8 +87,7 @@ public class StagedRollbackTest {
* Enable rollback phase.
*/
@Test
- public void testBadApkOnly_Phase1() throws Exception {
- Uninstall.packages(TestApp.A);
+ public void testBadApkOnly_Phase1_Install() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
Install.single(TestApp.A1).commit();
@@ -105,7 +102,7 @@ public class StagedRollbackTest {
* Confirm that rollback was successfully enabled.
*/
@Test
- public void testBadApkOnly_Phase2() throws Exception {
+ public void testBadApkOnly_Phase2_VerifyInstall() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
InstallUtils.processUserData(TestApp.A);
@@ -126,21 +123,11 @@ public class StagedRollbackTest {
}
/**
- * Test rollbacks of staged installs involving only apks with bad update.
- * Trigger rollback phase.
- */
- @Test
- public void testBadApkOnly_Phase3() throws Exception {
- // One more crash to trigger rollback
- RollbackUtils.sendCrashBroadcast(TestApp.A, 1);
- }
-
- /**
* Test rollbacks of staged installs involving only apks.
* Confirm rollback phase.
*/
@Test
- public void testBadApkOnly_Phase4() throws Exception {
+ public void testBadApkOnly_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
InstallUtils.processUserData(TestApp.A);
@@ -159,8 +146,7 @@ public class StagedRollbackTest {
* Stage install an apk with rollback that will be later triggered by unattributable crash.
*/
@Test
- public void testNativeWatchdogTriggersRollback_Phase1() throws Exception {
- Uninstall.packages(TestApp.A);
+ public void testNativeWatchdogTriggersRollback_Phase1_Install() throws Exception {
Install.single(TestApp.A1).commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
@@ -171,7 +157,7 @@ public class StagedRollbackTest {
* Verify the rollback is available.
*/
@Test
- public void testNativeWatchdogTriggersRollback_Phase2() throws Exception {
+ public void testNativeWatchdogTriggersRollback_Phase2_VerifyInstall() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
@@ -182,7 +168,7 @@ public class StagedRollbackTest {
* Verify the rollback is committed after crashing.
*/
@Test
- public void testNativeWatchdogTriggersRollback_Phase3() throws Exception {
+ public void testNativeWatchdogTriggersRollback_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
@@ -193,8 +179,7 @@ public class StagedRollbackTest {
* Stage install an apk with rollback that will be later triggered by unattributable crash.
*/
@Test
- public void testNativeWatchdogTriggersRollbackForAll_Phase1() throws Exception {
- Uninstall.packages(TestApp.A);
+ public void testNativeWatchdogTriggersRollbackForAll_Phase1_InstallA() throws Exception {
Install.single(TestApp.A1).commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
@@ -205,14 +190,13 @@ public class StagedRollbackTest {
* Verify the rollback is available and then install another package with rollback.
*/
@Test
- public void testNativeWatchdogTriggersRollbackForAll_Phase2() throws Exception {
+ public void testNativeWatchdogTriggersRollbackForAll_Phase2_InstallB() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
TestApp.A)).isNotNull();
// Install another package with rollback
- Uninstall.packages(TestApp.B);
Install.single(TestApp.B1).commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
@@ -223,7 +207,7 @@ public class StagedRollbackTest {
* Verify the rollbacks are available.
*/
@Test
- public void testNativeWatchdogTriggersRollbackForAll_Phase3() throws Exception {
+ public void testNativeWatchdogTriggersRollbackForAll_Phase3_VerifyInstall() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
RollbackManager rm = RollbackUtils.getRollbackManager();
@@ -237,7 +221,7 @@ public class StagedRollbackTest {
* Verify the rollbacks are committed after crashing.
*/
@Test
- public void testNativeWatchdogTriggersRollbackForAll_Phase4() throws Exception {
+ public void testNativeWatchdogTriggersRollbackForAll_Phase4_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
RollbackManager rm = RollbackUtils.getRollbackManager();
@@ -248,8 +232,7 @@ public class StagedRollbackTest {
}
@Test
- public void testPreviouslyAbandonedRollbacks_Phase1() throws Exception {
- Uninstall.packages(TestApp.A);
+ public void testPreviouslyAbandonedRollbacks_Phase1_InstallAndAbandon() throws Exception {
Install.single(TestApp.A1).commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
@@ -258,15 +241,11 @@ public class StagedRollbackTest {
.getPackageManager().getPackageInstaller();
pi.abandonSession(sessionId);
- // Remove the first intent sender result, so that the next staged install session does not
- // erroneously think that it has itself been abandoned.
- // TODO(b/136260017): Restructure LocalIntentSender to negate the need for this step.
- LocalIntentSender.getIntentSenderResult();
Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
}
@Test
- public void testPreviouslyAbandonedRollbacks_Phase2() throws Exception {
+ public void testPreviouslyAbandonedRollbacks_Phase2_Rollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
InstallUtils.processUserData(TestApp.A);
@@ -277,10 +256,9 @@ public class StagedRollbackTest {
}
@Test
- public void testPreviouslyAbandonedRollbacks_Phase3() throws Exception {
+ public void testPreviouslyAbandonedRollbacks_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
InstallUtils.processUserData(TestApp.A);
- Uninstall.packages(TestApp.A);
}
private static String getModuleMetadataPackageName() {
@@ -289,7 +267,7 @@ public class StagedRollbackTest {
}
@Test
- public void testRollbackWhitelistedApp_Phase1() throws Exception {
+ public void testRollbackAllowlistedApp_Phase1_Install() throws Exception {
// Remove available rollbacks
String pkgName = getModuleMetadataPackageName();
RollbackUtils.getRollbackManager().expireRollbackForPackage(pkgName);
@@ -301,7 +279,7 @@ public class StagedRollbackTest {
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.MANAGE_ROLLBACKS);
- // Re-install a whitelisted app with rollbacks enabled
+ // Re-install a allowlisted app with rollbacks enabled
String filePath = InstrumentationRegistry.getInstrumentation().getContext()
.getPackageManager().getPackageInfo(pkgName, 0).applicationInfo.sourceDir;
TestApp app = new TestApp("ModuleMetadata", pkgName, -1, false, new File(filePath));
@@ -310,50 +288,56 @@ public class StagedRollbackTest {
}
@Test
- public void testRollbackWhitelistedApp_Phase2() throws Exception {
+ public void testRollbackAllowlistedApp_Phase2_VerifyInstall() throws Exception {
assertThat(RollbackUtils.getAvailableRollback(getModuleMetadataPackageName())).isNotNull();
}
@Test
- public void testRollbackDataPolicy_Phase1() throws Exception {
- Uninstall.packages(TestApp.A, TestApp.B);
- Install.multi(TestApp.A1, TestApp.B1).commit();
+ public void testRollbackDataPolicy_Phase1_Install() throws Exception {
+ Install.multi(TestApp.A1, TestApp.B1, TestApp.C1).commit();
// Write user data version = 1
InstallUtils.processUserData(TestApp.A);
InstallUtils.processUserData(TestApp.B);
+ InstallUtils.processUserData(TestApp.C);
Install a2 = Install.single(TestApp.A2).setStaged()
.setEnableRollback(PackageManager.RollbackDataPolicy.WIPE);
Install b2 = Install.single(TestApp.B2).setStaged()
.setEnableRollback(PackageManager.RollbackDataPolicy.RESTORE);
- Install.multi(a2, b2).setEnableRollback().setStaged().commit();
+ // The rollback data policy of C2 is specified in the manifest
+ Install c2 = Install.single(TestApp.C2).setStaged().setEnableRollback();
+ Install.multi(a2, b2, c2).setEnableRollback().setStaged().commit();
}
@Test
- public void testRollbackDataPolicy_Phase2() throws Exception {
+ public void testRollbackDataPolicy_Phase2_Rollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
// Write user data version = 2
InstallUtils.processUserData(TestApp.A);
InstallUtils.processUserData(TestApp.B);
+ InstallUtils.processUserData(TestApp.C);
RollbackInfo info = RollbackUtils.getAvailableRollback(TestApp.A);
RollbackUtils.rollback(info.getRollbackId());
}
@Test
- public void testRollbackDataPolicy_Phase3() throws Exception {
+ public void testRollbackDataPolicy_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.C)).isEqualTo(1);
// Read user data version from userdata.txt
// A's user data version is -1 for user data is wiped.
// B's user data version is 1 as rollback committed.
+ // C's user data version is -1 for user data is wiped.
assertThat(InstallUtils.getUserDataVersion(TestApp.A)).isEqualTo(-1);
assertThat(InstallUtils.getUserDataVersion(TestApp.B)).isEqualTo(1);
+ assertThat(InstallUtils.getUserDataVersion(TestApp.C)).isEqualTo(-1);
}
@Test
- public void testCleanUp() throws Exception {
+ public void expireRollbacks() throws Exception {
// testNativeWatchdogTriggersRollback will fail if multiple staged sessions are
// committed on a device which doesn't support checkpoint. Let's clean up all rollbacks
// so there is only one rollback to commit when testing native crashes.
@@ -376,7 +360,7 @@ public class StagedRollbackTest {
APK_IN_APEX_TESTAPEX_NAME + "_v2Crashing.apex");
@Test
- public void testRollbackApexWithApk_Phase1() throws Exception {
+ public void testRollbackApexWithApk_Phase1_Install() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
InstallUtils.processUserData(TestApp.A);
@@ -386,7 +370,7 @@ public class StagedRollbackTest {
}
@Test
- public void testRollbackApexWithApk_Phase2() throws Exception {
+ public void testRollbackApexWithApk_Phase2_Rollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(2);
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
InstallUtils.processUserData(TestApp.A);
@@ -414,7 +398,7 @@ public class StagedRollbackTest {
}
@Test
- public void testRollbackApexWithApk_Phase3() throws Exception {
+ public void testRollbackApexWithApk_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(1);
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
InstallUtils.processUserData(TestApp.A);
@@ -424,7 +408,7 @@ public class StagedRollbackTest {
* Installs an apex with an apk that can crash.
*/
@Test
- public void testRollbackApexWithApkCrashing_Phase1() throws Exception {
+ public void testRollbackApexWithApkCrashing_Phase1_Install() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
int sessionId = Install.single(TEST_APEX_WITH_APK_V2_CRASHING).setStaged()
.setEnableRollback().commit();
@@ -435,7 +419,7 @@ public class StagedRollbackTest {
* Verifies rollback has been enabled successfully. Then makes TestApp.A crash.
*/
@Test
- public void testRollbackApexWithApkCrashing_Phase2() throws Exception {
+ public void testRollbackApexWithApkCrashing_Phase2_Crash() throws Exception {
assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(2);
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
@@ -445,25 +429,27 @@ public class StagedRollbackTest {
Rollback.from(TEST_APEX_WITH_APK_V2).to(TEST_APEX_WITH_APK_V1),
Rollback.from(TestApp.A, 0).to(TestApp.A1));
- // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
- RollbackUtils.sendCrashBroadcast(TestApp.A, 5);
+ // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT-1 times
+ RollbackUtils.sendCrashBroadcast(TestApp.A, 4);
+ // Sleep for a while to make sure we don't trigger rollback
+ Thread.sleep(TimeUnit.SECONDS.toMillis(30));
}
@Test
- public void testRollbackApexWithApkCrashing_Phase3() throws Exception {
+ public void testRollbackApexWithApkCrashing_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(1);
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
}
@Test
- public void testRollbackApexDataDirectories_Phase1() throws Exception {
+ public void testRollbackApexDataDirectories_Phase1_Install() throws Exception {
int sessionId = Install.single(TEST_APEX_WITH_APK_V2).setStaged().setEnableRollback()
.commit();
InstallUtils.waitForSessionReady(sessionId);
}
@Test
- public void testRollbackApexDataDirectories_Phase2() throws Exception {
+ public void testRollbackApexDataDirectories_Phase2_Rollback() throws Exception {
RollbackInfo available = RollbackUtils.getAvailableRollback(APK_IN_APEX_TESTAPEX_NAME);
RollbackUtils.rollback(available.getRollbackId(), TEST_APEX_WITH_APK_V2);
@@ -475,6 +461,26 @@ public class StagedRollbackTest {
}
@Test
+ public void testRollbackApkDataDirectories_Phase1_InstallV1() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ Install.single(TestApp.A1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ }
+
+ @Test
+ public void testRollbackApkDataDirectories_Phase2_InstallV2() throws Exception {
+ Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
+ }
+
+ @Test
+ public void testRollbackApkDataDirectories_Phase3_Rollback() throws Exception {
+ RollbackInfo available = RollbackUtils.getAvailableRollback(TestApp.A);
+ RollbackUtils.rollback(available.getRollbackId(), TestApp.A2);
+ RollbackInfo committed = RollbackUtils.getCommittedRollbackById(available.getRollbackId());
+ InstallUtils.waitForSessionReady(committed.getCommittedSessionId());
+ }
+
+ @Test
public void isCheckpointSupported() {
Context context = InstrumentationRegistry.getInstrumentation().getContext();
StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
@@ -482,6 +488,72 @@ public class StagedRollbackTest {
}
@Test
+ public void testWatchdogMonitorsAcrossReboots_Phase1_Install() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ Install.single(TestApp.A1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ InstallUtils.processUserData(TestApp.A);
+
+ Install.single(TestApp.ACrashing2).setEnableRollback().setStaged().commit();
+ }
+
+ @Test
+ public void testWatchdogMonitorsAcrossReboots_Phase2_VerifyInstall() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+
+ // Trigger rollback of test app.
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
+ Integer.toString(5), false);
+
+ // The final crash that causes rollback will come from the host side.
+ RollbackUtils.sendCrashBroadcast(TestApp.A, 4);
+ }
+
+ @Test
+ public void testWatchdogMonitorsAcrossReboots_Phase3_VerifyRollback() {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ InstallUtils.processUserData(TestApp.A);
+
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TestApp.A);
+ assertThat(rollback).isNotNull();
+ assertThat(rollback).packagesContainsExactly(
+ Rollback.from(TestApp.A2).to(TestApp.A1));
+ assertThat(rollback).causePackagesContainsExactly(TestApp.ACrashing2);
+ assertThat(rollback).isStaged();
+ assertThat(rollback.getCommittedSessionId()).isNotEqualTo(-1);
+ }
+
+ @Test
+ public void testExpireSession_Phase1_Install() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ Install.single(TestApp.A1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ Install.single(TestApp.A2).setEnableRollback().setStaged().commit();
+ }
+
+ @Test
+ public void testExpireSession_Phase2_VerifyInstall() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TestApp.A);
+ assertThat(rollback).isNotNull();
+ assertThat(rollback).packagesContainsExactly(Rollback.from(TestApp.A2).to(TestApp.A1));
+ assertThat(rollback.isStaged()).isTrue();
+ }
+
+ @Test
+ public void testExpireSession_Phase3_VerifyRollback() throws Exception {
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TestApp.A);
+ assertThat(rollback).isNotNull();
+ }
+
+ @Test
public void hasMainlineModule() throws Exception {
String pkgName = getModuleMetadataPackageName();
boolean existed = InstrumentationRegistry.getInstrumentation().getContext()
diff --git a/tests/RollbackTest/StagedRollbackTest.xml b/tests/RollbackTest/StagedRollbackTest.xml
index 83fef8e0a04b..0ca4dafae59d 100644
--- a/tests/RollbackTest/StagedRollbackTest.xml
+++ b/tests/RollbackTest/StagedRollbackTest.xml
@@ -24,6 +24,8 @@
<option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ <option name="run-command" value="setprop persist.rollback.is_test 1" />
+ <option name="teardown-command" value="setprop persist.rollback.is_test 0" />
</target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.tests.rollback.host.StagedRollbackTest" />
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 9169ef517bf7..1aa5c249ff18 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -16,15 +16,16 @@
package com.android.tests.rollback.host;
-import static com.android.tests.rollback.host.WatchdogEventLogger.watchdogEventOccurred;
+import static com.android.tests.rollback.host.WatchdogEventLogger.Subject.assertThat;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.ddmlib.Log;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.IFileEntry;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -34,11 +35,14 @@ import com.android.tradefed.util.CommandStatus;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
+import java.time.Instant;
import java.util.Collections;
+import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -50,6 +54,7 @@ import java.util.stream.Collectors;
*/
@RunWith(DeviceJUnit4ClassRunner.class)
public class StagedRollbackTest extends BaseHostJUnit4Test {
+ private static final String TAG = "StagedRollbackTest";
private static final int NATIVE_CRASHES_THRESHOLD = 5;
/**
@@ -59,9 +64,9 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
* For example, <code>runPhase("testApkOnlyEnableRollback");</code>
*/
private void runPhase(String phase) throws Exception {
- assertTrue(runDeviceTests("com.android.tests.rollback",
+ assertThat(runDeviceTests("com.android.tests.rollback",
"com.android.tests.rollback.StagedRollbackTest",
- phase));
+ phase)).isTrue();
}
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
@@ -87,18 +92,27 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
private WatchdogEventLogger mLogger = new WatchdogEventLogger();
+ @Rule
+ public AbandonSessionsRule mHostTestRule = new AbandonSessionsRule(this);
+
@Before
public void setUp() throws Exception {
deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
"/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex");
- runPhase("testCleanUp");
+ runPhase("expireRollbacks");
mLogger.start(getDevice());
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A");
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.B");
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.C");
}
@After
public void tearDown() throws Exception {
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A");
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.B");
+ getDevice().uninstallPackage("com.android.cts.install.lib.testapp.C");
mLogger.stop();
- runPhase("testCleanUp");
+ runPhase("expireRollbacks");
deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
"/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + "*",
@@ -120,50 +134,55 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
}
if (found) {
- if (!getDevice().isAdbRoot()) {
+ try {
getDevice().enableAdbRoot();
- }
- getDevice().remountSystemWritable();
- for (String file : files) {
- getDevice().executeShellCommand("rm -rf " + file);
+ getDevice().remountSystemWritable();
+ for (String file : files) {
+ getDevice().executeShellCommand("rm -rf " + file);
+ }
+ } finally {
+ getDevice().disableAdbRoot();
}
getDevice().reboot();
}
}
+ private void waitForDeviceNotAvailable(long timeout, TimeUnit unit) {
+ assertWithMessage("waitForDeviceNotAvailable() timed out in %s %s", timeout, unit)
+ .that(getDevice().waitForDeviceNotAvailable(unit.toMillis(timeout))).isTrue();
+ }
+
/**
* Tests watchdog triggered staged rollbacks involving only apks.
*/
@Test
public void testBadApkOnly() throws Exception {
- runPhase("testBadApkOnly_Phase1");
+ runPhase("testBadApkOnly_Phase1_Install");
getDevice().reboot();
- runPhase("testBadApkOnly_Phase2");
+ runPhase("testBadApkOnly_Phase2_VerifyInstall");
- // Trigger rollback and wait for reboot to happen
- runPhase("testBadApkOnly_Phase3");
- assertTrue(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(2)));
+ // Launch the app to crash to trigger rollback
+ startActivity(TESTAPP_A);
+ // Wait for reboot to happen
+ waitForDeviceNotAvailable(2, TimeUnit.MINUTES);
getDevice().waitForDeviceAvailable();
- runPhase("testBadApkOnly_Phase4");
+ runPhase("testBadApkOnly_Phase3_VerifyRollback");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
- REASON_APP_CRASH, TESTAPP_A));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
- null, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_SUCCESS, null, null, null));
+ assertThat(mLogger).eventOccurred(ROLLBACK_INITIATE, null, REASON_APP_CRASH, TESTAPP_A);
+ assertThat(mLogger).eventOccurred(ROLLBACK_BOOT_TRIGGERED, null, null, null);
+ assertThat(mLogger).eventOccurred(ROLLBACK_SUCCESS, null, null, null);
}
@Test
public void testNativeWatchdogTriggersRollback() throws Exception {
- runPhase("testNativeWatchdogTriggersRollback_Phase1");
+ runPhase("testNativeWatchdogTriggersRollback_Phase1_Install");
// Reboot device to activate staged package
getDevice().reboot();
- runPhase("testNativeWatchdogTriggersRollback_Phase2");
+ runPhase("testNativeWatchdogTriggersRollback_Phase2_VerifyInstall");
// crash system_server enough times to trigger a rollback
crashProcess("system_server", NATIVE_CRASHES_THRESHOLD);
@@ -176,18 +195,15 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
// 3. Staged rollback session becomes ready.
// 4. Device actually reboots.
// So we give a generous timeout here.
- assertTrue(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(5)));
+ waitForDeviceNotAvailable(5, TimeUnit.MINUTES);
getDevice().waitForDeviceAvailable();
// verify rollback committed
- runPhase("testNativeWatchdogTriggersRollback_Phase3");
+ runPhase("testNativeWatchdogTriggersRollback_Phase3_VerifyRollback");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
- REASON_NATIVE_CRASH, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
- null, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_SUCCESS, null, null, null));
+ assertThat(mLogger).eventOccurred(ROLLBACK_INITIATE, null, REASON_NATIVE_CRASH, null);
+ assertThat(mLogger).eventOccurred(ROLLBACK_BOOT_TRIGGERED, null, null, null);
+ assertThat(mLogger).eventOccurred(ROLLBACK_SUCCESS, null, null, null);
}
@Test
@@ -196,15 +212,15 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
assumeTrue(isCheckpointSupported());
// Install a package with rollback enabled.
- runPhase("testNativeWatchdogTriggersRollbackForAll_Phase1");
+ runPhase("testNativeWatchdogTriggersRollbackForAll_Phase1_InstallA");
getDevice().reboot();
// Once previous staged install is applied, install another package
- runPhase("testNativeWatchdogTriggersRollbackForAll_Phase2");
+ runPhase("testNativeWatchdogTriggersRollbackForAll_Phase2_InstallB");
getDevice().reboot();
// Verify the new staged install has also been applied successfully.
- runPhase("testNativeWatchdogTriggersRollbackForAll_Phase3");
+ runPhase("testNativeWatchdogTriggersRollbackForAll_Phase3_VerifyInstall");
// crash system_server enough times to trigger a rollback
crashProcess("system_server", NATIVE_CRASHES_THRESHOLD);
@@ -217,18 +233,15 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
// 3. Staged rollback session becomes ready.
// 4. Device actually reboots.
// So we give a generous timeout here.
- assertTrue(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(5)));
+ waitForDeviceNotAvailable(5, TimeUnit.MINUTES);
getDevice().waitForDeviceAvailable();
// verify all available rollbacks have been committed
- runPhase("testNativeWatchdogTriggersRollbackForAll_Phase4");
+ runPhase("testNativeWatchdogTriggersRollbackForAll_Phase4_VerifyRollback");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
- REASON_NATIVE_CRASH, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
- null, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_SUCCESS, null, null, null));
+ assertThat(mLogger).eventOccurred(ROLLBACK_INITIATE, null, REASON_NATIVE_CRASH, null);
+ assertThat(mLogger).eventOccurred(ROLLBACK_BOOT_TRIGGERED, null, null, null);
+ assertThat(mLogger).eventOccurred(ROLLBACK_SUCCESS, null, null, null);
}
/**
@@ -236,31 +249,41 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
*/
@Test
public void testPreviouslyAbandonedRollbacks() throws Exception {
- runPhase("testPreviouslyAbandonedRollbacks_Phase1");
+ runPhase("testPreviouslyAbandonedRollbacks_Phase1_InstallAndAbandon");
getDevice().reboot();
- runPhase("testPreviouslyAbandonedRollbacks_Phase2");
+ runPhase("testPreviouslyAbandonedRollbacks_Phase2_Rollback");
getDevice().reboot();
- runPhase("testPreviouslyAbandonedRollbacks_Phase3");
+ runPhase("testPreviouslyAbandonedRollbacks_Phase3_VerifyRollback");
}
/**
- * Tests we can enable rollback for a whitelisted app.
+ * Tests we can enable rollback for a allowlisted app.
*/
@Test
- public void testRollbackWhitelistedApp() throws Exception {
+ public void testRollbackAllowlistedApp() throws Exception {
assumeTrue(hasMainlineModule());
- runPhase("testRollbackWhitelistedApp_Phase1");
+ runPhase("testRollbackAllowlistedApp_Phase1_Install");
getDevice().reboot();
- runPhase("testRollbackWhitelistedApp_Phase2");
+ runPhase("testRollbackAllowlistedApp_Phase2_VerifyInstall");
}
@Test
public void testRollbackDataPolicy() throws Exception {
- runPhase("testRollbackDataPolicy_Phase1");
+ List<String> before = getSnapshotDirectories("/data/misc_ce/0/rollback");
+
+ runPhase("testRollbackDataPolicy_Phase1_Install");
getDevice().reboot();
- runPhase("testRollbackDataPolicy_Phase2");
+ runPhase("testRollbackDataPolicy_Phase2_Rollback");
getDevice().reboot();
- runPhase("testRollbackDataPolicy_Phase3");
+ runPhase("testRollbackDataPolicy_Phase3_VerifyRollback");
+
+ // Verify snapshots are deleted after restoration
+ List<String> after = getSnapshotDirectories("/data/misc_ce/0/rollback");
+ // Only check directories newly created during the test
+ after.removeAll(before);
+ // There should be only one /data/misc_ce/0/rollback/<rollbackId> created during test
+ assertThat(after).hasSize(1);
+ assertDirectoryIsEmpty(after.get(0));
}
/**
@@ -268,13 +291,12 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
*/
@Test
public void testRollbackApexWithApk() throws Exception {
- getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A");
pushTestApex();
- runPhase("testRollbackApexWithApk_Phase1");
+ runPhase("testRollbackApexWithApk_Phase1_Install");
getDevice().reboot();
- runPhase("testRollbackApexWithApk_Phase2");
+ runPhase("testRollbackApexWithApk_Phase2_Rollback");
getDevice().reboot();
- runPhase("testRollbackApexWithApk_Phase3");
+ runPhase("testRollbackApexWithApk_Phase3_VerifyRollback");
}
/**
@@ -282,26 +304,24 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
*/
@Test
public void testRollbackApexWithApkCrashing() throws Exception {
- getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A");
pushTestApex();
// Install an apex with apk that crashes
- runPhase("testRollbackApexWithApkCrashing_Phase1");
+ runPhase("testRollbackApexWithApkCrashing_Phase1_Install");
getDevice().reboot();
// Verify apex was installed and then crash the apk
- runPhase("testRollbackApexWithApkCrashing_Phase2");
- // Wait for crash to trigger rollback
- assertTrue(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(5)));
+ runPhase("testRollbackApexWithApkCrashing_Phase2_Crash");
+ // Launch the app to crash to trigger rollback
+ startActivity(TESTAPP_A);
+ // Wait for reboot to happen
+ waitForDeviceNotAvailable(2, TimeUnit.MINUTES);
getDevice().waitForDeviceAvailable();
// Verify rollback occurred due to crash of apk-in-apex
- runPhase("testRollbackApexWithApkCrashing_Phase3");
+ runPhase("testRollbackApexWithApkCrashing_Phase3_VerifyRollback");
- List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
- REASON_APP_CRASH, TESTAPP_A));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
- null, null));
- assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_SUCCESS, null, null, null));
+ assertThat(mLogger).eventOccurred(ROLLBACK_INITIATE, null, REASON_APP_CRASH, TESTAPP_A);
+ assertThat(mLogger).eventOccurred(ROLLBACK_BOOT_TRIGGERED, null, null, null);
+ assertThat(mLogger).eventOccurred(ROLLBACK_SUCCESS, null, null, null);
}
/**
@@ -316,37 +336,45 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
String oldFilePath1 = apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + "/" + TEST_FILENAME_1;
String oldFilePath2 =
apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + TEST_SUBDIR + TEST_FILENAME_2;
- assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1));
- assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2));
+ runAsRoot(() -> {
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
+ });
// Install new version of the APEX with rollback enabled
- runPhase("testRollbackApexDataDirectories_Phase1");
+ runPhase("testRollbackApexDataDirectories_Phase1_Install");
getDevice().reboot();
// Replace files in data directory
- getDevice().deleteFile(oldFilePath1);
- getDevice().deleteFile(oldFilePath2);
String newFilePath3 = apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + "/" + TEST_FILENAME_3;
String newFilePath4 =
apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + TEST_SUBDIR + TEST_FILENAME_4;
- assertTrue(getDevice().pushString(TEST_STRING_3, newFilePath3));
- assertTrue(getDevice().pushString(TEST_STRING_4, newFilePath4));
+ runAsRoot(() -> {
+ getDevice().deleteFile(oldFilePath1);
+ getDevice().deleteFile(oldFilePath2);
+ pushString(TEST_STRING_3, newFilePath3);
+ pushString(TEST_STRING_4, newFilePath4);
+ });
// Roll back the APEX
- runPhase("testRollbackApexDataDirectories_Phase2");
+ runPhase("testRollbackApexDataDirectories_Phase2_Rollback");
getDevice().reboot();
// Verify that old files have been restored and new files are gone
- assertEquals(TEST_STRING_1, getDevice().pullFileContents(oldFilePath1));
- assertEquals(TEST_STRING_2, getDevice().pullFileContents(oldFilePath2));
- assertNull(getDevice().pullFile(newFilePath3));
- assertNull(getDevice().pullFile(newFilePath4));
+ runAsRoot(() -> {
+ assertFileContents(TEST_STRING_1, oldFilePath1);
+ assertFileContents(TEST_STRING_2, oldFilePath2);
+ assertFileNotExists(newFilePath3);
+ assertFileNotExists(newFilePath4);
+ });
// Verify snapshots are deleted after restoration
List<String> after = getSnapshotDirectories("/data/misc/apexrollback");
// Only check directories newly created during the test
after.removeAll(before);
- after.forEach(dir -> assertDirectoryIsEmpty(dir));
+ // There should be only one /data/misc/apexrollback/<rollbackId> created during test
+ assertThat(after).hasSize(1);
+ assertDirectoryIsEmpty(after.get(0));
}
/**
@@ -362,38 +390,46 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_1;
String oldFilePath2 =
apexDataDirDeUser(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
- assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1));
- assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2));
+ runAsRoot(() -> {
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
+ });
// Install new version of the APEX with rollback enabled
- runPhase("testRollbackApexDataDirectories_Phase1");
+ runPhase("testRollbackApexDataDirectories_Phase1_Install");
getDevice().reboot();
// Replace files in data directory
- getDevice().deleteFile(oldFilePath1);
- getDevice().deleteFile(oldFilePath2);
String newFilePath3 =
apexDataDirDeUser(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_3;
String newFilePath4 =
apexDataDirDeUser(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_4;
- assertTrue(getDevice().pushString(TEST_STRING_3, newFilePath3));
- assertTrue(getDevice().pushString(TEST_STRING_4, newFilePath4));
+ runAsRoot(() -> {
+ getDevice().deleteFile(oldFilePath1);
+ getDevice().deleteFile(oldFilePath2);
+ pushString(TEST_STRING_3, newFilePath3);
+ pushString(TEST_STRING_4, newFilePath4);
+ });
// Roll back the APEX
- runPhase("testRollbackApexDataDirectories_Phase2");
+ runPhase("testRollbackApexDataDirectories_Phase2_Rollback");
getDevice().reboot();
// Verify that old files have been restored and new files are gone
- assertEquals(TEST_STRING_1, getDevice().pullFileContents(oldFilePath1));
- assertEquals(TEST_STRING_2, getDevice().pullFileContents(oldFilePath2));
- assertNull(getDevice().pullFile(newFilePath3));
- assertNull(getDevice().pullFile(newFilePath4));
+ runAsRoot(() -> {
+ assertFileContents(TEST_STRING_1, oldFilePath1);
+ assertFileContents(TEST_STRING_2, oldFilePath2);
+ assertFileNotExists(newFilePath3);
+ assertFileNotExists(newFilePath4);
+ });
// Verify snapshots are deleted after restoration
List<String> after = getSnapshotDirectories("/data/misc_de/0/apexrollback");
// Only check directories newly created during the test
after.removeAll(before);
- after.forEach(dir -> assertDirectoryIsEmpty(dir));
+ // There should be only one /data/misc_de/0/apexrollback/<rollbackId> created during test
+ assertThat(after).hasSize(1);
+ assertDirectoryIsEmpty(after.get(0));
}
/**
@@ -408,51 +444,198 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
String oldFilePath1 = apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_1;
String oldFilePath2 =
apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
- assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1));
- assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2));
+ runAsRoot(() -> {
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
+ });
// Install new version of the APEX with rollback enabled
- runPhase("testRollbackApexDataDirectories_Phase1");
+ runPhase("testRollbackApexDataDirectories_Phase1_Install");
getDevice().reboot();
// Replace files in data directory
- getDevice().deleteFile(oldFilePath1);
- getDevice().deleteFile(oldFilePath2);
String newFilePath3 = apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_3;
String newFilePath4 =
apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_4;
- assertTrue(getDevice().pushString(TEST_STRING_3, newFilePath3));
- assertTrue(getDevice().pushString(TEST_STRING_4, newFilePath4));
+ runAsRoot(() -> {
+ getDevice().deleteFile(oldFilePath1);
+ getDevice().deleteFile(oldFilePath2);
+ pushString(TEST_STRING_3, newFilePath3);
+ pushString(TEST_STRING_4, newFilePath4);
+ });
// Roll back the APEX
- runPhase("testRollbackApexDataDirectories_Phase2");
+ runPhase("testRollbackApexDataDirectories_Phase2_Rollback");
getDevice().reboot();
// Verify that old files have been restored and new files are gone
- assertEquals(TEST_STRING_1, getDevice().pullFileContents(oldFilePath1));
- assertEquals(TEST_STRING_2, getDevice().pullFileContents(oldFilePath2));
- assertNull(getDevice().pullFile(newFilePath3));
- assertNull(getDevice().pullFile(newFilePath4));
+ runAsRoot(() -> {
+ assertFileContents(TEST_STRING_1, oldFilePath1);
+ assertFileContents(TEST_STRING_2, oldFilePath2);
+ assertFileNotExists(newFilePath3);
+ assertFileNotExists(newFilePath4);
+ });
// Verify snapshots are deleted after restoration
List<String> after = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
// Only check directories newly created during the test
after.removeAll(before);
- after.forEach(dir -> assertDirectoryIsEmpty(dir));
+ // There should be only one /data/misc_ce/0/apexrollback/<rollbackId> created during test
+ assertThat(after).hasSize(1);
+ assertDirectoryIsEmpty(after.get(0));
+ }
+
+ /**
+ * Tests that data in DE apk data directory is restored when apk is rolled back.
+ */
+ @Test
+ public void testRollbackApkDataDirectories_De() throws Exception {
+ // Install version 1 of TESTAPP_A
+ runPhase("testRollbackApkDataDirectories_Phase1_InstallV1");
+
+ // Push files to apk data directory
+ String oldFilePath1 = apkDataDirDe(TESTAPP_A, 0) + "/" + TEST_FILENAME_1;
+ String oldFilePath2 = apkDataDirDe(TESTAPP_A, 0) + TEST_SUBDIR + TEST_FILENAME_2;
+ runAsRoot(() -> {
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
+ });
+
+ // Install version 2 of TESTAPP_A with rollback enabled
+ runPhase("testRollbackApkDataDirectories_Phase2_InstallV2");
+ getDevice().reboot();
+
+ // Replace files in data directory
+ String newFilePath3 = apkDataDirDe(TESTAPP_A, 0) + "/" + TEST_FILENAME_3;
+ String newFilePath4 = apkDataDirDe(TESTAPP_A, 0) + TEST_SUBDIR + TEST_FILENAME_4;
+ runAsRoot(() -> {
+ getDevice().deleteFile(oldFilePath1);
+ getDevice().deleteFile(oldFilePath2);
+ pushString(TEST_STRING_3, newFilePath3);
+ pushString(TEST_STRING_4, newFilePath4);
+ });
+
+ // Roll back the APK
+ runPhase("testRollbackApkDataDirectories_Phase3_Rollback");
+ getDevice().reboot();
+
+ // Verify that old files have been restored and new files are gone
+ runAsRoot(() -> {
+ assertFileContents(TEST_STRING_1, oldFilePath1);
+ assertFileContents(TEST_STRING_2, oldFilePath2);
+ assertFileNotExists(newFilePath3);
+ assertFileNotExists(newFilePath4);
+ });
+ }
+
+ @Test
+ public void testExpireApexRollback() throws Exception {
+ List<String> before = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
+ pushTestApex();
+
+ // Push files to apex data directory
+ String oldFilePath1 = apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_1;
+ String oldFilePath2 =
+ apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
+ runAsRoot(() -> {
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
+ });
+
+ // Install new version of the APEX with rollback enabled
+ runPhase("testRollbackApexDataDirectories_Phase1_Install");
+ getDevice().reboot();
+
+ List<String> after = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
+ // Only check directories newly created during the test
+ after.removeAll(before);
+ // There should be only one /data/misc_ce/0/apexrollback/<rollbackId> created during test
+ assertThat(after).hasSize(1);
+ // Expire all rollbacks and check CE snapshot directories are deleted
+ runPhase("expireRollbacks");
+ runAsRoot(() -> {
+ for (String dir : after) {
+ assertFileNotExists(dir);
+ }
+ });
+ }
+
+ /**
+ * Tests that packages are monitored across multiple reboots.
+ */
+ @Test
+ public void testWatchdogMonitorsAcrossReboots() throws Exception {
+ runPhase("testWatchdogMonitorsAcrossReboots_Phase1_Install");
+
+ // The first reboot will make the rollback available.
+ // Information about which packages are monitored will be persisted to a file before the
+ // second reboot, and read from disk after the second reboot.
+ getDevice().reboot();
+ getDevice().reboot();
+
+ runPhase("testWatchdogMonitorsAcrossReboots_Phase2_VerifyInstall");
+
+ // Launch the app to crash to trigger rollback
+ startActivity(TESTAPP_A);
+ // Wait for reboot to happen
+ waitForDeviceNotAvailable(2, TimeUnit.MINUTES);
+ getDevice().waitForDeviceAvailable();
+
+ runPhase("testWatchdogMonitorsAcrossReboots_Phase3_VerifyRollback");
+ }
+
+ /**
+ * Tests an available rollback shouldn't be deleted when its session expires.
+ */
+ @Test
+ public void testExpireSession() throws Exception {
+ runPhase("testExpireSession_Phase1_Install");
+ getDevice().reboot();
+ runPhase("testExpireSession_Phase2_VerifyInstall");
+
+ // Advance system clock by 7 days to expire the staged session
+ Instant t1 = Instant.ofEpochMilli(getDevice().getDeviceDate());
+ Instant t2 = t1.plusMillis(TimeUnit.DAYS.toMillis(7));
+ runAsRoot(() -> getDevice().setDate(Date.from(t2)));
+
+ // Somehow we need to wait for a while before reboot. Otherwise the change to the
+ // system clock will be reset after reboot.
+ Thread.sleep(3000);
+ getDevice().reboot();
+ runPhase("testExpireSession_Phase3_VerifyRollback");
}
private void pushTestApex() throws Exception {
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex";
final File apex = buildHelper.getTestFile(fileName);
- if (!getDevice().isAdbRoot()) {
+ try {
getDevice().enableAdbRoot();
+ getDevice().remountSystemWritable();
+ assertThat(getDevice().pushFile(apex, "/system/apex/" + fileName)).isTrue();
+ } finally {
+ getDevice().disableAdbRoot();
}
- getDevice().remountSystemWritable();
- assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName));
getDevice().reboot();
}
+ private void pushString(String contents, String path) throws Exception {
+ assertWithMessage("Failed to push file to device, content=%s path=%s", contents, path)
+ .that(getDevice().pushString(contents, path)).isTrue();
+ }
+
+ private void assertFileContents(String expectedContents, String path) throws Exception {
+ String actualContents = getDevice().pullFileContents(path);
+ assertWithMessage("Failed to retrieve file=%s", path).that(actualContents).isNotNull();
+ assertWithMessage("Mismatched file contents, path=%s", path)
+ .that(actualContents).isEqualTo(expectedContents);
+ }
+
+ private void assertFileNotExists(String path) throws Exception {
+ assertWithMessage("File shouldn't exist, path=%s", path)
+ .that(getDevice().getFileEntry(path)).isNull();
+ }
+
private static String apexDataDirDeSys(String apexName) {
return String.format("/data/misc/apexdata/%s", apexName);
}
@@ -465,28 +648,49 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
return String.format("/data/misc_ce/%d/apexdata/%s", userId, apexName);
}
- private List<String> getSnapshotDirectories(String baseDir) {
+ private static String apkDataDirDe(String apexName, int userId) {
+ return String.format("/data/user_de/%d/%s", userId, apexName);
+ }
+
+ private List<String> getSnapshotDirectories(String baseDir) throws Exception {
try {
- return getDevice().getFileEntry(baseDir).getChildren(false)
+ getDevice().enableAdbRoot();
+ IFileEntry f = getDevice().getFileEntry(baseDir);
+ if (f == null) {
+ Log.d(TAG, "baseDir doesn't exist: " + baseDir);
+ return Collections.EMPTY_LIST;
+ }
+ List<String> list = f.getChildren(false)
.stream().filter(entry -> entry.getName().matches("\\d+(-prerestore)?"))
.map(entry -> entry.getFullPath())
.collect(Collectors.toList());
- } catch (Exception e) {
- // Return an empty list if any error
- return Collections.EMPTY_LIST;
+ Log.d(TAG, "getSnapshotDirectories=" + list);
+ return list;
+ } finally {
+ getDevice().disableAdbRoot();
}
}
- private void assertDirectoryIsEmpty(String path) {
+ private void assertDirectoryIsEmpty(String path) throws Exception {
try {
+ getDevice().enableAdbRoot();
IFileEntry file = getDevice().getFileEntry(path);
- assertTrue("Not a directory: " + path, file.isDirectory());
- assertTrue("Directory not empty: " + path, file.getChildren(false).isEmpty());
+ assertWithMessage("Not a directory: " + path).that(file.isDirectory()).isTrue();
+ assertWithMessage("Directory not empty: " + path)
+ .that(file.getChildren(false)).isEmpty();
} catch (DeviceNotAvailableException e) {
fail("Can't access directory: " + path);
+ } finally {
+ getDevice().disableAdbRoot();
}
}
+ private void startActivity(String packageName) throws Exception {
+ String cmd = "am start -S -a android.intent.action.MAIN "
+ + "-c android.intent.category.LAUNCHER " + packageName;
+ getDevice().executeShellCommand(cmd);
+ }
+
private void crashProcess(String processName, int numberOfCrashes) throws Exception {
String pid = "";
String lastPid = "invalid";
@@ -521,4 +725,18 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
return false;
}
}
+
+ @FunctionalInterface
+ private interface ExceptionalRunnable {
+ void run() throws Exception;
+ }
+
+ private void runAsRoot(ExceptionalRunnable runnable) throws Exception {
+ try {
+ getDevice().enableAdbRoot();
+ runnable.run();
+ } finally {
+ getDevice().disableAdbRoot();
+ }
+ }
}
diff --git a/tests/RollbackTest/TEST_MAPPING b/tests/RollbackTest/TEST_MAPPING
index 0f4c4603f9b4..7f9f2dcf2bde 100644
--- a/tests/RollbackTest/TEST_MAPPING
+++ b/tests/RollbackTest/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "presubmit": [
+ "presubmit-large": [
{
"name": "RollbackTest"
},
diff --git a/tests/RollbackTest/lib/src/com/android/tests/rollback/host/WatchdogEventLogger.java b/tests/RollbackTest/lib/src/com/android/tests/rollback/host/WatchdogEventLogger.java
index 88731504eafe..8c16079dca85 100644
--- a/tests/RollbackTest/lib/src/com/android/tests/rollback/host/WatchdogEventLogger.java
+++ b/tests/RollbackTest/lib/src/com/android/tests/rollback/host/WatchdogEventLogger.java
@@ -17,52 +17,52 @@
package com.android.tests.rollback.host;
import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.device.LogcatReceiver;
-import com.android.tradefed.result.InputStreamSource;
+import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.Truth;
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.List;
+import static com.google.common.truth.Truth.assertThat;
public class WatchdogEventLogger {
- private LogcatReceiver mReceiver;
+ private static final String[] ROLLBACK_EVENT_TYPES = {
+ "ROLLBACK_INITIATE", "ROLLBACK_BOOT_TRIGGERED", "ROLLBACK_SUCCESS"};
+ private static final String[] ROLLBACK_EVENT_ATTRS = {
+ "logPackage", "rollbackReason", "failedPackageName"};
+ private static final String PROP_PREFIX = "persist.sys.rollbacktest.";
- public void start(ITestDevice device) {
- mReceiver = new LogcatReceiver(device, "logcat -s WatchdogRollbackLogger",
- device.getOptions().getMaxLogcatDataSize(), 0);
- mReceiver.start();
- }
+ private ITestDevice mDevice;
- public void stop() {
- if (mReceiver != null) {
- mReceiver.stop();
- mReceiver.clear();
+ private void resetProperties(boolean enabled) throws Exception {
+ try {
+ mDevice.enableAdbRoot();
+ assertThat(mDevice.setProperty(
+ PROP_PREFIX + "enabled", String.valueOf(enabled))).isTrue();
+ for (String type : ROLLBACK_EVENT_TYPES) {
+ String key = PROP_PREFIX + type;
+ assertThat(mDevice.setProperty(key, "")).isTrue();
+ for (String attr : ROLLBACK_EVENT_ATTRS) {
+ assertThat(mDevice.setProperty(key + "." + attr, "")).isTrue();
+ }
+ }
+ } finally {
+ mDevice.disableAdbRoot();
}
}
- /**
- * Returns a list of all Watchdog logging events which have occurred.
- */
- public List<String> getWatchdogLoggingEvents() throws Exception {
- try (InputStreamSource logcatStream = mReceiver.getLogcatData()) {
- return getWatchdogLoggingEvents(logcatStream);
- }
+ public void start(ITestDevice device) throws Exception {
+ mDevice = device;
+ resetProperties(true);
}
- private static List<String> getWatchdogLoggingEvents(InputStreamSource inputStreamSource)
- throws Exception {
- List<String> watchdogEvents = new ArrayList<>();
- InputStream inputStream = inputStreamSource.createInputStream();
- BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
- String line;
- while ((line = reader.readLine()) != null) {
- if (line.contains("Watchdog event occurred")) {
- watchdogEvents.add(line);
- }
+ public void stop() throws Exception {
+ if (mDevice != null) {
+ resetProperties(false);
}
- return watchdogEvents;
+ }
+
+ private boolean matchProperty(String type, String attr, String expectedVal) throws Exception {
+ String key = PROP_PREFIX + type + "." + attr;
+ String val = mDevice.getProperty(key);
+ return expectedVal == null || expectedVal.equals(val);
}
/**
@@ -71,33 +71,37 @@ public class WatchdogEventLogger {
* Check the value of all non-null parameters against the list of Watchdog events that have
* occurred, and return {@code true} if an event exists which matches all criteria.
*/
- public static boolean watchdogEventOccurred(List<String> loggingEvents,
- String type, String logPackage,
+ public boolean watchdogEventOccurred(String type, String logPackage,
String rollbackReason, String failedPackageName) throws Exception {
- List<String> eventCriteria = new ArrayList<>();
- if (type != null) {
- eventCriteria.add("type: " + type);
- }
- if (logPackage != null) {
- eventCriteria.add("logPackage: " + logPackage);
+ return mDevice.getBooleanProperty(PROP_PREFIX + type, false)
+ && matchProperty(type, "logPackage", logPackage)
+ && matchProperty(type, "rollbackReason", rollbackReason)
+ && matchProperty(type, "failedPackageName", failedPackageName);
+ }
+
+ static class Subject extends com.google.common.truth.Subject {
+ private final WatchdogEventLogger mActual;
+
+ private Subject(FailureMetadata failureMetadata, WatchdogEventLogger subject) {
+ super(failureMetadata, subject);
+ mActual = subject;
}
- if (rollbackReason != null) {
- eventCriteria.add("rollbackReason: " + rollbackReason);
+
+ private static com.google.common.truth.Subject.Factory<Subject,
+ WatchdogEventLogger> loggers() {
+ return Subject::new;
}
- if (failedPackageName != null) {
- eventCriteria.add("failedPackageName: " + failedPackageName);
+
+ static Subject assertThat(WatchdogEventLogger actual) {
+ return Truth.assertAbout(loggers()).that(actual);
}
- for (String loggingEvent: loggingEvents) {
- boolean matchesCriteria = true;
- for (String criterion: eventCriteria) {
- if (!loggingEvent.contains(criterion)) {
- matchesCriteria = false;
- }
- }
- if (matchesCriteria) {
- return true;
- }
+
+ void eventOccurred(String type, String logPackage, String rollbackReason,
+ String failedPackageName) throws Exception {
+ check("watchdogEventOccurred(type=%s, logPackage=%s, rollbackReason=%s, "
+ + "failedPackageName=%s)", type, logPackage, rollbackReason, failedPackageName)
+ .that(mActual.watchdogEventOccurred(type, logPackage, rollbackReason,
+ failedPackageName)).isTrue();
}
- return false;
}
}
diff --git a/tests/SerialChat/Android.bp b/tests/SerialChat/Android.bp
index 3c18035a4aab..8719e01031d5 100644
--- a/tests/SerialChat/Android.bp
+++ b/tests/SerialChat/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "SerialChat",
srcs: ["**/*.java"],
diff --git a/tests/SerialChat/AndroidManifest.xml b/tests/SerialChat/AndroidManifest.xml
index 0efdb58d72cb..7aedb52752c5 100644
--- a/tests/SerialChat/AndroidManifest.xml
+++ b/tests/SerialChat/AndroidManifest.xml
@@ -15,16 +15,18 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.serialchat">
+ package="com.android.serialchat">
<uses-permission android:name="android.permission.SERIAL_PORT"/>
<application android:label="Serial Chat">
- <activity android:name="SerialChat" android:label="Serial Chat">
+ <activity android:name="SerialChat"
+ android:label="Serial Chat"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/ServiceCrashTest/Android.bp b/tests/ServiceCrashTest/Android.bp
index 40a377de852f..fb98b7631b7e 100644
--- a/tests/ServiceCrashTest/Android.bp
+++ b/tests/ServiceCrashTest/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "ServiceCrashTest",
// Only compile source java files in this apk.
diff --git a/tests/ServiceCrashTest/AndroidManifest.xml b/tests/ServiceCrashTest/AndroidManifest.xml
index 387c8b8ae36b..e906fe2109e1 100644
--- a/tests/ServiceCrashTest/AndroidManifest.xml
+++ b/tests/ServiceCrashTest/AndroidManifest.xml
@@ -1,23 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.servicecrashtest">
+ package="com.android.tests.servicecrashtest">
<application android:label="Service Crash Test">
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
<service android:name=".CrashingService"
- android:process=":badservice" />
+ android:process=":badservice"/>
- <activity android:name=".MainActivity" >
+ <activity android:name=".MainActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity>
</application>
<instrumentation android:label="Test bound service crash restart"
- android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.tests.servicecrashtest" />
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.tests.servicecrashtest"/>
</manifest>
diff --git a/tests/SharedLibrary/client/Android.bp b/tests/SharedLibrary/client/Android.bp
index dbf6dc94eb8d..6eab7c2e2dce 100644
--- a/tests/SharedLibrary/client/Android.bp
+++ b/tests/SharedLibrary/client/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "SharedLibraryClient",
srcs: ["**/*.java"],
diff --git a/tests/SharedLibrary/client/AndroidManifest.xml b/tests/SharedLibrary/client/AndroidManifest.xml
index d1167fa7322f..9903a98c0ae9 100644
--- a/tests/SharedLibrary/client/AndroidManifest.xml
+++ b/tests/SharedLibrary/client/AndroidManifest.xml
@@ -15,23 +15,26 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.lib_client">
- <application android:label="@string/app_title" android:theme="@style/Theme">
- <uses-library android:name="android.test.runner" />
- <uses-library android:name="com.google.android.test.shared_library" />
- <activity android:name="ActivityMain">
+ package="com.google.android.test.lib_client">
+ <application android:label="@string/app_title"
+ android:theme="@style/Theme">
+ <uses-library android:name="android.test.runner"/>
+ <uses-library android:name="com.google.android.test.shared_library"/>
+ <activity android:name="ActivityMain"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <receiver android:name="DependentAppwidgetProvider">
+ <receiver android:name="DependentAppwidgetProvider"
+ android:exported="true">
<intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider"
- android:resource="@xml/dependent_appwidget_info" />
+ android:resource="@xml/dependent_appwidget_info"/>
</receiver>
</application>
</manifest>
diff --git a/tests/SharedLibrary/lib/Android.bp b/tests/SharedLibrary/lib/Android.bp
index f69d388ef0f1..0595cb1e116a 100644
--- a/tests/SharedLibrary/lib/Android.bp
+++ b/tests/SharedLibrary/lib/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_app {
name: "SharedLibrary",
srcs: ["**/*.java"],
diff --git a/tests/SharedLibrary/lib/AndroidManifest.xml b/tests/SharedLibrary/lib/AndroidManifest.xml
index bb939dd4cb55..df2fdca18f6e 100644
--- a/tests/SharedLibrary/lib/AndroidManifest.xml
+++ b/tests/SharedLibrary/lib/AndroidManifest.xml
@@ -15,15 +15,16 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.shared_library"
- android:versionCode="2">
+ package="com.google.android.test.shared_library"
+ android:versionCode="2">
<application android:label="SharedLibrary">
- <library android:name="com.google.android.test.shared_library" />
+ <library android:name="com.google.android.test.shared_library"/>
<activity android:name="ActivityMain"
- android:icon="@drawable/size_48x48">
+ android:icon="@drawable/size_48x48"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/ShowWhenLockedApp/Android.bp b/tests/ShowWhenLockedApp/Android.bp
index dba564c91059..f24834a53a36 100644
--- a/tests/ShowWhenLockedApp/Android.bp
+++ b/tests/ShowWhenLockedApp/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "ShowWhenLocked",
srcs: ["**/*.java"],
diff --git a/tests/ShowWhenLockedApp/AndroidManifest.xml b/tests/ShowWhenLockedApp/AndroidManifest.xml
index a872e061526f..82957b719a48 100644
--- a/tests/ShowWhenLockedApp/AndroidManifest.xml
+++ b/tests/ShowWhenLockedApp/AndroidManifest.xml
@@ -16,12 +16,13 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.showwhenlocked">
+ package="com.android.showwhenlocked">
<application android:label="ShowWhenLocked">
<activity android:name=".ShowWhenLockedActivity"
- android:showWhenLocked="true"
- android:turnScreenOn="true"
- android:launchMode="singleTask">
+ android:showWhenLocked="true"
+ android:turnScreenOn="true"
+ android:launchMode="singleTask"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
diff --git a/tests/SilkFX/Android.bp b/tests/SilkFX/Android.bp
new file mode 100644
index 000000000000..088d9a2d7f41
--- /dev/null
+++ b/tests/SilkFX/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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
+ // 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"],
+}
+
+android_test {
+ name: "SilkFX",
+ srcs: ["**/*.java", "**/*.kt"],
+ platform_apis: true,
+ certificate: "platform",
+ static_libs: [
+ "androidx.core_core",
+ "androidx.appcompat_appcompat",
+ "com.google.android.material_material",
+ "androidx-constraintlayout_constraintlayout",
+ ],
+}
diff --git a/tests/AutoVerify/app4/AndroidManifest.xml b/tests/SilkFX/AndroidManifest.xml
index 1c975f8336c9..c30d76137f76 100644
--- a/tests/AutoVerify/app4/AndroidManifest.xml
+++ b/tests/SilkFX/AndroidManifest.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2020 The Android Open Source Project
+<!-- Copyright (C) 2010 The Android Open 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,30 +15,39 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.autoverify" >
+ package="com.android.test.silkfx">
- <uses-sdk android:targetSdkVersion="26" />
+ <uses-sdk android:minSdkVersion="30"/>
- <application
- android:label="@string/app_name" >
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name" >
+ <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" />
+
+ <application android:label="SilkFX"
+ android:theme="@android:style/Theme.Material">
+
+ <activity android:name=".Main"
+ android:label="SilkFX Demos"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
+ </activity>
- <!-- intentionally does not autoVerify -->
+ <activity android:name=".app.CommonDemoActivity" />
+
+ <activity android:name=".hdr.GlowActivity"
+ android:label="Glow Examples"/>
+
+ <activity android:name=".materials.GlassActivity"
+ android:label="Glass Examples"
+ android:banner="@drawable/background1"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:host="explicit.example.com" />
- <data android:host="*.wildcard.tld" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>
+
</application>
</manifest>
diff --git a/tests/SilkFX/OWNERS b/tests/SilkFX/OWNERS
new file mode 100644
index 000000000000..c88a9f82c347
--- /dev/null
+++ b/tests/SilkFX/OWNERS
@@ -0,0 +1 @@
+include /libs/hwui/OWNERS
diff --git a/tests/SilkFX/res/drawable-hdpi/background1.jpeg b/tests/SilkFX/res/drawable-hdpi/background1.jpeg
new file mode 100644
index 000000000000..dcdfa7b850bc
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/background1.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/background2.jpeg b/tests/SilkFX/res/drawable-hdpi/background2.jpeg
new file mode 100644
index 000000000000..dc7ce84e6784
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/background2.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/background3.jpeg b/tests/SilkFX/res/drawable-hdpi/background3.jpeg
new file mode 100644
index 000000000000..12b3429e3920
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/background3.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/noise.png b/tests/SilkFX/res/drawable-hdpi/noise.png
new file mode 100644
index 000000000000..053995dad760
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/noise.png
Binary files differ
diff --git a/tests/SilkFX/res/drawable-nodpi/dark_notification.png b/tests/SilkFX/res/drawable-nodpi/dark_notification.png
new file mode 100644
index 000000000000..6de6c2ae785c
--- /dev/null
+++ b/tests/SilkFX/res/drawable-nodpi/dark_notification.png
Binary files differ
diff --git a/tests/SilkFX/res/drawable-nodpi/light_notification.png b/tests/SilkFX/res/drawable-nodpi/light_notification.png
new file mode 100644
index 000000000000..81a67cd3d388
--- /dev/null
+++ b/tests/SilkFX/res/drawable-nodpi/light_notification.png
Binary files differ
diff --git a/tests/SilkFX/res/layout-television/activity_glass.xml b/tests/SilkFX/res/layout-television/activity_glass.xml
new file mode 100644
index 000000000000..1f566860da3d
--- /dev/null
+++ b/tests/SilkFX/res/layout-television/activity_glass.xml
@@ -0,0 +1,302 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** 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.
+-->
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity">
+
+ <ImageView
+ android:id="@+id/background"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:scaleType="matrix"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:srcCompat="@drawable/background1" />
+
+ <com.android.test.silkfx.materials.GlassView
+ android:id="@+id/materialView"
+ android:layout_width="400dp"
+ android:layout_height="100dp"
+ android:layout_marginEnd="64dp"
+ android:layout_marginStart="64dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="@id/background"
+ app:layout_constraintStart_toStartOf="@id/background"
+ app:layout_constraintTop_toTopOf="parent">
+ <TextView
+ android:id="@+id/textOverlay"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="18dp"
+ android:layout_gravity="center"
+ android:textColor="#ffffff"
+ android:text="Lorem Ipsum dolor sit amet." />
+ </com.android.test.silkfx.materials.GlassView>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/bottomPanel"
+ android:layout_width="400dp"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/colorBackground"
+ android:paddingTop="24dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent">
+
+ <SeekBar
+ android:id="@+id/materialOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="16dp"
+ android:max="100"
+ android:progress="12"
+ app:layout_constraintBottom_toTopOf="@+id/scrimOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/zoom"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginStart="12dp"
+ android:min="-100"
+ android:max="100"
+ android:progress="-15"
+ app:layout_constraintBottom_toTopOf="@+id/blurRadiusTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/blurRadius"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginStart="12dp"
+ android:max="150"
+ android:progress="40"
+ app:layout_constraintBottom_toTopOf="@+id/materialOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/scrimOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="16dp"
+ android:max="100"
+ android:progress="50"
+ app:layout_constraintBottom_toTopOf="@+id/noiseOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/noiseOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="24dp"
+ android:max="100"
+ android:progress="15"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/scrimOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Scrim Opacity"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/scrimOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/materialOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Soft light Opacity"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/materialOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/zoomTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Zoom"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/zoom"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/blurRadiusTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Blur Radius"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/blurRadius"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/noiseOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:textColor="@android:color/white"
+ android:text="Noise Opacity"
+ app:layout_constraintBottom_toTopOf="@+id/noiseOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <ImageView
+ android:id="@+id/background1"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="16dp"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toTopOf="@+id/lightMaterialSwitch"
+ app:layout_constraintStart_toStartOf="parent"
+ android:src="@drawable/background1" />
+
+ <ImageView
+ android:id="@+id/background2"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="8dp"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toBottomOf="@+id/background1"
+ app:layout_constraintStart_toEndOf="@+id/background1"
+ android:src="@drawable/background2" />
+
+ <ImageView
+ android:id="@+id/background3"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="8dp"
+ android:scaleType="centerCrop"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ app:layout_constraintBottom_toBottomOf="@+id/background1"
+ app:layout_constraintStart_toEndOf="@+id/background2"
+ android:src="@drawable/background3" />
+
+ <Button
+ android:id="@+id/pickImage"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="8dp"
+ android:scaleType="centerCrop"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onPickImageClick"
+ app:layout_constraintBottom_toBottomOf="@+id/background1"
+ app:layout_constraintStart_toEndOf="@+id/background3"
+ android:text="Pick file" />
+
+ <Switch
+ android:id="@+id/lightMaterialSwitch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Light Material"
+ app:layout_constraintBottom_toTopOf="@+id/zoomTitle"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/blurRadiusValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/blurRadiusTitle"
+ app:layout_constraintStart_toEndOf="@+id/blurRadiusTitle" />
+
+ <TextView
+ android:id="@+id/zoomValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/zoomTitle"
+ app:layout_constraintStart_toEndOf="@+id/zoomTitle" />
+
+ <TextView
+ android:id="@+id/materialOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/materialOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/materialOpacityTitle" />
+
+ <TextView
+ android:id="@+id/noiseOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/noiseOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/noiseOpacityTitle" />
+
+
+ <TextView
+ android:id="@+id/scrimOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/scrimOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/scrimOpacityTitle" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/tests/SilkFX/res/layout/activity_glass.xml b/tests/SilkFX/res/layout/activity_glass.xml
new file mode 100644
index 000000000000..aa09f276d5c8
--- /dev/null
+++ b/tests/SilkFX/res/layout/activity_glass.xml
@@ -0,0 +1,303 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+-->
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity">
+
+ <ImageView
+ android:id="@+id/background"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:scaleType="matrix"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:srcCompat="@drawable/background1" />
+
+ <com.android.test.silkfx.materials.GlassView
+ android:id="@+id/materialView"
+ android:layout_width="0dp"
+ android:layout_height="180dp"
+ android:layout_marginEnd="64dp"
+ android:layout_marginStart="64dp"
+ app:layout_constraintBottom_toTopOf="@+id/bottomPanel"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
+ <TextView
+ android:id="@+id/textOverlay"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="18dp"
+ android:layout_gravity="center"
+ android:textColor="#ffffff"
+ android:text="Lorem Ipsum dolor sit amet." />
+ </com.android.test.silkfx.materials.GlassView>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/bottomPanel"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/colorBackground"
+ android:paddingTop="24dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent">
+
+ <SeekBar
+ android:id="@+id/materialOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="16dp"
+ android:max="100"
+ android:progress="12"
+ app:layout_constraintBottom_toTopOf="@+id/scrimOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/zoom"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginStart="12dp"
+ android:min="-100"
+ android:max="100"
+ android:progress="-15"
+ app:layout_constraintBottom_toTopOf="@+id/blurRadiusTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/blurRadius"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginStart="12dp"
+ android:max="150"
+ android:progress="40"
+ app:layout_constraintBottom_toTopOf="@+id/materialOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/scrimOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="16dp"
+ android:max="100"
+ android:progress="50"
+ app:layout_constraintBottom_toTopOf="@+id/noiseOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/noiseOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="24dp"
+ android:max="100"
+ android:progress="15"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/scrimOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Scrim Opacity"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/scrimOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/materialOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Soft light Opacity"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/materialOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/zoomTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Zoom"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/zoom"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/blurRadiusTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Blur Radius"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/blurRadius"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/noiseOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:textColor="@android:color/white"
+ android:text="Noise Opacity"
+ app:layout_constraintBottom_toTopOf="@+id/noiseOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <ImageView
+ android:id="@+id/background1"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="16dp"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toTopOf="@+id/lightMaterialSwitch"
+ app:layout_constraintStart_toStartOf="parent"
+ android:src="@drawable/background1" />
+
+ <ImageView
+ android:id="@+id/background2"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="8dp"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toBottomOf="@+id/background1"
+ app:layout_constraintStart_toEndOf="@+id/background1"
+ android:src="@drawable/background2" />
+
+ <ImageView
+ android:id="@+id/background3"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="8dp"
+ android:scaleType="centerCrop"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ app:layout_constraintBottom_toBottomOf="@+id/background1"
+ app:layout_constraintStart_toEndOf="@+id/background2"
+ android:src="@drawable/background3" />
+
+ <Button
+ android:id="@+id/pickImage"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="8dp"
+ android:scaleType="centerCrop"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onPickImageClick"
+ app:layout_constraintBottom_toBottomOf="@+id/background1"
+ app:layout_constraintStart_toEndOf="@+id/background3"
+ android:text="Pick file" />
+
+ <Switch
+ android:id="@+id/lightMaterialSwitch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Light Material"
+ app:layout_constraintBottom_toTopOf="@+id/zoomTitle"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/blurRadiusValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/blurRadiusTitle"
+ app:layout_constraintStart_toEndOf="@+id/blurRadiusTitle" />
+
+ <TextView
+ android:id="@+id/zoomValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/zoomTitle"
+ app:layout_constraintStart_toEndOf="@+id/zoomTitle" />
+
+ <TextView
+ android:id="@+id/materialOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/materialOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/materialOpacityTitle" />
+
+ <TextView
+ android:id="@+id/noiseOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/noiseOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/noiseOpacityTitle" />
+
+
+ <TextView
+ android:id="@+id/scrimOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/scrimOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/scrimOpacityTitle" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+
+</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/tests/SilkFX/res/layout/bling_notifications.xml b/tests/SilkFX/res/layout/bling_notifications.xml
new file mode 100644
index 000000000000..6d266b701a68
--- /dev/null
+++ b/tests/SilkFX/res/layout/bling_notifications.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <com.android.test.silkfx.hdr.BlingyNotification
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:src="@drawable/dark_notification" />
+
+ <com.android.test.silkfx.hdr.BlingyNotification
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:src="@drawable/light_notification" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/SilkFX/res/layout/color_mode_controls.xml b/tests/SilkFX/res/layout/color_mode_controls.xml
new file mode 100644
index 000000000000..c0c0bab8a605
--- /dev/null
+++ b/tests/SilkFX/res/layout/color_mode_controls.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<com.android.test.silkfx.common.ColorModeControls
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/current_mode"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/mode_default"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="Default (sRGB)" />
+
+ <Button
+ android:id="@+id/mode_wide"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="Wide Gamut (P3)" />
+
+ <Button
+ android:id="@+id/mode_hdr"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="HDR" />
+
+ <Button
+ android:id="@+id/mode_hdr10"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="HDR10" />
+
+ </LinearLayout>
+
+</com.android.test.silkfx.common.ColorModeControls> \ No newline at end of file
diff --git a/tests/SilkFX/res/layout/common_base.xml b/tests/SilkFX/res/layout/common_base.xml
new file mode 100644
index 000000000000..944c6846fbf7
--- /dev/null
+++ b/tests/SilkFX/res/layout/common_base.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <include layout="@layout/color_mode_controls" />
+
+ <FrameLayout android:id="@+id/demo_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <com.android.test.silkfx.common.HDRIndicator
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_margin="8dp" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/SilkFX/res/layout/hdr_glows.xml b/tests/SilkFX/res/layout/hdr_glows.xml
new file mode 100644
index 000000000000..b6050645866a
--- /dev/null
+++ b/tests/SilkFX/res/layout/hdr_glows.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <include layout="@layout/color_mode_controls" />
+
+ <com.android.test.silkfx.hdr.GlowingCard
+ android:layout_width="match_parent"
+ android:layout_height="100dp"
+ android:layout_margin="8dp" />
+
+ <com.android.test.silkfx.hdr.GlowingCard
+ android:id="@+id/card2"
+ android:layout_width="match_parent"
+ android:layout_height="100dp"
+ android:layout_margin="8dp"/>
+
+ <com.android.test.silkfx.hdr.RadialGlow
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:layout_margin="8dp" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <com.android.test.silkfx.common.HDRIndicator
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_margin="8dp" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/Main.kt b/tests/SilkFX/src/com/android/test/silkfx/Main.kt
new file mode 100644
index 000000000000..9ed8d2f5edf7
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/Main.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.silkfx
+
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.BaseExpandableListAdapter
+import android.widget.ExpandableListView
+import android.widget.TextView
+import com.android.test.silkfx.app.CommonDemoActivity
+import com.android.test.silkfx.app.EXTRA_LAYOUT
+import com.android.test.silkfx.app.EXTRA_TITLE
+import com.android.test.silkfx.hdr.GlowActivity
+import com.android.test.silkfx.materials.GlassActivity
+import kotlin.reflect.KClass
+
+class Demo(val name: String, val makeIntent: (Context) -> Intent) {
+ constructor(name: String, activity: KClass<out Activity>) : this(name, { context ->
+ Intent(context, activity.java)
+ })
+ constructor(name: String, layout: Int) : this(name, { context ->
+ Intent(context, CommonDemoActivity::class.java).apply {
+ putExtra(EXTRA_LAYOUT, layout)
+ putExtra(EXTRA_TITLE, name)
+ }
+ })
+}
+data class DemoGroup(val groupName: String, val demos: List<Demo>)
+
+private val AllDemos = listOf(
+ DemoGroup("HDR", listOf(
+ Demo("Glow", GlowActivity::class),
+ Demo("Blingy Notifications", R.layout.bling_notifications)
+ )),
+ DemoGroup("Materials", listOf(
+ Demo("Glass", GlassActivity::class)
+ ))
+)
+
+class Main : Activity() {
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val list = ExpandableListView(this)
+
+ setContentView(list)
+
+ val inflater = LayoutInflater.from(this)
+ list.setAdapter(object : BaseExpandableListAdapter() {
+ override fun getGroup(groupPosition: Int): DemoGroup {
+ return AllDemos[groupPosition]
+ }
+
+ override fun isChildSelectable(groupPosition: Int, childPosition: Int): Boolean = true
+
+ override fun hasStableIds(): Boolean = true
+
+ override fun getGroupView(
+ groupPosition: Int,
+ isExpanded: Boolean,
+ convertView: View?,
+ parent: ViewGroup?
+ ): View {
+ val view = (convertView ?: inflater.inflate(
+ android.R.layout.simple_expandable_list_item_1, parent, false)) as TextView
+ view.text = AllDemos[groupPosition].groupName
+ return view
+ }
+
+ override fun getChildrenCount(groupPosition: Int): Int {
+ return AllDemos[groupPosition].demos.size
+ }
+
+ override fun getChild(groupPosition: Int, childPosition: Int): Demo {
+ return AllDemos[groupPosition].demos[childPosition]
+ }
+
+ override fun getGroupId(groupPosition: Int): Long = groupPosition.toLong()
+
+ override fun getChildView(
+ groupPosition: Int,
+ childPosition: Int,
+ isLastChild: Boolean,
+ convertView: View?,
+ parent: ViewGroup?
+ ): View {
+ val view = (convertView ?: inflater.inflate(
+ android.R.layout.simple_expandable_list_item_1, parent, false)) as TextView
+ view.text = AllDemos[groupPosition].demos[childPosition].name
+ return view
+ }
+
+ override fun getChildId(groupPosition: Int, childPosition: Int): Long {
+ return (groupPosition.toLong() shl 32) or childPosition.toLong()
+ }
+
+ override fun getGroupCount(): Int {
+ return AllDemos.size
+ }
+ })
+
+ list.setOnChildClickListener { _, _, groupPosition, childPosition, _ ->
+ val demo = AllDemos[groupPosition].demos[childPosition]
+ startActivity(demo.makeIntent(this))
+ return@setOnChildClickListener true
+ }
+
+ AllDemos.forEachIndexed { index, _ -> list.expandGroup(index) }
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt
new file mode 100644
index 000000000000..89011b51b8d6
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.silkfx.app
+
+import android.app.Activity
+import android.content.Context
+import android.os.Bundle
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.MenuItem
+import android.view.View
+
+open class BaseDemoActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val inflater = LayoutInflater.from(this)
+ inflater.factory2 = object : LayoutInflater.Factory2 {
+ private val sClassPrefixList = arrayOf(
+ "android.widget.",
+ "android.webkit.",
+ "android.app.",
+ null
+ )
+ override fun onCreateView(
+ parent: View?,
+ name: String,
+ context: Context,
+ attrs: AttributeSet
+ ): View? {
+ return onCreateView(name, context, attrs)
+ }
+
+ override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {
+ for (prefix in sClassPrefixList) {
+ try {
+ val view = inflater.createView(name, prefix, attrs)
+ if (view != null) {
+ if (view is WindowObserver) {
+ view.setWindow(window)
+ }
+ return view
+ }
+ } catch (e: ClassNotFoundException) { }
+ }
+ return null
+ }
+ }
+ }
+
+ override fun onStart() {
+ super.onStart()
+ actionBar?.setDisplayHomeAsUpEnabled(true)
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) {
+ onBackPressed()
+ return true
+ }
+ return super.onOptionsItemSelected(item)
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt
new file mode 100644
index 000000000000..e0a0a20bc0a0
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.silkfx.app
+
+import com.android.test.silkfx.R
+import android.os.Bundle
+import android.view.LayoutInflater
+
+const val EXTRA_LAYOUT = "layout"
+const val EXTRA_TITLE = "title"
+
+class CommonDemoActivity : BaseDemoActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val extras = intent.extras ?: return finish()
+
+ val layout = extras.getInt(EXTRA_LAYOUT, -1)
+ if (layout == -1) {
+ finish()
+ return
+ }
+ val title = extras.getString(EXTRA_TITLE, "SilkFX")
+ window.setTitle(title)
+
+ setContentView(R.layout.common_base)
+ actionBar?.title = title
+ LayoutInflater.from(this).inflate(layout, findViewById(R.id.demo_container), true)
+ }
+} \ No newline at end of file
diff --git a/tests/AutoVerify/app3/src/com/android/test/autoverify/MainActivity.java b/tests/SilkFX/src/com/android/test/silkfx/app/WindowObserver.kt
index 09ef47212622..3d989a54cf27 100644
--- a/tests/AutoVerify/app3/src/com/android/test/autoverify/MainActivity.java
+++ b/tests/SilkFX/src/com/android/test/silkfx/app/WindowObserver.kt
@@ -13,3 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+package com.android.test.silkfx.app
+
+import android.view.Window
+
+interface WindowObserver {
+ fun setWindow(window: Window)
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt b/tests/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt
new file mode 100644
index 000000000000..4b85953a24b9
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.silkfx.common
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.ColorSpace
+import android.util.AttributeSet
+import android.view.View
+
+open class BaseDrawingView : View {
+ val scRGB = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)
+ val bt2020 = ColorSpace.get(ColorSpace.Named.BT2020)
+ val lab = ColorSpace.get(ColorSpace.Named.CIE_LAB)
+
+ val density: Float
+ val dp: Int.() -> Float
+
+ fun color(red: Float, green: Float, blue: Float, alpha: Float = 1f): Long {
+ return Color.pack(red, green, blue, alpha, scRGB)
+ }
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ setWillNotDraw(false)
+ isClickable = true
+ density = resources.displayMetrics.density
+ dp = { this * density }
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
new file mode 100644
index 000000000000..b41ee3a9ef2c
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.silkfx.common
+
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.hardware.display.DisplayManager
+import android.os.IBinder
+import android.util.AttributeSet
+import android.util.Log
+import android.view.SurfaceControl
+import android.view.SurfaceControlHdrLayerInfoListener
+import android.view.Window
+import android.widget.Button
+import android.widget.LinearLayout
+import android.widget.TextView
+import com.android.test.silkfx.R
+import com.android.test.silkfx.app.WindowObserver
+
+class ColorModeControls : LinearLayout, WindowObserver {
+ private val COLOR_MODE_HDR10 = 3
+ private val SDR_WHITE_POINTS = floatArrayOf(200f, 250f, 300f, 350f, 400f, 100f, 150f)
+
+ constructor(context: Context) : this(context, null)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ displayManager = context.getSystemService(DisplayManager::class.java)!!
+ displayId = context.getDisplayId()
+ displayToken = SurfaceControl.getInternalDisplayToken()
+ }
+
+ private var window: Window? = null
+ private var currentModeDisplay: TextView? = null
+ private val displayManager: DisplayManager
+ private var targetSdrWhitePointIndex = 0
+ private var displayId: Int
+ private var displayToken: IBinder
+
+ private val whitePoint get() = SDR_WHITE_POINTS[targetSdrWhitePointIndex]
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ val window = window ?: throw IllegalStateException("Failed to attach window")
+
+ currentModeDisplay = findViewById(R.id.current_mode)!!
+ setColorMode(window.colorMode)
+
+ findViewById<Button>(R.id.mode_default)!!.setOnClickListener {
+ setColorMode(ActivityInfo.COLOR_MODE_DEFAULT)
+ }
+ findViewById<Button>(R.id.mode_wide)!!.setOnClickListener {
+ setColorMode(ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT)
+ }
+ findViewById<Button>(R.id.mode_hdr)!!.setOnClickListener {
+ setColorMode(ActivityInfo.COLOR_MODE_HDR)
+ }
+ findViewById<Button>(R.id.mode_hdr10)!!.setOnClickListener {
+ setColorMode(COLOR_MODE_HDR10)
+ }
+ }
+
+ private fun setColorMode(newMode: Int) {
+ val window = window!!
+ var sdrWhitepointChanged = false
+ // Need to do this before setting the colorMode, as setting the colorMode will
+ // trigger the attribute change listener
+ if (newMode == ActivityInfo.COLOR_MODE_HDR ||
+ newMode == COLOR_MODE_HDR10) {
+ if (window.colorMode == newMode) {
+ targetSdrWhitePointIndex = (targetSdrWhitePointIndex + 1) % SDR_WHITE_POINTS.size
+ sdrWhitepointChanged = true
+ }
+ setBrightness(1.0f)
+ } else {
+ setBrightness(.4f)
+ }
+ window.colorMode = newMode
+ if (sdrWhitepointChanged) {
+ threadedRenderer?.setColorMode(newMode, whitePoint)
+ }
+ val whitePoint = whitePoint.toInt()
+ currentModeDisplay?.run {
+ text = "Current Mode: " + when (newMode) {
+ ActivityInfo.COLOR_MODE_DEFAULT -> "Default/SRGB"
+ ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT -> "Wide Gamut"
+ ActivityInfo.COLOR_MODE_HDR -> "HDR (sdr white point $whitePoint)"
+ COLOR_MODE_HDR10 -> "HDR10 (sdr white point $whitePoint)"
+ else -> "Unknown"
+ }
+ }
+ }
+
+ override fun setWindow(window: Window) {
+ this.window = window
+ }
+
+ private fun setBrightness(level: Float) {
+ // To keep window state in sync
+ window?.attributes?.screenBrightness = level
+ invalidate()
+ // To force an 'immediate' snap to what we want
+ // Imperfect, but close enough, synchronization by waiting for frame commit to set the value
+ viewTreeObserver.registerFrameCommitCallback {
+ try {
+ SurfaceControl.setDisplayBrightness(displayToken, level)
+ displayManager.setTemporaryBrightness(displayId, level)
+ } catch (ex: Exception) {
+ // Ignore a permission denied rejection - it doesn't meaningfully change much
+ }
+ }
+ }
+
+ private val listener = object : SurfaceControlHdrLayerInfoListener() {
+ override fun onHdrInfoChanged(
+ displayToken: IBinder?,
+ numberOfHdrLayers: Int,
+ maxW: Int,
+ maxH: Int,
+ flags: Int
+ ) {
+ Log.d("HDRInfo", "onHdrInfoChanged: numLayer = $numberOfHdrLayers ($maxW x $maxH)" +
+ ", flags = $flags")
+ }
+ }
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+
+ threadedRenderer?.setColorMode(window!!.colorMode, whitePoint)
+ listener.register(displayToken)
+ }
+
+ override fun onDetachedFromWindow() {
+ super.onDetachedFromWindow()
+ listener.unregister(displayToken)
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt b/tests/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt
new file mode 100644
index 000000000000..f42161f63811
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.silkfx.common
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.ColorSpace
+import android.graphics.Paint
+import android.graphics.RectF
+import android.util.AttributeSet
+import android.view.View
+
+class HDRIndicator(context: Context) : View(context) {
+ constructor(context: Context, attrs: AttributeSet?) : this(context)
+
+ val scRGB = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+
+ val paint = Paint()
+ paint.isAntiAlias = true
+ val rect = RectF(0f, 0f, width.toFloat(), height.toFloat())
+ paint.textSize = height.toFloat()
+
+ canvas.drawColor(Color.pack(1f, 1f, 1f, 1f, scRGB))
+
+ paint.setColor(Color.pack(1.1f, 1.1f, 1.1f, 1f, scRGB))
+ canvas.drawText("H", rect.left, rect.bottom, paint)
+ paint.setColor(Color.pack(1.2f, 1.2f, 1.2f, 1f, scRGB))
+ canvas.drawText("D", rect.left + height.toFloat(), rect.bottom, paint)
+ paint.setColor(Color.pack(1.3f, 1.3f, 1.3f, 1f, scRGB))
+ canvas.drawText("R", rect.left + height.toFloat() * 2, rect.bottom, paint)
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt
new file mode 100644
index 000000000000..4ad21faec9d4
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.silkfx.hdr
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.BlendMode
+import android.graphics.Canvas
+import android.graphics.LinearGradient
+import android.graphics.Paint
+import android.graphics.Rect
+import android.graphics.Shader
+import android.graphics.drawable.BitmapDrawable
+import android.util.AttributeSet
+import com.android.test.silkfx.common.BaseDrawingView
+
+class BlingyNotification : BaseDrawingView {
+
+ private val image: Bitmap?
+ private val bounds = Rect()
+ private val paint = Paint()
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ val typed = context.obtainStyledAttributes(attrs, intArrayOf(android.R.attr.src))
+ val drawable = typed.getDrawable(0)
+ image = if (drawable is BitmapDrawable) {
+ drawable.bitmap
+ } else {
+ null
+ }
+ typed.recycle()
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ val image = image ?: return super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+
+ val widthMode = MeasureSpec.getMode(widthMeasureSpec)
+ val heightMode = MeasureSpec.getMode(heightMeasureSpec)
+
+ // Currently only used in this mode, so that's all we'll bother to support
+ if (widthMode == MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY) {
+ val width = MeasureSpec.getSize(widthMeasureSpec)
+
+ var height = image.height * width / image.width
+ if (heightMode == MeasureSpec.AT_MOST) {
+ height = minOf(MeasureSpec.getSize(heightMeasureSpec), height)
+ }
+ setMeasuredDimension(width, height)
+ } else {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ }
+ }
+
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ super.onSizeChanged(w, h, oldw, oldh)
+ bounds.set(0, 0, w, h)
+ paint.shader = LinearGradient(0f, 0f, w.toFloat(), 0f,
+ longArrayOf(
+ color(1f, 1f, 1f, 0f),
+ color(1f, 1f, 1f, .1f),
+ color(2f, 2f, 2f, .3f),
+ color(1f, 1f, 1f, .2f),
+ color(1f, 1f, 1f, 0f)
+ ),
+ floatArrayOf(.2f, .4f, .5f, .6f, .8f),
+ Shader.TileMode.CLAMP)
+ paint.blendMode = BlendMode.PLUS
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+
+ val image = image ?: return
+
+ canvas.drawBitmap(image, null, bounds, null)
+
+ canvas.save()
+ val frac = ((drawingTime % 2000) / 300f) - 1f
+ canvas.translate(width * frac, 0f)
+ canvas.rotate(-45f)
+ canvas.drawPaint(paint)
+ canvas.restore()
+ invalidate()
+ }
+} \ No newline at end of file
diff --git a/tests/AutoVerify/app2/src/com/android/test/autoverify/MainActivity.java b/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowActivity.kt
index 09ef47212622..64dbb22ace43 100644
--- a/tests/AutoVerify/app2/src/com/android/test/autoverify/MainActivity.java
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowActivity.kt
@@ -13,3 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+package com.android.test.silkfx.hdr
+
+import android.os.Bundle
+import com.android.test.silkfx.R
+import com.android.test.silkfx.app.BaseDemoActivity
+
+class GlowActivity : BaseDemoActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.hdr_glows)
+ findViewById<GlowingCard>(R.id.card2)!!.setGlowIntensity(4f)
+ }
+}
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt
new file mode 100644
index 000000000000..b388bb659685
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.silkfx.hdr
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.LinearGradient
+import android.graphics.Paint
+import android.graphics.RectF
+import android.graphics.Shader
+import android.util.AttributeSet
+import com.android.test.silkfx.common.BaseDrawingView
+
+class GlowingCard : BaseDrawingView {
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+ val radius: Float
+ var COLOR_MAXIMIZER = 1f
+
+ init {
+ radius = 10.dp()
+ }
+
+ fun setGlowIntensity(multiplier: Float) {
+ COLOR_MAXIMIZER = multiplier
+ invalidate()
+ }
+
+ override fun setPressed(pressed: Boolean) {
+ super.setPressed(pressed)
+ invalidate()
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ val paint = Paint()
+ paint.isAntiAlias = true
+ val rect = RectF(0f, 0f, width.toFloat(), height.toFloat())
+ val glowColor = Color.pack(.5f * COLOR_MAXIMIZER, .4f * COLOR_MAXIMIZER,
+ .75f * COLOR_MAXIMIZER, 1f, scRGB)
+
+ if (isPressed) {
+ paint.setColor(Color.pack(2f, 2f, 2f, 1f, scRGB))
+ paint.strokeWidth = 4.dp()
+ paint.style = Paint.Style.FILL
+ paint.shader = LinearGradient(rect.left, rect.bottom, rect.right, rect.top,
+ glowColor,
+ Color.pack(0f, 0f, 0f, 0f, scRGB),
+ Shader.TileMode.CLAMP)
+ canvas.drawRoundRect(rect, radius, radius, paint)
+ }
+
+ rect.inset(3.dp(), 3.dp())
+
+ paint.setColor(Color.pack(.14f, .14f, .14f, .8f, scRGB))
+ paint.style = Paint.Style.FILL
+ paint.shader = null
+ canvas.drawRoundRect(rect, radius, radius, paint)
+
+ rect.inset(5.dp(), 5.dp())
+ paint.textSize = 14.dp()
+ paint.isFakeBoldText = true
+
+ paint.color = Color.WHITE
+ canvas.drawText("glow = scRGB{${Color.red(glowColor)}, ${Color.green(glowColor)}, " +
+ "${Color.blue(glowColor)}}", rect.left, rect.centerY(), paint)
+ canvas.drawText("(press to activate)", rect.left, rect.bottom, paint)
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt
new file mode 100644
index 000000000000..599585e9d125
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.silkfx.hdr
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.RadialGradient
+import android.graphics.RectF
+import android.graphics.Shader
+import android.util.AttributeSet
+import com.android.test.silkfx.common.BaseDrawingView
+import kotlin.math.min
+
+class RadialGlow : BaseDrawingView {
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+ var glowToggle = false
+
+ val glowColor = color(4f, 3.3f, 2.8f)
+ val bgColor = color(.15f, .15f, .15f)
+ val fgColor = color(.51f, .52f, .50f, .4f)
+ var glow: RadialGradient
+
+ init {
+ glow = RadialGradient(0f, 0f, 100.dp(), glowColor, bgColor, Shader.TileMode.CLAMP)
+ isClickable = true
+ setOnClickListener {
+ glowToggle = !glowToggle
+ invalidate()
+ }
+ }
+
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ super.onSizeChanged(w, h, oldw, oldh)
+ glow = RadialGradient(0f, 0f,
+ min(w, h).toFloat(), glowColor, bgColor, Shader.TileMode.CLAMP)
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ val radius = 10.dp()
+
+ val paint = Paint()
+ paint.isDither = true
+ paint.isAntiAlias = true
+ paint.textSize = 18.dp()
+ paint.textAlign = Paint.Align.CENTER
+
+ val rect = RectF(0f, 0f, width.toFloat(), height.toFloat())
+
+ paint.setColor(bgColor)
+ canvas.drawRoundRect(rect, radius, radius, paint)
+
+ if (glowToggle) {
+ paint.shader = glow
+ canvas.save()
+ val frac = (drawingTime % 5000) / 5000f
+ canvas.translate(rect.width() * frac, rect.height() - (rect.height() * frac))
+ canvas.drawPaint(paint)
+ canvas.restore()
+ paint.shader = null
+ invalidate()
+ }
+
+ paint.setColor(fgColor)
+ val innerRect = RectF(rect)
+ innerRect.inset(rect.width() / 4, rect.height() / 4)
+ canvas.drawRoundRect(innerRect, radius, radius, paint)
+
+ paint.setColor(color(1f, 1f, 1f))
+ canvas.drawText("Tap to toggle animation", rect.centerX(), innerRect.top - 4.dp(), paint)
+ canvas.drawText("Outside text", rect.centerX(), rect.bottom - 4.dp(), paint)
+ canvas.drawText("Inside text", innerRect.centerX(), innerRect.bottom - 4.dp(), paint)
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt
new file mode 100644
index 000000000000..dde245ff9baf
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.silkfx.materials
+
+import android.app.Activity
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Color
+import android.os.Bundle
+import android.util.TypedValue
+import android.view.View
+import android.widget.ImageView
+import android.widget.SeekBar
+import android.widget.Switch
+import android.widget.TextView
+import com.android.test.silkfx.R
+
+class GlassActivity : Activity(), SeekBar.OnSeekBarChangeListener {
+
+ lateinit var backgroundButton1: ImageView
+ lateinit var backgroundButton2: ImageView
+ lateinit var backgroundButton3: ImageView
+ lateinit var backgroundView: ImageView
+ lateinit var materialView: GlassView
+ lateinit var lightMaterialSwitch: Switch
+ lateinit var noiseOpacitySeekBar: SeekBar
+ lateinit var materialOpacitySeekBar: SeekBar
+ lateinit var scrimOpacitySeekBar: SeekBar
+ lateinit var zoomSeekBar: SeekBar
+ lateinit var blurRadiusSeekBar: SeekBar
+ lateinit var noiseOpacityValue: TextView
+ lateinit var materialOpacityValue: TextView
+ lateinit var scrimOpacityValue: TextView
+ lateinit var blurRadiusValue: TextView
+ lateinit var zoomValue: TextView
+ lateinit var textOverlay: TextView
+
+ var background: Bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
+ set(value) {
+ field = value
+ backgroundView.setImageBitmap(background)
+ materialView.backgroundBitmap = background
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_glass)
+ backgroundButton1 = requireViewById(R.id.background1)
+ backgroundButton2 = requireViewById(R.id.background2)
+ backgroundButton3 = requireViewById(R.id.background3)
+ backgroundView = requireViewById(R.id.background)
+ lightMaterialSwitch = requireViewById(R.id.lightMaterialSwitch)
+ materialView = requireViewById(R.id.materialView)
+ materialOpacitySeekBar = requireViewById(R.id.materialOpacity)
+ blurRadiusSeekBar = requireViewById(R.id.blurRadius)
+ zoomSeekBar = requireViewById(R.id.zoom)
+ noiseOpacitySeekBar = requireViewById(R.id.noiseOpacity)
+ scrimOpacitySeekBar = requireViewById(R.id.scrimOpacity)
+ noiseOpacityValue = requireViewById(R.id.noiseOpacityValue)
+ materialOpacityValue = requireViewById(R.id.materialOpacityValue)
+ scrimOpacityValue = requireViewById(R.id.scrimOpacityValue)
+ blurRadiusValue = requireViewById(R.id.blurRadiusValue)
+ zoomValue = requireViewById(R.id.zoomValue)
+ textOverlay = requireViewById(R.id.textOverlay)
+
+ background = BitmapFactory.decodeResource(resources, R.drawable.background1)
+
+ blurRadiusSeekBar.setOnSeekBarChangeListener(this)
+ materialOpacitySeekBar.setOnSeekBarChangeListener(this)
+ noiseOpacitySeekBar.setOnSeekBarChangeListener(this)
+ scrimOpacitySeekBar.setOnSeekBarChangeListener(this)
+
+ arrayOf(blurRadiusSeekBar, materialOpacitySeekBar, noiseOpacitySeekBar,
+ scrimOpacitySeekBar, zoomSeekBar).forEach {
+ it.setOnSeekBarChangeListener(this)
+ onProgressChanged(it, it.progress, fromUser = false)
+ }
+
+ lightMaterialSwitch.setOnCheckedChangeListener { _, isChecked ->
+ materialView.color = if (isChecked) Color.WHITE else Color.BLACK
+ textOverlay.setTextColor(if (isChecked) Color.BLACK else Color.WHITE)
+ }
+ }
+
+ override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+ when (seekBar) {
+ blurRadiusSeekBar -> {
+ materialView.blurRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ progress.toFloat(), resources.displayMetrics)
+ blurRadiusValue.text = progress.toString()
+ }
+ materialOpacitySeekBar -> {
+ materialView.materialOpacity = progress / seekBar.max.toFloat()
+ materialOpacityValue.text = progress.toString()
+ }
+ noiseOpacitySeekBar -> {
+ materialView.noiseOpacity = progress / seekBar.max.toFloat()
+ noiseOpacityValue.text = progress.toString()
+ }
+ scrimOpacitySeekBar -> {
+ materialView.scrimOpacity = progress / seekBar.max.toFloat()
+ scrimOpacityValue.text = progress.toString()
+ }
+ zoomSeekBar -> {
+ materialView.zoom = progress / seekBar.max.toFloat()
+ zoomValue.text = progress.toString()
+ }
+ else -> throw IllegalArgumentException("Unknown seek bar")
+ }
+ }
+
+ override fun onStop() {
+ super.onStop()
+ materialView.resetGyroOffsets()
+ }
+
+ override fun onStartTrackingTouch(seekBar: SeekBar?) {}
+ override fun onStopTrackingTouch(seekBar: SeekBar?) {}
+
+ fun onBackgroundClick(view: View) {
+ val resource = when (view) {
+ backgroundButton1 -> R.drawable.background1
+ backgroundButton2 -> R.drawable.background2
+ backgroundButton3 -> R.drawable.background3
+ else -> throw IllegalArgumentException("Invalid button")
+ }
+
+ background = BitmapFactory.decodeResource(resources, resource)
+ }
+
+ fun onPickImageClick(view: View) {
+ val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
+ addCategory(Intent.CATEGORY_OPENABLE)
+ type = "image/*"
+ }
+ startActivityForResult(intent, 0)
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ if (resultCode === RESULT_OK) {
+ data?.data?.also {
+ contentResolver.openFileDescriptor(it, "r").let {
+ background = BitmapFactory.decodeFileDescriptor(it?.fileDescriptor)
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
new file mode 100644
index 000000000000..2f2578b87f35
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.silkfx.materials
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.BitmapShader
+import android.graphics.BlendMode
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Outline
+import android.graphics.Paint
+import android.graphics.Rect
+import android.graphics.RenderEffect
+import android.graphics.RenderNode
+import android.graphics.Shader
+import android.hardware.Sensor
+import android.hardware.SensorEvent
+import android.hardware.SensorEventListener
+import android.hardware.SensorManager
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewOutlineProvider
+import android.widget.FrameLayout
+import com.android.test.silkfx.R
+import kotlin.math.sin
+import kotlin.math.sqrt
+
+class GlassView(context: Context, attributeSet: AttributeSet) : FrameLayout(context, attributeSet) {
+
+ private val textureTranslationMultiplier = 200f
+
+ private var gyroXRotation = 0f
+ private var gyroYRotation = 0f
+
+ private var noise = BitmapFactory.decodeResource(resources, R.drawable.noise)
+ private var materialPaint = Paint()
+ private var scrimPaint = Paint()
+ private var noisePaint = Paint()
+ private var blurPaint = Paint()
+
+ private val src = Rect()
+ private val dst = Rect()
+
+ private val sensorManager = context.getSystemService(SensorManager::class.java)
+ private val sensorListener = object : SensorEventListener {
+
+ // Constant to convert nanoseconds to seconds.
+ private val NS2S = 1.0f / 1000000000.0f
+ private val EPSILON = 0.000001f
+ private var timestamp: Float = 0f
+
+ override fun onSensorChanged(event: SensorEvent?) {
+ // This timestep's delta rotation to be multiplied by the current rotation
+ // after computing it from the gyro sample data.
+ if (timestamp != 0f && event != null) {
+ val dT = (event.timestamp - timestamp) * NS2S
+ // Axis of the rotation sample, not normalized yet.
+ var axisX: Float = event.values[0]
+ var axisY: Float = event.values[1]
+ var axisZ: Float = event.values[2]
+
+ // Calculate the angular speed of the sample
+ val omegaMagnitude: Float = sqrt(axisX * axisX + axisY * axisY + axisZ * axisZ)
+
+ // Normalize the rotation vector if it's big enough to get the axis
+ // (that is, EPSILON should represent your maximum allowable margin of error)
+ if (omegaMagnitude > EPSILON) {
+ axisX /= omegaMagnitude
+ axisY /= omegaMagnitude
+ axisZ /= omegaMagnitude
+ }
+
+ // Integrate around this axis with the angular speed by the timestep
+ // in order to get a delta rotation from this sample over the timestep
+ // We will convert this axis-angle representation of the delta rotation
+ // into a quaternion before turning it into the rotation matrix.
+ val thetaOverTwo: Float = omegaMagnitude * dT / 2.0f
+ val sinThetaOverTwo: Float = sin(thetaOverTwo)
+ gyroXRotation += sinThetaOverTwo * axisX
+ gyroYRotation += sinThetaOverTwo * axisY
+
+ invalidate()
+ }
+ timestamp = event?.timestamp?.toFloat() ?: 0f
+ }
+
+ override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { }
+ }
+
+ var backgroundBitmap: Bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
+ set(value) {
+ field = value
+ invalidate()
+ }
+
+ var noiseOpacity = 0.0f
+ set(value) {
+ field = value
+ noisePaint.alpha = (value * 255).toInt()
+ invalidate()
+ }
+
+ var materialOpacity = 0.0f
+ set(value) {
+ field = value
+ materialPaint.alpha = (value * 255).toInt()
+ invalidate()
+ }
+
+ var scrimOpacity = 0.5f
+ set(value) {
+ field = value
+ scrimPaint.alpha = (value * 255).toInt()
+ invalidate()
+ }
+
+ var zoom = 0.0f
+ set(value) {
+ field = value
+ invalidate()
+ }
+
+ var color = Color.BLACK
+ set(value) {
+ field = value
+ var alpha = materialPaint.alpha
+ materialPaint.color = color
+ materialPaint.alpha = alpha
+
+ alpha = scrimPaint.alpha
+ scrimPaint.color = color
+ scrimPaint.alpha = alpha
+ invalidate()
+ }
+
+ var blurRadius = 150f
+ set(value) {
+ field = value
+ renderNode.setRenderEffect(
+ RenderEffect.createBlurEffect(value, value, Shader.TileMode.CLAMP))
+ invalidate()
+ }
+
+ private var renderNodeIsDirty = true
+ private val renderNode = RenderNode("GlassRenderNode")
+
+ override fun invalidate() {
+ renderNodeIsDirty = true
+ super.invalidate()
+ }
+
+ init {
+ setWillNotDraw(false)
+ materialPaint.blendMode = BlendMode.SOFT_LIGHT
+ noisePaint.blendMode = BlendMode.SOFT_LIGHT
+ noisePaint.shader = BitmapShader(noise, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT)
+ scrimPaint.alpha = (scrimOpacity * 255).toInt()
+ noisePaint.alpha = (noiseOpacity * 255).toInt()
+ materialPaint.alpha = (materialOpacity * 255).toInt()
+ outlineProvider = object : ViewOutlineProvider() {
+ override fun getOutline(view: View?, outline: Outline?) {
+ outline?.setRoundRect(Rect(0, 0, width, height), 100f)
+ }
+ }
+ clipToOutline = true
+ }
+
+ override fun onAttachedToWindow() {
+ sensorManager?.getSensorList(Sensor.TYPE_GYROSCOPE)?.firstOrNull().let {
+ sensorManager?.registerListener(sensorListener, it, SensorManager.SENSOR_DELAY_GAME)
+ }
+ }
+
+ override fun onDetachedFromWindow() {
+ sensorManager?.unregisterListener(sensorListener)
+ }
+
+ override fun onDraw(canvas: Canvas?) {
+ updateGlassRenderNode()
+ canvas?.drawRenderNode(renderNode)
+ }
+
+ fun resetGyroOffsets() {
+ gyroXRotation = 0f
+ gyroYRotation = 0f
+ invalidate()
+ }
+
+ private fun updateGlassRenderNode() {
+ if (renderNodeIsDirty) {
+ renderNode.setPosition(0, 0, getWidth(), getHeight())
+
+ val canvas = renderNode.beginRecording()
+
+ src.set(-width / 2, -height / 2, width / 2, height / 2)
+ src.scale(1.0f + zoom)
+ val centerX = left + width / 2
+ val centerY = top + height / 2
+ val textureXOffset = (textureTranslationMultiplier * gyroYRotation).toInt()
+ val textureYOffset = (textureTranslationMultiplier * gyroXRotation).toInt()
+ src.set(src.left + centerX + textureXOffset, src.top + centerY + textureYOffset,
+ src.right + centerX + textureXOffset, src.bottom + centerY + textureYOffset)
+
+ dst.set(0, 0, width, height)
+ canvas.drawBitmap(backgroundBitmap, src, dst, blurPaint)
+ canvas.drawRect(dst, materialPaint)
+ canvas.drawRect(dst, noisePaint)
+ canvas.drawRect(dst, scrimPaint)
+
+ renderNode.endRecording()
+
+ renderNodeIsDirty = false
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/SmokeTest/Android.bp b/tests/SmokeTest/Android.bp
index bc45ee6799b4..4c853e3c5267 100644
--- a/tests/SmokeTest/Android.bp
+++ b/tests/SmokeTest/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "SmokeTestApp",
// This builds "SmokeTestApp"
diff --git a/tests/SmokeTest/AndroidManifest.xml b/tests/SmokeTest/AndroidManifest.xml
index f141bdcc704f..57f0431ad2e3 100644
--- a/tests/SmokeTest/AndroidManifest.xml
+++ b/tests/SmokeTest/AndroidManifest.xml
@@ -15,18 +15,19 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.smoketest">
+ package="com.android.smoketest">
<application>
- <uses-library android:name="android.test.runner" />
- <activity android:name=".SmokeTestActivity"
- android:label="Smoke Tests">
+ <uses-library android:name="android.test.runner"/>
+ <activity android:name=".SmokeTestActivity"
+ android:label="Smoke Tests"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.TEST"/>
</intent-filter>
</activity>
</application>
-
+
</manifest>
diff --git a/tests/SmokeTest/tests/Android.bp b/tests/SmokeTest/tests/Android.bp
index ceb2d193de79..5542dd0119ea 100644
--- a/tests/SmokeTest/tests/Android.bp
+++ b/tests/SmokeTest/tests/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "SmokeTest",
// Include all test java files.
diff --git a/tests/SmokeTestApps/Android.bp b/tests/SmokeTestApps/Android.bp
index 0feb00040eac..3505fe1c4afb 100644
--- a/tests/SmokeTestApps/Android.bp
+++ b/tests/SmokeTestApps/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "SmokeTestTriggerApps",
srcs: ["src/**/*.java"],
diff --git a/tests/SmokeTestApps/AndroidManifest.xml b/tests/SmokeTestApps/AndroidManifest.xml
index 0f20107f60d1..89e63b1a4198 100644
--- a/tests/SmokeTestApps/AndroidManifest.xml
+++ b/tests/SmokeTestApps/AndroidManifest.xml
@@ -15,30 +15,33 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.smoketest.triggers">
+ package="com.android.smoketest.triggers">
<application android:label="something">
<activity android:name=".CrashyApp"
- android:label="Test Crashy App">
+ android:label="Test Crashy App"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".CrashyApp2"
- android:label="Test Crashy App2">
+ android:label="Test Crashy App2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".UnresponsiveApp"
- android:label="Test Unresponsive App">
+ android:label="Test Unresponsive App"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/SoundTriggerTestApp/Android.bp b/tests/SoundTriggerTestApp/Android.bp
index d3a1300b8e12..09f1e10561e3 100644
--- a/tests/SoundTriggerTestApp/Android.bp
+++ b/tests/SoundTriggerTestApp/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_app {
name: "SoundTriggerTestApp",
srcs: ["**/*.java"],
diff --git a/tests/SoundTriggerTestApp/AndroidManifest.xml b/tests/SoundTriggerTestApp/AndroidManifest.xml
index 87f3e92b3a60..587a25dd71bc 100644
--- a/tests/SoundTriggerTestApp/AndroidManifest.xml
+++ b/tests/SoundTriggerTestApp/AndroidManifest.xml
@@ -1,27 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.soundtrigger">
- <uses-permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD" />
- <uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER" />
- <uses-permission android:name="android.permission.RECORD_AUDIO" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
+ package="com.android.test.soundtrigger">
+ <uses-permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD"/>
+ <uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER"/>
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
<application>
- <activity
- android:name=".SoundTriggerTestActivity"
- android:label="SoundTrigger Test Application"
- android:screenOrientation="portrait"
- android:theme="@android:style/Theme.Material">
+ <activity android:name=".SoundTriggerTestActivity"
+ android:label="SoundTrigger Test Application"
+ android:screenOrientation="portrait"
+ android:theme="@android:style/Theme.Material"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <service
- android:name=".SoundTriggerTestService"
- android:stopWithTask="false"
- android:exported="true">
+ <service android:name=".SoundTriggerTestService"
+ android:stopWithTask="false"
+ android:exported="true">
<intent-filter>
- <action android:name="com.android.intent.action.MANAGE_SOUND_TRIGGER" />
+ <action android:name="com.android.intent.action.MANAGE_SOUND_TRIGGER"/>
</intent-filter>
</service>
</application>
diff --git a/tests/SoundTriggerTestApp/OWNERS b/tests/SoundTriggerTestApp/OWNERS
new file mode 100644
index 000000000000..816bc6bba639
--- /dev/null
+++ b/tests/SoundTriggerTestApp/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/media/soundtrigger/OWNERS
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
index 9324ba0b8b72..380e29984c63 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
@@ -23,7 +23,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
-import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
@@ -31,6 +30,7 @@ import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaPlayer;
import android.media.soundtrigger.SoundTriggerDetector;
+import android.media.soundtrigger.SoundTriggerManager;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
@@ -232,8 +232,8 @@ public class SoundTriggerTestService extends Service {
public AudioTrack captureAudioTrack;
}
- private GenericSoundModel createNewSoundModel(ModelInfo modelInfo) {
- return new GenericSoundModel(modelInfo.modelUuid, modelInfo.vendorUuid,
+ private SoundTriggerManager.Model createNewSoundModel(ModelInfo modelInfo) {
+ return SoundTriggerManager.Model.create(modelInfo.modelUuid, modelInfo.vendorUuid,
modelInfo.modelData);
}
@@ -246,16 +246,16 @@ public class SoundTriggerTestService extends Service {
postMessage("Loading model: " + modelInfo.name);
- GenericSoundModel soundModel = createNewSoundModel(modelInfo);
+ SoundTriggerManager.Model soundModel = createNewSoundModel(modelInfo);
boolean status = mSoundTriggerUtil.addOrUpdateSoundModel(soundModel);
if (status) {
postToast("Successfully loaded " + modelInfo.name + ", UUID="
- + soundModel.getUuid());
+ + soundModel.getModelUuid());
setModelState(modelInfo, "Loaded");
} else {
postErrorToast("Failed to load " + modelInfo.name + ", UUID="
- + soundModel.getUuid() + "!");
+ + soundModel.getModelUuid() + "!");
setModelState(modelInfo, "Failed to load");
}
}
@@ -269,7 +269,7 @@ public class SoundTriggerTestService extends Service {
postMessage("Unloading model: " + modelInfo.name);
- GenericSoundModel soundModel = mSoundTriggerUtil.getSoundModel(modelUuid);
+ SoundTriggerManager.Model soundModel = mSoundTriggerUtil.getSoundModel(modelUuid);
if (soundModel == null) {
postErrorToast("Sound model not found for " + modelInfo.name + "!");
return;
@@ -278,11 +278,11 @@ public class SoundTriggerTestService extends Service {
boolean status = mSoundTriggerUtil.deleteSoundModel(modelUuid);
if (status) {
postToast("Successfully unloaded " + modelInfo.name + ", UUID="
- + soundModel.getUuid());
+ + soundModel.getModelUuid());
setModelState(modelInfo, "Unloaded");
} else {
postErrorToast("Failed to unload " +
- modelInfo.name + ", UUID=" + soundModel.getUuid() + "!");
+ modelInfo.name + ", UUID=" + soundModel.getModelUuid() + "!");
setModelState(modelInfo, "Failed to unload");
}
}
@@ -294,12 +294,12 @@ public class SoundTriggerTestService extends Service {
return;
}
postMessage("Reloading model: " + modelInfo.name);
- GenericSoundModel soundModel = mSoundTriggerUtil.getSoundModel(modelUuid);
+ SoundTriggerManager.Model soundModel = mSoundTriggerUtil.getSoundModel(modelUuid);
if (soundModel == null) {
postErrorToast("Sound model not found for " + modelInfo.name + "!");
return;
}
- GenericSoundModel updated = createNewSoundModel(modelInfo);
+ SoundTriggerManager.Model updated = createNewSoundModel(modelInfo);
boolean status = mSoundTriggerUtil.addOrUpdateSoundModel(updated);
if (status) {
postToast("Successfully reloaded " + modelInfo.name + ", UUID="
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
index 6b89b62bb1e3..cfe8c855ac81 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
@@ -18,7 +18,6 @@ package com.android.test.soundtrigger;
import android.annotation.Nullable;
import android.content.Context;
-import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
import android.media.soundtrigger.SoundTriggerDetector;
import android.media.soundtrigger.SoundTriggerManager;
import android.os.RemoteException;
@@ -37,13 +36,10 @@ import java.util.UUID;
public class SoundTriggerUtil {
private static final String TAG = "SoundTriggerTestUtil";
- private final ISoundTriggerService mSoundTriggerService;
private final SoundTriggerManager mSoundTriggerManager;
private final Context mContext;
public SoundTriggerUtil(Context context) {
- mSoundTriggerService = ISoundTriggerService.Stub.asInterface(
- ServiceManager.getService(Context.SOUND_TRIGGER_SERVICE));
mSoundTriggerManager = (SoundTriggerManager) context.getSystemService(
Context.SOUND_TRIGGER_SERVICE);
mContext = context;
@@ -55,15 +51,11 @@ public class SoundTriggerUtil {
*
* @param soundModel The sound model to add/update.
*/
- public boolean addOrUpdateSoundModel(GenericSoundModel soundModel) {
- try {
- if (soundModel == null) {
- throw new RuntimeException("Bad sound model");
- }
- mSoundTriggerService.updateSoundModel(soundModel);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in updateSoundModel", e);
+ public boolean addOrUpdateSoundModel(SoundTriggerManager.Model soundModel) {
+ if (soundModel == null) {
+ throw new RuntimeException("Bad sound model");
}
+ mSoundTriggerManager.updateModel(soundModel);
return true;
}
@@ -71,19 +63,15 @@ public class SoundTriggerUtil {
* Gets the sound model for the given keyphrase, null if none exists.
* If a sound model for a given keyphrase exists, and it needs to be updated,
* it should be obtained using this method, updated and then passed in to
- * {@link #addOrUpdateSoundModel(GenericSoundModel)} without changing the IDs.
+ * {@link #addOrUpdateSoundModel(SoundTriggerManager.Model)} without changing the IDs.
*
* @param modelId The model ID to look-up the sound model for.
* @return The sound model if one was found, null otherwise.
*/
@Nullable
- public GenericSoundModel getSoundModel(UUID modelId) {
- GenericSoundModel model = null;
- try {
- model = mSoundTriggerService.getSoundModel(new ParcelUuid(modelId));
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in updateKeyphraseSoundModel");
- }
+ public SoundTriggerManager.Model getSoundModel(UUID modelId) {
+ SoundTriggerManager.Model model = null;
+ model = mSoundTriggerManager.getModel(modelId);
if (model == null) {
Log.w(TAG, "No models present for the given keyphrase ID");
@@ -100,12 +88,7 @@ public class SoundTriggerUtil {
* @return {@code true} if the call succeeds, {@code false} otherwise.
*/
public boolean deleteSoundModel(UUID modelId) {
- try {
- mSoundTriggerService.deleteSoundModel(new ParcelUuid(modelId));
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in deleteSoundModel");
- return false;
- }
+ mSoundTriggerManager.deleteModel(modelId);
return true;
}
diff --git a/tests/SoundTriggerTests/Android.mk b/tests/SoundTriggerTests/Android.mk
index 204a74eed882..cc0fa1cd0840 100644
--- a/tests/SoundTriggerTests/Android.mk
+++ b/tests/SoundTriggerTests/Android.mk
@@ -31,6 +31,9 @@ LOCAL_STATIC_JAVA_LIBRARIES := mockito-target
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_PACKAGE_NAME := SoundTriggerTests
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)
diff --git a/tests/SoundTriggerTests/OWNERS b/tests/SoundTriggerTests/OWNERS
new file mode 100644
index 000000000000..816bc6bba639
--- /dev/null
+++ b/tests/SoundTriggerTests/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/media/soundtrigger/OWNERS
diff --git a/tests/Split/Android.bp b/tests/Split/Android.bp
index d8c89bab2857..727b2026461c 100644
--- a/tests/Split/Android.bp
+++ b/tests/Split/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "Split",
srcs: ["**/*.java"],
diff --git a/tests/Split/AndroidManifest.xml b/tests/Split/AndroidManifest.xml
index 0de8344077f6..e0365273107e 100644
--- a/tests/Split/AndroidManifest.xml
+++ b/tests/Split/AndroidManifest.xml
@@ -15,13 +15,14 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.example.split">
+ package="com.android.example.split">
<application android:label="@string/app_title"
- android:icon="@mipmap/ic_app">
- <activity android:name="ActivityMain">
+ android:icon="@mipmap/ic_app">
+ <activity android:name="ActivityMain"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index c3fdd695c2b7..cac14a72a706 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -12,20 +12,53 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test_helper_app {
name: "StagedInstallInternalTestApp",
manifest: "app/AndroidManifest.xml",
srcs: ["app/src/**/*.java"],
- static_libs: ["androidx.test.rules", "cts-install-lib"],
+ static_libs: [
+ "androidx.test.rules",
+ "cts-install-lib",
+ ],
test_suites: ["general-tests"],
+ java_resources: [
+ ":com.android.apex.apkrollback.test_v2",
+ ":StagedInstallTestApexV2",
+ ":StagedInstallTestApexV2_WrongSha",
+ ":test.rebootless_apex_v1",
+ ":test.rebootless_apex_v2",
+ ],
}
java_test_host {
name: "StagedInstallInternalTest",
srcs: ["src/**/*.java"],
- libs: ["tradefed"],
- static_libs: ["testng", "compatibility-tradefed"],
+ libs: [
+ "tradefed",
+ "cts-shim-host-lib",
+ ],
+ static_libs: [
+ "testng",
+ "compatibility-tradefed",
+ "frameworks-base-hostutils",
+ "cts-install-lib-host",
+ ],
+ data: [
+ ":com.android.apex.apkrollback.test_v1",
+ ":com.android.apex.cts.shim.v2_prebuilt",
+ ":StagedInstallTestApexV2_WrongSha",
+ ":TestAppAv1",
+ ":test.rebootless_apex_v1",
+ ],
test_suites: ["general-tests"],
test_config: "StagedInstallInternalTest.xml",
}
-
diff --git a/tests/StagedInstallTest/OWNERS b/tests/StagedInstallTest/OWNERS
new file mode 100644
index 000000000000..aac68e994a39
--- /dev/null
+++ b/tests/StagedInstallTest/OWNERS
@@ -0,0 +1,5 @@
+include /services/core/java/com/android/server/pm/OWNERS
+
+dariofreni@google.com
+ioffe@google.com
+olilan@google.com
diff --git a/tests/StagedInstallTest/StagedInstallInternalTest.xml b/tests/StagedInstallTest/StagedInstallInternalTest.xml
index 1b8fa672fe38..1f22cae8f3cf 100644
--- a/tests/StagedInstallTest/StagedInstallInternalTest.xml
+++ b/tests/StagedInstallTest/StagedInstallInternalTest.xml
@@ -15,7 +15,7 @@
~ limitations under the License.
-->
<configuration description="Runs the internal staged install tests">
- <option name="test-suite-tag" value="StagedInstallTest" />
+ <option name="test-suite-tag" value="StagedInstallInternalTest" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="StagedInstallInternalTestApp.apk" />
diff --git a/tests/StagedInstallTest/TEST_MAPPING b/tests/StagedInstallTest/TEST_MAPPING
index 5a7a5a766b88..cc31f2c98425 100644
--- a/tests/StagedInstallTest/TEST_MAPPING
+++ b/tests/StagedInstallTest/TEST_MAPPING
@@ -1,5 +1,15 @@
{
- "presubmit": [
+ "presubmit-large": [
+ {
+ "name": "StagedInstallInternalTest",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
{
"name": "StagedInstallInternalTest"
}
diff --git a/tests/StagedInstallTest/app/AndroidManifest.xml b/tests/StagedInstallTest/app/AndroidManifest.xml
index a678f1ec3691..d7ac9d0f9ce4 100644
--- a/tests/StagedInstallTest/app/AndroidManifest.xml
+++ b/tests/StagedInstallTest/app/AndroidManifest.xml
@@ -20,8 +20,6 @@
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<application>
- <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
- android:exported="true" />
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index e67354982b05..4684f0182d03 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -17,12 +17,16 @@
package com.android.tests.stagedinstallinternal;
import static com.android.cts.install.lib.InstallUtils.getPackageInstaller;
+import static com.android.cts.shim.lib.ShimPackage.SHIM_APEX_PACKAGE_NAME;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import android.Manifest;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -47,8 +51,15 @@ import java.util.function.Consumer;
@RunWith(JUnit4.class)
public class StagedInstallInternalTest {
-
- private static final String TAG = StagedInstallInternalTest.class.getSimpleName();
+ private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
+ private static final TestApp TEST_APEX_WITH_APK_V2 = new TestApp("TestApexWithApkV2",
+ APK_IN_APEX_TESTAPEX_NAME, 2, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v2.apex");
+ private static final TestApp APEX_WRONG_SHA_V2 = new TestApp(
+ "ApexWrongSha2", SHIM_APEX_PACKAGE_NAME, 2, /* isApex= */ true,
+ "com.android.apex.cts.shim.v2_wrong_sha.apex");
+ private static final TestApp APEX_V2 = new TestApp(
+ "ApexV2", SHIM_APEX_PACKAGE_NAME, 2, /* isApex= */ true,
+ "com.android.apex.cts.shim.v2.apex");
private File mTestStateFile = new File(
InstrumentationRegistry.getInstrumentation().getContext().getFilesDir(),
@@ -82,6 +93,24 @@ public class StagedInstallInternalTest {
}
@Test
+ public void testDuplicateApkInApexShouldFail_Commit() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ // Duplicate packages(TestApp.A) in TEST_APEX_WITH_APK_V2(apk-in-apex) and TestApp.A2(apk)
+ // should fail to install.
+ int sessionId = Install.multi(TEST_APEX_WITH_APK_V2, TestApp.A2).setStaged().commit();
+ storeSessionId(sessionId);
+ }
+
+ @Test
+ public void testDuplicateApkInApexShouldFail_Verify() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ int sessionId = retrieveLastSessionId();
+ PackageInstaller.SessionInfo info =
+ InstallUtils.getPackageInstaller().getSessionInfo(sessionId);
+ assertThat(info.isStagedSessionFailed()).isTrue();
+ }
+
+ @Test
public void testSystemServerRestartDoesNotAffectStagedSessions_Commit() throws Exception {
int sessionId = Install.single(TestApp.A1).setStaged().commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
@@ -97,6 +126,38 @@ public class StagedInstallInternalTest {
}
@Test
+ public void testAbandonStagedSessionShouldCleanUp() throws Exception {
+ int id1 = Install.single(TestApp.A1).setStaged().createSession();
+ InstallUtils.getPackageInstaller().abandonSession(id1);
+ int id2 = Install.multi(TestApp.A1).setStaged().createSession();
+ InstallUtils.getPackageInstaller().abandonSession(id2);
+ int id3 = Install.single(TestApp.A1).setStaged().commit();
+ InstallUtils.getPackageInstaller().abandonSession(id3);
+ int id4 = Install.multi(TestApp.A1).setStaged().commit();
+ InstallUtils.getPackageInstaller().abandonSession(id4);
+ }
+
+ @Test
+ public void testStagedSessionShouldCleanUpOnVerificationFailure() throws Exception {
+ InstallUtils.commitExpectingFailure(AssertionError.class, "apexd verification failed",
+ Install.single(APEX_WRONG_SHA_V2).setStaged());
+ }
+
+ @Test
+ public void testStagedSessionShouldCleanUpOnOnSuccess_Commit() throws Exception {
+ int sessionId = Install.single(TestApp.A1).setStaged().commit();
+ storeSessionId(sessionId);
+ }
+
+ @Test
+ public void testStagedSessionShouldCleanUpOnOnSuccess_Verify() throws Exception {
+ int sessionId = retrieveLastSessionId();
+ PackageInstaller.SessionInfo info = InstallUtils.getStagedSessionInfo(sessionId);
+ assertThat(info).isNotNull();
+ assertThat(info.isStagedSessionApplied()).isTrue();
+ }
+
+ @Test
public void testStagedInstallationShouldCleanUpOnValidationFailure() throws Exception {
InstallUtils.commitExpectingFailure(AssertionError.class, "INSTALL_FAILED_INVALID_APK",
Install.single(TestApp.AIncompleteSplit).setStaged());
@@ -109,6 +170,259 @@ public class StagedInstallInternalTest {
Install.multi(TestApp.AIncompleteSplit, TestApp.B1, TestApp.Apex1).setStaged());
}
+ @Test
+ public void testFailStagedSessionIfStagingDirectoryDeleted_Commit() throws Exception {
+ int sessionId = Install.multi(TestApp.A1, TestApp.Apex1).setStaged().commit();
+ assertSessionReady(sessionId);
+ storeSessionId(sessionId);
+ }
+
+ @Test
+ public void testFailStagedSessionIfStagingDirectoryDeleted_Verify() throws Exception {
+ int sessionId = retrieveLastSessionId();
+ PackageInstaller.SessionInfo info =
+ InstallUtils.getPackageInstaller().getSessionInfo(sessionId);
+ assertThat(info.isStagedSessionFailed()).isTrue();
+ }
+
+ @Test
+ public void testApexActivationFailureIsCapturedInSession_Commit() throws Exception {
+ int sessionId = Install.single(TestApp.Apex1).setStaged().commit();
+ assertSessionReady(sessionId);
+ storeSessionId(sessionId);
+ }
+
+ @Test
+ public void testApexActivationFailureIsCapturedInSession_Verify() throws Exception {
+ int sessionId = retrieveLastSessionId();
+ assertSessionFailedWithMessage(sessionId, "has unexpected SHA512 hash");
+ }
+
+ @Test
+ public void testActiveApexIsRevertedOnCheckpointRollback_Prepare() throws Exception {
+ int sessionId = Install.single(TestApp.Apex2).setStaged().commit();
+ assertSessionReady(sessionId);
+ storeSessionId(sessionId);
+ }
+
+ @Test
+ public void testActiveApexIsRevertedOnCheckpointRollback_Commit() throws Exception {
+ // Verify apex installed during preparation was successful
+ int sessionId = retrieveLastSessionId();
+ assertSessionApplied(sessionId);
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(2);
+ // Commit a new staged session
+ sessionId = Install.single(TestApp.Apex3).setStaged().commit();
+ assertSessionReady(sessionId);
+ storeSessionId(sessionId);
+ }
+
+ @Test
+ public void testActiveApexIsRevertedOnCheckpointRollback_VerifyPostReboot() throws Exception {
+ int sessionId = retrieveLastSessionId();
+ assertSessionFailed(sessionId);
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(2);
+ }
+
+ @Test
+ public void testApexIsNotActivatedIfNotInCheckpointMode_Commit() throws Exception {
+ int sessionId = Install.single(TestApp.Apex2).setStaged().commit();
+ assertSessionReady(sessionId);
+ storeSessionId(sessionId);
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+ }
+
+ @Test
+ public void testApexIsNotActivatedIfNotInCheckpointMode_VerifyPostReboot() throws Exception {
+ int sessionId = retrieveLastSessionId();
+ assertSessionFailed(sessionId);
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+ }
+
+ @Test
+ public void testApexInstallerNotInAllowListCanNotInstall_staged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+ // We don't really care which APEX we are trying to install here, since the session creation
+ // should fail immediately.
+ InstallUtils.commitExpectingFailure(
+ SecurityException.class,
+ "Installer not allowed to commit staged install",
+ Install.single(APEX_WRONG_SHA_V2).setBypassStangedInstallerCheck(false)
+ .setStaged());
+ }
+
+ @Test
+ public void testApexInstallerNotInAllowListCanNotInstall_nonStaged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+ // We don't really care which APEX we are trying to install here, since the session creation
+ // should fail immediately.
+ InstallUtils.commitExpectingFailure(
+ SecurityException.class,
+ "Installer not allowed to commit non-staged APEX install",
+ Install.single(APEX_WRONG_SHA_V2).setBypassStangedInstallerCheck(false));
+ }
+
+ @Test
+ public void testApexNotInAllowListCanNotInstall_staged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Update of APEX package test.apex.rebootless is not allowed "
+ + "for com.android.tests.stagedinstallinternal",
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
+ }
+
+ @Test
+ public void testApexNotInAllowListCanNotInstall_nonStaged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Update of APEX package test.apex.rebootless is not allowed "
+ + "for com.android.tests.stagedinstallinternal",
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false));
+ }
+
+ @Test
+ public void testVendorApexWrongInstaller_staged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Update of APEX package test.apex.rebootless is not allowed "
+ + "for com.android.tests.stagedinstallinternal",
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
+ }
+
+ @Test
+ public void testVendorApexWrongInstaller_nonStaged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Update of APEX package test.apex.rebootless is not allowed "
+ + "for com.android.tests.stagedinstallinternal",
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false));
+ }
+
+ @Test
+ public void testVendorApexCorrectInstaller_staged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ int sessionId =
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged().commit();
+ InstallUtils.getPackageInstaller().abandonSession(sessionId);
+ }
+
+ @Test
+ public void testVendorApexCorrectInstaller_nonStaged() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
+ TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ Install.single(apex).setBypassAllowedApexUpdateCheck(false).commit();
+ assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(2);
+ }
+
+ @Test
+ public void testRebootlessUpdates() throws Exception {
+ InstallUtils.dropShellPermissionIdentity();
+ InstallUtils.adoptShellPermissionIdentity(Manifest.permission.INSTALL_PACKAGE_UPDATES);
+
+ final PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
+ {
+ PackageInfo apex = pm.getPackageInfo("test.apex.rebootless", PackageManager.MATCH_APEX);
+ assertThat(apex.getLongVersionCode()).isEqualTo(1);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+ .isEqualTo(ApplicationInfo.FLAG_SYSTEM);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
+ .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
+ assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex");
+ }
+
+ TestApp apex1 = new TestApp("TestRebootlessApexV1", "test.apex.rebootless", 1,
+ /* isApex= */ true, "test.rebootless_apex_v1.apex");
+ Install.single(apex1).commit();
+
+ {
+ PackageInfo apex = pm.getPackageInfo("test.apex.rebootless", PackageManager.MATCH_APEX);
+ assertThat(apex.getLongVersionCode()).isEqualTo(1);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
+ .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
+ assertThat(apex.applicationInfo.sourceDir).startsWith("/data/apex/active");
+ }
+ {
+ PackageInfo apex = pm.getPackageInfo("test.apex.rebootless",
+ PackageManager.MATCH_APEX | PackageManager.MATCH_FACTORY_ONLY);
+ assertThat(apex.getLongVersionCode()).isEqualTo(1);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+ .isEqualTo(ApplicationInfo.FLAG_SYSTEM);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0);
+ assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex");
+ }
+
+ TestApp apex2 = new TestApp("TestRebootlessApexV1", "test.apex.rebootless", 2,
+ /* isApex= */ true, "test.rebootless_apex_v2.apex");
+ Install.single(apex2).commit();
+
+ {
+ PackageInfo apex = pm.getPackageInfo("test.apex.rebootless", PackageManager.MATCH_APEX);
+ assertThat(apex.getLongVersionCode()).isEqualTo(2);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
+ .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
+ assertThat(apex.applicationInfo.sourceDir).startsWith("/data/apex/active");
+ }
+ {
+ PackageInfo apex = pm.getPackageInfo("test.apex.rebootless",
+ PackageManager.MATCH_APEX | PackageManager.MATCH_FACTORY_ONLY);
+ assertThat(apex.getLongVersionCode()).isEqualTo(1);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+ .isEqualTo(ApplicationInfo.FLAG_SYSTEM);
+ assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0);
+ assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex");
+ }
+ }
+
+ @Test
+ public void testRebootlessUpdate_hasStagedSessionWithSameApex_fails() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+
+ int sessionId = Install.single(APEX_V2).setStaged().commit();
+ assertSessionReady(sessionId);
+ InstallUtils.commitExpectingFailure(
+ AssertionError.class,
+ "Staged session " + sessionId + " already contains " + SHIM_APEX_PACKAGE_NAME,
+ Install.single(APEX_V2));
+
+ }
+
+ private static void assertSessionApplied(int sessionId) {
+ assertSessionState(sessionId, (session) -> {
+ assertThat(session.isStagedSessionApplied()).isTrue();
+ });
+ }
+
+ private static void assertSessionFailed(int sessionId) {
+ assertSessionState(sessionId, (session) -> {
+ assertThat(session.isStagedSessionFailed()).isTrue();
+ });
+ }
+
+ private static void assertSessionFailedWithMessage(int sessionId, String msg) {
+ assertSessionState(sessionId, (session) -> {
+ assertThat(session.isStagedSessionFailed()).isTrue();
+ assertThat(session.getStagedSessionErrorMessage()).contains(msg);
+ });
+ }
+
private static void assertSessionReady(int sessionId) {
assertSessionState(sessionId,
(session) -> assertThat(session.isStagedSessionReady()).isTrue());
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index 28a5424199a4..5021009f65ae 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -16,22 +16,36 @@
package com.android.tests.stagedinstallinternal.host;
+import static com.android.cts.shim.lib.ShimPackage.SHIM_APEX_PACKAGE_NAME;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import android.cts.install.lib.host.InstallUtilsHost;
+import android.platform.test.annotations.LargeTest;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.Log;
+import com.android.tests.rollback.host.AbandonSessionsRule;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
import com.android.tradefed.util.ProcessInfo;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.Collections;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
import java.util.List;
import java.util.stream.Collectors;
@@ -40,7 +54,18 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
private static final String TAG = StagedInstallInternalTest.class.getSimpleName();
private static final long SYSTEM_SERVER_TIMEOUT_MS = 60 * 1000;
- private boolean mWasRoot = false;
+
+ @Rule
+ public AbandonSessionsRule mHostTestRule = new AbandonSessionsRule(this);
+ private static final String SHIM_V2 = "com.android.apex.cts.shim.v2.apex";
+ private static final String APEX_WRONG_SHA = "com.android.apex.cts.shim.v2_wrong_sha.apex";
+ private static final String APK_A = "TestAppAv1.apk";
+ private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
+
+ private static final String TEST_VENDOR_APEX_ALLOW_LIST =
+ "/vendor/etc/sysconfig/test-vendor-apex-allow-list.xml";
+
+ private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this);
/**
* Runs the given phase of a test by calling into the device.
@@ -63,28 +88,91 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
} catch (AssertionError e) {
Log.e(TAG, e);
}
+ deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
+ "/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
+ "/data/apex/active/" + SHIM_APEX_PACKAGE_NAME + "*.apex",
+ "/system/apex/test.rebootless_apex_v1.apex",
+ "/data/apex/active/test.apex.rebootless*.apex",
+ TEST_VENDOR_APEX_ALLOW_LIST);
}
@Before
public void setUp() throws Exception {
- mWasRoot = getDevice().isAdbRoot();
- if (!mWasRoot) {
- getDevice().enableAdbRoot();
- }
cleanUp();
- // Abandon all staged sessions
- getDevice().executeShellCommand("pm install-abandon $(pm get-stagedsessions --only-ready "
- + "--only-parent --only-sessionid)");
}
@After
public void tearDown() throws Exception {
- if (!mWasRoot) {
- getDevice().disableAdbRoot();
- }
cleanUp();
}
+ /**
+ * Deletes files and reboots the device if necessary.
+ * @param files the paths of files which might contain wildcards
+ */
+ private void deleteFiles(String... files) throws Exception {
+ boolean found = false;
+ for (String file : files) {
+ CommandResult result = getDevice().executeShellV2Command("ls " + file);
+ if (result.getStatus() == CommandStatus.SUCCESS) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ if (!getDevice().isAdbRoot()) {
+ getDevice().enableAdbRoot();
+ }
+ getDevice().remountSystemWritable();
+ for (String file : files) {
+ getDevice().executeShellCommand("rm -rf " + file);
+ }
+ getDevice().reboot();
+ }
+ }
+
+ private void pushTestApex(String fileName) throws Exception {
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
+ final File apex = buildHelper.getTestFile(fileName);
+ if (!getDevice().isAdbRoot()) {
+ getDevice().enableAdbRoot();
+ }
+ getDevice().remountSystemWritable();
+ assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName));
+ }
+
+ private void pushTestVendorApexAllowList(String installerPackageName) throws Exception {
+ if (!getDevice().isAdbRoot()) {
+ getDevice().enableAdbRoot();
+ }
+ getDevice().remountSystemWritable();
+ File file = File.createTempFile("test-vendor-apex-allow-list", ".xml");
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
+ final String fmt =
+ "<config>\n"
+ + " <allowed-vendor-apex package=\"test.apex.rebootless\" "
+ + " installerPackage=\"%s\" />\n"
+ + "</config>";
+ writer.write(String.format(fmt, installerPackageName));
+ }
+ getDevice().pushFile(file, TEST_VENDOR_APEX_ALLOW_LIST);
+ }
+
+ /**
+ * Tests that duplicate packages in apk-in-apex and apk should fail to install.
+ */
+ @Test
+ @LargeTest
+ public void testDuplicateApkInApexShouldFail() throws Exception {
+ pushTestApex(APK_IN_APEX_TESTAPEX_NAME + "_v1.apex");
+ getDevice().reboot();
+
+ runPhase("testDuplicateApkInApexShouldFail_Commit");
+ getDevice().reboot();
+ runPhase("testDuplicateApkInApexShouldFail_Verify");
+ }
+
@Test
public void testSystemServerRestartDoesNotAffectStagedSessions() throws Exception {
runPhase("testSystemServerRestartDoesNotAffectStagedSessions_Commit");
@@ -92,6 +180,125 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
runPhase("testSystemServerRestartDoesNotAffectStagedSessions_Verify");
}
+ // Test waiting time for staged session to be ready using adb staged install can be altered
+ @Test
+ public void testAdbStagdReadyTimeoutFlagWorks() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ final File apexFile = mHostUtils.getTestFile(SHIM_V2);
+ final String output = getDevice().executeAdbCommand("install", "--staged",
+ "--staged-ready-timeout", "60000", apexFile.getAbsolutePath());
+ assertThat(output).contains("Reboot device to apply staged session");
+ final String sessionId = getDevice().executeShellCommand(
+ "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim();
+ assertThat(sessionId).isNotEmpty();
+ }
+
+ // Test adb staged installation wait for session to be ready by default
+ @Test
+ public void testAdbStagedInstallWaitsTillReadyByDefault() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ final File apexFile = mHostUtils.getTestFile(SHIM_V2);
+ final String output = getDevice().executeAdbCommand("install", "--staged",
+ apexFile.getAbsolutePath());
+ assertThat(output).contains("Reboot device to apply staged session");
+ final String sessionId = getDevice().executeShellCommand(
+ "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim();
+ assertThat(sessionId).isNotEmpty();
+ }
+
+ // Test we can skip waiting for staged session to be ready
+ @Test
+ public void testAdbStagedReadyWaitCanBeSkipped() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ final File apexFile = mHostUtils.getTestFile(SHIM_V2);
+ final String output = getDevice().executeAdbCommand("install", "--staged",
+ "--staged-ready-timeout", "0", apexFile.getAbsolutePath());
+ assertThat(output).doesNotContain("Reboot device to apply staged session");
+ assertThat(output).contains("Success");
+ final String sessionId = getDevice().executeShellCommand(
+ "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim();
+ assertThat(sessionId).isEmpty();
+ }
+
+ // Test rollback-app command waits for staged sessions to be ready
+ @Test
+ @LargeTest
+ public void testAdbRollbackAppWaitsForStagedReady() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ final File apexFile = mHostUtils.getTestFile(SHIM_V2);
+ String output = getDevice().executeAdbCommand("install", "--staged",
+ "--enable-rollback", apexFile.getAbsolutePath());
+ assertThat(output).contains("Reboot device to apply staged session");
+ getDevice().reboot();
+ output = getDevice().executeShellCommand("pm rollback-app " + SHIM_APEX_PACKAGE_NAME);
+ assertThat(output).contains("Reboot device to apply staged session");
+ final String sessionId = getDevice().executeShellCommand(
+ "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim();
+ assertThat(sessionId).isNotEmpty();
+ }
+
+ @Test
+ public void testAdbInstallMultiPackageCommandWorks() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ final File apexFile = mHostUtils.getTestFile(SHIM_V2);
+ final File apkFile = mHostUtils.getTestFile(APK_A);
+ final String output = getDevice().executeAdbCommand("install-multi-package",
+ apexFile.getAbsolutePath(), apkFile.getAbsolutePath());
+ assertThat(output).contains("Created parent session");
+ assertThat(output).contains("Created child session");
+ assertThat(output).contains("Success. Reboot device to apply staged session");
+
+ // Ensure there is only one parent session
+ String[] sessionIds = getDevice().executeShellCommand(
+ "pm get-stagedsessions --only-ready --only-parent --only-sessionid").split("\n");
+ assertThat(sessionIds.length).isEqualTo(1);
+ // Ensure there are two children session
+ sessionIds = getDevice().executeShellCommand(
+ "pm get-stagedsessions --only-ready --only-sessionid").split("\n");
+ assertThat(sessionIds.length).isEqualTo(3);
+ }
+
+ @Test
+ public void testAbandonStagedSessionShouldCleanUp() throws Exception {
+ List<String> before = getStagingDirectories();
+ runPhase("testAbandonStagedSessionShouldCleanUp");
+ List<String> after = getStagingDirectories();
+ // The staging directories generated during the test should be deleted
+ assertThat(after).isEqualTo(before);
+ }
+
+ @Test
+ public void testStagedSessionShouldCleanUpOnVerificationFailure() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+ List<String> before = getStagingDirectories();
+ runPhase("testStagedSessionShouldCleanUpOnVerificationFailure");
+ List<String> after = getStagingDirectories();
+ assertThat(after).isEqualTo(before);
+ }
+
+ @Test
+ @LargeTest
+ public void testStagedSessionShouldCleanUpOnOnSuccess() throws Exception {
+ List<String> before = getStagingDirectories();
+ runPhase("testStagedSessionShouldCleanUpOnOnSuccess_Commit");
+ assertThat(getStagingDirectories()).isNotEqualTo(before);
+ getDevice().reboot();
+ runPhase("testStagedSessionShouldCleanUpOnOnSuccess_Verify");
+ List<String> after = getStagingDirectories();
+ assertThat(after).isEqualTo(before);
+ }
+
@Test
public void testStagedInstallationShouldCleanUpOnValidationFailure() throws Exception {
List<String> before = getStagingDirectories();
@@ -110,16 +317,165 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
}
@Test
+ @LargeTest
public void testOrphanedStagingDirectoryGetsCleanedUpOnReboot() throws Exception {
//create random directories in /data/app-staging folder
getDevice().enableAdbRoot();
getDevice().executeShellCommand("mkdir /data/app-staging/session_123");
- getDevice().executeShellCommand("mkdir /data/app-staging/random_name");
+ getDevice().executeShellCommand("mkdir /data/app-staging/session_456");
+ getDevice().disableAdbRoot();
+
+ assertThat(getStagingDirectories()).contains("session_123");
+ assertThat(getStagingDirectories()).contains("session_456");
+ getDevice().reboot();
+ assertThat(getStagingDirectories()).doesNotContain("session_123");
+ assertThat(getStagingDirectories()).doesNotContain("session_456");
+ }
+
+ @Test
+ @LargeTest
+ public void testFailStagedSessionIfStagingDirectoryDeleted() throws Exception {
+ // Create a staged session
+ runPhase("testFailStagedSessionIfStagingDirectoryDeleted_Commit");
+
+ // Delete the staging directory
+ getDevice().enableAdbRoot();
+ getDevice().executeShellCommand("rm -r /data/app-staging");
getDevice().disableAdbRoot();
- assertThat(getStagingDirectories()).isNotEmpty();
getDevice().reboot();
- assertThat(getStagingDirectories()).isEmpty();
+
+ runPhase("testFailStagedSessionIfStagingDirectoryDeleted_Verify");
+ }
+
+ @Test
+ public void testApexActivationFailureIsCapturedInSession() throws Exception {
+ // We initiate staging a normal apex update which passes pre-reboot verification.
+ // Then we replace the valid apex waiting in /data/app-staging with something
+ // that cannot be activated and reboot. The apex should fail to activate, which
+ // is what we want for this test.
+ runPhase("testApexActivationFailureIsCapturedInSession_Commit");
+ final String sessionId = getDevice().executeShellCommand(
+ "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim();
+ assertThat(sessionId).isNotEmpty();
+ // Now replace the valid staged apex with something invalid
+ getDevice().enableAdbRoot();
+ getDevice().executeShellCommand("rm /data/app-staging/session_" + sessionId + "/*");
+ final File invalidApexFile = mHostUtils.getTestFile(APEX_WRONG_SHA);
+ getDevice().pushFile(invalidApexFile,
+ "/data/app-staging/session_" + sessionId + "/base.apex");
+ getDevice().reboot();
+
+ runPhase("testApexActivationFailureIsCapturedInSession_Verify");
+ }
+
+ @Test
+ public void testActiveApexIsRevertedOnCheckpointRollback() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+ assumeTrue("Device does not support file-system checkpoint",
+ mHostUtils.isCheckpointSupported());
+
+ // Install something so that /data/apex/active is not empty
+ runPhase("testActiveApexIsRevertedOnCheckpointRollback_Prepare");
+ getDevice().reboot();
+
+ // Stage another session which will be installed during fs-rollback mode
+ runPhase("testActiveApexIsRevertedOnCheckpointRollback_Commit");
+
+ // Set checkpoint to 0 so that we enter fs-rollback mode immediately on reboot
+ getDevice().enableAdbRoot();
+ getDevice().executeShellCommand("vdc checkpoint startCheckpoint 0");
+ getDevice().disableAdbRoot();
+ getDevice().reboot();
+
+ // Verify that session was reverted and we have fallen back to
+ // apex installed during preparation stage.
+ runPhase("testActiveApexIsRevertedOnCheckpointRollback_VerifyPostReboot");
+ }
+
+ @Test
+ public void testApexIsNotActivatedIfNotInCheckpointMode() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+ assumeTrue("Device does not support file-system checkpoint",
+ mHostUtils.isCheckpointSupported());
+
+ runPhase("testApexIsNotActivatedIfNotInCheckpointMode_Commit");
+ // Delete checkpoint file in /metadata so that device thinks
+ // fs-checkpointing was never activated
+ getDevice().enableAdbRoot();
+ getDevice().executeShellCommand("rm /metadata/vold/checkpoint");
+ getDevice().disableAdbRoot();
+ getDevice().reboot();
+ // Verify that session was not installed when not in fs-checkpoint mode
+ runPhase("testApexIsNotActivatedIfNotInCheckpointMode_VerifyPostReboot");
+ }
+
+ @Test
+ public void testApexInstallerNotInAllowListCanNotInstall() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ runPhase("testApexInstallerNotInAllowListCanNotInstall_staged");
+ runPhase("testApexInstallerNotInAllowListCanNotInstall_nonStaged");
+ }
+
+ @Test
+ @LargeTest
+ public void testApexNotInAllowListCanNotInstall() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ pushTestApex("test.rebootless_apex_v1.apex");
+ getDevice().reboot();
+
+ runPhase("testApexNotInAllowListCanNotInstall_staged");
+ runPhase("testApexNotInAllowListCanNotInstall_nonStaged");
+ }
+
+ @Test
+ @LargeTest
+ public void testVendorApexWrongInstaller() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ pushTestVendorApexAllowList("com.wrong.installer");
+ pushTestApex("test.rebootless_apex_v1.apex");
+ getDevice().reboot();
+
+ runPhase("testVendorApexWrongInstaller_staged");
+ runPhase("testVendorApexWrongInstaller_nonStaged");
+ }
+
+ @Test
+ @LargeTest
+ public void testVendorApexCorrectInstaller() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ pushTestVendorApexAllowList("com.android.tests.stagedinstallinternal");
+ pushTestApex("test.rebootless_apex_v1.apex");
+ getDevice().reboot();
+
+ runPhase("testVendorApexCorrectInstaller_staged");
+ runPhase("testVendorApexCorrectInstaller_nonStaged");
+ }
+
+ @Test
+ public void testRebootlessUpdates() throws Exception {
+ pushTestApex("test.rebootless_apex_v1.apex");
+ getDevice().reboot();
+
+ runPhase("testRebootlessUpdates");
+ }
+
+ @Test
+ public void testRebootlessUpdate_hasStagedSessionWithSameApex_fails() throws Exception {
+ assumeTrue("Device does not support updating APEX",
+ mHostUtils.isApexUpdateSupported());
+
+ runPhase("testRebootlessUpdate_hasStagedSessionWithSameApex_fails");
}
private List<String> getStagingDirectories() throws DeviceNotAvailableException {
@@ -130,9 +486,6 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
.stream().filter(entry -> entry.getName().matches("session_\\d+"))
.map(entry -> entry.getName())
.collect(Collectors.toList());
- } catch (Exception e) {
- // Return an empty list if any error
- return Collections.EMPTY_LIST;
} finally {
getDevice().disableAdbRoot();
}
@@ -140,23 +493,24 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
private void restartSystemServer() throws Exception {
// Restart the system server
- long oldStartTime = getDevice().getProcessByName("system_server").getStartTime();
+ final ProcessInfo oldPs = getDevice().getProcessByName("system_server");
+
+ getDevice().enableAdbRoot(); // Need root to restart system server
assertThat(getDevice().executeShellCommand("am restart")).contains("Restart the system");
+ getDevice().disableAdbRoot();
// Wait for new system server process to start
- long start = System.currentTimeMillis();
- long newStartTime = oldStartTime;
+ final long start = System.currentTimeMillis();
while (System.currentTimeMillis() < start + SYSTEM_SERVER_TIMEOUT_MS) {
- ProcessInfo newPs = getDevice().getProcessByName("system_server");
+ final ProcessInfo newPs = getDevice().getProcessByName("system_server");
if (newPs != null) {
- newStartTime = newPs.getStartTime();
- if (newStartTime != oldStartTime) {
- break;
+ if (newPs.getPid() != oldPs.getPid()) {
+ getDevice().waitForDeviceAvailable();
+ return;
}
}
Thread.sleep(500);
}
- assertThat(newStartTime).isNotEqualTo(oldStartTime);
- getDevice().waitForDeviceAvailable();
+ fail("Timed out in restarting system server");
}
}
diff --git a/tests/StatusBar/Android.bp b/tests/StatusBar/Android.bp
index 0b650ed3afc8..2fad051300c7 100644
--- a/tests/StatusBar/Android.bp
+++ b/tests/StatusBar/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "StatusBarTest",
srcs: ["**/*.java"],
diff --git a/tests/StatusBar/AndroidManifest.xml b/tests/StatusBar/AndroidManifest.xml
index 6a082e990dab..8744dae1b360 100644
--- a/tests/StatusBar/AndroidManifest.xml
+++ b/tests/StatusBar/AndroidManifest.xml
@@ -1,56 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.statusbartest">
- <uses-permission android:name="android.permission.DEVICE_POWER" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-permission android:name="android.permission.STATUS_BAR" />
- <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
- <uses-permission android:name="android.permission.VIBRATE" />
- <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
- <uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS" />
+ package="com.android.statusbartest">
+ <uses-permission android:name="android.permission.DEVICE_POWER"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
+ <uses-permission android:name="android.permission.STATUS_BAR"/>
+ <uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>
+ <uses-permission android:name="android.permission.VIBRATE"/>
+ <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
+ <uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS"/>
<application>
- <activity android:name="StatusBarTest" android:label="_StatusBar">
+ <activity android:name="StatusBarTest"
+ android:label="_StatusBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="NotificationTestList" android:label="_Notifications">
+ <activity android:name="NotificationTestList"
+ android:label="_Notifications"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="NotificationBuilderTest"
- android:label="_Notify Builder"
- android:theme="@android:style/Theme.Holo"
- android:hardwareAccelerated="true"
- >
+ android:label="_Notify Builder"
+ android:theme="@android:style/Theme.Holo"
+ android:hardwareAccelerated="true"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="ToastTest" android:label="_Toasts">
+ <activity android:name="ToastTest"
+ android:label="_Toasts"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="PowerTest" android:label="_Power">
+ <activity android:name="PowerTest"
+ android:label="_Power"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="ConfirmationActivity" android:theme="@android:style/Theme.Dialog">
+ <activity android:name="ConfirmationActivity"
+ android:theme="@android:style/Theme.Dialog">
</activity>
- <activity android:name="TestAlertActivity" android:theme="@android:style/Theme.Dialog">
+ <activity android:name="TestAlertActivity"
+ android:theme="@android:style/Theme.Dialog">
</activity>
</application>
</manifest>
diff --git a/tests/StatusBar/OWNERS b/tests/StatusBar/OWNERS
new file mode 100644
index 000000000000..2e96c97c8bb3
--- /dev/null
+++ b/tests/StatusBar/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/OWNERS
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
index 9862116e376b..601688ed783d 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
@@ -497,7 +497,7 @@ public class NotificationBuilderTest extends Activity
intent.setData(Uri.fromParts("content", "//status_bar_test/delete/" + id, null));
intent.putExtra(ConfirmationActivity.EXTRA_TITLE, "Delete intent");
intent.putExtra(ConfirmationActivity.EXTRA_TEXT, "id: " + id);
- return PendingIntent.getActivity(this, 0, intent, 0);
+ return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
}
private PendingIntent makeContentIntent(int id) {
@@ -505,7 +505,7 @@ public class NotificationBuilderTest extends Activity
intent.setData(Uri.fromParts("content", "//status_bar_test/content/" + id, null));
intent.putExtra(ConfirmationActivity.EXTRA_TITLE, "Content intent");
intent.putExtra(ConfirmationActivity.EXTRA_TEXT, "id: " + id);
- return PendingIntent.getActivity(this, 0, intent, 0);
+ return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
}
}
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 163250d9d666..ef324e7c1377 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -25,27 +25,22 @@ import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.content.Context;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Icon;
import android.media.AudioAttributes;
+import android.net.Uri;
import android.os.Bundle;
-import android.os.Vibrator;
import android.os.Handler;
-import android.os.UserHandle;
-import android.util.Log;
-import android.net.Uri;
+import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.Vibrator;
+import android.util.Log;
import android.widget.RemoteViews;
-import android.os.PowerManager;
-
-// private NM API
-import android.app.INotificationManager;
import android.widget.Toast;
public class NotificationTestList extends TestActivity
@@ -185,6 +180,7 @@ public class NotificationTestList extends TestActivity
.setContentTitle("default priority group 1")
.setGroup("group1")
.setOngoing(true)
+ .setColor(Color.WHITE)
.setColorized(true)
.build();
mNM.notify(6002, n);
@@ -1160,12 +1156,12 @@ public class NotificationTestList extends TestActivity
private PendingIntent makeIntent() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
- return PendingIntent.getActivity(this, 0, intent, 0);
+ return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
}
private PendingIntent makeIntent2() {
Intent intent = new Intent(this, StatusBarTest.class);
- return PendingIntent.getActivity(this, 0, intent, 0);
+ return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
}
diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
index 3d72ee67a227..6bcfebc752f1 100644
--- a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
@@ -160,7 +160,7 @@ public class StatusBarTest extends TestActivity
StatusBarTest.this,
0,
fullScreenIntent,
- PendingIntent.FLAG_CANCEL_CURRENT);
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
Notification not = new Notification.Builder(StatusBarTest.this)
.setSmallIcon(R.drawable.stat_sys_phone)
.setWhen(System.currentTimeMillis() - (1000 * 60 * 60 * 24))
diff --git a/tests/SurfaceComposition/Android.bp b/tests/SurfaceComposition/Android.bp
index 53e4d52b2efd..f5aba8f5a2f2 100644
--- a/tests/SurfaceComposition/Android.bp
+++ b/tests/SurfaceComposition/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "SurfaceComposition",
// Don't include this package in any target
diff --git a/tests/SurfaceComposition/AndroidManifest.xml b/tests/SurfaceComposition/AndroidManifest.xml
index 4c0a9b61fd8f..46c8f88626c3 100644
--- a/tests/SurfaceComposition/AndroidManifest.xml
+++ b/tests/SurfaceComposition/AndroidManifest.xml
@@ -16,21 +16,22 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.surfacecomposition">
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ package="android.surfacecomposition">
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application android:theme="@style/noeffects">
- <uses-library android:name="android.test.runner" />
- <activity android:name="android.surfacecomposition.SurfaceCompositionMeasuringActivity" >
+ <uses-library android:name="android.test.runner"/>
+ <activity android:name="android.surfacecomposition.SurfaceCompositionMeasuringActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
</application>
<!-- self-instrumenting test package. -->
<instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="android.surfacecomposition">
+ android:targetPackage="android.surfacecomposition">
</instrumentation>
</manifest>
diff --git a/tests/SurfaceControlViewHostTest/Android.bp b/tests/SurfaceControlViewHostTest/Android.bp
index e4e060010eea..0127ba559500 100644
--- a/tests/SurfaceControlViewHostTest/Android.bp
+++ b/tests/SurfaceControlViewHostTest/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "SurfaceControlViewHostTest",
srcs: ["**/*.java"],
diff --git a/tests/SurfaceControlViewHostTest/AndroidManifest.xml b/tests/SurfaceControlViewHostTest/AndroidManifest.xml
index ee95763453f7..7e9a04dfa82c 100644
--- a/tests/SurfaceControlViewHostTest/AndroidManifest.xml
+++ b/tests/SurfaceControlViewHostTest/AndroidManifest.xml
@@ -13,10 +13,12 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.viewembed">
+ package="com.android.test.viewembed">
<application>
- <activity android:name="SurfaceControlViewHostTest" android:label="View Embedding Test">
+ <activity android:name="SurfaceControlViewHostTest"
+ android:label="View Embedding Test"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java
index 3bc530975580..73e01634709e 100644
--- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceControlViewHostTest.java
@@ -22,12 +22,11 @@ import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.view.Gravity;
-import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
-import android.view.SurfaceControlViewHost;
import android.widget.Button;
import android.widget.FrameLayout;
@@ -46,8 +45,6 @@ public class SurfaceControlViewHostTest extends Activity implements SurfaceHolde
mView.setZOrderOnTop(true);
mView.getHolder().addCallback(this);
-
- addEmbeddedView();
}
void addEmbeddedView() {
@@ -63,6 +60,8 @@ public class SurfaceControlViewHostTest extends Activity implements SurfaceHolde
v.setBackgroundColor(Color.RED);
}
});
+ v.getViewTreeObserver().addOnWindowFocusChangeListener(focused ->
+ v.setBackgroundColor(focused ? Color.MAGENTA : Color.DKGRAY));
WindowManager.LayoutParams lp =
new WindowManager.LayoutParams(500, 500, WindowManager.LayoutParams.TYPE_APPLICATION,
0, PixelFormat.OPAQUE);
@@ -71,6 +70,7 @@ public class SurfaceControlViewHostTest extends Activity implements SurfaceHolde
@Override
public void surfaceCreated(SurfaceHolder holder) {
+ addEmbeddedView();
}
@Override
diff --git a/tests/SurfaceViewBufferTests/Android.bp b/tests/SurfaceViewBufferTests/Android.bp
new file mode 100644
index 000000000000..dc75f00e7cdc
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/Android.bp
@@ -0,0 +1,70 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // 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"],
+}
+
+android_test {
+ name: "SurfaceViewBufferTests",
+ srcs: ["**/*.java","**/*.kt"],
+ manifest: "AndroidManifest.xml",
+ test_config: "AndroidTest.xml",
+ platform_apis: true,
+ certificate: "platform",
+ use_embedded_native_libs: true,
+ jni_libs: [
+ "libsurface_jni",
+ ],
+
+ static_libs: [
+ "androidx.appcompat_appcompat",
+ "androidx.test.rules",
+ "androidx.test.runner",
+ "androidx.test.ext.junit",
+ "kotlin-stdlib",
+ "kotlinx-coroutines-android",
+ "flickerlib",
+ "truth-prebuilt",
+ "cts-wm-util",
+ "CtsSurfaceValidatorLib",
+ ],
+}
+
+cc_library_shared {
+ name: "libsurface_jni",
+ srcs: [
+ "cpp/SurfaceProxy.cpp",
+ ],
+ shared_libs: [
+ "libutils",
+ "libui",
+ "libgui",
+ "liblog",
+ "libandroid",
+ ],
+ include_dirs: [
+ "system/core/include"
+ ],
+ stl: "libc++_static",
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
diff --git a/tests/SurfaceViewBufferTests/AndroidManifest.xml b/tests/SurfaceViewBufferTests/AndroidManifest.xml
new file mode 100644
index 000000000000..c910ecdac1b3
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/AndroidManifest.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test">
+
+ <uses-sdk android:minSdkVersion="29"
+ android:targetSdkVersion="29"/>
+ <!-- Enable / Disable tracing !-->
+ <uses-permission android:name="android.permission.DUMP" />
+ <!-- Enable / Disable sv blast adapter !-->
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <!-- Readback virtual display output !-->
+ <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/>
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
+ <!-- Save failed test bitmap images !-->
+ <uses-permission android:name="android.Manifest.permission.WRITE_EXTERNAL_STORAGE"/>
+
+ <application android:allowBackup="false"
+ android:supportsRtl="true">
+ <activity android:name=".MainActivity"
+ android:taskAffinity="com.android.test.MainActivity"
+ android:theme="@style/AppTheme"
+ android:configChanges="orientation|screenSize"
+ android:label="SurfaceViewBufferTestApp"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ <service android:name="android.view.cts.surfacevalidator.LocalMediaProjectionService"
+ android:foregroundServiceType="mediaProjection"
+ android:enabled="true">
+ </service>
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.test"
+ android:label="SurfaceViewBufferTests">
+ </instrumentation>
+</manifest>
diff --git a/tests/SurfaceViewBufferTests/AndroidTest.xml b/tests/SurfaceViewBufferTests/AndroidTest.xml
new file mode 100644
index 000000000000..b73fe4853ecf
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs SurfaceView Buffer Tests">
+ <option name="test-tag" value="SurfaceViewBufferTests" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on" />
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="false"/>
+ <option name="test-file-name" value="SurfaceViewBufferTests.apk"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.test"/>
+ <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+ <option name="shell-timeout" value="6600s" />
+ <option name="test-timeout" value="6000s" />
+ <option name="hidden-api-checks" value="false" />
+ </test>
+</configuration>
diff --git a/tests/SurfaceViewBufferTests/OWNERS b/tests/SurfaceViewBufferTests/OWNERS
new file mode 100644
index 000000000000..d50528c237ff
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp b/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp
new file mode 100644
index 000000000000..926ff4d5793c
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/cpp/SurfaceProxy.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/log.h>
+#include <android/native_window.h>
+#include <android/native_window_jni.h>
+#include <android/window.h>
+#include <gui/Surface.h>
+#include <jni.h>
+#include <system/window.h>
+#include <utils/RefBase.h>
+#include <cassert>
+#include <chrono>
+#include <thread>
+
+#define TAG "SurfaceViewBufferTests"
+#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
+
+extern "C" {
+int i = 0;
+static ANativeWindow* sAnw;
+static std::map<uint32_t /* slot */, ANativeWindowBuffer*> sBuffers;
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_setSurface(JNIEnv* env, jclass,
+ jobject surfaceObject) {
+ sAnw = ANativeWindow_fromSurface(env, surfaceObject);
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ surface->enableFrameTimestamps(true);
+ surface->connect(NATIVE_WINDOW_API_CPU, nullptr, false);
+ native_window_set_usage(sAnw, GRALLOC_USAGE_SW_WRITE_OFTEN);
+ native_window_set_buffers_format(sAnw, HAL_PIXEL_FORMAT_RGBA_8888);
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_waitUntilBufferDisplayed(
+ JNIEnv*, jclass, jlong jFrameNumber, jint timeoutMs) {
+ using namespace std::chrono_literals;
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+
+ uint64_t frameNumber = static_cast<uint64_t>(jFrameNumber);
+ nsecs_t outRequestedPresentTime, outAcquireTime, outLatchTime, outFirstRefreshStartTime;
+ nsecs_t outLastRefreshStartTime, outGlCompositionDoneTime, outDequeueReadyTime;
+ nsecs_t outDisplayPresentTime = -1;
+ nsecs_t outReleaseTime;
+
+ auto start = std::chrono::steady_clock::now();
+ while (outDisplayPresentTime < 0) {
+ std::this_thread::sleep_for(8ms);
+ surface->getFrameTimestamps(frameNumber, &outRequestedPresentTime, &outAcquireTime,
+ &outLatchTime, &outFirstRefreshStartTime,
+ &outLastRefreshStartTime, &outGlCompositionDoneTime,
+ &outDisplayPresentTime, &outDequeueReadyTime, &outReleaseTime);
+ if (outDisplayPresentTime < 0) {
+ auto end = std::chrono::steady_clock::now();
+ if (std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() >
+ timeoutMs) {
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_draw(JNIEnv*, jclass) {
+ assert(sAnw);
+ ANativeWindow_Buffer outBuffer;
+ ANativeWindow_lock(sAnw, &outBuffer, nullptr);
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowLock(JNIEnv*, jclass) {
+ assert(sAnw);
+ ANativeWindow_Buffer outBuffer;
+ ANativeWindow_lock(sAnw, &outBuffer, nullptr);
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowUnlockAndPost(JNIEnv*,
+ jclass) {
+ assert(sAnw);
+ ANativeWindow_unlockAndPost(sAnw);
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowSetBuffersGeometry(
+ JNIEnv* /* env */, jclass /* clazz */, jobject /* surfaceObject */, jint w, jint h,
+ jint format) {
+ assert(sAnw);
+ return ANativeWindow_setBuffersGeometry(sAnw, w, h, format);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowSetBuffersTransform(
+ JNIEnv* /* env */, jclass /* clazz */, jint transform) {
+ assert(sAnw);
+ return native_window_set_buffers_transform(sAnw, transform);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetScalingMode(JNIEnv* /* env */,
+ jclass /* clazz */,
+ jint scalingMode) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ return surface->setScalingMode(scalingMode);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceDequeueBuffer(JNIEnv* /* env */,
+ jclass /* clazz */,
+ jint slot,
+ jint timeoutMs) {
+ assert(sAnw);
+ ANativeWindowBuffer* anb;
+ int fenceFd;
+ int result = sAnw->dequeueBuffer(sAnw, &anb, &fenceFd);
+ if (result != android::OK) {
+ return result;
+ }
+ sBuffers[slot] = anb;
+ if (timeoutMs == 0) {
+ return android::OK;
+ }
+ android::sp<android::Fence> fence(new android::Fence(fenceFd));
+ int waitResult = fence->wait(timeoutMs);
+ if (waitResult != android::OK) {
+ sAnw->cancelBuffer(sAnw, sBuffers[slot], -1);
+ sBuffers[slot] = nullptr;
+ return waitResult;
+ }
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceCancelBuffer(JNIEnv* /* env */,
+ jclass /* clazz */,
+ jint slot) {
+ assert(sAnw);
+ assert(sBuffers[slot]);
+ int result = sAnw->cancelBuffer(sAnw, sBuffers[slot], -1);
+ sBuffers[slot] = nullptr;
+ return result;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_drawBuffer(JNIEnv* env,
+ jclass /* clazz */, jint slot,
+ jintArray jintArrayColor) {
+ assert(sAnw);
+ assert(sBuffers[slot]);
+
+ int* color = env->GetIntArrayElements(jintArrayColor, nullptr);
+
+ ANativeWindowBuffer* buffer = sBuffers[slot];
+ android::sp<android::GraphicBuffer> graphicBuffer(static_cast<android::GraphicBuffer*>(buffer));
+ const android::Rect bounds(buffer->width, buffer->height);
+ android::Region newDirtyRegion;
+ newDirtyRegion.set(bounds);
+
+ void* vaddr;
+ int fenceFd = -1;
+ graphicBuffer->lockAsync(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ newDirtyRegion.bounds(), &vaddr, fenceFd);
+
+ for (int32_t row = 0; row < buffer->height; row++) {
+ uint8_t* dst = static_cast<uint8_t*>(vaddr) + (buffer->stride * row) * 4;
+ for (int32_t column = 0; column < buffer->width; column++) {
+ dst[0] = color[0];
+ dst[1] = color[1];
+ dst[2] = color[2];
+ dst[3] = color[3];
+ dst += 4;
+ }
+ }
+ graphicBuffer->unlockAsync(&fenceFd);
+ env->ReleaseIntArrayElements(jintArrayColor, color, JNI_ABORT);
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceQueueBuffer(JNIEnv* /* env */,
+ jclass /* clazz */,
+ jint slot,
+ jboolean freeSlot) {
+ assert(sAnw);
+ assert(sBuffers[slot]);
+ int result = sAnw->queueBuffer(sAnw, sBuffers[slot], -1);
+ if (freeSlot) {
+ sBuffers[slot] = nullptr;
+ }
+ return result;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetAsyncMode(JNIEnv* /* env */,
+ jclass /* clazz */,
+ jboolean async) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ return surface->setAsyncMode(async);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetDequeueTimeout(
+ JNIEnv* /* env */, jclass /* clazz */, jlong timeoutMs) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ return surface->setDequeueTimeout(timeoutMs);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetMaxDequeuedBufferCount(
+ JNIEnv* /* env */, jclass /* clazz */, jint maxDequeuedBuffers) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ return surface->setMaxDequeuedBufferCount(maxDequeuedBuffers);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetBufferCount(
+ JNIEnv* /* env */, jclass /* clazz */, jint count) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ int result = native_window_set_buffer_count(sAnw, count);
+ return result;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetSharedBufferMode(
+ JNIEnv* /* env */, jclass /* clazz */, jboolean shared) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ int result = native_window_set_shared_buffer_mode(sAnw, shared);
+ return result;
+}
+
+JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetAutoRefresh(
+ JNIEnv* /* env */, jclass /* clazz */, jboolean autoRefresh) {
+ assert(sAnw);
+ android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
+ int result = native_window_set_auto_refresh(sAnw, autoRefresh);
+ return result;
+}
+} \ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml b/tests/SurfaceViewBufferTests/res/values/styles.xml
index 2c58d91e34fe..8b50738a06de 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml
+++ b/tests/SurfaceViewBufferTests/res/values/styles.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2018 The Android Open Source Project
+ 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.
@@ -14,13 +14,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/holo_blue_bright">
- <Button android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/enter_pip"
- android:text="Enter PIP"/>
-</LinearLayout>
+<resources>
+<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <item name="windowNoTitle">true</item>
+ <item name="windowActionBar">false</item>
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ <item name="android:windowDisablePreview">true</item>
+</style>
+</resources>
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt
new file mode 100644
index 000000000000..b67dc380efab
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test
+
+import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class BufferPresentationTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase(useBlastAdapter) {
+ /** Submit buffers as fast as possible and make sure they are presented on display */
+ @Test
+ fun testQueueBuffers() {
+ val numFrames = 100L
+ val trace = withTrace { activity ->
+ for (i in 1..numFrames) {
+ activity.mSurfaceProxy.ANativeWindowLock()
+ activity.mSurfaceProxy.ANativeWindowUnlockAndPost()
+ }
+ assertEquals(0, activity.mSurfaceProxy.waitUntilBufferDisplayed(numFrames,
+ 1000 /* ms */))
+ }
+
+ assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames)
+ }
+
+ @Test
+ fun testSetBufferScalingMode_outOfOrderQueueBuffer() {
+ val trace = withTrace { activity ->
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
+
+ activity.mSurfaceProxy.SurfaceQueueBuffer(1)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ assertEquals(0, activity.mSurfaceProxy.waitUntilBufferDisplayed(2, 5000 /* ms */))
+ }
+
+ assertThat(trace).hasFrameSequence("SurfaceView", 1..2L)
+ }
+
+ @Test
+ fun testSetBufferScalingMode_multipleDequeueBuffer() {
+ val numFrames = 20L
+ val trace = withTrace { activity ->
+ for (count in 1..(numFrames / 2)) {
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
+
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(1)
+ }
+ assertEquals(0, activity.mSurfaceProxy.waitUntilBufferDisplayed(numFrames,
+ 5000 /* ms */))
+ }
+
+ assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames)
+ }
+
+ @Test
+ fun testSetBufferCount_queueMaxBufferCountMinusOne() {
+ val numBufferCount = 8
+ val numFrames = numBufferCount * 5L
+ val trace = withTrace { activity ->
+ assertEquals(0, activity.mSurfaceProxy.NativeWindowSetBufferCount(numBufferCount + 1))
+ for (i in 1..numFrames / numBufferCount) {
+ for (bufferSlot in 0..numBufferCount - 1) {
+ assertEquals(0,
+ activity.mSurfaceProxy.SurfaceDequeueBuffer(bufferSlot, 1000 /* ms */))
+ }
+
+ for (bufferSlot in 0..numBufferCount - 1) {
+ activity.mSurfaceProxy.SurfaceQueueBuffer(bufferSlot)
+ }
+ }
+ assertEquals(0, activity.mSurfaceProxy.waitUntilBufferDisplayed(numFrames,
+ 5000 /* ms */))
+ }
+
+ assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames)
+ }
+
+ @Test
+ // Leave IGBP in sync mode, try to dequeue and queue as fast as possible. Check that we
+ // occasionally get timeout errors.
+ fun testSyncMode_dequeueWithoutBlockingFails() {
+ val numFrames = 1000L
+ runOnUiThread { activity ->
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetDequeueTimeout(3L))
+ var failures = false
+ for (i in 1..numFrames) {
+ if (activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 0 /* ms */) != 0) {
+ failures = true
+ break
+ }
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ }
+ assertTrue(failures)
+ }
+ }
+
+ @Test
+ // Set IGBP to be in async mode, try to dequeue and queue as fast as possible. Client should be
+ // able to dequeue and queue buffers without being blocked.
+ fun testAsyncMode_dequeueWithoutBlocking() {
+ val numFrames = 1000L
+ runOnUiThread { activity ->
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetDequeueTimeout(3L))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetAsyncMode(async = true))
+ for (i in 1..numFrames) {
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 0 /* ms */))
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ }
+ }
+ }
+
+ @Test
+ // Disable triple buffering in the system and leave IGBP in sync mode. Check that we
+ // occasionally get timeout errors.
+ fun testSyncModeWithDisabledTripleBuffering_dequeueWithoutBlockingFails() {
+ val numFrames = 1000L
+ runOnUiThread { activity ->
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetMaxDequeuedBufferCount(1))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetDequeueTimeout(3L))
+ var failures = false
+ for (i in 1..numFrames) {
+ if (activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 0 /* ms */) != 0) {
+ failures = true
+ break
+ }
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ }
+ assertTrue(failures)
+ }
+ }
+
+ @Test
+ // Disable triple buffering in the system and set IGBP to be in async mode. Try to dequeue and
+ // queue as fast as possible. Without triple buffering, the client does not have an extra buffer
+ // to dequeue and will not be able to dequeue and queue buffers without being blocked.
+ fun testAsyncModeWithDisabledTripleBuffering_dequeueWithoutBlockingFails() {
+ val numFrames = 1000L
+ runOnUiThread { activity ->
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetMaxDequeuedBufferCount(1))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetDequeueTimeout(3L))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceSetAsyncMode(async = true))
+ var failures = false
+ for (i in 1..numFrames) {
+ if (activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 0 /* ms */) != 0) {
+ failures = true
+ break
+ }
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ }
+ assertTrue(failures)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt
new file mode 100644
index 000000000000..e9e0246a207d
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test
+
+import android.graphics.Point
+import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
+import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode
+import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
+import junit.framework.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class BufferRejectionTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase(useBlastAdapter) {
+ @Test
+ fun testSetBuffersGeometry_0x0_rejectsBuffer() {
+ val trace = withTrace { activity ->
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, 100, 100,
+ R8G8B8A8_UNORM)
+ activity.mSurfaceProxy.ANativeWindowLock()
+ activity.mSurfaceProxy.ANativeWindowUnlockAndPost()
+ activity.mSurfaceProxy.ANativeWindowLock()
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, 0, 0,
+ R8G8B8A8_UNORM)
+ // Submit buffer one with a different size which should be rejected
+ activity.mSurfaceProxy.ANativeWindowUnlockAndPost()
+
+ // submit a buffer with the default buffer size
+ activity.mSurfaceProxy.ANativeWindowLock()
+ activity.mSurfaceProxy.ANativeWindowUnlockAndPost()
+ activity.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */)
+ }
+ // Verify we reject buffers since scaling mode == NATIVE_WINDOW_SCALING_MODE_FREEZE
+ assertThat(trace).layer("SurfaceView", 2).doesNotExist()
+
+ // Verify the next buffer is submitted with the correct size
+ assertThat(trace).layer("SurfaceView", 3).also {
+ it.hasBufferSize(defaultBufferSize)
+ // scaling mode is not passed down to the layer for blast
+ if (useBlastAdapter) {
+ it.hasScalingMode(ScalingMode.SCALE_TO_WINDOW.ordinal)
+ } else {
+ it.hasScalingMode(ScalingMode.FREEZE.ordinal)
+ }
+ }
+ }
+
+ @Test
+ fun testSetBufferScalingMode_freeze() {
+ val bufferSize = Point(300, 200)
+ val trace = withTrace { activity ->
+ activity.drawFrame()
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */), 0)
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, bufferSize,
+ R8G8B8A8_UNORM)
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
+ // Change buffer size and set scaling mode to freeze
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, Point(0, 0),
+ R8G8B8A8_UNORM)
+
+ // first dequeued buffer does not have the new size so it should be rejected.
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ activity.mSurfaceProxy.SurfaceSetScalingMode(ScalingMode.SCALE_TO_WINDOW)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(1)
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */), 0)
+ }
+
+ // verify buffer size is reset to default buffer size
+ assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize)
+ assertThat(trace).layer("SurfaceView", 2).doesNotExist()
+ assertThat(trace).layer("SurfaceView", 3).hasBufferSize(bufferSize)
+ }
+
+ @Test
+ fun testSetBufferScalingMode_freeze_withBufferRotation() {
+ val rotatedBufferSize = Point(defaultBufferSize.y, defaultBufferSize.x)
+ val trace = withTrace { activity ->
+ activity.drawFrame()
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */), 0)
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!,
+ rotatedBufferSize, R8G8B8A8_UNORM)
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
+ // Change buffer size and set scaling mode to freeze
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, Point(0, 0),
+ R8G8B8A8_UNORM)
+
+ // first dequeued buffer does not have the new size so it should be rejected.
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ // add a buffer transform so the buffer size is correct.
+ activity.mSurfaceProxy.ANativeWindowSetBuffersTransform(Transform.ROT_90)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(1)
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */), 0)
+ }
+
+ // verify buffer size is reset to default buffer size
+ assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize)
+ assertThat(trace).layer("SurfaceView", 2).doesNotExist()
+ assertThat(trace).layer("SurfaceView", 3).hasBufferSize(rotatedBufferSize)
+ assertThat(trace).layer("SurfaceView", 3).hasBufferOrientation(Transform.ROT_90.value)
+ }
+
+ @Test
+ fun testRejectedBuffersAreReleased() {
+ val bufferSize = Point(300, 200)
+ val trace = withTrace { activity ->
+ for (count in 0 until 5) {
+ activity.drawFrame()
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed((count * 3) + 1L,
+ 500 /* ms */), 0)
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!,
+ bufferSize, R8G8B8A8_UNORM)
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
+ // Change buffer size and set scaling mode to freeze
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!,
+ Point(0, 0), R8G8B8A8_UNORM)
+
+ // first dequeued buffer does not have the new size so it should be rejected.
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ activity.mSurfaceProxy.SurfaceSetScalingMode(ScalingMode.SCALE_TO_WINDOW)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(1)
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed((count * 3) + 3L,
+ 500 /* ms */), 0)
+ }
+ }
+
+ for (count in 0 until 5) {
+ assertThat(trace).layer("SurfaceView", (count * 3) + 1L)
+ .hasBufferSize(defaultBufferSize)
+ assertThat(trace).layer("SurfaceView", (count * 3) + 2L)
+ .doesNotExist()
+ assertThat(trace).layer("SurfaceView", (count * 3) + 3L)
+ .hasBufferSize(bufferSize)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt
new file mode 100644
index 000000000000..0802990beeab
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test
+
+import android.graphics.Color
+import android.graphics.Point
+import android.graphics.Rect
+import android.os.SystemClock
+import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
+import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode
+import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+
+@RunWith(Parameterized::class)
+class GeometryTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase(useBlastAdapter) {
+ @Test
+ fun testSetBuffersGeometry_0x0_resetsBufferSize() {
+ val trace = withTrace { activity ->
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, 0, 0,
+ R8G8B8A8_UNORM)
+ activity.mSurfaceProxy.ANativeWindowLock()
+ activity.mSurfaceProxy.ANativeWindowUnlockAndPost()
+ activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */)
+ }
+
+ // verify buffer size is reset to default buffer size
+ assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize)
+ }
+
+ @Test
+ fun testSetBuffersGeometry_smallerThanBuffer() {
+ val bufferSize = Point(300, 200)
+ val trace = withTrace { activity ->
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, bufferSize,
+ R8G8B8A8_UNORM)
+ activity.drawFrame()
+ activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */)
+ }
+
+ assertThat(trace).layer("SurfaceView", 1).also {
+ it.hasBufferSize(bufferSize)
+ it.hasLayerSize(defaultBufferSize)
+ it.hasScalingMode(ScalingMode.SCALE_TO_WINDOW.ordinal)
+ }
+ }
+
+ @Test
+ fun testSetBuffersGeometry_largerThanBuffer() {
+ val bufferSize = Point(3000, 2000)
+ val trace = withTrace { activity ->
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, bufferSize,
+ R8G8B8A8_UNORM)
+ activity.drawFrame()
+ activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */)
+ }
+
+ assertThat(trace).layer("SurfaceView", 1).also {
+ it.hasBufferSize(bufferSize)
+ it.hasLayerSize(defaultBufferSize)
+ it.hasScalingMode(ScalingMode.SCALE_TO_WINDOW.ordinal)
+ }
+ }
+
+ @Test
+ fun testSetBufferScalingMode_freeze() {
+ val bufferSize = Point(300, 200)
+ val trace = withTrace { activity ->
+ activity.drawFrame()
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */), 0)
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, bufferSize,
+ R8G8B8A8_UNORM)
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
+ // Change buffer size and set scaling mode to freeze
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, Point(0, 0),
+ R8G8B8A8_UNORM)
+
+ // first dequeued buffer does not have the new size so it should be rejected.
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ activity.mSurfaceProxy.SurfaceSetScalingMode(ScalingMode.SCALE_TO_WINDOW)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(1)
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */), 0)
+ }
+
+ // verify buffer size is reset to default buffer size
+ assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize)
+ assertThat(trace).layer("SurfaceView", 2).doesNotExist()
+ assertThat(trace).layer("SurfaceView", 3).hasBufferSize(bufferSize)
+ }
+
+ @Test
+ fun testSetBuffersTransform_FLIP() {
+ val transforms = arrayOf(Transform.FLIP_H, Transform.FLIP_V, Transform.ROT_180).withIndex()
+ for ((index, transform) in transforms) {
+ val trace = withTrace { activity ->
+ activity.mSurfaceProxy.ANativeWindowSetBuffersTransform(transform)
+ activity.mSurfaceProxy.ANativeWindowLock()
+ activity.mSurfaceProxy.ANativeWindowUnlockAndPost()
+ activity.mSurfaceProxy.waitUntilBufferDisplayed(index + 1L, 500 /* ms */)
+ }
+
+ assertThat(trace).layer("SurfaceView", index + 1L).also {
+ it.hasBufferSize(defaultBufferSize)
+ it.hasLayerSize(defaultBufferSize)
+ it.hasBufferOrientation(transform.value)
+ }
+ }
+ }
+
+ @Test
+ fun testSurfaceViewResizeImmediatelyWithNonFreezeScaling() {
+ val surfaceViewPosition = Rect()
+ var trace = withTrace { activity ->
+ activity.mSurfaceProxy.SurfaceSetScalingMode(ScalingMode.SCALE_TO_WINDOW)
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1 /* ms */))
+ activity.mSurfaceProxy.drawBuffer(0, Color.BLUE)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */)
+ activity.mSurfaceView!!.getBoundsOnScreen(surfaceViewPosition)
+ }
+
+ runOnUiThread {
+ val svBounds = Rect(0, 0, defaultBufferSize.x, defaultBufferSize.y)
+ svBounds.offsetTo(surfaceViewPosition.left, surfaceViewPosition.top)
+ checkPixels(svBounds, Color.BLUE)
+ }
+
+ // check that the layer and buffer starts with the default size
+ assertThat(trace).layer("SurfaceView", 1).also {
+ it.hasBufferSize(defaultBufferSize)
+ it.hasLayerSize(defaultBufferSize)
+ }
+ val newSize = Point(1280, 960)
+ lateinit var resizeCountDownLatch: CountDownLatch
+ runOnUiThread {
+ resizeCountDownLatch = it.resizeSurfaceView(newSize)
+ }
+ assertTrue(resizeCountDownLatch.await(1000, TimeUnit.MILLISECONDS))
+ // wait for sf to handle the resize transaction request
+ SystemClock.sleep(500)
+ trace = withTrace { _ ->
+ // take a trace with the new size
+ }
+
+ // check that the layer size has changed and the buffer is now streched to the new layer
+ // size
+ runOnUiThread {
+ val svBounds = Rect(0, 0, newSize.x, newSize.y)
+ svBounds.offsetTo(surfaceViewPosition.left, surfaceViewPosition.top)
+ checkPixels(svBounds, Color.BLUE)
+ }
+
+ assertThat(trace).layer("SurfaceView", 1).also {
+ it.hasLayerSize(newSize)
+ it.hasBufferSize(defaultBufferSize)
+ }
+ }
+
+ @Test
+ fun testSurfaceViewDoesNotResizeWithDefaultScaling() {
+ val surfaceViewPosition = Rect()
+ var trace = withTrace { activity ->
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1 /* ms */))
+ activity.mSurfaceProxy.drawBuffer(0, Color.BLUE)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */)
+ activity.mSurfaceView!!.getBoundsOnScreen(surfaceViewPosition)
+ }
+
+ runOnUiThread {
+ val svBounds = Rect(0, 0, defaultBufferSize.x, defaultBufferSize.y)
+ svBounds.offsetTo(surfaceViewPosition.left, surfaceViewPosition.top)
+ checkPixels(svBounds, Color.BLUE)
+ }
+
+ // check that the layer and buffer starts with the default size
+ assertThat(trace).layer("SurfaceView", 1).also {
+ it.hasBufferSize(defaultBufferSize)
+ it.hasLayerSize(defaultBufferSize)
+ }
+ val newSize = Point(1280, 960)
+ lateinit var resizeCountDownLatch: CountDownLatch
+ runOnUiThread {
+ resizeCountDownLatch = it.resizeSurfaceView(newSize)
+ }
+ assertTrue(resizeCountDownLatch.await(1000, TimeUnit.MILLISECONDS))
+ // wait for sf to handle the resize transaction request
+ SystemClock.sleep(500)
+ trace = withTrace { _ ->
+ // take a trace after the size change
+ }
+
+ // check the layer and buffer remains the same size
+ runOnUiThread {
+ val svBounds = Rect(0, 0, defaultBufferSize.x, defaultBufferSize.y)
+ svBounds.offsetTo(surfaceViewPosition.left, surfaceViewPosition.top)
+ checkPixels(svBounds, Color.BLUE)
+ }
+
+ assertThat(trace).layer("SurfaceView", 1).also {
+ it.hasLayerSize(defaultBufferSize)
+ it.hasBufferSize(defaultBufferSize)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt
new file mode 100644
index 000000000000..69012bdd7d7c
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test
+
+import android.graphics.Point
+import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
+import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
+import junit.framework.Assert.assertEquals
+import org.junit.Assume.assumeFalse
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class InverseDisplayTransformTests(useBlastAdapter: Boolean) :
+ SurfaceTracingTestBase(useBlastAdapter) {
+ @Before
+ override fun setup() {
+ scenarioRule.getScenario().onActivity {
+ it.rotate90()
+ }
+ instrumentation.waitForIdleSync()
+ super.setup()
+ }
+
+ @Test
+ fun testSetBufferScalingMode_freeze_withInvDisplayTransform() {
+ assumeFalse("Blast does not support buffer rejection with Inv display " +
+ "transform since the only user for this hidden api is camera which does not use" +
+ "fixed scaling mode.", useBlastAdapter)
+
+ val rotatedBufferSize = Point(defaultBufferSize.y, defaultBufferSize.x)
+ val trace = withTrace { activity ->
+ // Inverse display transforms are sticky AND they are only consumed by the sf after
+ // a valid buffer has been acquired.
+ activity.mSurfaceProxy.ANativeWindowSetBuffersTransform(Transform.INVERSE_DISPLAY.value)
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed(1, 500 /* ms */), 0)
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!,
+ rotatedBufferSize, R8G8B8A8_UNORM)
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1000 /* ms */))
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(1, 1000 /* ms */))
+ // Change buffer size and set scaling mode to freeze
+ activity.mSurfaceProxy.ANativeWindowSetBuffersGeometry(activity.surface!!, Point(0, 0),
+ R8G8B8A8_UNORM)
+
+ // first dequeued buffer does not have the new size so it should be rejected.
+ activity.mSurfaceProxy.ANativeWindowSetBuffersTransform(Transform.ROT_90.value)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ activity.mSurfaceProxy.ANativeWindowSetBuffersTransform(0)
+ activity.mSurfaceProxy.SurfaceQueueBuffer(1)
+ assertEquals(activity.mSurfaceProxy.waitUntilBufferDisplayed(3, 500 /* ms */), 0)
+ }
+
+ // verify buffer size is reset to default buffer size
+ assertThat(trace).layer("SurfaceView", 1).hasBufferSize(defaultBufferSize)
+ assertThat(trace).layer("SurfaceView", 2).doesNotExist()
+ assertThat(trace).layer("SurfaceView", 3).hasBufferSize(rotatedBufferSize)
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/MainActivity.kt b/tests/SurfaceViewBufferTests/src/com/android/test/MainActivity.kt
new file mode 100644
index 000000000000..5f398f380b01
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/MainActivity.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test
+
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.content.res.Configuration.ORIENTATION_LANDSCAPE
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Point
+import android.graphics.Rect
+import android.os.Bundle
+import android.view.Gravity
+import android.view.Surface
+import android.view.SurfaceHolder
+import android.view.SurfaceView
+import android.view.View
+import android.view.WindowManager
+import android.view.cts.surfacevalidator.CapturedActivity
+import android.widget.FrameLayout
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.locks.ReentrantLock
+import kotlin.concurrent.withLock
+
+class MainActivity : CapturedActivity() {
+ val mSurfaceProxy = SurfaceProxy()
+ private var mSurfaceHolder: SurfaceHolder? = null
+ private val mDrawLock = ReentrantLock()
+ var mSurfaceView: SurfaceView? = null
+ private var mCountDownLatch: CountDownLatch? = null
+
+ val surface: Surface? get() = mSurfaceHolder?.surface
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ window.decorView.apply {
+ systemUiVisibility =
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN
+ }
+ }
+
+ override fun getCaptureDurationMs(): Long {
+ return 30000
+ }
+
+ fun addSurfaceView(size: Point): CountDownLatch {
+ val layout = findViewById<FrameLayout>(android.R.id.content)
+ val surfaceReadyLatch = CountDownLatch(1)
+ mSurfaceView = createSurfaceView(applicationContext, size, surfaceReadyLatch)
+ layout!!.addView(mSurfaceView!!,
+ FrameLayout.LayoutParams(size.x, size.y, Gravity.TOP or Gravity.LEFT)
+ .also { it.setMargins(100, 100, 0, 0) })
+
+ return surfaceReadyLatch
+ }
+
+ fun resizeSurfaceView(size: Point): CountDownLatch {
+ mCountDownLatch = CountDownLatch(1)
+ mSurfaceView!!.layoutParams.also {
+ it.width = size.x
+ it.height = size.y
+ }
+ mSurfaceView!!.requestLayout()
+ return mCountDownLatch!!
+ }
+
+ fun enableSeamlessRotation() {
+ val p: WindowManager.LayoutParams = window.attributes
+ p.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS
+ window.attributes = p
+ }
+
+ fun rotate90() {
+ if (getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE) {
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
+ } else {
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
+ }
+ }
+
+ private fun createSurfaceView(
+ context: Context,
+ size: Point,
+ surfaceReadyLatch: CountDownLatch
+ ): SurfaceView {
+ val surfaceView = SurfaceView(context)
+ surfaceView.setWillNotDraw(false)
+ surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
+ override fun surfaceCreated(holder: SurfaceHolder) {
+ mDrawLock.withLock {
+ mSurfaceHolder = holder
+ mSurfaceProxy.setSurface(holder.surface)
+ }
+ surfaceReadyLatch.countDown()
+ }
+
+ override fun surfaceChanged(
+ holder: SurfaceHolder,
+ format: Int,
+ width: Int,
+ height: Int
+ ) {
+ mCountDownLatch?.countDown()
+ }
+
+ override fun surfaceDestroyed(holder: SurfaceHolder) {
+ mDrawLock.withLock {
+ mSurfaceHolder = null
+ }
+ }
+ })
+ return surfaceView
+ }
+
+ fun drawFrame(): Rect {
+ mDrawLock.withLock {
+ val holder = mSurfaceHolder ?: return Rect()
+ val canvas = holder.lockCanvas()
+ val canvasSize = Rect(0, 0, canvas.width, canvas.height)
+ canvas.drawColor(Color.GREEN)
+ val p = Paint()
+ p.color = Color.RED
+ canvas.drawRect(canvasSize, p)
+ holder.unlockCanvasAndPost(canvas)
+ return canvasSize
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/ScreenRecordTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/ScreenRecordTestBase.kt
new file mode 100644
index 000000000000..df3d30e13908
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/ScreenRecordTestBase.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test
+
+import android.annotation.ColorInt
+import android.content.Context
+import android.content.Intent
+import android.graphics.Rect
+import android.server.wm.WindowManagerState.getLogicalDisplaySize
+import android.view.cts.surfacevalidator.CapturedActivity
+import android.view.cts.surfacevalidator.ISurfaceValidatorTestCase
+import android.view.cts.surfacevalidator.PixelChecker
+import android.view.cts.surfacevalidator.RectChecker
+import android.widget.FrameLayout
+import androidx.test.rule.ActivityTestRule
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import java.util.concurrent.CountDownLatch
+
+open class ScreenRecordTestBase(useBlastAdapter: Boolean) :
+ SurfaceViewBufferTestBase(useBlastAdapter) {
+ @get:Rule
+ var mActivityRule = ActivityTestRule(MainActivity::class.java)
+
+ private lateinit var mActivity: MainActivity
+
+ @Before
+ override fun setup() {
+ super.setup()
+ mActivity = mActivityRule.launchActivity(Intent())
+ lateinit var surfaceReadyLatch: CountDownLatch
+ runOnUiThread {
+ it.dismissPermissionDialog()
+ it.setLogicalDisplaySize(getLogicalDisplaySize())
+ surfaceReadyLatch = it.addSurfaceView(defaultBufferSize)
+ }
+ surfaceReadyLatch.await()
+ // sleep to finish animations
+ instrumentation.waitForIdleSync()
+ }
+
+ @After
+ override fun teardown() {
+ super.teardown()
+ mActivityRule.finishActivity()
+ }
+
+ fun runOnUiThread(predicate: (it: MainActivity) -> Unit) {
+ mActivityRule.runOnUiThread {
+ predicate(mActivity)
+ }
+ }
+
+ fun withScreenRecording(
+ boundsToCheck: Rect,
+ @ColorInt color: Int,
+ predicate: (it: MainActivity) -> Unit
+ ): CapturedActivity.TestResult {
+ val testCase = object : ISurfaceValidatorTestCase {
+ override fun getChecker(): PixelChecker = RectChecker(boundsToCheck, color)
+ override fun start(context: Context, parent: FrameLayout) {
+ predicate(mActivity)
+ }
+ override fun end() { /* do nothing */ }
+ }
+
+ return mActivity.runTest(testCase)
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeScreenRecordTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeScreenRecordTests.kt
new file mode 100644
index 000000000000..996a1d3d79da
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeScreenRecordTests.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test
+
+import android.graphics.Color
+import android.graphics.Rect
+import android.os.SystemClock
+import android.view.cts.surfacevalidator.PixelColor
+import junit.framework.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class SharedBufferModeScreenRecordTests(useBlastAdapter: Boolean) :
+ ScreenRecordTestBase(useBlastAdapter) {
+
+ /** When auto refresh is set, surface flinger will wake up and refresh the display presenting
+ * the latest content in the buffer.
+ */
+ @Test
+ fun testAutoRefresh() {
+ var svBounds = Rect()
+ runOnUiThread {
+ assertEquals(0, it.mSurfaceProxy.NativeWindowSetSharedBufferMode(true))
+ assertEquals(0, it.mSurfaceProxy.NativeWindowSetAutoRefresh(true))
+ assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1 /* ms */))
+ it.mSurfaceProxy.SurfaceQueueBuffer(0, false /* freeSlot */)
+ assertEquals(0,
+ it.mSurfaceProxy.waitUntilBufferDisplayed(1, 5000 /* ms */))
+
+ svBounds = Rect(0, 0, it.mSurfaceView!!.width, it.mSurfaceView!!.height)
+ val position = Rect()
+ it.mSurfaceView!!.getBoundsOnScreen(position)
+ svBounds.offsetTo(position.left, position.top)
+
+ // wait for buffers from other layers to be latched and transactions to be processed before
+ // updating the buffer
+ SystemClock.sleep(4000)
+ }
+
+ val result = withScreenRecording(svBounds, PixelColor.RED) {
+ it.mSurfaceProxy.drawBuffer(0, Color.RED)
+ }
+ val failRatio = 1.0f * result.failFrames / (result.failFrames + result.passFrames)
+
+ assertTrue("Error: " + result.failFrames +
+ " incorrect frames observed (out of " + (result.failFrames + result.passFrames) +
+ " frames)", failRatio < 0.05)
+ assertTrue("Error: Did not receive sufficient frame updates expected: >1000 actual:" +
+ result.passFrames, result.passFrames > 1000)
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt
new file mode 100644
index 000000000000..ee41d7941470
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test
+
+import android.graphics.Color
+import android.graphics.Rect
+import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
+import junit.framework.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class SharedBufferModeTests(useBlastAdapter: Boolean) : SurfaceTracingTestBase(useBlastAdapter) {
+ /** Sanity test to check each buffer is presented if its submitted with enough delay
+ * for SF to present the buffers. */
+ @Test
+ fun testCanPresentBuffers() {
+ val numFrames = 15L
+ val trace = withTrace { activity ->
+ assertEquals(0, activity.mSurfaceProxy.NativeWindowSetSharedBufferMode(true))
+ for (i in 1..numFrames) {
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1 /* ms */))
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ assertEquals(0, activity.mSurfaceProxy.waitUntilBufferDisplayed(i, 5000 /* ms */))
+ }
+ }
+
+ assertThat(trace).hasFrameSequence("SurfaceView", 1..numFrames)
+ }
+
+ /** Submit buffers as fast as possible testing that we are not blocked when dequeuing the buffer
+ * by setting the dequeue timeout to 1ms and checking that we present the newest buffer. */
+ @Test
+ fun testFastQueueBuffers() {
+ val numFrames = 15L
+ val trace = withTrace { activity ->
+ assertEquals(0, activity.mSurfaceProxy.NativeWindowSetSharedBufferMode(true))
+ for (i in 1..numFrames) {
+ assertEquals(0, activity.mSurfaceProxy.SurfaceDequeueBuffer(0, 1 /* ms */))
+ activity.mSurfaceProxy.SurfaceQueueBuffer(0)
+ }
+ assertEquals(0, activity.mSurfaceProxy.waitUntilBufferDisplayed(numFrames,
+ 5000 /* ms */))
+ }
+
+ assertThat(trace).hasFrameSequence("SurfaceView", numFrames..numFrames)
+ }
+
+ /** Keep overwriting the buffer without queuing buffers and check that we present the latest
+ * buffer content. */
+ @Test
+ fun testAutoRefresh() {
+ var svBounds = Rect()
+ runOnUiThread {
+ assertEquals(0, it.mSurfaceProxy.NativeWindowSetSharedBufferMode(true))
+ assertEquals(0, it.mSurfaceProxy.NativeWindowSetAutoRefresh(true))
+ assertEquals(0, it.mSurfaceProxy.SurfaceDequeueBuffer(0, 1 /* ms */))
+ it.mSurfaceProxy.SurfaceQueueBuffer(0, false /* freeSlot */)
+ assertEquals(0, it.mSurfaceProxy.waitUntilBufferDisplayed(1, 5000 /* ms */))
+
+ svBounds = Rect(0, 0, it.mSurfaceView!!.width, it.mSurfaceView!!.height)
+ val position = Rect()
+ it.mSurfaceView!!.getBoundsOnScreen(position)
+ svBounds.offsetTo(position.left, position.top)
+ }
+
+ runOnUiThread {
+ it.mSurfaceProxy.drawBuffer(0, Color.RED)
+ checkPixels(svBounds, Color.RED)
+ it.mSurfaceProxy.drawBuffer(0, Color.GREEN)
+ checkPixels(svBounds, Color.GREEN)
+ it.mSurfaceProxy.drawBuffer(0, Color.BLUE)
+ checkPixels(svBounds, Color.BLUE)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt
new file mode 100644
index 000000000000..45a70944204c
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceProxy.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test
+
+import android.annotation.ColorInt
+import android.graphics.Color
+import android.graphics.Point
+import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode
+import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
+
+class SurfaceProxy {
+ init {
+ System.loadLibrary("surface_jni")
+ }
+
+ external fun setSurface(surface: Any)
+ external fun waitUntilBufferDisplayed(frameNumber: Long, timeoutMs: Int): Int
+ external fun draw()
+ fun drawBuffer(slot: Int, @ColorInt c: Int) {
+ drawBuffer(slot, intArrayOf(Color.red(c), Color.green(c), Color.blue(c), Color.alpha(c)))
+ }
+ external fun drawBuffer(slot: Int, color: IntArray)
+
+ // android/native_window.h functions
+ external fun ANativeWindowLock()
+ external fun ANativeWindowUnlockAndPost()
+ fun ANativeWindowSetBuffersGeometry(surface: Any, size: Point, format: Int) {
+ ANativeWindowSetBuffersGeometry(surface, size.x, size.y, format)
+ }
+ external fun ANativeWindowSetBuffersGeometry(surface: Any, width: Int, height: Int, format: Int)
+ fun ANativeWindowSetBuffersTransform(transform: Transform) {
+ ANativeWindowSetBuffersTransform(transform.value)
+ }
+ external fun ANativeWindowSetBuffersTransform(transform: Int)
+
+ // gui/Surface.h functions
+ fun SurfaceSetScalingMode(scalingMode: ScalingMode) {
+ SurfaceSetScalingMode(scalingMode.ordinal)
+ }
+ external fun SurfaceSetScalingMode(scalingMode: Int)
+ external fun SurfaceDequeueBuffer(slot: Int, timeoutMs: Int): Int
+ external fun SurfaceCancelBuffer(slot: Int)
+ external fun SurfaceQueueBuffer(slot: Int, freeSlot: Boolean = true): Int
+ external fun SurfaceSetAsyncMode(async: Boolean): Int
+ external fun SurfaceSetDequeueTimeout(timeout: Long): Int
+ external fun SurfaceQuery(what: Int): Int
+ external fun SurfaceSetMaxDequeuedBufferCount(maxDequeuedBuffers: Int): Int
+
+ // system/native_window.h functions
+ external fun NativeWindowSetBufferCount(count: Int): Int
+ external fun NativeWindowSetSharedBufferMode(shared: Boolean): Int
+ external fun NativeWindowSetAutoRefresh(autoRefresh: Boolean): Int
+}
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
new file mode 100644
index 000000000000..6383da5a0a98
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test
+
+import android.annotation.ColorInt
+import android.graphics.Bitmap
+import android.graphics.Color
+import android.graphics.Rect
+import android.util.Log
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import com.android.server.wm.flicker.monitor.LayersTraceMonitor
+import com.android.server.wm.flicker.monitor.withSFTracing
+import com.android.server.wm.traces.common.layers.LayersTrace
+import junit.framework.Assert
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import java.io.FileOutputStream
+import java.io.IOException
+import java.util.concurrent.CountDownLatch
+
+open class SurfaceTracingTestBase(useBlastAdapter: Boolean) :
+ SurfaceViewBufferTestBase(useBlastAdapter) {
+ @get:Rule
+ var scenarioRule: ActivityScenarioRule<MainActivity> =
+ ActivityScenarioRule<MainActivity>(MainActivity::class.java)
+
+ @Before
+ override fun setup() {
+ super.setup()
+ stopLayerTrace()
+ addSurfaceView()
+ }
+
+ @After
+ override fun teardown() {
+ super.teardown()
+ scenarioRule.getScenario().close()
+ }
+
+ fun withTrace(predicate: (it: MainActivity) -> Unit): LayersTrace {
+ return withSFTracing(TRACE_FLAGS,
+ outputDir = instrumentation.targetContext.dataDir.toPath()) {
+ scenarioRule.getScenario().onActivity {
+ predicate(it)
+ }
+ }
+ }
+
+ fun withTrace(predicate: () -> Unit): LayersTrace {
+ return withSFTracing(TRACE_FLAGS,
+ outputDir = instrumentation.targetContext.dataDir.toPath()) {
+ predicate()
+ }
+ }
+
+ fun runOnUiThread(predicate: (it: MainActivity) -> Unit) {
+ scenarioRule.getScenario().onActivity {
+ predicate(it)
+ }
+ }
+
+ private fun addSurfaceView() {
+ lateinit var surfaceReadyLatch: CountDownLatch
+ scenarioRule.getScenario().onActivity {
+ surfaceReadyLatch = it.addSurfaceView(defaultBufferSize)
+ }
+ surfaceReadyLatch.await()
+ // sleep to finish animations
+ instrumentation.waitForIdleSync()
+ }
+
+ private fun stopLayerTrace() {
+ val tmpDir = instrumentation.targetContext.dataDir.toPath()
+ LayersTraceMonitor(tmpDir).stop()
+ }
+
+ fun checkPixels(bounds: Rect, @ColorInt color: Int) {
+ val screenshot = instrumentation.getUiAutomation().takeScreenshot()
+ val pixels = IntArray(screenshot.width * screenshot.height)
+ screenshot.getPixels(pixels, 0, screenshot.width, 0, 0, screenshot.width, screenshot.height)
+ for (i in bounds.left + 10..bounds.right - 10) {
+ for (j in bounds.top + 10..bounds.bottom - 10) {
+ val actualColor = pixels[j * screenshot.width + i]
+ if (actualColor != color) {
+ val screenshotPath = instrumentation.targetContext
+ .getExternalFilesDir(null)?.resolve("screenshot.png")
+ try {
+ FileOutputStream(screenshotPath).use { out ->
+ screenshot.compress(Bitmap.CompressFormat.PNG, 100, out)
+ }
+ Log.e("SurfaceViewBufferTests", "Bitmap written to $screenshotPath")
+ } catch (e: IOException) {
+ Log.e("SurfaceViewBufferTests", "Error writing bitmap to file", e)
+ }
+ }
+ Assert.assertEquals("Checking $bounds found mismatch $i,$j",
+ Color.valueOf(color), Color.valueOf(actualColor))
+ }
+ }
+ }
+
+ private companion object {
+ private const val TRACE_FLAGS =
+ (1 shl 0) or (1 shl 5) or (1 shl 6) // TRACE_CRITICAL | TRACE_BUFFERS | TRACE_SYNC
+ }
+} \ No newline at end of file
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt
new file mode 100644
index 000000000000..093c3125f253
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test
+
+import android.app.Instrumentation
+import android.graphics.Point
+import android.provider.Settings
+import androidx.test.InstrumentationRegistry
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.rules.TestName
+import org.junit.runners.Parameterized
+import kotlin.properties.Delegates
+
+open class SurfaceViewBufferTestBase(val useBlastAdapter: Boolean) {
+ private var mInitialBlastConfig by Delegates.notNull<Boolean>()
+
+ val instrumentation: Instrumentation
+ get() = InstrumentationRegistry.getInstrumentation()
+
+ @get:Rule
+ var mName = TestName()
+
+ @Before
+ open fun setup() {
+ mInitialBlastConfig = getBlastAdapterSvEnabled()
+ setBlastAdapterSvEnabled(useBlastAdapter)
+ }
+
+ @After
+ open fun teardown() {
+ setBlastAdapterSvEnabled(mInitialBlastConfig)
+ }
+
+ private fun getBlastAdapterSvEnabled(): Boolean {
+ return Settings.Global.getInt(instrumentation.context.contentResolver,
+ "use_blast_adapter_sv", 0) != 0
+ }
+
+ private fun setBlastAdapterSvEnabled(enable: Boolean) {
+ Settings.Global.putInt(instrumentation.context.contentResolver, "use_blast_adapter_sv",
+ if (enable) 1 else 0)
+ }
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "blast={0}")
+ fun data(): Collection<Array<Any>> {
+ return listOf(
+ arrayOf(false), // First test: submit buffers via bufferqueue
+ arrayOf(true) // Second test: submit buffers via blast adapter
+ )
+ }
+
+ const val R8G8B8A8_UNORM = 1
+ val defaultBufferSize = Point(640, 480)
+
+ // system/window.h definitions
+ enum class ScalingMode() {
+ FREEZE, // = 0
+ SCALE_TO_WINDOW, // =1
+ SCALE_CROP, // = 2
+ NO_SCALE_CROP // = 3
+ }
+
+ // system/window.h definitions
+ enum class Transform(val value: Int) {
+ /* flip source image horizontally */
+ FLIP_H(1),
+ /* flip source image vertically */
+ FLIP_V(2),
+ /* rotate source image 90 degrees clock-wise, and is applied after TRANSFORM_FLIP_{H|V} */
+ ROT_90(4),
+ /* rotate source image 180 degrees */
+ ROT_180(3),
+ /* rotate source image 270 degrees clock-wise */
+ ROT_270(7),
+ /* transforms source by the inverse transform of the screen it is displayed onto. This
+ * transform is applied last */
+ INVERSE_DISPLAY(0x08)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/SystemMemoryTest/device/Android.bp b/tests/SystemMemoryTest/device/Android.bp
index 2bf0fec0fd1f..d7cec1aedaed 100644
--- a/tests/SystemMemoryTest/device/Android.bp
+++ b/tests/SystemMemoryTest/device/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test_helper_app {
name: "SystemMemoryTestDevice",
sdk_version: "current",
diff --git a/tests/SystemMemoryTest/host/Android.bp b/tests/SystemMemoryTest/host/Android.bp
index 3bb5489dab6c..79744625b752 100644
--- a/tests/SystemMemoryTest/host/Android.bp
+++ b/tests/SystemMemoryTest/host/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
java_test_host {
name: "system-memory-test",
srcs: ["src/**/*.java"],
diff --git a/tests/SystemUIDemoModeController/Android.bp b/tests/SystemUIDemoModeController/Android.bp
index 1e4c43792d70..d952cf6a4b3e 100644
--- a/tests/SystemUIDemoModeController/Android.bp
+++ b/tests/SystemUIDemoModeController/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "DemoModeController",
srcs: ["**/*.java"],
diff --git a/tests/SystemUIDemoModeController/AndroidManifest.xml b/tests/SystemUIDemoModeController/AndroidManifest.xml
index 2e97932df525..5feb4acf259d 100644
--- a/tests/SystemUIDemoModeController/AndroidManifest.xml
+++ b/tests/SystemUIDemoModeController/AndroidManifest.xml
@@ -15,23 +15,21 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.demomodecontroller"
- android:versionCode="1"
- android:versionName="0.1" >
+ package="com.example.android.demomodecontroller"
+ android:versionCode="1"
+ android:versionName="0.1">
- <uses-sdk
- android:minSdkVersion="19"
- android:targetSdkVersion="19" />
+ <uses-sdk android:minSdkVersion="19"
+ android:targetSdkVersion="19"/>
- <application
- android:allowBackup="false"
- android:label="@string/app_name" >
- <activity
- android:name=".DemoModeController" >
+ <application android:allowBackup="false"
+ android:label="@string/app_name">
+ <activity android:name=".DemoModeController"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/TaskOrganizerTest/Android.bp b/tests/TaskOrganizerTest/Android.bp
index 8a13dbc52c66..9b72d359aae6 100644
--- a/tests/TaskOrganizerTest/Android.bp
+++ b/tests/TaskOrganizerTest/Android.bp
@@ -14,9 +14,31 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "TaskOrganizerTest",
- srcs: ["**/*.java"],
+ srcs: ["**/*.java","**/*.kt"],
+ manifest: "AndroidManifest.xml",
+ test_config: "AndroidTest.xml",
platform_apis: true,
certificate: "platform",
-}
+
+ static_libs: [
+ "androidx.appcompat_appcompat",
+ "androidx.test.rules",
+ "androidx.test.runner",
+ "androidx.test.ext.junit",
+ "kotlin-stdlib",
+ "kotlinx-coroutines-android",
+ "flickerlib",
+ "truth-prebuilt",
+ ],
+} \ No newline at end of file
diff --git a/tests/TaskOrganizerTest/AndroidManifest.xml b/tests/TaskOrganizerTest/AndroidManifest.xml
index a77d7ee80242..1f1bd3ef7d81 100644
--- a/tests/TaskOrganizerTest/AndroidManifest.xml
+++ b/tests/TaskOrganizerTest/AndroidManifest.xml
@@ -10,20 +10,47 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.taskembed">
- <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
- <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ package="com.android.test.taskembed">
+ <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
+ <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+ <!-- Enable / Disable tracing !-->
+ <uses-permission android:name="android.permission.DUMP" />
<application>
- <service android:name=".TaskOrganizerPipTest"
- android:exported="true">
- </service>
- <activity android:name="TaskOrganizerMultiWindowTest" android:label="TaskOrganizer MW Test">
+ <activity android:name="TaskOrganizerMultiWindowTest"
+ android:label="TaskOrganizer MW Test"
+ android:exported="true"
+ android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+ <activity android:name="TaskOrganizerMultiWindowTest$TestActivity1"
+ android:label="Test Activity 1"
+ android:exported="false"
+ android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen"
+ android:taskAffinity="com.android.test.taskembed.task1"
+ android:excludeFromRecents="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ </intent-filter>
+ </activity>
+ <activity android:name="TaskOrganizerMultiWindowTest$TestActivity2"
+ android:label="Test Activity 2"
+ android:exported="false"
+ android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen"
+ android:taskAffinity="com.android.test.taskembed.task2"
+ android:excludeFromRecents="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ </intent-filter>
+ </activity>
</application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.test.taskembed"
+ android:label="TaskOrganizerTest">
+ </instrumentation>
</manifest>
diff --git a/tests/TaskOrganizerTest/AndroidTest.xml b/tests/TaskOrganizerTest/AndroidTest.xml
new file mode 100644
index 000000000000..45fd8b0a6e3a
--- /dev/null
+++ b/tests/TaskOrganizerTest/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs TaskOrganizer Test">
+ <option name="test-tag" value="TaskOrganizerTest" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on" />
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="false"/>
+ <option name="test-file-name" value="TaskOrganizerTest.apk"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.test.taskembed"/>
+ <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+ <option name="shell-timeout" value="6600s" />
+ <option name="test-timeout" value="6000s" />
+ <option name="hidden-api-checks" value="false" />
+ </test>
+</configuration>
diff --git a/tests/TaskOrganizerTest/OWNERS b/tests/TaskOrganizerTest/OWNERS
new file mode 100644
index 000000000000..0862c05e0ee4
--- /dev/null
+++ b/tests/TaskOrganizerTest/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
new file mode 100644
index 000000000000..03b43cc5b18c
--- /dev/null
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.taskembed
+
+import android.app.Instrumentation
+import android.graphics.Point
+import android.graphics.Rect
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.runner.AndroidJUnit4
+import com.android.server.wm.flicker.monitor.LayersTraceMonitor
+import com.android.server.wm.flicker.monitor.withSFTracing
+import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import java.util.concurrent.CountDownLatch
+import org.junit.Assert.assertNotEquals
+
+@RunWith(AndroidJUnit4::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class ResizeTasksSyncTest {
+ @get:Rule
+ var scenarioRule: ActivityScenarioRule<TaskOrganizerMultiWindowTest> =
+ ActivityScenarioRule<TaskOrganizerMultiWindowTest>(
+ TaskOrganizerMultiWindowTest::class.java)
+
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+
+ @Before
+ fun setup() {
+ val tmpDir = instrumentation.targetContext.dataDir.toPath()
+ LayersTraceMonitor(tmpDir).stop()
+ val firstTaskBounds = Rect(0, 0, 1080, 1000)
+ val secondTaskBounds = Rect(0, 1000, 1080, 2000)
+
+ lateinit var surfaceReadyLatch: CountDownLatch
+ scenarioRule.getScenario().onActivity {
+ surfaceReadyLatch = it.openTaskView(firstTaskBounds, secondTaskBounds)
+ }
+ surfaceReadyLatch.await()
+ }
+
+ @After
+ fun teardown() {
+ scenarioRule.getScenario().close()
+ }
+
+ @Test
+ fun testResizeTwoTaskSync() {
+ val firstBounds = Rect(0, 0, 1080, 800)
+ val secondBounds = Rect(0, 1000, 1080, 1800)
+
+ val trace = withSFTracing(TRACE_FLAGS,
+ outputDir = instrumentation.targetContext.dataDir.toPath()) {
+ lateinit var resizeReadyLatch: CountDownLatch
+ scenarioRule.getScenario().onActivity {
+ resizeReadyLatch = it.resizeTaskView(firstBounds, secondBounds)
+ }
+ resizeReadyLatch.await()
+ }
+
+ // find the frame which match resized buffer size.
+ val frame = trace.entries.flatMap { it.flattenedLayers.toList() }
+ .firstOrNull { layer ->
+ !layer.isActiveBufferEmpty &&
+ layer.activeBuffer?.width == firstBounds.width() &&
+ layer.activeBuffer?.height == firstBounds.height()
+ }?.currFrame ?: -1
+
+ assertNotEquals(-1, frame)
+ // layer bounds should be related to parent surfaceview.
+ secondBounds.offsetTo(0, 0)
+
+ // verify buffer size should be changed to expected values.
+ assertThat(trace).layer(FIRST_ACTIVITY, frame.toLong()).also {
+ val firstTaskSize = Point(firstBounds.width(), firstBounds.height())
+ it.hasLayerSize(firstTaskSize)
+ it.hasBufferSize(firstTaskSize)
+ }
+
+ assertThat(trace).layer(SECOND_ACTIVITY, frame.toLong()).also {
+ val secondTaskSize = Point(secondBounds.width(), secondBounds.height())
+ it.hasLayerSize(secondTaskSize)
+ it.hasBufferSize(secondTaskSize)
+ }
+ }
+
+ companion object {
+ private const val TRACE_FLAGS = 0x1 // TRACE_CRITICAL
+ private const val FIRST_ACTIVITY = "Activity1"
+ private const val SECOND_ACTIVITY = "Activity2"
+ }
+} \ No newline at end of file
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
index 073ae30aaf1a..0cf5a41de82a 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,189 +16,182 @@
package com.android.test.taskembed;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import android.app.Activity;
import android.app.ActivityManager;
-import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.Gravity;
-import android.view.MotionEvent;
import android.view.SurfaceControl;
-import android.view.SurfaceHolder;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
+import android.widget.FrameLayout;
+import android.widget.TextView;
import android.window.TaskOrganizer;
-import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransactionCallback;
-public class TaskOrganizerMultiWindowTest extends Activity {
- static class SplitLayout extends LinearLayout implements View.OnTouchListener {
- View mView1;
- View mView2;
- View mDividerView;
-
- public boolean onTouch(View v, MotionEvent e) {
- if (e.getAction() != MotionEvent.ACTION_UP) {
- return true;
- }
-
- float x = e.getRawX(0);
- float ratio = (float) x / (float) getWidth() ;
- ratio = 1-ratio;
-
- LinearLayout.LayoutParams lp1 =
- new LinearLayout.LayoutParams(0,
- ViewGroup.LayoutParams.WRAP_CONTENT, ratio-0.02f);
- LinearLayout.LayoutParams lp2 =
- new LinearLayout.LayoutParams(0,
- ViewGroup.LayoutParams.WRAP_CONTENT, 1-ratio-0.02f);
- updateViewLayout(mView1, lp2);
- updateViewLayout(mView2, lp1);
- return true;
- }
-
- SplitLayout(Context c, View v1, View v2) {
- super(c);
- LinearLayout.LayoutParams lp1 =
- new LinearLayout.LayoutParams(0,
- ViewGroup.LayoutParams.WRAP_CONTENT, 0.48f);
- LinearLayout.LayoutParams lp3 =
- new LinearLayout.LayoutParams(0,
- ViewGroup.LayoutParams.WRAP_CONTENT, 0.48f);
- LinearLayout.LayoutParams lp2 =
- new LinearLayout.LayoutParams(0,
- ViewGroup.LayoutParams.FILL_PARENT, 0.04f);
- lp2.gravity = Gravity.CENTER;
-
- setWeightSum(1);
-
- mView1 = v1;
- mView2 = v2;
- addView(mView1, lp1);
-
- mDividerView = new View(getContext());
- mDividerView.setBackgroundColor(Color.BLACK);
- addView(mDividerView, lp2);
- mDividerView.setOnTouchListener(this);
-
- addView(mView2, lp3);
- }
- }
-
- class ResizingTaskView extends TaskView {
- final Intent mIntent;
- boolean launched = false;
- ResizingTaskView(Context c, Intent i) {
- super(c);
- mIntent = i;
- }
+import java.util.concurrent.CountDownLatch;
- @Override
- public void surfaceChanged(SurfaceHolder h, int format, int width, int height) {
- if (!launched) {
- launchOrganizedActivity(mIntent, width, height);
- launched = true;
- } else {
- resizeTask(width, height);
- }
- }
-
- void resizeTask(int width, int height) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setBounds(mWc, new Rect(0, 0, width, height));
- try {
- mOrganizer.applySyncTransaction(wct, mOrganizer.mTransactionCallback);
- } catch (Exception e) {
- // Oh well
- }
- }
- }
-
- private TaskView mTaskView1;
- private TaskView mTaskView2;
- private boolean mGotFirstTask = false;
+public class TaskOrganizerMultiWindowTest extends Activity {
+ private CountDownLatch mTasksReadyLatch;
+ private CountDownLatch mTasksResizeLatch;
class Organizer extends TaskOrganizer {
- private int receivedTransactions = 0;
- SurfaceControl.Transaction mergedTransaction = new SurfaceControl.Transaction();
+ private int mReceivedTransactions = 0;
+ private SurfaceControl.Transaction mMergedTransaction = new SurfaceControl.Transaction();
WindowContainerTransactionCallback mTransactionCallback =
new WindowContainerTransactionCallback() {
@Override
public void onTransactionReady(int id, SurfaceControl.Transaction t) {
- mergedTransaction.merge(t);
- receivedTransactions++;
- if (receivedTransactions == 2) {
- mergedTransaction.apply();
- receivedTransactions = 0;
+ mMergedTransaction.merge(t);
+ mReceivedTransactions++;
+ if (mReceivedTransactions == 2) {
+ mReceivedTransactions = 0;
+ mMergedTransaction.apply(true);
+ if (mTasksResizeLatch != null) {
+ mTasksResizeLatch.countDown();
+ }
}
}
};
@Override
public void onTaskAppeared(ActivityManager.RunningTaskInfo ti, SurfaceControl leash) {
- if (!mGotFirstTask) {
+ if (ti.baseActivity == null) {
+ return;
+ }
+
+ final String clsName = ti.baseActivity.getClassName();
+ if (clsName.contentEquals(TestActivity1.class.getName())) {
mTaskView1.reparentTask(ti.token, leash);
- mGotFirstTask = true;
- } else {
+ mOrganizer.setInterceptBackPressedOnTaskRoot(ti.token, true);
+ mTasksReadyLatch.countDown();
+ } else if (clsName.contentEquals(TestActivity2.class.getName())) {
mTaskView2.reparentTask(ti.token, leash);
+ mOrganizer.setInterceptBackPressedOnTaskRoot(ti.token, true);
+ mTasksReadyLatch.countDown();
}
}
+
+ @Override
+ public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
+ getMainThreadHandler().post(() -> {
+ finish();
+ });
+ }
}
private Organizer mOrganizer = new Organizer();
-
+ private FrameLayout mTasksLayout;
+ private TaskView mTaskView1;
+ private TaskView mTaskView2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ getWindow().getAttributes().layoutInDisplayCutoutMode =
+ LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
- mOrganizer.registerOrganizer(WINDOWING_MODE_MULTI_WINDOW);
-
- mTaskView1 = new ResizingTaskView(this, makeSettingsIntent());
- mTaskView2 = new ResizingTaskView(this, makeContactsIntent());
- View splitView = new SplitLayout(this, mTaskView1, mTaskView2);
+ mTasksLayout = new FrameLayout(this);
+ setContentView(mTasksLayout);
- setContentView(splitView);
+ mOrganizer.registerOrganizer();
}
@Override
protected void onDestroy() {
super.onDestroy();
mOrganizer.unregisterOrganizer();
+ mTasksLayout.removeAllViews();
}
- private void addFlags(Intent intent) {
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
+ private Intent makeActivityIntent(final Class<?> clazz) {
+ Intent intent = new Intent(this, clazz);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION
+ | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ return intent;
}
- private Intent makeSettingsIntent() {
- Intent intent = new Intent();
- intent.setAction(android.provider.Settings.ACTION_SETTINGS);
- addFlags(intent);
- return intent;
+ public CountDownLatch openTaskView(Rect firstBounds, Rect secondBounds) {
+ mTasksReadyLatch = new CountDownLatch(2);
+ mTaskView1 = new TaskView(this, mOrganizer, makeActivityIntent(TestActivity1.class));
+ mTaskView1.setBackgroundColor(Color.DKGRAY);
+
+ FrameLayout.LayoutParams viewLayout1 =
+ new FrameLayout.LayoutParams(firstBounds.width(), firstBounds.height(),
+ Gravity.TOP | Gravity.LEFT);
+ viewLayout1.setMargins(firstBounds.left, firstBounds.top, 0, 0);
+ mTasksLayout.addView(mTaskView1, viewLayout1);
+
+ mTaskView2 = new TaskView(this, mOrganizer, makeActivityIntent(TestActivity2.class));
+ mTaskView2.setBackgroundColor(Color.LTGRAY);
+ FrameLayout.LayoutParams viewLayout2 =
+ new FrameLayout.LayoutParams(secondBounds.width(), secondBounds.height(),
+ Gravity.TOP | Gravity.LEFT);
+ viewLayout2.setMargins(secondBounds.left, secondBounds.top, 0, 0);
+ mTasksLayout.addView(mTaskView2, viewLayout2);
+ return mTasksReadyLatch;
}
- private Intent makeContactsIntent() {
- Intent intent = new Intent();
- intent.setAction(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_APP_CONTACTS);
- addFlags(intent);
- return intent;
+ public CountDownLatch resizeTaskView(Rect firstBounds, Rect secondBounds) {
+ mTasksResizeLatch = new CountDownLatch(1);
+
+ mTaskView1.resizeTask(firstBounds.width(), firstBounds.height());
+ mTaskView2.resizeTask(secondBounds.width(), secondBounds.height());
+
+ return mTasksResizeLatch;
}
- private Bundle makeLaunchOptions(int width, int height) {
- ActivityOptions o = ActivityOptions.makeBasic();
- o.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- o.setLaunchBounds(new Rect(0, 0, width, height));
- return o.toBundle();
+ static class InstrumentedTextView extends TextView {
+ private final boolean mSlowDraw;
+ InstrumentedTextView(Context context, boolean slowDraw) {
+ super(context);
+ mSlowDraw = slowDraw;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (mSlowDraw) {
+ try {
+ Thread.sleep(20);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
}
- private void launchOrganizedActivity(Intent i, int width, int height) {
- startActivity(i, makeLaunchOptions(width, height));
+ public static class TestActivity1 extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().getAttributes().layoutInDisplayCutoutMode =
+ LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+
+ TextView v = new InstrumentedTextView(this, true);
+ v.setText("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
+ + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");
+ v.setBackgroundColor(Color.RED);
+ v.setTextColor(Color.BLACK);
+ setContentView(v);
+ }
+ }
+
+ public static class TestActivity2 extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().getAttributes().layoutInDisplayCutoutMode =
+ LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ TextView v = new InstrumentedTextView(this, false);
+ v.setText("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ + "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ v.setBackgroundColor(Color.GREEN);
+ v.setTextColor(Color.BLACK);
+ setContentView(v);
+ }
}
}
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
deleted file mode 100644
index 8fc5c5d78b60..000000000000
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.test.taskembed;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-
-import android.app.ActivityManager;
-import android.app.Service;
-import android.content.Intent;
-import android.graphics.Rect;
-import android.os.IBinder;
-import android.view.SurfaceControl;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-import android.window.TaskOrganizer;
-import android.window.WindowContainerTransaction;
-
-public class TaskOrganizerPipTest extends Service {
- private static final int PIP_WIDTH = 640;
- private static final int PIP_HEIGHT = 360;
-
- private TaskView mTaskView;
-
- class Organizer extends TaskOrganizer {
- public void onTaskAppeared(ActivityManager.RunningTaskInfo ti, SurfaceControl leash) {
- mTaskView.reparentTask(ti.token, leash);
-
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.scheduleFinishEnterPip(ti.token, new Rect(0, 0, PIP_WIDTH, PIP_HEIGHT));
- applyTransaction(wct);
- }
- }
-
- private Organizer mOrganizer = new Organizer();
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- mOrganizer.registerOrganizer(WINDOWING_MODE_PINNED);
-
- final WindowManager.LayoutParams wlp = new WindowManager.LayoutParams();
- wlp.setTitle("TaskOrganizerPipTest");
- wlp.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
- wlp.width = wlp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
-
- FrameLayout layout = new FrameLayout(this);
- ViewGroup.LayoutParams lp =
- new ViewGroup.LayoutParams(PIP_WIDTH, PIP_HEIGHT);
- mTaskView = new TaskView(this);
- layout.addView(mTaskView, lp);
-
- WindowManager wm = getSystemService(WindowManager.class);
- wm.addView(layout, wlp);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- mOrganizer.unregisterOrganizer();
- }
-}
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
index 208018c2543a..4ef91c7807f6 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
@@ -16,65 +16,113 @@
package com.android.test.taskembed;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
+import android.app.ActivityOptions;
import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Bundle;
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
/**
* Simple SurfaceView wrapper which registers a TaskOrganizer
* after it's Surface is ready.
*/
-class TaskView extends SurfaceView implements SurfaceHolder.Callback {
- WindowContainerToken mWc;
+class TaskView extends SurfaceView {
+ private WindowContainerToken mWc;
+ private Context mContext;
private SurfaceControl mLeash;
+ private TaskOrganizerMultiWindowTest.Organizer mOrganizer;
+ private Intent mIntent;
+ private boolean mLaunched = false;
- private boolean mSurfaceCreated = false;
- private boolean mNeedsReparent;
-
- TaskView(Context c) {
+ TaskView(Context c, TaskOrganizerMultiWindowTest.Organizer organizer,
+ Intent intent) {
super(c);
- getHolder().addCallback(this);
+ mContext = c;
+ mOrganizer = organizer;
+ mIntent = intent;
+ getHolder().addCallback(
+ new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {}
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder,
+ int format, int width, int height) {
+ if (!mLaunched) {
+ launchOrganizedActivity(mIntent, width, height);
+ mLaunched = true;
+ } else {
+ resizeTask(width, height);
+ }
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {}
+ }
+ );
setZOrderOnTop(true);
}
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- mSurfaceCreated = true;
- if (mNeedsReparent) {
- mNeedsReparent = false;
- reparentLeash();
- }
+ private void launchOrganizedActivity(Intent i, int width, int height) {
+ mContext.startActivity(i, makeLaunchOptions(width, height));
}
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ private Bundle makeLaunchOptions(int width, int height) {
+ ActivityOptions o = ActivityOptions.makeBasic();
+ o.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ o.setLaunchBounds(new Rect(0, 0, width, height));
+ o.setTaskOverlay(true, true);
+ o.setTaskAlwaysOnTop(true);
+ return o.toBundle();
}
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
+ void resizeTask(int width, int height) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setBounds(mWc, new Rect(0, 0, width, height)).setHidden(mWc, false);
+ try {
+ mOrganizer.applySyncTransaction(wct, mOrganizer.mTransactionCallback);
+ } catch (Exception e) {
+ // Oh well
+ }
+ }
+
+ void hideTask() {
+ if (mWc == null) {
+ return;
+ }
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setWindowingMode(mWc, WINDOWING_MODE_UNDEFINED).setHidden(mWc, true);
+ try {
+ mOrganizer.applySyncTransaction(wct, mOrganizer.mTransactionCallback);
+ } catch (Exception e) {
+ // Oh well
+ }
+ releaseLeash();
}
void reparentTask(WindowContainerToken wc, SurfaceControl leash) {
mWc = wc;
mLeash = leash;
- if (!mSurfaceCreated) {
- mNeedsReparent = true;
- } else {
- reparentLeash();
- }
+ reparentLeash();
}
- private void reparentLeash() {
+ void reparentLeash() {
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- if (mLeash == null) {
- return;
- }
-
t.reparent(mLeash, getSurfaceControl())
- .setPosition(mLeash, 0, 0)
.show(mLeash)
.apply();
}
+
+ void releaseLeash() {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.remove(mLeash).apply();
+ }
}
diff --git a/tests/TelephonyCommonTests/Android.bp b/tests/TelephonyCommonTests/Android.bp
index 4f7569d4f451..a9fbfd97225d 100644
--- a/tests/TelephonyCommonTests/Android.bp
+++ b/tests/TelephonyCommonTests/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "TelephonyCommonTests",
srcs: [
diff --git a/tests/TelephonyCommonTests/OWNERS b/tests/TelephonyCommonTests/OWNERS
new file mode 100644
index 000000000000..640baf2297b4
--- /dev/null
+++ b/tests/TelephonyCommonTests/OWNERS
@@ -0,0 +1 @@
+include /telephony/OWNERS
diff --git a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
index 83fd20803ed8..7ee19fb37244 100644
--- a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
+++ b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
@@ -46,6 +46,7 @@ import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Telephony;
import android.telephony.TelephonyManager;
@@ -103,6 +104,7 @@ public class SmsApplicationTest {
@Mock private TelephonyManager mTelephonyManager;
@Mock private RoleManager mRoleManager;
@Mock private PackageManager mPackageManager;
+ @Mock private UserManager mUserManager;
@Mock private AppOpsManager mAppOpsManager;
@Before
@@ -112,6 +114,7 @@ public class SmsApplicationTest {
when(mContext.getSystemService(Context.ROLE_SERVICE)).thenReturn(mRoleManager);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getSystemService(RoleManager.class)).thenReturn(mRoleManager);
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOpsManager);
when(mContext.createContextAsUser(isNotNull(), anyInt())).thenReturn(mContext);
@@ -130,8 +133,10 @@ public class SmsApplicationTest {
when(mTelephonyManager.isSmsCapable()).thenReturn(true);
when(mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)).thenReturn(true);
- when(mRoleManager.getDefaultSmsPackage(anyInt()))
+ when(mRoleManager.getSmsRoleHolder(anyInt()))
.thenReturn(TEST_COMPONENT_NAME.getPackageName());
+ when(mUserManager.getUserHandles(true))
+ .thenReturn(Collections.singletonList(UserHandle.SYSTEM));
for (String opStr : APP_OPS_TO_CHECK) {
when(mAppOpsManager.unsafeCheckOp(
diff --git a/tests/TouchLatency/Android.bp b/tests/TouchLatency/Android.bp
index 1174bcb0d4d6..3a9e240d9746 100644
--- a/tests/TouchLatency/Android.bp
+++ b/tests/TouchLatency/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "TouchLatency",
manifest: "app/src/main/AndroidManifest.xml",
diff --git a/tests/TouchLatency/app/src/main/AndroidManifest.xml b/tests/TouchLatency/app/src/main/AndroidManifest.xml
index e4aa4dc6c3f0..98947367bd7b 100644
--- a/tests/TouchLatency/app/src/main/AndroidManifest.xml
+++ b/tests/TouchLatency/app/src/main/AndroidManifest.xml
@@ -15,20 +15,19 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.prefabulated.touchlatency" >
+ package="com.prefabulated.touchlatency">
- <application
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- <activity
- android:name=".TouchLatencyActivity"
- android:label="@string/app_name" >
+ <application android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
+ <activity android:name=".TouchLatencyActivity"
+ android:label="@string/app_name"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/TouchLatency/gradle/wrapper/gradle-wrapper.jar b/tests/TouchLatency/gradle/wrapper/gradle-wrapper.jar
index 8c0fb64a8698..758de960ec79 100644
--- a/tests/TouchLatency/gradle/wrapper/gradle-wrapper.jar
+++ b/tests/TouchLatency/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties b/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties
index 111992a460fa..2d80b69a7665 100644
--- a/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties
+++ b/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Tue Nov 27 13:37:59 PST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
diff --git a/tests/TouchLatency/gradlew b/tests/TouchLatency/gradlew
index 91a7e269e19d..cccdd3d517fc 100755
--- a/tests/TouchLatency/gradlew
+++ b/tests/TouchLatency/gradlew
@@ -1,4 +1,4 @@
-#!/usr/bin/env bash
+#!/usr/bin/env sh
##############################################################################
##
@@ -6,20 +6,38 @@
##
##############################################################################
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
-warn ( ) {
+warn () {
echo "$*"
}
-die ( ) {
+die () {
echo
echo "$*"
echo
@@ -30,6 +48,7 @@ die ( ) {
cygwin=false
msys=false
darwin=false
+nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
@@ -40,31 +59,11 @@ case "`uname`" in
MINGW* )
msys=true
;;
+ NONSTOP* )
+ nonstop=true
+ ;;
esac
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
- [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
-APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -90,7 +89,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -114,6 +113,7 @@ fi
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
@@ -154,11 +154,19 @@ if $cygwin ; then
esac
fi
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
+exec "$JAVACMD" "$@"
diff --git a/tests/TouchLatency/gradlew.bat b/tests/TouchLatency/gradlew.bat
index aec99730b4e8..e95643d6a2ca 100644
--- a/tests/TouchLatency/gradlew.bat
+++ b/tests/TouchLatency/gradlew.bat
@@ -8,14 +8,14 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
@@ -46,10 +46,9 @@ echo location of your Java installation.
goto fail
:init
-@rem Get command-line arguments, handling Windowz variants
+@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@@ -60,11 +59,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
diff --git a/tests/TransformTest/Android.bp b/tests/TransformTest/Android.bp
index fd7aaeb35feb..f58fe8f13bda 100644
--- a/tests/TransformTest/Android.bp
+++ b/tests/TransformTest/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "TransformTest",
srcs: ["**/*.java"],
diff --git a/tests/TransformTest/AndroidManifest.xml b/tests/TransformTest/AndroidManifest.xml
index 5c9995f25ec6..19854feeabd3 100644
--- a/tests/TransformTest/AndroidManifest.xml
+++ b/tests/TransformTest/AndroidManifest.xml
@@ -15,13 +15,15 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.test.transform">
- <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="7" />
+ package="com.google.android.test.transform">
+ <uses-sdk android:minSdkVersion="7"
+ android:targetSdkVersion="7"/>
<application android:label="TransformTest">
- <activity android:name="TransformTestActivity">
+ <activity android:name="TransformTestActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/TransitionTests/Android.bp b/tests/TransitionTests/Android.bp
index 57f19e38330d..4daa5b84f71e 100644
--- a/tests/TransitionTests/Android.bp
+++ b/tests/TransitionTests/Android.bp
@@ -1,3 +1,14 @@
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
android_app {
name: "TransitionTests",
// Only compile source java files in this apk.
diff --git a/tests/TransitionTests/AndroidManifest.xml b/tests/TransitionTests/AndroidManifest.xml
index 35e7b6979b7e..482261932003 100644
--- a/tests/TransitionTests/AndroidManifest.xml
+++ b/tests/TransitionTests/AndroidManifest.xml
@@ -1,250 +1,284 @@
<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.transitiontests"
- android:versionCode="1"
- android:versionName="1.0">
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <application
- android:icon="@drawable/icon"
- android:label="@string/app_name"
- android:hardwareAccelerated="true"
- android:theme="@style/AppTheme">
+ package="com.android.transitiontests"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <application android:icon="@drawable/icon"
+ android:label="@string/app_name"
+ android:hardwareAccelerated="true"
+ android:theme="@style/AppTheme">
<activity android:label="@string/states_test1"
- android:name="ScenesTestv21">
+ android:name="ScenesTestv21"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="@string/states_test_auto_targets"
- android:name="ScenesTestAutoTargets">
+ android:name="ScenesTestAutoTargets"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="@string/states_test_auto_transition"
- android:name="ScenesTestAutoTransition">
+ android:name="ScenesTestAutoTransition"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="@string/states_test_auto_transition2"
- android:name="ScenesTestAutoTransition2">
+ android:name="ScenesTestAutoTransition2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="@string/contacts_expansion"
- android:name="ContactsExpansion">
+ android:name="ContactsExpansion"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="Demo0"
- android:name="Demo0">
+ android:name="Demo0"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="Demo1"
- android:name="Demo1">
+ android:name="Demo1"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="Demo2"
- android:name="Demo2">
+ android:name="Demo2"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="Demo3"
- android:name="Demo3">
+ android:name="Demo3"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="Demo4"
- android:name="Demo4">
+ android:name="Demo4"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="Demo5"
- android:name="Demo5">
+ android:name="Demo5"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="LoginActivity"
- android:name="LoginActivity">
+ android:name="LoginActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="LoginActivityFromResources"
- android:name="LoginActivityFromResources">
+ android:name="LoginActivityFromResources"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="OverlayTest"
- android:name="OverlayTest">
+ android:name="OverlayTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="ResourceLoadingTest"
- android:name="ResourceLoadingTest">
+ android:name="ResourceLoadingTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="FadingTest"
- android:name="FadingTest">
+ android:name="FadingTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="UniqueIds"
- android:name="UniqueIds">
+ android:name="UniqueIds"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="HitRectBug"
- android:name="HitRectBug">
+ android:name="HitRectBug"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="SequenceTest"
- android:name="SequenceTest">
+ android:name="SequenceTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="SequenceTestSimple"
- android:name="SequenceTestSimple">
+ android:name="SequenceTestSimple"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="ChangingText"
- android:name="ChangingText">
+ android:name="ChangingText"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="ClippingText"
- android:name="ClippingText">
+ android:name="ClippingText"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="ListViewAddRemove"
- android:name="ListViewAddRemove">
+ android:name="ListViewAddRemove"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="ListViewAddRemoveNoTransition"
- android:name="ListViewAddRemoveNoTransition">
+ android:name="ListViewAddRemoveNoTransition"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="CrossFadeDemo"
- android:name="CrossFadeDemo">
+ android:name="CrossFadeDemo"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="Reparenting"
- android:name="Reparenting">
+ android:name="Reparenting"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="SurfaceAndTextureViews"
- android:name="SurfaceAndTextureViews">
+ android:name="SurfaceAndTextureViews"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="InstanceTargets"
- android:name="InstanceTargets">
+ android:name="InstanceTargets"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="InterruptionTest"
- android:name="InterruptionTest">
+ android:name="InterruptionTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="DelayedTransition"
- android:name="DelayedTransition">
+ android:name="DelayedTransition"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="FadingHierachy"
- android:name=".FadingHierarchy">
+ android:name=".FadingHierarchy"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="HierarchicalMove"
- android:name=".HierarchicalMove">
+ android:name=".HierarchicalMove"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="CrossfadeImage"
- android:name=".CrossfadeImage">
+ android:name=".CrossfadeImage"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:label="CrossfadeMultiple"
- android:name=".CrossfadeMultiple">
+ android:name=".CrossfadeMultiple"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
diff --git a/tests/TtsTests/Android.bp b/tests/TtsTests/Android.bp
index b137523803a6..b7aa5d4a38aa 100644
--- a/tests/TtsTests/Android.bp
+++ b/tests/TtsTests/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "TtsTests",
srcs: ["**/*.java"],
diff --git a/tests/TtsTests/AndroidManifest.xml b/tests/TtsTests/AndroidManifest.xml
index b6d51114e399..cf1c1628951d 100644
--- a/tests/TtsTests/AndroidManifest.xml
+++ b/tests/TtsTests/AndroidManifest.xml
@@ -15,29 +15,32 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.speech.tts">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.speech.tts">
<application>
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
<service android:name=".MockableTextToSpeechService"
- android:label="Mockable Text-to-speech Service">
+ android:label="Mockable Text-to-speech Service"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.TTS_SERVICE" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.intent.action.TTS_SERVICE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
<activity android:name=".MockableCheckVoiceData"
- android:theme="@android:style/Theme.NoDisplay">
+ android:theme="@android:style/Theme.NoDisplay"
+ android:exported="true">
<intent-filter>
- <action android:name="android.speech.tts.engine.CHECK_TTS_DATA" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.speech.tts.engine.CHECK_TTS_DATA"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.speech.tts"
- android:label="Tests for android.speech.tts" />
+ android:targetPackage="com.android.speech.tts"
+ android:label="Tests for android.speech.tts"/>
</manifest>
diff --git a/tests/UiBench/Android.bp b/tests/UiBench/Android.bp
index e0608e288459..0d2f2ef46cab 100644
--- a/tests/UiBench/Android.bp
+++ b/tests/UiBench/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "UiBench",
sdk_version: "current",
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index dd255ef5233b..4fc6ec71f29c 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2015 The Android Open Source Project
~
@@ -13,303 +14,304 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- package="com.android.test.uibench">
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.test.uibench">
- <application
- android:allowBackup="false"
- android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
- tools:ignore="MissingApplicationIcon">
- <uses-library android:name="android.test.runner" />
+ <application android:allowBackup="false"
+ android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
+ tools:ignore="MissingApplicationIcon">
+ <uses-library android:name="android.test.runner"/>
<!-- Root navigation activity -->
- <activity
- android:name=".MainActivity"
- android:label="UiBench">
+ <activity android:name=".MainActivity"
+ android:label="UiBench"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- General -->
- <activity
- android:name=".DialogListActivity"
- android:label="General/Dialog List" >
+ <activity android:name=".DialogListActivity"
+ android:label="General/Dialog List"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".GlTextureViewActivity"
- android:label="General/GL TextureView" >
+ <activity android:name=".GlTextureViewActivity"
+ android:label="General/GL TextureView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".FullscreenOverdrawActivity"
- android:label="General/Fullscreen Overdraw" >
+ <activity android:name=".FullscreenOverdrawActivity"
+ android:label="General/Fullscreen Overdraw"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".InvalidateActivity"
- android:label="General/Invalidate" >
+ <activity android:name=".InvalidateActivity"
+ android:label="General/Invalidate"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".InvalidateTreeActivity"
- android:label="General/Invalidate Tree" >
+ <activity android:name=".InvalidateTreeActivity"
+ android:label="General/Invalidate Tree"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".ResizeHWLayerActivity"
- android:label="General/Resize HW Layer" >
+ <activity android:name=".ResizeHWLayerActivity"
+ android:label="General/Resize HW Layer"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".TrivialAnimationActivity"
- android:label="General/Trivial Animation" >
+ <activity android:name=".TrivialAnimationActivity"
+ android:label="General/Trivial Animation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".TrivialAnimationActivityWideGamut"
- android:label="General/Trivial Animation (Wide Gamut)"
- android:colorMode="wideColorGamut">
+ <activity android:name=".TrivialAnimationActivityWideGamut"
+ android:label="General/Trivial Animation (Wide Gamut)"
+ android:colorMode="wideColorGamut"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".TrivialListActivity"
- android:label="General/Trivial ListView" >
+ <activity android:name=".TrivialListActivity"
+ android:label="General/Trivial ListView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".FadingEdgeListActivity"
- android:label="General/Fading Edge ListView" >
+ <activity android:name=".FadingEdgeListActivity"
+ android:label="General/Fading Edge ListView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".SaveLayerInterleaveActivity"
- android:label="General/SaveLayer Animation" >
+ <activity android:name=".SaveLayerInterleaveActivity"
+ android:label="General/SaveLayer Animation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".ClippedListActivity"
- android:label="General/Clipped ListView"
- android:theme="@style/NoActionBar">
+ <activity android:name=".ClippedListActivity"
+ android:label="General/Clipped ListView"
+ android:theme="@style/NoActionBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".TrivialRecyclerViewActivity"
- android:label="General/Trivial RecyclerView" >
+ <activity android:name=".TrivialRecyclerViewActivity"
+ android:label="General/Trivial RecyclerView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".SlowBindRecyclerViewActivity"
- android:label="General/Slow Bind RecyclerView" >
+ <activity android:name=".SlowBindRecyclerViewActivity"
+ android:label="General/Slow Bind RecyclerView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".SlowNestedRecyclerViewActivity"
- android:label="General/Slow Nested RecyclerView" >
+ <activity android:name=".SlowNestedRecyclerViewActivity"
+ android:label="General/Slow Nested RecyclerView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".ActivityTransition"
- android:label="Transitions/Activity Transition" >
+ <activity android:name=".ActivityTransition"
+ android:label="Transitions/Activity Transition"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".ActivityTransitionDetails"
- android:label="Transitions/Activity Transition " >
+ <activity android:name=".ActivityTransitionDetails"
+ android:label="Transitions/Activity Transition "
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
<!-- Part of ActivityTransition test above, so not in TEST category -->
</intent-filter>
</activity>
<!-- Rendering -->
- <activity
- android:name=".BitmapUploadActivity"
- android:label="Rendering/Bitmap Upload" >
+ <activity android:name=".BitmapUploadActivity"
+ android:label="Rendering/Bitmap Upload"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".ShadowGridActivity"
- android:label="Rendering/Shadow Grid" >
+ <activity android:name=".ShadowGridActivity"
+ android:label="Rendering/Shadow Grid"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".RenderingJitter"
- android:label="Rendering/Jitter" >
+ <activity android:name=".RenderingJitter"
+ android:label="Rendering/Jitter"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
<!-- Inflation -->
- <activity
- android:name=".InflatingListActivity"
- android:label="Inflation/Inflating ListView" >
+ <activity android:name=".InflatingListActivity"
+ android:label="Inflation/Inflating ListView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity-alias
- android:name=".InflatingEmojiListActivity"
- android:label="Inflation/Inflating ListView with Emoji"
- android:targetActivity=".InflatingListActivity">
+ <activity-alias android:name=".InflatingEmojiListActivity"
+ android:label="Inflation/Inflating ListView with Emoji"
+ android:targetActivity=".InflatingListActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity-alias>
- <activity-alias
- android:name=".InflatingHanListActivity"
- android:label="Inflation/Inflating ListView with Han Characters"
- android:targetActivity=".InflatingListActivity">
+ <activity-alias android:name=".InflatingHanListActivity"
+ android:label="Inflation/Inflating ListView with Han Characters"
+ android:targetActivity=".InflatingListActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity-alias>
- <activity-alias
- android:name=".InflatingLongStringListActivity"
- android:label="Inflation/Inflating ListView with long string"
- android:targetActivity=".InflatingListActivity">
+ <activity-alias android:name=".InflatingLongStringListActivity"
+ android:label="Inflation/Inflating ListView with long string"
+ android:targetActivity=".InflatingListActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity-alias>
<!-- Text -->
- <activity
- android:name=".EditTextTypeActivity"
- android:label="Text/EditText Typing" >
+ <activity android:name=".EditTextTypeActivity"
+ android:label="Text/EditText Typing"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".TextCacheLowHitrateActivity"
- android:label="Text/Layout Cache Low Hitrate" >
+ <activity android:name=".TextCacheLowHitrateActivity"
+ android:label="Text/Layout Cache Low Hitrate"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".TextCacheHighHitrateActivity"
- android:label="Text/Layout Cache High Hitrate" >
+ <activity android:name=".TextCacheHighHitrateActivity"
+ android:label="Text/Layout Cache High Hitrate"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
<!-- WebView -->
- <activity
- android:name=".ScrollableWebViewActivity"
- android:label="WebView/Scrollable WebView" >
+ <activity android:name=".ScrollableWebViewActivity"
+ android:label="WebView/Scrollable WebView"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
<!-- Navigation Drawer -->
- <activity
- android:name=".NavigationDrawerActivity"
- android:label="Navigation Drawer Activity"
- android:theme="@style/NoActionBar">
+ <activity android:name=".NavigationDrawerActivity"
+ android:label="Navigation Drawer Activity"
+ android:theme="@style/NoActionBar"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
<!-- Notification Shade -->
- <activity
- android:name=".NotificationShadeActivity"
- android:label="Notification Shade">
+ <activity android:name=".NotificationShadeActivity"
+ android:label="Notification Shade"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name=".leanback.BrowseActivity"
- android:theme="@style/Theme.Leanback.Browse"
- android:label="Leanback/Browse Fragment" >
+ <activity android:name=".leanback.BrowseActivity"
+ android:theme="@style/Theme.Leanback.Browse"
+ android:label="Leanback/Browse Fragment"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.uibench.TEST"/>
</intent-filter>
</activity>
<activity
android:name="WindowInsetsControllerActivity"
- android:label="WindowInsetsControllerActivity" >
+ android:label="WindowInsetsControllerActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.android.test.uibench.TEST" />
diff --git a/tests/UiBench/res/layout/recycler_view.xml b/tests/UiBench/res/layout/recycler_view.xml
index 53eab68f7866..c8a85de81710 100644
--- a/tests/UiBench/res/layout/recycler_view.xml
+++ b/tests/UiBench/res/layout/recycler_view.xml
@@ -17,5 +17,6 @@
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recyclerView"
+ android:overScrollMode="never"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
diff --git a/tests/UpdatableSystemFontTest/Android.bp b/tests/UpdatableSystemFontTest/Android.bp
new file mode 100644
index 000000000000..e07fbbf7a1c1
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/Android.bp
@@ -0,0 +1,51 @@
+// 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
+ // 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"],
+}
+
+android_test {
+ name: "UpdatableSystemFontTest",
+ srcs: ["src/**/*.java"],
+ libs: ["android.test.runner"],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "androidx.test.uiautomator_uiautomator",
+ "compatibility-device-util-axt",
+ "platform-test-annotations",
+ "truth-prebuilt",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+ data: [
+ ":NotoColorEmojiTtf",
+ ":UpdatableSystemFontTestCertDer",
+ ":UpdatableSystemFontTestNotoColorEmojiTtfFsvSig",
+ ":UpdatableSystemFontTestNotoColorEmojiV0Ttf",
+ ":UpdatableSystemFontTestNotoColorEmojiV0TtfFsvSig",
+ ":UpdatableSystemFontTestNotoColorEmojiVPlus1Ttf",
+ ":UpdatableSystemFontTestNotoColorEmojiVPlus1TtfFsvSig",
+ ":UpdatableSystemFontTestNotoColorEmojiVPlus2Ttf",
+ ":UpdatableSystemFontTestNotoColorEmojiVPlus2TtfFsvSig",
+ ],
+ sdk_version: "test_current",
+}
diff --git a/tests/UpdatableSystemFontTest/AndroidManifest.xml b/tests/UpdatableSystemFontTest/AndroidManifest.xml
new file mode 100644
index 000000000000..531ee981a92c
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.updatablesystemfont">
+
+ <application android:label="UpdatableSystemFontTest">
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:label="UpdatableSystemFontTest"
+ android:targetPackage="com.android.updatablesystemfont">
+ </instrumentation>
+
+</manifest>
diff --git a/tests/UpdatableSystemFontTest/AndroidTest.xml b/tests/UpdatableSystemFontTest/AndroidTest.xml
new file mode 100644
index 000000000000..4f6487e7e953
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/AndroidTest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Updatable system font integration/regression test">
+ <option name="test-suite-tag" value="apct" />
+
+ <!-- This test requires root to side load fs-verity cert. -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="UpdatableSystemFontTest.apk" />
+ <option name="test-file-name" value="EmojiRenderingTestApp.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="UpdatableSystemFontTestCert.der->/data/local/tmp/UpdatableSystemFontTestCert.der" />
+ <option name="push" value="NotoColorEmoji.ttf->/data/local/tmp/NotoColorEmoji.ttf" />
+ <option name="push" value="UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig" />
+ <option name="push" value="UpdatableSystemFontTestNotoColorEmojiV0.ttf->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV0.ttf" />
+ <option name="push" value="UpdatableSystemFontTestNotoColorEmojiV0.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV0.ttf.fsv_sig" />
+ <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf" />
+ <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf.fsv_sig" />
+ <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf" />
+ <option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.updatablesystemfont" />
+ </test>
+</configuration>
diff --git a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/Android.bp b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/Android.bp
new file mode 100644
index 000000000000..ed34fa9fc1d0
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // 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"],
+}
+
+android_test_helper_app {
+ name: "EmojiRenderingTestApp",
+ manifest: "AndroidManifest.xml",
+ srcs: ["src/**/*.java"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/AndroidManifest.xml b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/AndroidManifest.xml
new file mode 100644
index 000000000000..8c3d87698e17
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.emojirenderingtestapp">
+ <application>
+ <activity android:name=".EmojiRenderingTestActivity"/>
+ <activity android:name=".GetAvailableFontsTestActivity"/>
+ </application>
+</manifest>
diff --git a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java
new file mode 100644
index 000000000000..947e9c2ff56a
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/EmojiRenderingTestActivity.java
@@ -0,0 +1,40 @@
+/*
+ * 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.emojirenderingtestapp;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/** Test app to render an emoji. */
+public class EmojiRenderingTestActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ LinearLayout container = new LinearLayout(this);
+ container.setOrientation(LinearLayout.VERTICAL);
+ TextView textView = new TextView(this);
+ textView.setText("\uD83E\uDD72"); // 🥲
+ container.addView(textView, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+ setContentView(container);
+ }
+}
diff --git a/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/GetAvailableFontsTestActivity.java b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/GetAvailableFontsTestActivity.java
new file mode 100644
index 000000000000..b9a91490f517
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/EmojiRenderingTestApp/src/com/android/emojirenderingtestapp/GetAvailableFontsTestActivity.java
@@ -0,0 +1,53 @@
+/*
+ * 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.emojirenderingtestapp;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import android.app.Activity;
+import android.graphics.fonts.Font;
+import android.graphics.fonts.SystemFonts;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class GetAvailableFontsTestActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ String emojiFontPath = "<Not found>";
+ for (Font font : SystemFonts.getAvailableFonts()) {
+ // Calls font attribute getters to make sure that they don't open font files.
+ font.getAxes();
+ font.getFile();
+ font.getLocaleList();
+ font.getStyle();
+ font.getTtcIndex();
+ if ("NotoColorEmoji.ttf".equals(font.getFile().getName())) {
+ emojiFontPath = font.getFile().getAbsolutePath();
+ }
+ }
+ LinearLayout container = new LinearLayout(this);
+ container.setOrientation(LinearLayout.VERTICAL);
+ TextView textView = new TextView(this);
+ textView.setText(emojiFontPath);
+ container.addView(textView, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+ setContentView(container);
+ }
+}
diff --git a/tests/UpdatableSystemFontTest/OWNERS b/tests/UpdatableSystemFontTest/OWNERS
new file mode 100644
index 000000000000..34ac813f02e0
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 24939
+
+include /graphics/java/android/graphics/fonts/OWNERS
diff --git a/tests/UpdatableSystemFontTest/TEST_MAPPING b/tests/UpdatableSystemFontTest/TEST_MAPPING
new file mode 100644
index 000000000000..7fbf426c71c4
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "UpdatableSystemFontTest"
+ }
+ ]
+}
diff --git a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
new file mode 100644
index 000000000000..6bd07d0a84fd
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
@@ -0,0 +1,451 @@
+/*
+ * 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.updatablesystemfont;
+
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import android.app.UiAutomation;
+import android.content.Context;
+import android.graphics.fonts.FontFamilyUpdateRequest;
+import android.graphics.fonts.FontFileUpdateRequest;
+import android.graphics.fonts.FontManager;
+import android.os.ParcelFileDescriptor;
+import android.platform.test.annotations.RootPermissionTest;
+import android.security.FileIntegrityManager;
+import android.text.FontConfig;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.annotation.Nullable;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import com.android.compatibility.common.util.StreamUtil;
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * Tests if fonts can be updated by {@link FontManager} API.
+ */
+@RootPermissionTest
+@RunWith(AndroidJUnit4.class)
+public class UpdatableSystemFontTest {
+
+ private static final String TAG = "UpdatableSystemFontTest";
+ private static final String SYSTEM_FONTS_DIR = "/system/fonts/";
+ private static final String DATA_FONTS_DIR = "/data/fonts/files/";
+ private static final String CERT_PATH = "/data/local/tmp/UpdatableSystemFontTestCert.der";
+ private static final String NOTO_COLOR_EMOJI_POSTSCRIPT_NAME = "NotoColorEmoji";
+
+ private static final String ORIGINAL_NOTO_COLOR_EMOJI_TTF =
+ "/data/local/tmp/NotoColorEmoji.ttf";
+ private static final String ORIGINAL_NOTO_COLOR_EMOJI_TTF_FSV_SIG =
+ "/data/local/tmp/UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig";
+ // A font with revision == 0.
+ private static final String TEST_NOTO_COLOR_EMOJI_V0_TTF =
+ "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV0.ttf";
+ private static final String TEST_NOTO_COLOR_EMOJI_V0_TTF_FSV_SIG =
+ "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV0.ttf.fsv_sig";
+ // A font with revision == original + 1
+ private static final String TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF =
+ "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf";
+ private static final String TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG =
+ "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf.fsv_sig";
+ // A font with revision == original + 2
+ private static final String TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF =
+ "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf";
+ private static final String TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG =
+ "/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig";
+
+ private static final String EMOJI_RENDERING_TEST_APP_ID = "com.android.emojirenderingtestapp";
+ private static final String EMOJI_RENDERING_TEST_ACTIVITY =
+ EMOJI_RENDERING_TEST_APP_ID + "/.EmojiRenderingTestActivity";
+ private static final long ACTIVITY_TIMEOUT_MILLIS = SECONDS.toMillis(10);
+
+ private static final String GET_AVAILABLE_FONTS_TEST_ACTIVITY =
+ EMOJI_RENDERING_TEST_APP_ID + "/.GetAvailableFontsTestActivity";
+
+ private static final Pattern PATTERN_FONT_FILES = Pattern.compile("\\.(ttf|otf|ttc|otc)$");
+ private static final Pattern PATTERN_TMP_FILES = Pattern.compile("^/data/local/tmp/");
+ private static final Pattern PATTERN_DATA_FONT_FILES = Pattern.compile("^/data/fonts/files/");
+ private static final Pattern PATTERN_SYSTEM_FONT_FILES =
+ Pattern.compile("^/(system|product)/fonts/");
+
+ private String mKeyId;
+ private FontManager mFontManager;
+ private UiDevice mUiDevice;
+
+ @Before
+ public void setUp() throws Exception {
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ // Run tests only if updatable system font is enabled.
+ FileIntegrityManager fim = context.getSystemService(FileIntegrityManager.class);
+ assumeTrue(fim != null);
+ assumeTrue(fim.isApkVeritySupported());
+ mKeyId = insertCert(CERT_PATH);
+ mFontManager = context.getSystemService(FontManager.class);
+ expectCommandToSucceed("cmd font clear");
+ mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ // Ignore errors because this may fail if updatable system font is not enabled.
+ runShellCommand("cmd font clear", null);
+ if (mKeyId != null) {
+ expectCommandToSucceed("mini-keyctl unlink " + mKeyId + " .fs-verity");
+ }
+ }
+
+ @Test
+ public void updateFont() throws Exception {
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(fontPath).startsWith(DATA_FONTS_DIR);
+ // The updated font should be readable and unmodifiable.
+ expectCommandToSucceed("dd status=none if=" + fontPath + " of=/dev/null");
+ expectCommandToFail("dd status=none if=" + CERT_PATH + " of=" + fontPath);
+ }
+
+ @Test
+ public void updateFont_twice() throws Exception {
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(fontPath2).startsWith(DATA_FONTS_DIR);
+ assertThat(fontPath2).isNotEqualTo(fontPath);
+ // The new file should be readable.
+ expectCommandToSucceed("dd status=none if=" + fontPath2 + " of=/dev/null");
+ // The old file should be still readable.
+ expectCommandToSucceed("dd status=none if=" + fontPath + " of=/dev/null");
+ }
+
+ @Test
+ public void updateFont_allowSameVersion() throws Exception {
+ // Update original font to the same version
+ assertThat(updateFontFile(
+ ORIGINAL_NOTO_COLOR_EMOJI_TTF, ORIGINAL_NOTO_COLOR_EMOJI_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ // Update updated font to the same version
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ String fontPath3 = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(fontPath).startsWith(DATA_FONTS_DIR);
+ assertThat(fontPath2).isNotEqualTo(fontPath);
+ assertThat(fontPath2).startsWith(DATA_FONTS_DIR);
+ assertThat(fontPath3).startsWith(DATA_FONTS_DIR);
+ assertThat(fontPath3).isNotEqualTo(fontPath);
+ }
+
+ @Test
+ public void updateFont_invalidCert() throws Exception {
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_ERROR_VERIFICATION_FAILURE);
+ }
+
+ @Test
+ public void updateFont_downgradeFromSystem() throws Exception {
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_V0_TTF, TEST_NOTO_COLOR_EMOJI_V0_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING);
+ }
+
+ @Test
+ public void updateFont_downgradeFromData() throws Exception {
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING);
+ }
+
+ @Test
+ public void launchApp() throws Exception {
+ String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(fontPath).startsWith(SYSTEM_FONTS_DIR);
+ startActivity(EMOJI_RENDERING_TEST_APP_ID, EMOJI_RENDERING_TEST_ACTIVITY);
+ SystemUtil.eventually(
+ () -> assertThat(isFileOpenedBy(fontPath, EMOJI_RENDERING_TEST_APP_ID)).isTrue(),
+ ACTIVITY_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void launchApp_afterUpdateFont() throws Exception {
+ String originalFontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(originalFontPath).startsWith(SYSTEM_FONTS_DIR);
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ String updatedFontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(updatedFontPath).startsWith(DATA_FONTS_DIR);
+ startActivity(EMOJI_RENDERING_TEST_APP_ID, EMOJI_RENDERING_TEST_ACTIVITY);
+ // The original font should NOT be opened by the app.
+ SystemUtil.eventually(() -> {
+ assertThat(isFileOpenedBy(updatedFontPath, EMOJI_RENDERING_TEST_APP_ID)).isTrue();
+ assertThat(isFileOpenedBy(originalFontPath, EMOJI_RENDERING_TEST_APP_ID)).isFalse();
+ }, ACTIVITY_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void reboot() throws Exception {
+ expectCommandToSucceed(String.format("cmd font update %s %s",
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
+ String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(fontPath).startsWith(DATA_FONTS_DIR);
+
+ // Emulate reboot by 'cmd font restart'.
+ expectCommandToSucceed("cmd font restart");
+ String fontPathAfterReboot = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ assertThat(fontPathAfterReboot).isEqualTo(fontPath);
+ }
+
+ @Test
+ public void fdLeakTest() throws Exception {
+ long originalOpenFontCount =
+ countMatch(getOpenFiles("system_server"), PATTERN_FONT_FILES);
+ Pattern patternEmojiVPlus1 =
+ Pattern.compile(Pattern.quote(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF));
+ for (int i = 0; i < 10; i++) {
+ assertThat(updateFontFile(
+ TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG))
+ .isEqualTo(FontManager.RESULT_SUCCESS);
+ List<String> openFiles = getOpenFiles("system_server");
+ for (Pattern p : Arrays.asList(PATTERN_FONT_FILES, PATTERN_SYSTEM_FONT_FILES,
+ PATTERN_DATA_FONT_FILES, PATTERN_TMP_FILES)) {
+ Log.i(TAG, String.format("num of %s: %d", p, countMatch(openFiles, p)));
+ }
+ // system_server should not keep /data/fonts files open.
+ assertThat(countMatch(openFiles, PATTERN_DATA_FONT_FILES)).isEqualTo(0);
+ // system_server should not keep passed FD open.
+ assertThat(countMatch(openFiles, patternEmojiVPlus1)).isEqualTo(0);
+ // The number of open font FD should not increase.
+ assertThat(countMatch(openFiles, PATTERN_FONT_FILES))
+ .isAtMost(originalOpenFontCount);
+ }
+ }
+
+ @Test
+ public void fdLeakTest_withoutPermission() throws Exception {
+ Pattern patternEmojiVPlus1 =
+ Pattern.compile(Pattern.quote(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF));
+ byte[] signature = Files.readAllBytes(Paths.get(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
+ try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(
+ new File(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF), MODE_READ_ONLY)) {
+ assertThrows(SecurityException.class,
+ () -> updateFontFileWithoutPermission(fd, signature, 0));
+ }
+ List<String> openFiles = getOpenFiles("system_server");
+ assertThat(countMatch(openFiles, patternEmojiVPlus1)).isEqualTo(0);
+ }
+
+ @Test
+ public void getAvailableFonts() throws Exception {
+ String fontPath = getFontPath(NOTO_COLOR_EMOJI_POSTSCRIPT_NAME);
+ startActivity(EMOJI_RENDERING_TEST_APP_ID, GET_AVAILABLE_FONTS_TEST_ACTIVITY);
+ // GET_AVAILABLE_FONTS_TEST_ACTIVITY shows the NotoColorEmoji path it got.
+ mUiDevice.wait(
+ Until.findObject(By.pkg(EMOJI_RENDERING_TEST_APP_ID).text(fontPath)),
+ ACTIVITY_TIMEOUT_MILLIS);
+ // The font file should not be opened just by querying the path using
+ // SystemFont.getAvailableFonts().
+ assertThat(isFileOpenedBy(fontPath, EMOJI_RENDERING_TEST_APP_ID)).isFalse();
+ }
+
+ private static String insertCert(String certPath) throws Exception {
+ Pair<String, String> result;
+ try (InputStream is = new FileInputStream(certPath)) {
+ result = runShellCommand("mini-keyctl padd asymmetric fsv_test .fs-verity", is);
+ }
+ // Assert that there are no errors.
+ assertThat(result.second).isEmpty();
+ String keyId = result.first.trim();
+ assertThat(keyId).matches("^\\d+$");
+ return keyId;
+ }
+
+ private int updateFontFile(String fontPath, String signaturePath) throws IOException {
+ byte[] signature = Files.readAllBytes(Paths.get(signaturePath));
+ try (ParcelFileDescriptor fd =
+ ParcelFileDescriptor.open(new File(fontPath), MODE_READ_ONLY)) {
+ return SystemUtil.runWithShellPermissionIdentity(() -> {
+ int configVersion = mFontManager.getFontConfig().getConfigVersion();
+ return updateFontFileWithoutPermission(fd, signature, configVersion);
+ });
+ }
+ }
+
+ private int updateFontFileWithoutPermission(ParcelFileDescriptor fd, byte[] signature,
+ int configVersion) {
+ return mFontManager.updateFontFamily(
+ new FontFamilyUpdateRequest.Builder()
+ .addFontFileUpdateRequest(new FontFileUpdateRequest(fd, signature))
+ .build(),
+ configVersion);
+ }
+
+ private String getFontPath(String psName) {
+ return SystemUtil.runWithShellPermissionIdentity(() -> {
+ FontConfig fontConfig = mFontManager.getFontConfig();
+ for (FontConfig.FontFamily family : fontConfig.getFontFamilies()) {
+ for (FontConfig.Font font : family.getFontList()) {
+ if (psName.equals(font.getPostScriptName())) {
+ return font.getFile().getAbsolutePath();
+ }
+ }
+ }
+ throw new AssertionError("Font not found: " + psName);
+ });
+ }
+
+ private static void startActivity(String appId, String activityId) throws Exception {
+ expectCommandToSucceed("am force-stop " + appId);
+ expectCommandToSucceed("am start-activity -n " + activityId);
+ }
+
+ private static String expectCommandToSucceed(String cmd) throws IOException {
+ Pair<String, String> result = runShellCommand(cmd, null);
+ // UiAutomation.runShellCommand() does not return exit code.
+ // Assume that the command fails if stderr is not empty.
+ assertThat(result.second.trim()).isEmpty();
+ return result.first;
+ }
+
+ private static void expectCommandToFail(String cmd) throws IOException {
+ Pair<String, String> result = runShellCommand(cmd, null);
+ // UiAutomation.runShellCommand() does not return exit code.
+ // Assume that the command fails if stderr is not empty.
+ assertThat(result.second.trim()).isNotEmpty();
+ }
+
+ /** Runs a command and returns (stdout, stderr). */
+ private static Pair<String, String> runShellCommand(String cmd, @Nullable InputStream input)
+ throws IOException {
+ Log.i(TAG, "runShellCommand: " + cmd);
+ UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ ParcelFileDescriptor[] rwe = automation.executeShellCommandRwe(cmd);
+ // executeShellCommandRwe returns [stdout, stdin, stderr].
+ try (ParcelFileDescriptor outFd = rwe[0];
+ ParcelFileDescriptor inFd = rwe[1];
+ ParcelFileDescriptor errFd = rwe[2]) {
+ if (input != null) {
+ try (OutputStream os = new FileOutputStream(inFd.getFileDescriptor())) {
+ StreamUtil.copyStreams(input, os);
+ }
+ }
+ // We have to close stdin before reading stdout and stderr.
+ // It's safe to close ParcelFileDescriptor multiple times.
+ inFd.close();
+ String stdout;
+ try (InputStream is = new FileInputStream(outFd.getFileDescriptor())) {
+ stdout = StreamUtil.readInputStream(is);
+ }
+ Log.i(TAG, "stdout = " + stdout);
+ String stderr;
+ try (InputStream is = new FileInputStream(errFd.getFileDescriptor())) {
+ stderr = StreamUtil.readInputStream(is);
+ }
+ Log.i(TAG, "stderr = " + stderr);
+ return new Pair<>(stdout, stderr);
+ }
+ }
+
+ private static boolean isFileOpenedBy(String path, String appId) throws Exception {
+ String pid = pidOf(appId);
+ if (pid.isEmpty()) {
+ return false;
+ }
+ String cmd = String.format("lsof -t -p %s %s", pid, path);
+ return !expectCommandToSucceed(cmd).trim().isEmpty();
+ }
+
+ private static List<String> getOpenFiles(String appId) throws Exception {
+ String pid = pidOf(appId);
+ if (pid.isEmpty()) {
+ return Collections.emptyList();
+ }
+ String cmd = String.format("lsof -p %s", pid);
+ String out = expectCommandToSucceed(cmd);
+ List<String> paths = new ArrayList<>();
+ boolean first = true;
+ for (String line : out.split("\n")) {
+ // Skip the header.
+ if (first) {
+ first = false;
+ continue;
+ }
+ String[] records = line.split(" ");
+ if (records.length > 0) {
+ paths.add(records[records.length - 1]);
+ }
+ }
+ return paths;
+ }
+
+ private static String pidOf(String appId) throws Exception {
+ return expectCommandToSucceed("pidof " + appId).trim();
+ }
+
+ private static long countMatch(List<String> paths, Pattern pattern) {
+ // Note: asPredicate() returns true for partial matching.
+ return paths.stream()
+ .filter(pattern.asPredicate())
+ .count();
+ }
+}
diff --git a/tests/UpdatableSystemFontTest/testdata/Android.bp b/tests/UpdatableSystemFontTest/testdata/Android.bp
new file mode 100644
index 000000000000..426464ea574e
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/testdata/Android.bp
@@ -0,0 +1,122 @@
+// 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
+ // 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"],
+}
+
+// An existing module name is reused to avoid merge conflicts.
+// TODO: fix the font and module name.
+filegroup {
+ name: "NotoColorEmojiTtf",
+ srcs: ["NotoColorEmoji.ttf"],
+}
+
+filegroup {
+ name: "UpdatableSystemFontTestKeyPem",
+ srcs: ["UpdatableSystemFontTestKey.pem"],
+}
+
+filegroup {
+ name: "UpdatableSystemFontTestCertPem",
+ srcs: ["UpdatableSystemFontTestCert.pem"],
+}
+
+filegroup {
+ name: "UpdatableSystemFontTestCertDer",
+ srcs: ["UpdatableSystemFontTestCert.der"],
+}
+
+genrule_defaults {
+ name: "updatable_system_font_increment_font_revision_default",
+}
+
+genrule {
+ name: "UpdatableSystemFontTestNotoColorEmojiV0Ttf",
+ srcs: [":NotoColorEmojiTtf"],
+ out: ["UpdatableSystemFontTestNotoColorEmojiV0.ttf"],
+ tools: ["update_font_metadata"],
+ cmd: "$(location update_font_metadata) " +
+ "--input=$(in) " +
+ "--output=$(out) " +
+ "--revision=0",
+}
+
+genrule {
+ name: "UpdatableSystemFontTestNotoColorEmojiVPlus1Ttf",
+ srcs: [":NotoColorEmojiTtf"],
+ out: ["UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf"],
+ tools: ["update_font_metadata"],
+ cmd: "$(location update_font_metadata) " +
+ "--input=$(in) " +
+ "--output=$(out) " +
+ "--revision=+1",
+}
+
+genrule {
+ name: "UpdatableSystemFontTestNotoColorEmojiVPlus2Ttf",
+ srcs: [":NotoColorEmojiTtf"],
+ out: ["UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf"],
+ tools: ["update_font_metadata"],
+ cmd: "$(location update_font_metadata) " +
+ "--input=$(in) " +
+ "--output=$(out) " +
+ "--revision=+2",
+}
+
+genrule_defaults {
+ name: "updatable_system_font_sig_gen_default",
+ tools: ["fsverity"],
+ tool_files: [
+ ":UpdatableSystemFontTestKeyPem",
+ ":UpdatableSystemFontTestCertPem",
+ ],
+ cmd: "$(location fsverity) sign $(in) $(out) " +
+ "--key=$(location :UpdatableSystemFontTestKeyPem) " +
+ "--cert=$(location :UpdatableSystemFontTestCertPem) " +
+ "> /dev/null",
+}
+
+genrule {
+ name: "UpdatableSystemFontTestNotoColorEmojiTtfFsvSig",
+ defaults: ["updatable_system_font_sig_gen_default"],
+ srcs: [":NotoColorEmojiTtf"],
+ out: ["UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig"],
+}
+
+genrule {
+ name: "UpdatableSystemFontTestNotoColorEmojiV0TtfFsvSig",
+ defaults: ["updatable_system_font_sig_gen_default"],
+ srcs: [":UpdatableSystemFontTestNotoColorEmojiV0Ttf"],
+ out: ["UpdatableSystemFontTestNotoColorEmojiV0.ttf.fsv_sig"],
+}
+
+genrule {
+ name: "UpdatableSystemFontTestNotoColorEmojiVPlus1TtfFsvSig",
+ defaults: ["updatable_system_font_sig_gen_default"],
+ srcs: [":UpdatableSystemFontTestNotoColorEmojiVPlus1Ttf"],
+ out: ["UpdatableSystemFontTestNotoColorEmojiVPlus1.ttf.fsv_sig"],
+}
+
+genrule {
+ name: "UpdatableSystemFontTestNotoColorEmojiVPlus2TtfFsvSig",
+ defaults: ["updatable_system_font_sig_gen_default"],
+ srcs: [":UpdatableSystemFontTestNotoColorEmojiVPlus2Ttf"],
+ out: ["UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig"],
+}
diff --git a/tests/UpdatableSystemFontTest/testdata/NotoColorEmoji.ttf b/tests/UpdatableSystemFontTest/testdata/NotoColorEmoji.ttf
new file mode 100644
index 000000000000..f71f52cbaa2b
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/testdata/NotoColorEmoji.ttf
Binary files differ
diff --git a/tests/UpdatableSystemFontTest/testdata/NotoColorEmoji.ttx b/tests/UpdatableSystemFontTest/testdata/NotoColorEmoji.ttx
new file mode 100644
index 000000000000..6540c5898ec5
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/testdata/NotoColorEmoji.ttx
@@ -0,0 +1,208 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="a"/>
+ <GlyphID id="2" name="u1F972"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <!-- Currently NotoColorEmoji.ttf's fontRevision is 2.xxx.
+ 100.0 will be sufficiently larger than that. -->
+ <fontRevision value="100.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Fri Jun 25 12:00:00 2021"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="93"/>
+ <mtx name="a" width="3000" lsb="93"/> <!-- 3em -->
+ <mtx name="u1F972" width="3000" lsb="93"/> <!-- 3em -->
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <!-- length will be calculated by the compiler. -->
+ <cmap_format_12 platformID="3" platEncID="10" format="12" reserved="0" length="0" language="0" nGroups="1">
+ <!-- The font must support at least one of the characters used
+ in OtfFontFileParser to validate the font. -->
+ <map code="0x61" name="a" />
+ <map code="0x1F972" name="u1F972" />
+ </cmap_format_12>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="a" xMin="0" yMin="0" xMax="300" yMax="300">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="0" y="300" on="1" />
+ <pt x="300" y="300" on="1" />
+ <pt x="300" y="0" on="1" />
+ </contour>
+ <instructions />
+ </TTGlyph>
+ <TTGlyph name="u1F972" xMin="0" yMin="0" xMax="300" yMax="300">
+ <contour>
+ <pt x="0" y="0" on="1" />
+ <pt x="0" y="300" on="1" />
+ <pt x="300" y="300" on="1" />
+ <pt x="300" y="0" on="1" />
+ </contour>
+ <instructions />
+ </TTGlyph>
+ </glyf>
+
+ <name>
+ <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+ Copyright (C) 2021 The Android Open Source Project
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ <!-- Android identifies the target font to be updated by PostScript name.
+ To test updating NotoColorEmoji.ttf, the PostScript needs to be
+ the same as NotoColorEmoji.ttf here. -->
+ NotoColorEmoji
+ </namerecord>
+ <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ </namerecord>
+ <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
+ http://www.apache.org/licenses/LICENSE-2.0
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestCert.der b/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestCert.der
new file mode 100644
index 000000000000..f7aa15fdef68
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestCert.der
Binary files differ
diff --git a/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestCert.pem b/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestCert.pem
new file mode 100644
index 000000000000..0cd1f666f9be
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestCert.pem
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFOTCCAyGgAwIBAgIUFaI1D5NtwkCVM3G4bFZ6sQSb598wDQYJKoZIhvcNAQEL
+BQAwLDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRAwDgYDVQQKDAdBbmRyb2lk
+MB4XDTIxMDIwMTA3MzAyNFoXDTIxMDMwMzA3MzAyNFowLDELMAkGA1UEBhMCVVMx
+CzAJBgNVBAgMAkNBMRAwDgYDVQQKDAdBbmRyb2lkMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEA0U1zptc41E65ooeBPD33Mjgp6cYPydyj2Acq80Xy7lP7
+d6/2t6w7nNNl2x3n8dAhOl3de3IxTp6JI2SdoRb7obfcp+hWJoo/cxnHpr3q/u4R
+KED0rmWaOVHpGbajSTFZgN+cTbTKJbgtXm/H65x1QfO18ep/vj5fRiu1xPpJqDv/
+xuvuko2U3eC2+NayxzCWXVFrKPLx8GvzSQ3Utaug17vs7/5GqkRJgq3lk4DvmjNA
+vY8YA4RAkII1sSaceAWFEG6ztENLu2kjcxAI9qHxxBwQZit/NtFVlFGqSN3MEYjS
+M9Fz04RsUxF672QJpAgwCJDZ41rdB3hkHvOUK9PcepBsHdZq9cQ+E64+TX+jsJLu
+VouViKlYr6WYjvhfqZeRhwbj7CoEZ2DyEZKrl27fgWaidUT5LGEQLVxg90ymbimI
+6UwXRUwmRBQJBdRO4RGvngtqxRuamyjAKDDHx5YccXCX4FWLUypyQlz0asojvbJZ
+Og7DFa1qsRdGrGIRoQJ8pYnAjBJfSudr1l0mR7fZSfZc0W9ZmuROWx9Ip7aJWQnQ
+8JLtbNPuFLD2qbmg9Y1lcXJp1FvI9FcM8JsBqZNEANQwwsdTaa8gw+3W6J2SXKQP
+H+yZI/fJWWWRFADtqmpxtvXK9K+Cy1HQmg7D0IIxVPp8rrbz6TGrg+R3/N9FBWMC
+AwEAAaNTMFEwHQYDVR0OBBYEFDS48o2UAstoOyLMcgamHKrZdl3cMB8GA1UdIwQY
+MBaAFDS48o2UAstoOyLMcgamHKrZdl3cMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggIBAF7taBYAe20tWZu0pY9d4Z8il4LoJcRrKF4YiA02UizErgCF
+h4iECy6+pcu7DJUfvCh3dCWE7CDG+OnfUWTwEHVG9n8XI/ydetBUG76PZwTadI7B
+gzJ1y7/vWqJo5U6ki+sXNmq3hkgNsNZgza3LpdovkWJYeRdffM6m/bimzwYx9id8
+5mKw2PcbVZcb25r+0dCoLVJsqqCoRjdYUy/MKPutWG2bPzmaIv8KsKFN+mzlwhJH
+lpJ/LR+3NoaHrOCFG7CW/2Ihe501vmdQ2m/VKosyk0igw8WmTsY6xMbw2t77yKkD
+hnJr1NbhKeEV9gAB2BFX8nRWI7NTgp8fG78YLVz1UcbIHmYLgFoc3ezyma+CoR86
+ER20lKd4+TNnz4RtaPdZlBa0Ba3bsMtEneqlrHvcPrZ5tgGsQR9+cy3ZtTZ/LUQX
++Xuj/EoJXuuB3hkhg52zawN5n7WUe8efWHcv1jHqeIj0phcgbZ6u4fFBPsYjzDKe
+VuYHXglNOchmoBQwEaJI/TCiEgI8dcSJXSquLAXrtznVnxzT46ZMEt5LaW1/1NLx
+q//yoPdolCI0lpunh5jvIZJpUl5XMjxVSyaveQDNVqJkITWzWqIxAT5yTLtkCNlW
+c1XyzeHkpMItiJtBruExmnaTmNjlVKsXP8wQFOYbDGgXY5iHIMbgovptRyH/
+-----END CERTIFICATE-----
diff --git a/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestKey.pem b/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestKey.pem
new file mode 100644
index 000000000000..09bb1040f112
--- /dev/null
+++ b/tests/UpdatableSystemFontTest/testdata/UpdatableSystemFontTestKey.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDRTXOm1zjUTrmi
+h4E8PfcyOCnpxg/J3KPYByrzRfLuU/t3r/a3rDuc02XbHefx0CE6Xd17cjFOnokj
+ZJ2hFvuht9yn6FYmij9zGcemver+7hEoQPSuZZo5UekZtqNJMVmA35xNtMoluC1e
+b8frnHVB87Xx6n++Pl9GK7XE+kmoO//G6+6SjZTd4Lb41rLHMJZdUWso8vHwa/NJ
+DdS1q6DXu+zv/kaqREmCreWTgO+aM0C9jxgDhECQgjWxJpx4BYUQbrO0Q0u7aSNz
+EAj2ofHEHBBmK3820VWUUapI3cwRiNIz0XPThGxTEXrvZAmkCDAIkNnjWt0HeGQe
+85Qr09x6kGwd1mr1xD4Trj5Nf6Owku5Wi5WIqVivpZiO+F+pl5GHBuPsKgRnYPIR
+kquXbt+BZqJ1RPksYRAtXGD3TKZuKYjpTBdFTCZEFAkF1E7hEa+eC2rFG5qbKMAo
+MMfHlhxxcJfgVYtTKnJCXPRqyiO9slk6DsMVrWqxF0asYhGhAnylicCMEl9K52vW
+XSZHt9lJ9lzRb1ma5E5bH0intolZCdDwku1s0+4UsPapuaD1jWVxcmnUW8j0Vwzw
+mwGpk0QA1DDCx1NpryDD7dbonZJcpA8f7Jkj98lZZZEUAO2qanG29cr0r4LLUdCa
+DsPQgjFU+nyutvPpMauD5Hf830UFYwIDAQABAoICAQCTVTcFCdl6MdSg4UwK0P/S
+fRCb/A0fJs67Agis6N9h/wI0NUyx7G6mLXU0si+U29KYGH0RKcgltJmKrYf8XoZR
+R3DvTTBfvs99QXd2G5hxTboMIPVcUi8nDE7PB+6XVkLP4hhP5uSpeqWNJZiQdTlh
+bKH2IgE8NQGyDpDMkPcKkvmw2GG/DiTtrwJ91fxRFRWzqN2LHMFMYWEHWtIR9Der
+xSC7q72om5s3fxvtIkUHwe5fwXvA9fbRAqezBR/9qL0LXTHowbpsuUz38SCuJD9g
+sfSlRxcsyly4pGf/FQpSiYKWcWlcSopKSzLDkyLqMc1GKlkGnu6aFJg95W63D1LS
+OaOXuYShHxLkqyhT8uQGRqDCu3E2ivb6fMxAPzJxxs3JrZvumNsqyxbp+HVF0idj
+NijMN/8Kb4KmNHG9I3SHG61tQFYDtxoMMNiHzq3fafBJnVcf6iThQdE5pGLN2OdF
+3rcSTeHI2HxhTrXtuiHmWXNk9aZ2TOhrssNZZjDkFL/KYh6G8guy+tn66YWy77VC
+id+6PBzYXTXsUauo4NWW1rLUfzT/y93IwVGpoXs7GHUUduZ6Q3PxsMTMF9IjBvqR
+JvfP84CUfGXoebVJmWyGhtW6N5ParvQxbonDitA0TPZcRyX3N8yqIGO/mb8MWA9M
+7s/xMZuksOpw5LSCoTAW6QKCAQEA9Z1WM/5XT+5HkwPBvS5aRz0SqMqPxAkZ0dNz
+O06zpXv6e2IPy40UzFWCIkyq3vWKQ5bqU1fnejUdmjvtnP+KhH6fxnQCgiunnrDq
+j1Sk2Y4gb1KyZY/C8IejOexM2qX7sfDTLI8XEvxJxVFCNmvYfnv4AX5QD8VOsjrg
+bvodLAgDSo2FVDP+mkpW7zAIoRV02l6QdZA+YcG940eqxB9sPR3/1KUHe9wUTTbJ
+FV5ahEPuXCyvRJkZ/rD5CPPZoQHfjKHxDlu7yfoatzCSYj10R+RInfqOFGVY4D/C
+2csXjymwTN4CFUnJcP410YhPFn5ekmc/E3xqPKgIDQhQ2+oivwKCAQEA2icN1iEo
+YuBJwB3pX3jrwk+1bpUXASueWhyAhSeNMrTrJ/lSgEAy9FBxJNnK1PjkABRnFhS+
+uxbC2hQdfAkNDS21PQOk6hOhebUVuBdfmKY1CL+P9y4Af0fjV1rgRGHihnZB5lKU
+1R/wFb8c4QgPwduiqDoZ5QP3dgxpZ4R3SCzuoyVelUSlgyWPoslg+yPddcnV8bTf
+BUlEOOyXgVudkSFlRpWZ+/ZAkLTj8rnrtKp8/+GtTQvJvPJHPfuSsDhI+EQVWqab
+HelMhxvIi9xOyN/OCc3Ex6JlEVa+X8EyNhQsV2sAKnld92hdEozW2uxRniIkxvL4
+CuBp/p3fWxEaXQKCAQEAw2j7RYCMnNZZ8Zhiko4HW3g2mT4XpYMMHMlbe4sBGJ8L
+yRBaurqzGmLJl1ph8+NsrpuqMMbWLn+F3sjhIjCZVxKbMbvopwHuaS4eYAya30/Z
+dFhaAL2g/dccQSBEgQzftFGC4YeydvNsCeW9hSjGZNNinGWPcwyqsNhw6Tpq7TYu
+0CjKNBTt8nlEsyYHJ4m3n2jvC+nIB+Spm+LP9Rt+9R0iBl+KFbwiFtCIqUyZPXQC
+dylCBJS+fsj0SXAg7J1d6ziIXcEUJfyrNqYZQLneAriYIcBPO+DqFfgEoVyYkNk9
+H9rd02wSLajCzsLhEWdW/KnSIEGzEDErvpqoIl8kZwKCAQEAjNO3T+sZyjKmCXqF
+xBcogsi4BAoEzsGcuOk7Yjn1Ia2/PI/r3VUUT7l6QOLD2JZPgWmqXovH0LjR0rw3
+iHHDViWSoS+wD1fa3tmyiqO0F7P7+ojHZDbzJTeAIE1PB3X1KP5AbnITGD5E25UD
+DJYKrgeeSmEvhDL6Vd+PT78ozZQL/Y/LLishebcOsXS0wYsWlMpV7XHoot34R5Mb
+/urond7kJRvASvJeHcxYdsHk0j1Y8kp6eIlKk0oICZBU0qOTH4m8C0gQTM/lkjay
+UO9IgM5RkOyfwowoGHhZ7zClvFlrgodVlRXCPkvGAYqfzLXPvnimKzSAQW07n53E
+qWIyFQKCAQAWRNG6hPCOzkNxMJ/RK7dwxZW6b4a1L3PMXTT/xrBKRIS1WNjbpkYO
+/FLIufOqJT6FQN2obM5uso3TI+R7MwH8DnTSnDDy0Hvs3CdHdtn2tapZOViF/UVv
+uCQa+/jMVKFCZ8k7pPFMIG6tB6WBA5MmJrW+8s0ouxLbRF5rZyzqOeyPdVBYYYDb
+68nGNA6GAtTQs9h7xV2tsQ1bXNP+6gqG3BgZYo+76xKITddT6s9aaC++LVBnPOdq
+LHV7gUvoBkVLjIp4L3Fb/DGMCcOVMCxmFlRBn+RBlV7slehvgq+Ywz2GHWLr+O/z
+V2NAtwvCfZE2Do/4f2mpHnamhS6AvrDe
+-----END PRIVATE KEY-----
diff --git a/tests/UsageReportingTest/Android.bp b/tests/UsageReportingTest/Android.bp
index 0bac5a224b26..dfce0705df59 100644
--- a/tests/UsageReportingTest/Android.bp
+++ b/tests/UsageReportingTest/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "UsageReportingTest",
// Only compile source java files in this apk.
diff --git a/tests/UsageReportingTest/AndroidManifest.xml b/tests/UsageReportingTest/AndroidManifest.xml
index be0b09e972a5..4a3487f29dc4 100644
--- a/tests/UsageReportingTest/AndroidManifest.xml
+++ b/tests/UsageReportingTest/AndroidManifest.xml
@@ -1,20 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
-
<!--
Note: Add android:sharedUserId="android.uid.system" to the root element to simulate the system UID
caller case.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.usagereporter"
- >
+ package="com.android.tests.usagereporter">
<application android:label="@string/reporter_app">
<activity android:name="UsageReporterActivity"
- android:label="UsageReporter">
+ android:label="UsageReporter"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
diff --git a/tests/UsageReportingTest/OWNERS b/tests/UsageReportingTest/OWNERS
new file mode 100644
index 000000000000..d3227de87684
--- /dev/null
+++ b/tests/UsageReportingTest/OWNERS
@@ -0,0 +1 @@
+include /services/usage/OWNERS
diff --git a/tests/UsageStatsPerfTests/Android.bp b/tests/UsageStatsPerfTests/Android.bp
index 3991fb8366ac..0e372a3ef95a 100644
--- a/tests/UsageStatsPerfTests/Android.bp
+++ b/tests/UsageStatsPerfTests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "UsageStatsPerfTests",
srcs: ["src/**/*.java"],
diff --git a/tests/UsageStatsPerfTests/OWNERS b/tests/UsageStatsPerfTests/OWNERS
new file mode 100644
index 000000000000..d3227de87684
--- /dev/null
+++ b/tests/UsageStatsPerfTests/OWNERS
@@ -0,0 +1 @@
+include /services/usage/OWNERS
diff --git a/tests/UsageStatsTest/Android.bp b/tests/UsageStatsTest/Android.bp
index 0808b05ec053..afb266bf326d 100644
--- a/tests/UsageStatsTest/Android.bp
+++ b/tests/UsageStatsTest/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "UsageStatsTest",
// Only compile source java files in this apk.
diff --git a/tests/UsageStatsTest/AndroidManifest.xml b/tests/UsageStatsTest/AndroidManifest.xml
index fefd99394a87..82e5be1bce3e 100644
--- a/tests/UsageStatsTest/AndroidManifest.xml
+++ b/tests/UsageStatsTest/AndroidManifest.xml
@@ -1,28 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
-
<!--
Note: Add android:sharedUserId="android.uid.system" to the root element to simulate the system UID
caller case.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.usagestats"
- >
+ package="com.android.tests.usagestats">
- <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
- <uses-permission android:name="android.permission.OBSERVE_APP_USAGE" />
- <uses-permission android:name="android.permission.SUSPEND_APPS" />
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
+ <uses-permission android:name="android.permission.OBSERVE_APP_USAGE"/>
+ <uses-permission android:name="android.permission.SUSPEND_APPS"/>
<application android:label="Usage Access Test">
<activity android:name=".UsageStatsActivity"
- android:label="Device Usage History">
+ android:label="Device Usage History"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name=".UsageLogActivity" />
+ <activity android:name=".UsageLogActivity"/>
</application>
</manifest>
diff --git a/tests/UsageStatsTest/OWNERS b/tests/UsageStatsTest/OWNERS
new file mode 100644
index 000000000000..d3227de87684
--- /dev/null
+++ b/tests/UsageStatsTest/OWNERS
@@ -0,0 +1 @@
+include /services/usage/OWNERS
diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
index bb985d7f8be2..53269efcbf05 100644
--- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
+++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
@@ -164,7 +164,7 @@ public class UsageStatsActivity extends ListActivity {
intent.putExtra(EXTRA_KEY_TIMEOUT, true);
mUsageStatsManager.registerAppUsageObserver(1, packages,
60, TimeUnit.SECONDS, PendingIntent.getActivity(UsageStatsActivity.this,
- 1, intent, 0));
+ 1, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED));
}
}
});
@@ -198,7 +198,7 @@ public class UsageStatsActivity extends ListActivity {
intent.putExtra(EXTRA_KEY_TIMEOUT, true);
mUsageStatsManager.registerAppUsageLimitObserver(1, packages,
Duration.ofSeconds(60), Duration.ofSeconds(0),
- PendingIntent.getActivity(UsageStatsActivity.this, 1, intent, 0));
+ PendingIntent.getActivity(UsageStatsActivity.this, 1, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED));
}
}
});
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.bp b/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.bp
index c7e9df0fe9cf..9133baed7179 100644
--- a/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.bp
+++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.bp
@@ -16,6 +16,15 @@
//#################################################
+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"],
+}
+
android_test {
name: "AoapTestDeviceApp",
srcs: ["src/**/*.java"],
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/AndroidManifest.xml b/tests/UsbHostExternalManagmentTest/AoapTestDevice/AndroidManifest.xml
index 99bb520ee902..fadd0ea21996 100644
--- a/tests/UsbHostExternalManagmentTest/AoapTestDevice/AndroidManifest.xml
+++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/AndroidManifest.xml
@@ -13,18 +13,19 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- package="com.android.hardware.usb.aoapdevicetest" >
- <application android:label="UsbAoapDeviceTestApp" >
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ package="com.android.hardware.usb.aoapdevicetest">
+ <application android:label="UsbAoapDeviceTestApp">
<activity android:name=".UsbAoapDeviceTestActivity"
- android:configChanges="keyboard|keyboardHidden" >
+ android:configChanges="keyboard|keyboardHidden"
+ android:exported="true">
<intent-filter>
- <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+ <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"/>
</intent-filter>
- <meta-data
- android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
- android:resource="@xml/accessory_filter"/>
+ <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+ android:resource="@xml/accessory_filter"/>
</activity>
</application>
</manifest>
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/src/com/android/hardware/usb/aoapdevicetest/UsbAoapDeviceTestActivity.java b/tests/UsbHostExternalManagmentTest/AoapTestDevice/src/com/android/hardware/usb/aoapdevicetest/UsbAoapDeviceTestActivity.java
index aa4f8caa0b20..ef179e2da26d 100644
--- a/tests/UsbHostExternalManagmentTest/AoapTestDevice/src/com/android/hardware/usb/aoapdevicetest/UsbAoapDeviceTestActivity.java
+++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/src/com/android/hardware/usb/aoapdevicetest/UsbAoapDeviceTestActivity.java
@@ -99,7 +99,7 @@ public class UsbAoapDeviceTestActivity extends Activity {
Intent intent = new Intent(ACTION_USB_ACCESSORY_PERMISSION);
intent.setPackage(getPackageName());
PendingIntent pendingIntent = PendingIntent.getBroadcast(
- this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
+ this, 0, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
mUsbManager.requestPermission(accessory, pendingIntent);
return;
}
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.bp b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.bp
index 6fa58cb5c682..68930023de96 100644
--- a/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.bp
+++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.bp
@@ -16,6 +16,15 @@
//#################################################
+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"],
+}
+
android_test {
name: "AoapTestHostApp",
srcs: ["src/**/*.java"],
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/AndroidManifest.xml b/tests/UsbHostExternalManagmentTest/AoapTestHost/AndroidManifest.xml
index 8cc470eaa85c..9ad17ab64bd0 100644
--- a/tests/UsbHostExternalManagmentTest/AoapTestHost/AndroidManifest.xml
+++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/AndroidManifest.xml
@@ -13,18 +13,19 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- package="com.android.hardware.usb.aoaphosttest" >
- <application android:label="UsbAoapHostTestApp" >
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ package="com.android.hardware.usb.aoaphosttest">
+ <application android:label="UsbAoapHostTestApp">
<activity android:name=".UsbAoapHostTestActivity"
- android:configChanges="keyboard|keyboardHidden" >
+ android:configChanges="keyboard|keyboardHidden"
+ android:exported="true">
<intent-filter>
- <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
+ <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
</intent-filter>
- <meta-data
- android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
- android:resource="@xml/usb_device_filter"/>
+ <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
+ android:resource="@xml/usb_device_filter"/>
</activity>
</application>
</manifest>
diff --git a/tests/UsbHostExternalManagmentTest/OWNERS b/tests/UsbHostExternalManagmentTest/OWNERS
new file mode 100644
index 000000000000..f7b2a37a297a
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/OWNERS
@@ -0,0 +1 @@
+include /services/usb/OWNERS
diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.bp b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.bp
index edd4205968b3..2fca4d35fe01 100644
--- a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.bp
+++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.bp
@@ -17,6 +17,15 @@
//#################################################
// TODO: should this be android_helper_test_app?
+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"],
+}
+
android_app {
name: "UsbHostExternalManagementTestApp",
srcs: ["src/**/*.java"],
diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/AndroidManifest.xml b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/AndroidManifest.xml
index 97bbefb5c4af..627e46b6304d 100644
--- a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/AndroidManifest.xml
+++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/AndroidManifest.xml
@@ -13,19 +13,21 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- package="com.android.hardware.usb.externalmanagementtest" >
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ package="com.android.hardware.usb.externalmanagementtest">
- <uses-permission android:name="android.permission.MANAGE_USB" />
- <application android:label="UsbHostExternalManagementTestApp" >
+ <uses-permission android:name="android.permission.MANAGE_USB"/>
+ <application android:label="UsbHostExternalManagementTestApp">
<activity android:name=".UsbHostManagementActivity"
- android:configChanges="keyboard|keyboardHidden" >
+ android:configChanges="keyboard|keyboardHidden"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
</intent-filter>
<intent-filter>
- <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
+ <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/UsbManagerTests/Android.bp b/tests/UsbManagerTests/Android.bp
index a03c6e223b74..97fbf5b32035 100644
--- a/tests/UsbManagerTests/Android.bp
+++ b/tests/UsbManagerTests/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "UsbManagerTests",
srcs: ["src/**/*.java"],
diff --git a/tests/UsbManagerTests/OWNERS b/tests/UsbManagerTests/OWNERS
new file mode 100644
index 000000000000..f7b2a37a297a
--- /dev/null
+++ b/tests/UsbManagerTests/OWNERS
@@ -0,0 +1 @@
+include /services/usb/OWNERS
diff --git a/tests/UsbManagerTests/lib/Android.bp b/tests/UsbManagerTests/lib/Android.bp
index 3c5d91b326d0..994484cd63bf 100644
--- a/tests/UsbManagerTests/lib/Android.bp
+++ b/tests/UsbManagerTests/lib/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_library {
name: "UsbManagerTestLib",
srcs: ["src/**/*.java"],
diff --git a/tests/UsbTests/Android.bp b/tests/UsbTests/Android.bp
index 7c2be9b63ac3..9328b67795cb 100644
--- a/tests/UsbTests/Android.bp
+++ b/tests/UsbTests/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "UsbTests",
srcs: ["**/*.java"],
diff --git a/tests/UsbTests/OWNERS b/tests/UsbTests/OWNERS
new file mode 100644
index 000000000000..f7b2a37a297a
--- /dev/null
+++ b/tests/UsbTests/OWNERS
@@ -0,0 +1 @@
+include /services/usb/OWNERS
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
index ef973acf763b..861d221238ff 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
@@ -182,6 +182,24 @@ public class UsbHandlerTest {
@SmallTest
@Test
+ public void setFunctionsNcmAndRndis() {
+ final long rndisPlusNcm = UsbManager.FUNCTION_RNDIS | UsbManager.FUNCTION_NCM;
+
+ mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
+ UsbManager.FUNCTION_NCM));
+ assertEquals(UsbManager.FUNCTION_NCM, mUsbHandler.getEnabledFunctions() & rndisPlusNcm);
+
+ mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
+ rndisPlusNcm));
+ assertEquals(rndisPlusNcm, mUsbHandler.getEnabledFunctions() & rndisPlusNcm);
+
+ mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
+ UsbManager.FUNCTION_NCM));
+ assertEquals(UsbManager.FUNCTION_NCM, mUsbHandler.getEnabledFunctions() & rndisPlusNcm);
+ }
+
+ @SmallTest
+ @Test
public void enableAdb() {
sendBootCompleteMessages(mUsbHandler);
Message msg = mUsbHandler.obtainMessage(MSG_ENABLE_ADB);
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbManagerNoPermTest.java b/tests/UsbTests/src/com/android/server/usb/UsbManagerNoPermTest.java
index a0fd9d40506b..b8bd98ea3f21 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbManagerNoPermTest.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbManagerNoPermTest.java
@@ -16,6 +16,8 @@
package com.android.server.usb;
+import static org.junit.Assert.assertEquals;
+
import android.content.Context;
import android.hardware.usb.UsbManager;
@@ -23,12 +25,12 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.usblib.UsbManagerTestLib;
+
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
-import com.android.server.usblib.UsbManagerTestLib;
-
/**
* Unit tests for {@link android.hardware.usb.UsbManager}.
* Note: NOT claimed MANAGE_USB permission in Manifest
@@ -78,4 +80,35 @@ public class UsbManagerNoPermTest {
public void testUsbApi_SetCurrentFunctions_OnSecurityException() throws Exception {
mUsbManagerTestLib.testSetCurrentFunctionsEx(UsbManager.FUNCTION_NONE);
}
+
+ public void assertSettableFunctions(boolean settable, long functions) {
+ assertEquals(
+ "areSettableFunctions(" + UsbManager.usbFunctionsToString(functions) + "):",
+ settable, UsbManager.areSettableFunctions(functions));
+ }
+
+ /**
+ * Tests the behaviour of the static areSettableFunctions method. This method performs no IPCs
+ * and requires no permissions.
+ */
+ @Test
+ public void testUsbManager_AreSettableFunctions() {
+ // NONE is settable.
+ assertSettableFunctions(true, UsbManager.FUNCTION_NONE);
+
+ // MTP, PTP, RNDIS, MIDI, NCM are all settable by themselves.
+ assertSettableFunctions(true, UsbManager.FUNCTION_MTP);
+ assertSettableFunctions(true, UsbManager.FUNCTION_PTP);
+ assertSettableFunctions(true, UsbManager.FUNCTION_RNDIS);
+ assertSettableFunctions(true, UsbManager.FUNCTION_MIDI);
+ assertSettableFunctions(true, UsbManager.FUNCTION_NCM);
+
+ // Setting two functions at the same time is not allowed...
+ assertSettableFunctions(false, UsbManager.FUNCTION_MTP | UsbManager.FUNCTION_PTP);
+ assertSettableFunctions(false, UsbManager.FUNCTION_PTP | UsbManager.FUNCTION_RNDIS);
+ assertSettableFunctions(false, UsbManager.FUNCTION_MIDI | UsbManager.FUNCTION_NCM);
+
+ // ... except in the special case of RNDIS and NCM.
+ assertSettableFunctions(true, UsbManager.FUNCTION_RNDIS | UsbManager.FUNCTION_NCM);
+ }
}
diff --git a/tests/UsesFeature2Test/Android.bp b/tests/UsesFeature2Test/Android.bp
index a1b77d07ccdc..624e4ec7ebd8 100644
--- a/tests/UsesFeature2Test/Android.bp
+++ b/tests/UsesFeature2Test/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "UsesFeature2Test",
srcs: ["**/*.java"],
diff --git a/tests/UsesFeature2Test/AndroidManifest.xml b/tests/UsesFeature2Test/AndroidManifest.xml
index 8caf4a158867..a0ea45adae19 100644
--- a/tests/UsesFeature2Test/AndroidManifest.xml
+++ b/tests/UsesFeature2Test/AndroidManifest.xml
@@ -22,6 +22,10 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH" />
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+ <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
+ <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-feature android:name="android.hardware.sensor.accelerometer" />
<feature-group android:label="@string/minimal">
diff --git a/tests/VectorDrawableTest/Android.bp b/tests/VectorDrawableTest/Android.bp
index 13f318ef7c42..9da7c5fdbb17 100644
--- a/tests/VectorDrawableTest/Android.bp
+++ b/tests/VectorDrawableTest/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
name: "VectorDrawableTest",
srcs: ["**/*.java"],
diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml
index 7b3beb27e0cc..5334dac57ca2 100644
--- a/tests/VectorDrawableTest/AndroidManifest.xml
+++ b/tests/VectorDrawableTest/AndroidManifest.xml
@@ -16,147 +16,146 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.dynamic" >
-
- <application
- android:hardwareAccelerated="true"
- android:label="vector"
- android:supportsRtl="true" >
- <activity
- android:name="VectorDrawablePerformance"
- android:label="Vector Performance" >
+ package="com.android.test.dynamic">
+
+ <application android:hardwareAccelerated="true"
+ android:label="vector"
+ android:supportsRtl="true">
+ <activity android:name="VectorDrawablePerformance"
+ android:label="Vector Performance"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="BitmapDrawableDupe"
- android:label="Bitmap Performance of clones" >
+ <activity android:name="BitmapDrawableDupe"
+ android:label="Bitmap Performance of clones"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="VectorDrawableAnimation"
- android:label="VectorTestAnimation" >
+ <activity android:name="VectorDrawableAnimation"
+ android:label="VectorTestAnimation"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="VectorDrawableTest"
- android:label="Vector Icon" >
+ <activity android:name="VectorDrawableTest"
+ android:label="Vector Icon"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity
- android:name="AnimatedVectorDrawableTest"
- android:label="AnimatedVectorDrawableTest" >
+ <activity android:name="AnimatedVectorDrawableTest"
+ android:label="AnimatedVectorDrawableTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="AnimatedStateVectorDrawableTest"
- android:label="AnimatedStateList and AnimatedVectorDrawable" >
+ <activity android:name="AnimatedStateVectorDrawableTest"
+ android:label="AnimatedStateList and AnimatedVectorDrawable"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="VectorDrawable01"
- android:label="VectorTest1" >
+ <activity android:name="VectorDrawable01"
+ android:label="VectorTest1"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="VectorDrawableDupPerf"
- android:label="Vector Performance of clones" >
+ <activity android:name="VectorDrawableDupPerf"
+ android:label="Vector Performance of clones"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="AnimatedVectorDrawableDupPerf"
- android:label="Animated Vector Performance of clones" >
+ <activity android:name="AnimatedVectorDrawableDupPerf"
+ android:label="Animated Vector Performance of clones"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="VectorDrawableStaticPerf"
- android:label="System icons" >
+ <activity android:name="VectorDrawableStaticPerf"
+ android:label="System icons"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="VectorCheckbox"
- android:label="Basic static vector drawables" >
+ <activity android:name="VectorCheckbox"
+ android:label="Basic static vector drawables"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="VectorPathChecking"
- android:label="Path Checking graphics" >
+ <activity android:name="VectorPathChecking"
+ android:label="Path Checking graphics"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="ScaleDrawableTests"
- android:label="Scale Type Test" >
+ <activity android:name="ScaleDrawableTests"
+ android:label="Scale Type Test"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="AnimatedVectorDrawableAttr"
- android:label="AnimatedVectorDrawable Attr Test" >
+ <activity android:name="AnimatedVectorDrawableAttr"
+ android:label="AnimatedVectorDrawable Attr Test"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
- <activity
- android:name="BoundsCheckTest"
- android:label="SetBound check" >
+ <activity android:name="BoundsCheckTest"
+ android:label="SetBound check"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.dynamic.TEST" />
+ <category android:name="com.android.test.dynamic.TEST"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/VoiceEnrollment/Android.bp b/tests/VoiceEnrollment/Android.bp
index e43b38c5a034..b5d62bbd68a8 100644
--- a/tests/VoiceEnrollment/Android.bp
+++ b/tests/VoiceEnrollment/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_app {
name: "VoiceEnrollment",
srcs: ["**/*.java"],
diff --git a/tests/VoiceEnrollment/AndroidManifest.xml b/tests/VoiceEnrollment/AndroidManifest.xml
index 46f6ff541b4d..d30f21c1cd57 100644
--- a/tests/VoiceEnrollment/AndroidManifest.xml
+++ b/tests/VoiceEnrollment/AndroidManifest.xml
@@ -1,20 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.voiceenrollment">
+ package="com.android.test.voiceenrollment">
- <uses-permission android:name="android.permission.MANAGE_VOICE_KEYPHRASES" />
- <application
- android:permission="android.permission.MANAGE_VOICE_KEYPHRASES">
- <activity
- android:name="TestEnrollmentActivity"
- android:label="Voice Enrollment Application"
- android:theme="@android:style/Theme.Material.Light.Voice">
+ <uses-permission android:name="android.permission.MANAGE_VOICE_KEYPHRASES"/>
+ <application android:permission="android.permission.MANAGE_VOICE_KEYPHRASES">
+ <activity android:name="TestEnrollmentActivity"
+ android:label="Voice Enrollment Application"
+ android:theme="@android:style/Theme.Material.Light.Voice"
+ android:exported="true">
<intent-filter>
- <action android:name="com.android.intent.action.MANAGE_VOICE_KEYPHRASES" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="com.android.intent.action.MANAGE_VOICE_KEYPHRASES"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
- <meta-data
- android:name="android.voice_enrollment"
- android:resource="@xml/enrollment_application"/>
+ <meta-data android:name="android.voice_enrollment"
+ android:resource="@xml/enrollment_application"/>
</application>
</manifest>
diff --git a/tests/VoiceInteraction/Android.bp b/tests/VoiceInteraction/Android.bp
index 7059473fb63f..1aa7fafcd37c 100644
--- a/tests/VoiceInteraction/Android.bp
+++ b/tests/VoiceInteraction/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "VoiceInteraction",
srcs: ["**/*.java"],
diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml
index 5fdf0dd3992c..5d8cea783dd7 100644
--- a/tests/VoiceInteraction/AndroidManifest.xml
+++ b/tests/VoiceInteraction/AndroidManifest.xml
@@ -1,74 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.voiceinteraction">
+ package="com.android.test.voiceinteraction">
- <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="25" />
+ <uses-sdk android:minSdkVersion="23"
+ android:targetSdkVersion="25"/>
- <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
- <uses-permission android:name="android.permission.READ_LOGS" />
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
+ <uses-permission android:name="android.permission.READ_LOGS"/>
<application>
- <activity android:name="VoiceInteractionMain" android:label="Voice Interaction"
- android:theme="@android:style/Theme.Material">
+ <activity android:name="VoiceInteractionMain"
+ android:label="Voice Interaction"
+ android:theme="@android:style/Theme.Material"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="AssistProxyActivity"
- android:label="Test Assist Proxy"
- android:theme="@android:style/Theme.NoDisplay"
- android:excludeFromRecents="true"
- android:noHistory="true"
- android:taskAffinity="">
+ android:label="Test Assist Proxy"
+ android:theme="@android:style/Theme.NoDisplay"
+ android:excludeFromRecents="true"
+ android:noHistory="true"
+ android:taskAffinity=""
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.ASSIST" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.intent.action.ASSIST"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name="SettingsActivity"
- android:label="Voice Interaction Settings">
+ android:label="Voice Interaction Settings"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<service android:name="MainInteractionService"
- android:label="Test Voice Interaction Service"
- android:permission="android.permission.BIND_VOICE_INTERACTION"
- android:process=":interactor">
+ android:label="Test Voice Interaction Service"
+ android:permission="android.permission.BIND_VOICE_INTERACTION"
+ android:process=":interactor"
+ android:exported="true">
<meta-data android:name="android.voice_interaction"
- android:resource="@xml/interaction_service" />
+ android:resource="@xml/interaction_service"/>
<intent-filter>
- <action android:name="android.service.voice.VoiceInteractionService" />
+ <action android:name="android.service.voice.VoiceInteractionService"/>
</intent-filter>
</service>
<service android:name="MainInteractionSessionService"
- android:permission="android.permission.BIND_VOICE_INTERACTION"
- android:process=":session">
+ android:permission="android.permission.BIND_VOICE_INTERACTION"
+ android:process=":session">
</service>
<service android:name="MainRecognitionService"
- android:label="Test Voice Interaction Service">
+ android:label="Test Voice Interaction Service"
+ android:exported="true">
<intent-filter>
- <action android:name="android.speech.RecognitionService" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.speech.RecognitionService"/>
+ <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
- <meta-data android:name="android.speech" android:resource="@xml/recognition_service" />
+ <meta-data android:name="android.speech"
+ android:resource="@xml/recognition_service"/>
</service>
- <activity android:name="TestInteractionActivity" android:label="Voice Interaction Target"
- android:theme="@android:style/Theme.Material.Light">
+ <activity android:name="TestInteractionActivity"
+ android:label="Voice Interaction Target"
+ android:theme="@android:style/Theme.Material.Light"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.VOICE" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.VOICE"/>
</intent-filter>
</activity>
- <activity android:name="StartVoiceInteractionActivity" android:label="In-Activity Voice"
- android:theme="@android:style/Theme.Material.Light">
+ <activity android:name="StartVoiceInteractionActivity"
+ android:label="In-Activity Voice"
+ android:theme="@android:style/Theme.Material.Light"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/VoiceInteraction/OWNERS b/tests/VoiceInteraction/OWNERS
new file mode 100644
index 000000000000..ef1061b28b63
--- /dev/null
+++ b/tests/VoiceInteraction/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/voice/OWNERS
diff --git a/tests/WallpaperTest/Android.bp b/tests/WallpaperTest/Android.bp
index f68b6ec2452d..b009af25f9da 100644
--- a/tests/WallpaperTest/Android.bp
+++ b/tests/WallpaperTest/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_app {
name: "WallpaperTest",
srcs: ["src/**/*.java"],
diff --git a/tests/WallpaperTest/AndroidManifest.xml b/tests/WallpaperTest/AndroidManifest.xml
index 4c914dd5498d..8d7ccb9476ca 100644
--- a/tests/WallpaperTest/AndroidManifest.xml
+++ b/tests/WallpaperTest/AndroidManifest.xml
@@ -1,31 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.wallpapertest" >
+ package="com.example.wallpapertest">
- <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />
+ <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS"/>
- <application
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name" >
+ <application android:label="@string/app_name"
+ android:theme="@style/AppTheme">
+ <activity android:name=".MainActivity"
+ android:label="@string/app_name"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <service
- android:label="@string/test_wallpaper"
- android:name=".TestWallpaper"
- android:permission="android.permission.BIND_WALLPAPER"
- android:enabled="true">
+ <service android:label="@string/test_wallpaper"
+ android:name=".TestWallpaper"
+ android:permission="android.permission.BIND_WALLPAPER"
+ android:enabled="true"
+ android:exported="true">
<intent-filter>
- <action android:name="android.service.wallpaper.WallpaperService" />
+ <action android:name="android.service.wallpaper.WallpaperService"/>
</intent-filter>
<meta-data android:name="android.service.wallpaper"
- android:resource="@xml/test_wallpaper" />
+ android:resource="@xml/test_wallpaper"/>
</service>
</application>
</manifest>
diff --git a/tests/WindowAnimationJank/Android.bp b/tests/WindowAnimationJank/Android.bp
index 50b2297386cc..ed86aa5f90ea 100644
--- a/tests/WindowAnimationJank/Android.bp
+++ b/tests/WindowAnimationJank/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "WindowAnimationJank",
srcs: ["src/**/*.java"],
diff --git a/tests/WindowAnimationJank/AndroidManifest.xml b/tests/WindowAnimationJank/AndroidManifest.xml
index d7aef3348af3..34d24408be1f 100644
--- a/tests/WindowAnimationJank/AndroidManifest.xml
+++ b/tests/WindowAnimationJank/AndroidManifest.xml
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
-
<!--
* Copyright (C) 2015 The Android Open Source Project
*
@@ -15,26 +14,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.windowanimationjank">
+ package="android.windowanimationjank">
- <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
+ <uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>
<application>
<uses-library android:name="android.test.runner"/>
<activity android:name="ElementLayoutActivity"
- android:label="ElementLayoutActivity"
- android:taskAffinity="android.windowanimationjank.ElementLayoutActivity" >
+ android:label="ElementLayoutActivity"
+ android:taskAffinity="android.windowanimationjank.ElementLayoutActivity"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
<!-- self-instrumenting test package. -->
<instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="android.windowanimationjank">
+ android:targetPackage="android.windowanimationjank">
</instrumentation>
</manifest>
diff --git a/tests/WindowAnimationJank/OWNERS b/tests/WindowAnimationJank/OWNERS
new file mode 100644
index 000000000000..0862c05e0ee4
--- /dev/null
+++ b/tests/WindowAnimationJank/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/tests/WindowInsetsTests/Android.bp b/tests/WindowInsetsTests/Android.bp
index 7272152dc257..b1f4819fc0bb 100644
--- a/tests/WindowInsetsTests/Android.bp
+++ b/tests/WindowInsetsTests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "WindowInsetsTests",
srcs: ["src/**/*.java"],
@@ -24,4 +33,3 @@ android_test {
"com.google.android.material_material",
],
}
-
diff --git a/tests/WindowInsetsTests/AndroidManifest.xml b/tests/WindowInsetsTests/AndroidManifest.xml
index 0f6282e20b41..61dd9d4cd021 100644
--- a/tests/WindowInsetsTests/AndroidManifest.xml
+++ b/tests/WindowInsetsTests/AndroidManifest.xml
@@ -18,15 +18,22 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.test.windowinsetstests">
- <application android:label="@string/activity_title">
- <activity android:name=".WindowInsetsActivity"
- android:theme="@style/appTheme"
- android:windowSoftInputMode="adjustResize">
-
+ <application android:label="@string/application_title">
+ <activity android:name=".WindowInsetsTestsMainActivity"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <activity android:name=".ChatActivity"
+ android:label="@string/chat_activity_title"
+ android:theme="@style/chat"
+ android:windowSoftInputMode="adjustResize" />
+
+ <activity android:name=".ControllerActivity"
+ android:label="@string/controller_activity_title"
+ android:theme="@style/controller" />
</application>
</manifest>
diff --git a/tests/WindowInsetsTests/OWNERS b/tests/WindowInsetsTests/OWNERS
new file mode 100644
index 000000000000..0862c05e0ee4
--- /dev/null
+++ b/tests/WindowInsetsTests/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/tests/WindowInsetsTests/res/layout/window_inset_activity.xml b/tests/WindowInsetsTests/res/layout/chat_activity.xml
index 1b51c4f83fe0..1b51c4f83fe0 100644
--- a/tests/WindowInsetsTests/res/layout/window_inset_activity.xml
+++ b/tests/WindowInsetsTests/res/layout/chat_activity.xml
diff --git a/tests/WindowInsetsTests/res/layout/controller_activity.xml b/tests/WindowInsetsTests/res/layout/controller_activity.xml
new file mode 100644
index 000000000000..d51a4ddd43e8
--- /dev/null
+++ b/tests/WindowInsetsTests/res/layout/controller_activity.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <Spinner
+ android:id="@+id/spinnerBehavior"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ android:layout_marginBottom="20dp" />
+
+ <ToggleButton
+ android:id="@+id/toggleButtonStatus"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:checked="true"
+ android:text="Status Bars Toggle Button"
+ android:textOff="Status Bars Invisible"
+ android:textOn="Status Bars Visible" />
+
+ <SeekBar
+ android:id="@+id/seekBarStatus"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ android:layout_marginBottom="20dp"
+ android:max="10000"
+ android:progress="10000" />
+
+ <ToggleButton
+ android:id="@+id/toggleButtonNavigation"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:checked="true"
+ android:text="Navigation Bars Toggle Button"
+ android:textOff="Navigation Bars Invisible"
+ android:textOn="Navigation Bars Visible" />
+
+ <SeekBar
+ android:id="@+id/seekBarNavigation"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ android:layout_marginBottom="20dp"
+ android:max="10000"
+ android:progress="10000" />
+
+ <ToggleButton
+ android:id="@+id/toggleButtonIme"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:checked="true"
+ android:text="IME Toggle Button"
+ android:textOff="IME Invisible"
+ android:textOn="IME Visible" />
+
+ <SeekBar
+ android:id="@+id/seekBarIme"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ android:layout_marginBottom="20dp"
+ android:max="10000"
+ android:progress="0" />
+
+ <TextView
+ android:id="@+id/textViewControllableInsets"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="5dp" />
+
+ <EditText
+ android:id="@+id/editText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ems="10"
+ android:hint="For testing IME..."
+ android:inputType="text"
+ android:text="" />
+
+ </LinearLayout>
+
+</ScrollView> \ No newline at end of file
diff --git a/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml b/tests/WindowInsetsTests/res/layout/main_activity.xml
index efcaef679a9c..621ed89204d1 100644
--- a/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml
+++ b/tests/WindowInsetsTests/res/layout/main_activity.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
+<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -21,30 +21,17 @@
android:orientation="vertical">
<Button
- android:id="@+id/activity_view_button"
+ android:id="@+id/chat_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Test ActivityView"
+ android:text="@string/chat_activity_title"
android:textAllCaps="false"/>
<Button
- android:id="@+id/scroll_activity_view_button"
+ android:id="@+id/controller_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Test Scroll ActivityView"
+ android:text="@string/controller_activity_title"
android:textAllCaps="false"/>
- <Button
- android:id="@+id/resize_activity_view_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Test Resize ActivityView"
- android:textAllCaps="false"/>
-
- <Button
- android:id="@+id/visibility_activity_view_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Test ActivityView Visibility"
- android:textAllCaps="false"/>
</LinearLayout>
diff --git a/tests/WindowInsetsTests/res/values/strings.xml b/tests/WindowInsetsTests/res/values/strings.xml
index 2b8e5f3da362..d6355f5a0464 100644
--- a/tests/WindowInsetsTests/res/values/strings.xml
+++ b/tests/WindowInsetsTests/res/values/strings.xml
@@ -16,5 +16,14 @@
-->
<resources>
- <string name="activity_title">New Insets Chat</string>
+ <string name="application_title">Window Insets Tests</string>
+ <string name="chat_activity_title">New Insets Chat</string>
+ <string name="controller_activity_title">Window Insets Controller</string>
+
+ <!-- The item positions should match the flag values respectively. -->
+ <string-array name="behaviors">
+ <item>BEHAVIOR_SHOW_BARS_BY_TOUCH</item>
+ <item>BEHAVIOR_DEFAULT</item>
+ <item>BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE</item>
+ </string-array>
</resources>
diff --git a/tests/WindowInsetsTests/res/values/styles.xml b/tests/WindowInsetsTests/res/values/styles.xml
index 220671fb8e71..a84ffbed600d 100644
--- a/tests/WindowInsetsTests/res/values/styles.xml
+++ b/tests/WindowInsetsTests/res/values/styles.xml
@@ -17,7 +17,7 @@
<resources>
- <style name="appTheme" parent="@style/Theme.MaterialComponents.Light">
+ <style name="chat" parent="@style/Theme.MaterialComponents.Light">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
@@ -63,5 +63,11 @@
<dimen name="bubble_padding">8dp</dimen>
<dimen name="bubble_padding_side">16dp</dimen>
+ <style name="controller" parent="android:Theme.Material">
+ <item name="android:colorPrimaryDark">#111111</item>
+ <item name="android:navigationBarColor">#111111</item>
+ <item name="android:colorPrimary">#222222</item>
+ <item name="android:colorAccent">#33ccff</item>
+ </style>
</resources> \ No newline at end of file
diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ChatActivity.java
index 498cb7c1c710..ba12acb2c877 100644
--- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
+++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ChatActivity.java
@@ -30,7 +30,6 @@ import android.content.Context;
import android.graphics.Insets;
import android.os.Bundle;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
@@ -39,8 +38,6 @@ import android.view.WindowInsetsAnimation;
import android.view.WindowInsetsAnimation.Callback;
import android.view.WindowInsetsAnimationControlListener;
import android.view.WindowInsetsAnimationController;
-import android.view.WindowInsetsController;
-import android.view.WindowInsetsController.OnControllableInsetsChangedListener;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
@@ -49,7 +46,7 @@ import java.util.List;
import androidx.appcompat.app.AppCompatActivity;
-public class WindowInsetsActivity extends AppCompatActivity {
+public class ChatActivity extends AppCompatActivity {
private View mRoot;
@@ -58,7 +55,7 @@ public class WindowInsetsActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.window_inset_activity);
+ setContentView(R.layout.chat_activity);
setSupportActionBar(findViewById(R.id.toolbar));
@@ -71,7 +68,7 @@ public class WindowInsetsActivity extends AppCompatActivity {
mRoot.setOnTouchListener(new View.OnTouchListener() {
private final ViewConfiguration mViewConfiguration =
- ViewConfiguration.get(WindowInsetsActivity.this);
+ ViewConfiguration.get(ChatActivity.this);
WindowInsetsAnimationController mAnimationController;
WindowInsetsAnimationControlListener mCurrentRequest;
boolean mRequestedController = false;
diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java
new file mode 100644
index 000000000000..95fd959e5587
--- /dev/null
+++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.test.windowinsetstests;
+
+import android.app.Activity;
+import android.graphics.Insets;
+import android.os.Bundle;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowInsets.Type;
+import android.view.WindowInsetsAnimationControlListener;
+import android.view.WindowInsetsAnimationController;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.CompoundButton;
+import android.widget.SeekBar;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.ToggleButton;
+
+public class ControllerActivity extends Activity implements View.OnApplyWindowInsetsListener {
+
+ private ToggleButton mToggleStatus;
+ private SeekBar mSeekStatus;
+ private ToggleButton mToggleNavigation;
+ private SeekBar mSeekNavigation;
+ private ToggleButton mToggleIme;
+ private SeekBar mSeekIme;
+ private TextView mTextControllableInsets;
+ private boolean[] mNotFromUser = {false};
+ private WindowInsets mLastInsets;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.controller_activity);
+ final Spinner spinnerBehavior = findViewById(R.id.spinnerBehavior);
+ ArrayAdapter<CharSequence> adapterBehavior = ArrayAdapter.createFromResource(this,
+ R.array.behaviors, android.R.layout.simple_spinner_item);
+ adapterBehavior.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spinnerBehavior.setAdapter(adapterBehavior);
+ spinnerBehavior.setSelection(
+ spinnerBehavior.getWindowInsetsController().getSystemBarsBehavior());
+ spinnerBehavior.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ parent.getWindowInsetsController().setSystemBarsBehavior(position);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) { }
+ });
+ mToggleStatus = findViewById(R.id.toggleButtonStatus);
+ mToggleStatus.setTag(mNotFromUser);
+ mToggleStatus.setOnCheckedChangeListener(new ToggleListener(Type.statusBars()));
+ mSeekStatus = findViewById(R.id.seekBarStatus);
+ mSeekStatus.setOnSeekBarChangeListener(new SeekBarListener(Type.statusBars()));
+ mToggleNavigation = findViewById(R.id.toggleButtonNavigation);
+ mToggleNavigation.setTag(mNotFromUser);
+ mToggleNavigation.setOnCheckedChangeListener(new ToggleListener(Type.navigationBars()));
+ mSeekNavigation = findViewById(R.id.seekBarNavigation);
+ mSeekNavigation.setOnSeekBarChangeListener(new SeekBarListener(Type.navigationBars()));
+ mToggleIme = findViewById(R.id.toggleButtonIme);
+ mToggleIme.setTag(mNotFromUser);
+ mToggleIme.setOnCheckedChangeListener(new ToggleListener(Type.ime()));
+ mSeekIme = findViewById(R.id.seekBarIme);
+ mSeekIme.setOnSeekBarChangeListener(new SeekBarListener(Type.ime()));
+ mTextControllableInsets = findViewById(R.id.textViewControllableInsets);
+ final View contentView = findViewById(R.id.content);
+ contentView.setOnApplyWindowInsetsListener(this);
+ contentView.getWindowInsetsController().addOnControllableInsetsChangedListener(
+ (c, types) -> mTextControllableInsets.setText("ControllableInsetsTypes=" + types));
+ }
+
+ @Override
+ public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
+ mNotFromUser[0] = true;
+ updateWidgets(insets, Type.statusBars(), mToggleStatus, mSeekStatus);
+ updateWidgets(insets, Type.navigationBars(), mToggleNavigation, mSeekNavigation);
+ updateWidgets(insets, Type.ime(), mToggleIme, mSeekIme);
+ mLastInsets = insets;
+ mNotFromUser[0] = false;
+
+ // Prevent triggering system gestures while controlling seek bars.
+ final Insets gestureInsets = insets.getInsets(Type.systemGestures());
+ v.setPadding(gestureInsets.left, 0, gestureInsets.right, 0);
+
+ return v.onApplyWindowInsets(insets);
+ }
+
+ private void updateWidgets(WindowInsets insets, int types, ToggleButton toggle, SeekBar seek) {
+ final boolean isVisible = insets.isVisible(types);
+ final boolean wasVisible = mLastInsets != null ? mLastInsets.isVisible(types) : !isVisible;
+ if (isVisible != wasVisible) {
+ toggle.setChecked(isVisible);
+ if (!seek.isPressed()) {
+ seek.setProgress(isVisible ? seek.getMax() : seek.getMin(), true /* animate*/);
+ }
+ }
+
+ }
+
+ private static class ToggleListener implements CompoundButton.OnCheckedChangeListener {
+
+ private final @Type.InsetsType int mTypes;
+
+ ToggleListener(int types) {
+ mTypes = types;
+ }
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (((boolean[]) buttonView.getTag())[0]) {
+ // not from user
+ return;
+ }
+ if (isChecked) {
+ buttonView.getWindowInsetsController().show(mTypes);
+ } else {
+ buttonView.getWindowInsetsController().hide(mTypes);
+ }
+ }
+ }
+
+ private static class SeekBarListener implements SeekBar.OnSeekBarChangeListener {
+
+ private final @Type.InsetsType int mTypes;
+
+ private WindowInsetsAnimationController mController;
+
+ SeekBarListener(int types) {
+ mTypes = types;
+ }
+
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if (mController != null && fromUser) {
+ final int min = seekBar.getMin();
+ final float fraction = (progress - min) / (float) (seekBar.getMax() - min);
+ final Insets shownInsets = mController.getShownStateInsets();
+ final Insets hiddenInsets = mController.getHiddenStateInsets();
+ final Insets currentInsets = Insets.of(
+ (int) (0.5f + fraction * (shownInsets.left - hiddenInsets.left)),
+ (int) (0.5f + fraction * (shownInsets.top - hiddenInsets.top)),
+ (int) (0.5f + fraction * (shownInsets.right - hiddenInsets.right)),
+ (int) (0.5f + fraction * (shownInsets.bottom - hiddenInsets.bottom)));
+ mController.setInsetsAndAlpha(currentInsets, 1f /* alpha */, fraction);
+ }
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ if (mController != null) {
+ return;
+ }
+ seekBar.getWindowInsetsController().controlWindowInsetsAnimation(mTypes,
+ -1 /* durationMs */, null /* interpolator */, null /* cancellationSignal */,
+ new WindowInsetsAnimationControlListener() {
+ @Override
+ public void onReady(WindowInsetsAnimationController controller, int types) {
+ mController = controller;
+ if (!seekBar.isPressed()) {
+ onStopTrackingTouch(seekBar);
+ }
+ }
+
+ @Override
+ public void onFinished(WindowInsetsAnimationController controller) {
+ mController = null;
+ }
+
+ @Override
+ public void onCancelled(WindowInsetsAnimationController controller) {
+ mController = null;
+ }
+ });
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ final int min = seekBar.getMin();
+ final int max = seekBar.getMax();
+ final boolean shown = (seekBar.getProgress() - min) * 2 > max - min;
+ seekBar.setProgress(shown ? max : min);
+ if (mController != null) {
+ mController.finish(shown);
+ }
+ }
+ }
+}
diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsTestsMainActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsTestsMainActivity.java
new file mode 100644
index 000000000000..8b77a78ff51e
--- /dev/null
+++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsTestsMainActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.test.windowinsetstests;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class WindowInsetsTestsMainActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main_activity);
+
+ findViewById(R.id.chat_button).setOnClickListener(
+ v -> startActivity(new Intent(this, ChatActivity.class)));
+
+ findViewById(R.id.controller_button).setOnClickListener(
+ v -> startActivity(new Intent(this, ControllerActivity.class)));
+ }
+}
diff --git a/tests/appwidgets/AppWidgetHostTest/Android.bp b/tests/appwidgets/AppWidgetHostTest/Android.bp
index 24b76136c045..a3838e5405d1 100644
--- a/tests/appwidgets/AppWidgetHostTest/Android.bp
+++ b/tests/appwidgets/AppWidgetHostTest/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_app {
name: "AppWidgetHostTest",
srcs: ["**/*.java"],
diff --git a/tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml b/tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml
index bf6a7cbfacef..3601992d13cc 100644
--- a/tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml
+++ b/tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml
@@ -1,36 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.appwidgethost">
- <uses-permission android:name="android.permission.VIBRATE" />
+ package="com.android.tests.appwidgethost">
+ <uses-permission android:name="android.permission.VIBRATE"/>
<application>
- <activity android:name="AppWidgetHostActivity" android:label="_AppWidgetHost">
+ <activity android:name="AppWidgetHostActivity"
+ android:label="_AppWidgetHost"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
- <activity android:name="TestAppWidgetConfigure" android:label="Configure TestAppWidgetProvider">
+ <activity android:name="TestAppWidgetConfigure"
+ android:label="Configure TestAppWidgetProvider"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- BEGIN_INCLUDE(AppWidgetProvider) -->
<receiver android:name="TestAppWidgetProvider"
- android:label="@string/oh_hai"
- android:icon="@drawable/oh_hai_icon"
- >
+ android:label="@string/oh_hai"
+ android:icon="@drawable/oh_hai_icon"
+ android:exported="true">
<intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider"
- android:resource="@xml/appwidget_info"
- />
+ android:resource="@xml/appwidget_info"/>
</receiver>
<!-- END_INCLUDE(AppWidgetProvider) -->
-
+
</application>
</manifest>
diff --git a/tests/appwidgets/AppWidgetProviderTest/Android.bp b/tests/appwidgets/AppWidgetProviderTest/Android.bp
index a1a599177a01..a9ee7ad93663 100644
--- a/tests/appwidgets/AppWidgetProviderTest/Android.bp
+++ b/tests/appwidgets/AppWidgetProviderTest/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_app {
name: "AppWidgetProvider",
srcs: ["**/*.java"],
diff --git a/tests/appwidgets/AppWidgetProviderTest/AndroidManifest.xml b/tests/appwidgets/AppWidgetProviderTest/AndroidManifest.xml
index ec4d583ddccb..4f6a81fadd52 100644
--- a/tests/appwidgets/AppWidgetProviderTest/AndroidManifest.xml
+++ b/tests/appwidgets/AppWidgetProviderTest/AndroidManifest.xml
@@ -1,13 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.appwidgetprovider">
- <uses-permission android:name="android.permission.VIBRATE" />
+ package="com.android.tests.appwidgetprovider">
+ <uses-permission android:name="android.permission.VIBRATE"/>
<application>
- <receiver android:name="TestAppWidgetProvider">
+ <receiver android:name="TestAppWidgetProvider"
+ android:exported="true">
<intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
- <meta-data android:name="android.appwidget.provider" android:resource="@xml/appwidget_info" />
+ <meta-data android:name="android.appwidget.provider"
+ android:resource="@xml/appwidget_info"/>
</receiver>
</application>
</manifest>
diff --git a/tests/backup/Android.mk b/tests/backup/Android.mk
index e9618300fc48..b6f34717658c 100644
--- a/tests/backup/Android.mk
+++ b/tests/backup/Android.mk
@@ -24,6 +24,9 @@ LOCAL_SRC_FILES := \
LOCAL_CFLAGS := -Wall -Werror
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := backup_helper_test
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
LOCAL_SHARED_LIBRARIES := libandroidfw libutils
@@ -44,4 +47,7 @@ LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
include $(BUILD_PACKAGE)
diff --git a/tests/backup/AndroidManifest.xml b/tests/backup/AndroidManifest.xml
index 3778742e105e..f0a3eb2da8ea 100644
--- a/tests/backup/AndroidManifest.xml
+++ b/tests/backup/AndroidManifest.xml
@@ -1,11 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.backuptest">
+ package="com.android.backuptest">
<application android:backupAgent="BackupTestAgent">
- <activity android:name="BackupTestActivity" android:label="_BackupTest">
+ <activity android:name="BackupTestActivity"
+ android:label="_BackupTest"
+ android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
diff --git a/tests/backup/OWNERS b/tests/backup/OWNERS
new file mode 100644
index 000000000000..d99779e3d9da
--- /dev/null
+++ b/tests/backup/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/tests/benchmarks/Android.bp b/tests/benchmarks/Android.bp
index f16ddb9bc68e..f87ca2ef928b 100644
--- a/tests/benchmarks/Android.bp
+++ b/tests/benchmarks/Android.bp
@@ -15,6 +15,15 @@
// build framework base core benchmarks
// ============================================================
+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"],
+}
+
java_library {
name: "networkStatsFactory-benchmarks",
installable: true,
diff --git a/tests/net/deflake/Android.bp b/tests/benchmarks/internal/Android.bp
index b1b017131c64..74ed7a34f626 100644
--- a/tests/net/deflake/Android.bp
+++ b/tests/benchmarks/internal/Android.bp
@@ -1,5 +1,4 @@
-//
-// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,19 +11,24 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
-java_test_host {
- name: "FrameworksNetDeflakeTest",
- srcs: ["src/**/*.kt"],
- libs: [
- "junit",
- "tradefed",
- ],
+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"],
+}
+
+android_test {
+ name: "InternalBenchTests",
+ srcs: ["src/**/*.java"],
static_libs: [
- "kotlin-test",
- "net-host-tests-utils",
+ "androidx.test.rules",
+ "androidx.annotation_annotation",
],
- data: [":FrameworksNetTests"],
test_suites: ["device-tests"],
+ platform_apis: true,
+ certificate: "platform"
}
diff --git a/tests/benchmarks/internal/AndroidManifest.xml b/tests/benchmarks/internal/AndroidManifest.xml
new file mode 100644
index 000000000000..16023c6f3617
--- /dev/null
+++ b/tests/benchmarks/internal/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.internal.bench">
+
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.internal.bench"/>
+</manifest>
+
diff --git a/tests/benchmarks/internal/AndroidTest.xml b/tests/benchmarks/internal/AndroidTest.xml
new file mode 100644
index 000000000000..d776ee681c04
--- /dev/null
+++ b/tests/benchmarks/internal/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Benchmark for internal classes/utilities.">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="InternalBenchTests.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.internal.bench" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+
+</configuration>
+
diff --git a/tests/benchmarks/internal/src/com/android/internal/LambdaPerfTest.java b/tests/benchmarks/internal/src/com/android/internal/LambdaPerfTest.java
new file mode 100644
index 000000000000..388548691b77
--- /dev/null
+++ b/tests/benchmarks/internal/src/com/android/internal/LambdaPerfTest.java
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import android.app.Activity;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.SystemClock;
+import android.util.Log;
+
+import androidx.test.filters.LargeTest;
+
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
+
+import org.junit.Assume;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.Statement;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/** Compares the performance of regular lambda and pooled lambda. */
+@LargeTest
+public class LambdaPerfTest {
+ private static final boolean DEBUG = false;
+ private static final String TAG = LambdaPerfTest.class.getSimpleName();
+
+ private static final String LAMBDA_FORM_REGULAR = "regular";
+ private static final String LAMBDA_FORM_POOLED = "pooled";
+
+ private static final int WARMUP_ITERATIONS = 1000;
+ private static final int TEST_ITERATIONS = 3000000;
+ private static final int TASK_COUNT = 10;
+ private static final long DELAY_AFTER_BENCH_MS = 1000;
+
+ private String mMethodName;
+
+ private final Bundle mTestResults = new Bundle();
+ private final ArrayList<Task> mTasks = new ArrayList<>();
+
+ // The member fields are used to ensure lambda capturing. They don't have the actual meaning.
+ private final Task mTask = new Task();
+ private final Rect mBounds = new Rect();
+ private int mTaskId;
+ private long mTime;
+ private boolean mTop;
+
+ @Rule
+ public final TestRule mRule = (base, description) -> new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ mMethodName = description.getMethodName();
+ mTasks.clear();
+ for (int i = 0; i < TASK_COUNT; i++) {
+ final Task t = new Task();
+ mTasks.add(t);
+ }
+ base.evaluate();
+
+ getInstrumentation().sendStatus(Activity.RESULT_OK, mTestResults);
+ }
+ };
+
+ @Test
+ public void test1ParamConsumer() {
+ evaluate(LAMBDA_FORM_REGULAR, () -> forAllTask(t -> t.doSomething(mTask)));
+ evaluate(LAMBDA_FORM_POOLED, () -> {
+ final PooledConsumer c = PooledLambda.obtainConsumer(Task::doSomething,
+ PooledLambda.__(Task.class), mTask);
+ forAllTask(c);
+ c.recycle();
+ });
+ }
+
+ @Test
+ public void test2PrimitiveParamsConsumer() {
+ // Not in Integer#IntegerCache (-128~127) for autoboxing, that will create new object.
+ mTaskId = 12345;
+ mTime = 54321;
+
+ evaluate(LAMBDA_FORM_REGULAR, () -> forAllTask(t -> t.doSomething(mTaskId, mTime)));
+ evaluate(LAMBDA_FORM_POOLED, () -> {
+ final PooledConsumer c = PooledLambda.obtainConsumer(Task::doSomething,
+ PooledLambda.__(Task.class), mTaskId, mTime);
+ forAllTask(c);
+ c.recycle();
+ });
+ }
+
+ @Test
+ public void test3ParamsPredicate() {
+ mTop = true;
+ // In Integer#IntegerCache.
+ mTaskId = 10;
+
+ evaluate(LAMBDA_FORM_REGULAR, () -> handleTask(t -> t.doSomething(mBounds, mTop, mTaskId)));
+ evaluate(LAMBDA_FORM_POOLED, () -> {
+ final PooledPredicate c = PooledLambda.obtainPredicate(Task::doSomething,
+ PooledLambda.__(Task.class), mBounds, mTop, mTaskId);
+ handleTask(c);
+ c.recycle();
+ });
+ }
+
+ @Test
+ public void testMessage() {
+ evaluate(LAMBDA_FORM_REGULAR, () -> {
+ final Message m = Message.obtain().setCallback(() -> mTask.doSomething(mTaskId, mTime));
+ m.getCallback().run();
+ m.recycle();
+ });
+ evaluate(LAMBDA_FORM_POOLED, () -> {
+ final Message m = PooledLambda.obtainMessage(Task::doSomething, mTask, mTaskId, mTime);
+ m.getCallback().run();
+ m.recycle();
+ });
+ }
+
+ @Test
+ public void testRunnable() {
+ evaluate(LAMBDA_FORM_REGULAR, () -> {
+ final Runnable r = mTask::doSomething;
+ r.run();
+ });
+ evaluate(LAMBDA_FORM_POOLED, () -> {
+ final Runnable r = PooledLambda.obtainRunnable(Task::doSomething, mTask).recycleOnUse();
+ r.run();
+ });
+ }
+
+ @Test
+ public void testMultiThread() {
+ final int numThread = 3;
+
+ final Runnable regularAction = () -> forAllTask(t -> t.doSomething(mTask));
+ final Runnable[] regularActions = new Runnable[numThread];
+ Arrays.fill(regularActions, regularAction);
+ evaluateMultiThread(LAMBDA_FORM_REGULAR, regularActions);
+
+ final Runnable pooledAction = () -> {
+ final PooledConsumer c = PooledLambda.obtainConsumer(Task::doSomething,
+ PooledLambda.__(Task.class), mTask);
+ forAllTask(c);
+ c.recycle();
+ };
+ final Runnable[] pooledActions = new Runnable[numThread];
+ Arrays.fill(pooledActions, pooledAction);
+ evaluateMultiThread(LAMBDA_FORM_POOLED, pooledActions);
+ }
+
+ private void forAllTask(Consumer<Task> callback) {
+ for (int i = mTasks.size() - 1; i >= 0; i--) {
+ callback.accept(mTasks.get(i));
+ }
+ }
+
+ private void handleTask(Predicate<Task> callback) {
+ for (int i = mTasks.size() - 1; i >= 0; i--) {
+ final Task task = mTasks.get(i);
+ if (callback.test(task)) {
+ return;
+ }
+ }
+ }
+
+ private void evaluate(String title, Runnable action) {
+ for (int i = 0; i < WARMUP_ITERATIONS; i++) {
+ action.run();
+ }
+ performGc();
+
+ final GcStatus startGcStatus = getGcStatus();
+ final long startTime = SystemClock.elapsedRealtime();
+ for (int i = 0; i < TEST_ITERATIONS; i++) {
+ action.run();
+ }
+ evaluateResult(title, startGcStatus, startTime);
+ }
+
+ private void evaluateMultiThread(String title, Runnable[] actions) {
+ performGc();
+
+ final CountDownLatch latch = new CountDownLatch(actions.length);
+ final GcStatus startGcStatus = getGcStatus();
+ final long startTime = SystemClock.elapsedRealtime();
+ for (Runnable action : actions) {
+ new Thread() {
+ @Override
+ public void run() {
+ for (int i = 0; i < TEST_ITERATIONS; i++) {
+ action.run();
+ }
+ latch.countDown();
+ };
+ }.start();
+ }
+ try {
+ latch.await();
+ } catch (InterruptedException ignored) {
+ }
+ evaluateResult(title, startGcStatus, startTime);
+ }
+
+ private void evaluateResult(String title, GcStatus startStatus, long startTime) {
+ final float elapsed = SystemClock.elapsedRealtime() - startTime;
+ // Sleep a while to see if GC may happen.
+ SystemClock.sleep(DELAY_AFTER_BENCH_MS);
+ final GcStatus endStatus = getGcStatus();
+ final GcInfo info = startStatus.calculateGcTime(endStatus, title, mTestResults);
+ Log.i(TAG, mMethodName + "_" + title + " execution time: "
+ + elapsed + "ms (avg=" + String.format("%.5f", elapsed / TEST_ITERATIONS) + "ms)"
+ + " GC time: " + String.format("%.3f", info.mTotalGcTime) + "ms"
+ + " GC paused time: " + String.format("%.3f", info.mTotalGcPausedTime) + "ms");
+ }
+
+ /** Cleans the test environment. */
+ private static void performGc() {
+ System.gc();
+ System.runFinalization();
+ System.gc();
+ }
+
+ private static GcStatus getGcStatus() {
+ if (DEBUG) {
+ Log.i(TAG, "===== Read GC dump =====");
+ }
+ final GcStatus status = new GcStatus();
+ final List<String> vmDump = getVmDump();
+ Assume.assumeFalse("VM dump is empty", vmDump.isEmpty());
+ for (String line : vmDump) {
+ status.visit(line);
+ if (line.startsWith("DALVIK THREADS")) {
+ break;
+ }
+ }
+ return status;
+ }
+
+ private static List<String> getVmDump() {
+ final int myPid = Process.myPid();
+ // Another approach Debug#dumpJavaBacktraceToFileTimeout requires setenforce 0.
+ Process.sendSignal(myPid, Process.SIGNAL_QUIT);
+ // Give a chance to handle the signal.
+ SystemClock.sleep(100);
+
+ String dump = null;
+ final String pattern = myPid + " written to: ";
+ final List<String> logs = shell("logcat -v brief -d tombstoned:I *:S");
+ for (int i = logs.size() - 1; i >= 0; i--) {
+ final String log = logs.get(i);
+ // Log pattern: Traces for pid 9717 written to: /data/anr/trace_07
+ final int pos = log.indexOf(pattern);
+ if (pos > 0) {
+ dump = log.substring(pattern.length() + pos);
+ break;
+ }
+ }
+
+ Assume.assumeNotNull("Unable to find VM dump", dump);
+ // It requires system or root uid to read the trace.
+ return shell("cat " + dump);
+ }
+
+ private static List<String> shell(String command) {
+ final ParcelFileDescriptor.AutoCloseInputStream stream =
+ new ParcelFileDescriptor.AutoCloseInputStream(
+ getInstrumentation().getUiAutomation().executeShellCommand(command));
+ final ArrayList<String> lines = new ArrayList<>();
+ try (BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ lines.add(line);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return lines;
+ }
+
+ /** An empty class which provides some methods with different type arguments. */
+ static class Task {
+ void doSomething() {
+ }
+
+ void doSomething(Task t) {
+ }
+
+ void doSomething(int taskId, long time) {
+ }
+
+ boolean doSomething(Rect bounds, boolean top, int taskId) {
+ return false;
+ }
+ }
+
+ static class ValPattern {
+ static final int TYPE_COUNT = 0;
+ static final int TYPE_TIME = 1;
+ static final String PATTERN_COUNT = "(\\d+)";
+ static final String PATTERN_TIME = "(\\d+\\.?\\d+)(\\w+)";
+ final String mRawPattern;
+ final Pattern mPattern;
+ final int mType;
+
+ int mIntValue;
+ float mFloatValue;
+
+ ValPattern(String p, int type) {
+ mRawPattern = p;
+ mPattern = Pattern.compile(
+ p + (type == TYPE_TIME ? PATTERN_TIME : PATTERN_COUNT) + ".*");
+ mType = type;
+ }
+
+ boolean visit(String line) {
+ final Matcher matcher = mPattern.matcher(line);
+ if (!matcher.matches()) {
+ return false;
+ }
+ final String value = matcher.group(1);
+ if (value == null) {
+ return false;
+ }
+ if (mType == TYPE_COUNT) {
+ mIntValue = Integer.parseInt(value);
+ return true;
+ }
+ final float time = Float.parseFloat(value);
+ final String unit = matcher.group(2);
+ if (unit == null) {
+ return false;
+ }
+ // Refer to art/libartbase/base/time_utils.cc
+ switch (unit) {
+ case "s":
+ mFloatValue = time * 1000;
+ break;
+ case "ms":
+ mFloatValue = time;
+ break;
+ case "us":
+ mFloatValue = time / 1000;
+ break;
+ case "ns":
+ mFloatValue = time / 1000 / 1000;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return mRawPattern + (mType == TYPE_TIME ? (mFloatValue + "ms") : mIntValue);
+ }
+ }
+
+ /** Parses the dump pattern of Heap::DumpGcPerformanceInfo. */
+ private static class GcStatus {
+ private static final int TOTAL_GC_TIME_INDEX = 1;
+ private static final int TOTAL_GC_PAUSED_TIME_INDEX = 5;
+
+ // Refer to art/runtime/gc/heap.cc
+ final ValPattern[] mPatterns = {
+ new ValPattern("Total GC count: ", ValPattern.TYPE_COUNT),
+ new ValPattern("Total GC time: ", ValPattern.TYPE_TIME),
+ new ValPattern("Total time waiting for GC to complete: ", ValPattern.TYPE_TIME),
+ new ValPattern("Total blocking GC count: ", ValPattern.TYPE_COUNT),
+ new ValPattern("Total blocking GC time: ", ValPattern.TYPE_TIME),
+ new ValPattern("Total mutator paused time: ", ValPattern.TYPE_TIME),
+ new ValPattern("Total number of allocations ", ValPattern.TYPE_COUNT),
+ new ValPattern("concurrent copying paused: Sum: ", ValPattern.TYPE_TIME),
+ new ValPattern("concurrent copying total time: ", ValPattern.TYPE_TIME),
+ new ValPattern("concurrent copying freed: ", ValPattern.TYPE_COUNT),
+ new ValPattern("Peak regions allocated ", ValPattern.TYPE_COUNT),
+ };
+
+ void visit(String dumpLine) {
+ for (ValPattern p : mPatterns) {
+ if (p.visit(dumpLine)) {
+ if (DEBUG) {
+ Log.i(TAG, " " + p);
+ }
+ }
+ }
+ }
+
+ GcInfo calculateGcTime(GcStatus newStatus, String title, Bundle result) {
+ Log.i(TAG, "===== GC status of " + title + " =====");
+ final GcInfo info = new GcInfo();
+ for (int i = 0; i < mPatterns.length; i++) {
+ final ValPattern p = mPatterns[i];
+ if (p.mType == ValPattern.TYPE_COUNT) {
+ final int diff = newStatus.mPatterns[i].mIntValue - p.mIntValue;
+ Log.i(TAG, " " + p.mRawPattern + diff);
+ if (diff > 0) {
+ result.putInt("[" + title + "] " + p.mRawPattern, diff);
+ }
+ continue;
+ }
+ final float diff = newStatus.mPatterns[i].mFloatValue - p.mFloatValue;
+ Log.i(TAG, " " + p.mRawPattern + diff + "ms");
+ if (diff > 0) {
+ result.putFloat("[" + title + "] " + p.mRawPattern + "(ms)", diff);
+ }
+ if (i == TOTAL_GC_TIME_INDEX) {
+ info.mTotalGcTime = diff;
+ } else if (i == TOTAL_GC_PAUSED_TIME_INDEX) {
+ info.mTotalGcPausedTime = diff;
+ }
+ }
+ return info;
+ }
+ }
+
+ private static class GcInfo {
+ float mTotalGcTime;
+ float mTotalGcPausedTime;
+ }
+}
diff --git a/tests/benchmarks/src/com/android/server/net/OWNERS b/tests/benchmarks/src/com/android/server/net/OWNERS
new file mode 100644
index 000000000000..aa87958f1d53
--- /dev/null
+++ b/tests/benchmarks/src/com/android/server/net/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/tests/libs-permissions/Android.bp b/tests/libs-permissions/Android.bp
index 66a1f83dc308..a8ce8a4cd956 100644
--- a/tests/libs-permissions/Android.bp
+++ b/tests/libs-permissions/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
java_library {
name: "com.android.test.libs.product",
installable: true,
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
deleted file mode 100644
index 0fe84abcbc7b..000000000000
--- a/tests/net/Android.bp
+++ /dev/null
@@ -1,71 +0,0 @@
-//########################################################################
-// Build FrameworksNetTests package
-//########################################################################
-java_defaults {
- name: "FrameworksNetTests-jni-defaults",
- jni_libs: [
- "ld-android",
- "libbacktrace",
- "libbase",
- "libbinder",
- "libbpf",
- "libbpf_android",
- "libc++",
- "libcgrouprc",
- "libcrypto",
- "libcutils",
- "libdl_android",
- "libhidl-gen-utils",
- "libhidlbase",
- "libjsoncpp",
- "liblog",
- "liblzma",
- "libnativehelper",
- "libnetdbpf",
- "libnetdutils",
- "libnetworkstatsfactorytestjni",
- "libpackagelistparser",
- "libpcre2",
- "libprocessgroup",
- "libselinux",
- "libtinyxml2",
- "libui",
- "libunwindstack",
- "libutils",
- "libutilscallstack",
- "libvndksupport",
- "libziparchive",
- "libz",
- "netd_aidl_interface-cpp",
- ],
-}
-
-android_test {
- name: "FrameworksNetTests",
- defaults: ["FrameworksNetTests-jni-defaults"],
- srcs: [
- "java/**/*.java",
- "java/**/*.kt",
- ],
- platform_apis: true,
- test_suites: ["device-tests"],
- certificate: "platform",
- static_libs: [
- "androidx.test.rules",
- "FrameworksNetCommonTests",
- "frameworks-base-testutils",
- "frameworks-net-integration-testutils",
- "framework-protos",
- "mockito-target-minus-junit4",
- "net-tests-utils",
- "platform-test-annotations",
- "services.core",
- "services.net",
- ],
- libs: [
- "android.net.ipsec.ike.stubs.module_lib",
- "android.test.runner",
- "android.test.base",
- "android.test.mock",
- ],
-}
diff --git a/tests/net/AndroidManifest.xml b/tests/net/AndroidManifest.xml
deleted file mode 100644
index 009f817af407..000000000000
--- a/tests/net/AndroidManifest.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.frameworks.tests.net">
-
- <uses-permission android:name="android.permission.READ_LOGS" />
- <uses-permission android:name="android.permission.WRITE_SETTINGS" />
- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
- <uses-permission android:name="android.permission.READ_PHONE_STATE" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.BROADCAST_STICKY" />
- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
- <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
- <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
- <uses-permission android:name="android.permission.REAL_GET_TASKS" />
- <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
- <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
- <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
- <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.MANAGE_USERS" />
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
- <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
- <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
- <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
- <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
- <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
- <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
- <uses-permission android:name="android.permission.NETWORK_STACK" />
- <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
- <uses-permission android:name="android.permission.NETWORK_FACTORY" />
- <uses-permission android:name="android.permission.NETWORK_STATS_PROVIDER" />
-
- <application>
- <uses-library android:name="android.test.runner" />
- <uses-library android:name="android.net.ipsec.ike" />
- </application>
-
- <instrumentation
- android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.frameworks.tests.net"
- android:label="Frameworks Networking Tests" />
-</manifest>
diff --git a/tests/net/OWNERS b/tests/net/OWNERS
deleted file mode 100644
index d3836d4c6c57..000000000000
--- a/tests/net/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-set noparent
-
-codewiz@google.com
-jchalard@google.com
-junyulai@google.com
-lorenzo@google.com
-reminv@google.com
-satk@google.com
diff --git a/tests/net/TEST_MAPPING b/tests/net/TEST_MAPPING
deleted file mode 100644
index 005cbe9ffdc4..000000000000
--- a/tests/net/TEST_MAPPING
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "presubmit": [
- {
- "name": "FrameworksNetIntegrationTests"
- }
- ],
- "postsubmit": [
- {
- "name": "FrameworksNetDeflakeTest"
- }
- ]
-} \ No newline at end of file
diff --git a/tests/net/common/java/android/net/CaptivePortalDataTest.kt b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
deleted file mode 100644
index bd1847b7c440..000000000000
--- a/tests/net/common/java/android/net/CaptivePortalDataTest.kt
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net
-
-import android.os.Build
-import androidx.test.filters.SmallTest
-import com.android.testutils.assertParcelSane
-import com.android.testutils.assertParcelingIsLossless
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import com.android.testutils.DevSdkIgnoreRunner
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-import kotlin.test.assertEquals
-import kotlin.test.assertNotEquals
-
-@SmallTest
-@RunWith(DevSdkIgnoreRunner::class)
-@IgnoreUpTo(Build.VERSION_CODES.Q)
-class CaptivePortalDataTest {
- private val data = CaptivePortalData.Builder()
- .setRefreshTime(123L)
- .setUserPortalUrl(Uri.parse("https://portal.example.com/test"))
- .setVenueInfoUrl(Uri.parse("https://venue.example.com/test"))
- .setSessionExtendable(true)
- .setBytesRemaining(456L)
- .setExpiryTime(789L)
- .setCaptive(true)
- .build()
-
- private fun makeBuilder() = CaptivePortalData.Builder(data)
-
- @Test
- fun testParcelUnparcel() {
- assertParcelSane(data, fieldCount = 7)
-
- assertParcelingIsLossless(makeBuilder().setUserPortalUrl(null).build())
- assertParcelingIsLossless(makeBuilder().setVenueInfoUrl(null).build())
- }
-
- @Test
- fun testEquals() {
- assertEquals(data, makeBuilder().build())
-
- assertNotEqualsAfterChange { it.setRefreshTime(456L) }
- assertNotEqualsAfterChange { it.setUserPortalUrl(Uri.parse("https://example.com/")) }
- assertNotEqualsAfterChange { it.setUserPortalUrl(null) }
- assertNotEqualsAfterChange { it.setVenueInfoUrl(Uri.parse("https://example.com/")) }
- assertNotEqualsAfterChange { it.setVenueInfoUrl(null) }
- assertNotEqualsAfterChange { it.setSessionExtendable(false) }
- assertNotEqualsAfterChange { it.setBytesRemaining(789L) }
- assertNotEqualsAfterChange { it.setExpiryTime(12L) }
- assertNotEqualsAfterChange { it.setCaptive(false) }
- }
-
- @Test
- fun testUserPortalUrl() {
- assertEquals(Uri.parse("https://portal.example.com/test"), data.userPortalUrl)
- }
-
- @Test
- fun testVenueInfoUrl() {
- assertEquals(Uri.parse("https://venue.example.com/test"), data.venueInfoUrl)
- }
-
- @Test
- fun testIsSessionExtendable() {
- assertTrue(data.isSessionExtendable)
- }
-
- @Test
- fun testByteLimit() {
- assertEquals(456L, data.byteLimit)
- // Test byteLimit unset.
- assertEquals(-1L, CaptivePortalData.Builder(null).build().byteLimit)
- }
-
- @Test
- fun testRefreshTimeMillis() {
- assertEquals(123L, data.refreshTimeMillis)
- }
-
- @Test
- fun testExpiryTimeMillis() {
- assertEquals(789L, data.expiryTimeMillis)
- // Test expiryTimeMillis unset.
- assertEquals(-1L, CaptivePortalData.Builder(null).build().expiryTimeMillis)
- }
-
- @Test
- fun testIsCaptive() {
- assertTrue(data.isCaptive)
- assertFalse(makeBuilder().setCaptive(false).build().isCaptive)
- }
-
- private fun CaptivePortalData.mutate(mutator: (CaptivePortalData.Builder) -> Unit) =
- CaptivePortalData.Builder(this).apply { mutator(this) }.build()
-
- private fun assertNotEqualsAfterChange(mutator: (CaptivePortalData.Builder) -> Unit) {
- assertNotEquals(data, data.mutate(mutator))
- }
-} \ No newline at end of file
diff --git a/tests/net/common/java/android/net/CaptivePortalTest.java b/tests/net/common/java/android/net/CaptivePortalTest.java
deleted file mode 100644
index 7a60cc105a26..000000000000
--- a/tests/net/common/java/android/net/CaptivePortalTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static org.junit.Assert.assertEquals;
-
-import android.os.Build;
-import android.os.RemoteException;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class CaptivePortalTest {
- @Rule
- public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
-
- private static final int DEFAULT_TIMEOUT_MS = 5000;
- private static final String TEST_PACKAGE_NAME = "com.google.android.test";
-
- private final class MyCaptivePortalImpl extends ICaptivePortal.Stub {
- int mCode = -1;
- String mPackageName = null;
-
- @Override
- public void appResponse(final int response) throws RemoteException {
- mCode = response;
- }
-
- @Override
- public void appRequest(final int request) throws RemoteException {
- mCode = request;
- }
-
- @Override
- public void logEvent(int eventId, String packageName) throws RemoteException {
- mCode = eventId;
- mPackageName = packageName;
- }
- }
-
- private interface TestFunctor {
- void useCaptivePortal(CaptivePortal o);
- }
-
- private MyCaptivePortalImpl runCaptivePortalTest(TestFunctor f) {
- final MyCaptivePortalImpl cp = new MyCaptivePortalImpl();
- f.useCaptivePortal(new CaptivePortal(cp.asBinder()));
- return cp;
- }
-
- @Test
- public void testReportCaptivePortalDismissed() {
- final MyCaptivePortalImpl result =
- runCaptivePortalTest(c -> c.reportCaptivePortalDismissed());
- assertEquals(result.mCode, CaptivePortal.APP_RETURN_DISMISSED);
- }
-
- @Test
- public void testIgnoreNetwork() {
- final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.ignoreNetwork());
- assertEquals(result.mCode, CaptivePortal.APP_RETURN_UNWANTED);
- }
-
- @Test
- public void testUseNetwork() {
- final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.useNetwork());
- assertEquals(result.mCode, CaptivePortal.APP_RETURN_WANTED_AS_IS);
- }
-
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- @Test
- public void testReevaluateNetwork() {
- final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.reevaluateNetwork());
- assertEquals(result.mCode, CaptivePortal.APP_REQUEST_REEVALUATION_REQUIRED);
- }
-
- @Test
- public void testLogEvent() {
- final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent(
- MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY,
- TEST_PACKAGE_NAME));
- assertEquals(result.mCode, MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY);
- assertEquals(result.mPackageName, TEST_PACKAGE_NAME);
- }
-}
diff --git a/tests/net/common/java/android/net/DependenciesTest.java b/tests/net/common/java/android/net/DependenciesTest.java
deleted file mode 100644
index ac1c28a45462..000000000000
--- a/tests/net/common/java/android/net/DependenciesTest.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.concurrent.TimeUnit;
-
-/**
- * A simple class that tests dependencies to java standard tools from the
- * Network stack. These tests are not meant to be comprehensive tests of
- * the relevant APIs : such tests belong in the relevant test suite for
- * these dependencies. Instead, this just makes sure coverage is present
- * by calling the methods in the exact way (or a representative way of how)
- * they are called in the network stack.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DependenciesTest {
- // Used to in ipmemorystore's RegularMaintenanceJobService to convert
- // 24 hours into seconds
- @Test
- public void testTimeUnit() {
- final int hours = 24;
- final long inSeconds = TimeUnit.HOURS.toMillis(hours);
- assertEquals(inSeconds, hours * 60 * 60 * 1000);
- }
-
- private byte[] makeTrivialArray(final int size) {
- final byte[] src = new byte[size];
- for (int i = 0; i < size; ++i) {
- src[i] = (byte) i;
- }
- return src;
- }
-
- // Used in ApfFilter to find an IP address from a byte array
- @Test
- public void testArrays() {
- final int size = 128;
- final byte[] src = makeTrivialArray(size);
-
- // Test copy
- final int copySize = 16;
- final int offset = 24;
- final byte[] expected = new byte[copySize];
- for (int i = 0; i < copySize; ++i) {
- expected[i] = (byte) (offset + i);
- }
-
- final byte[] copy = Arrays.copyOfRange(src, offset, offset + copySize);
- assertArrayEquals(expected, copy);
- assertArrayEquals(new byte[0], Arrays.copyOfRange(src, size, size));
- }
-
- // Used mainly in the Dhcp code
- @Test
- public void testCopyOf() {
- final byte[] src = makeTrivialArray(128);
- final byte[] copy = Arrays.copyOf(src, src.length);
- assertArrayEquals(src, copy);
- assertFalse(src == copy);
-
- assertArrayEquals(new byte[0], Arrays.copyOf(src, 0));
-
- final int excess = 16;
- final byte[] biggerCopy = Arrays.copyOf(src, src.length + excess);
- for (int i = src.length; i < src.length + excess; ++i) {
- assertEquals(0, biggerCopy[i]);
- }
- for (int i = src.length - 1; i >= 0; --i) {
- assertEquals(src[i], biggerCopy[i]);
- }
- }
-
- // Used mainly in DnsUtils but also various other places
- @Test
- public void testAsList() {
- final int size = 24;
- final Object[] src = new Object[size];
- final ArrayList<Object> expected = new ArrayList<>(size);
- for (int i = 0; i < size; ++i) {
- final Object o = new Object();
- src[i] = o;
- expected.add(o);
- }
- assertEquals(expected, Arrays.asList(src));
- }
-}
diff --git a/tests/net/common/java/android/net/DhcpInfoTest.java b/tests/net/common/java/android/net/DhcpInfoTest.java
deleted file mode 100644
index 4d45ad72a9b8..000000000000
--- a/tests/net/common/java/android/net/DhcpInfoTest.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTL;
-import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
-import static com.android.testutils.ParcelUtilsKt.parcelingRoundTrip;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.annotation.Nullable;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-
-@RunWith(AndroidJUnit4.class)
-public class DhcpInfoTest {
- private static final String STR_ADDR1 = "255.255.255.255";
- private static final String STR_ADDR2 = "127.0.0.1";
- private static final String STR_ADDR3 = "192.168.1.1";
- private static final String STR_ADDR4 = "192.168.1.0";
- private static final int LEASE_TIME = 9999;
-
- private int ipToInteger(String ipString) throws Exception {
- return inet4AddressToIntHTL((Inet4Address) InetAddress.getByName(ipString));
- }
-
- private DhcpInfo createDhcpInfoObject() throws Exception {
- final DhcpInfo dhcpInfo = new DhcpInfo();
- dhcpInfo.ipAddress = ipToInteger(STR_ADDR1);
- dhcpInfo.gateway = ipToInteger(STR_ADDR2);
- dhcpInfo.netmask = ipToInteger(STR_ADDR3);
- dhcpInfo.dns1 = ipToInteger(STR_ADDR4);
- dhcpInfo.dns2 = ipToInteger(STR_ADDR4);
- dhcpInfo.serverAddress = ipToInteger(STR_ADDR2);
- dhcpInfo.leaseDuration = LEASE_TIME;
- return dhcpInfo;
- }
-
- @Test
- public void testConstructor() {
- new DhcpInfo();
- }
-
- @Test
- public void testToString() throws Exception {
- final String expectedDefault = "ipaddr 0.0.0.0 gateway 0.0.0.0 netmask 0.0.0.0 "
- + "dns1 0.0.0.0 dns2 0.0.0.0 DHCP server 0.0.0.0 lease 0 seconds";
-
- DhcpInfo dhcpInfo = new DhcpInfo();
-
- // Test default string.
- assertEquals(expectedDefault, dhcpInfo.toString());
-
- dhcpInfo = createDhcpInfoObject();
-
- final String expected = "ipaddr " + STR_ADDR1 + " gateway " + STR_ADDR2 + " netmask "
- + STR_ADDR3 + " dns1 " + STR_ADDR4 + " dns2 " + STR_ADDR4 + " DHCP server "
- + STR_ADDR2 + " lease " + LEASE_TIME + " seconds";
- // Test with new values
- assertEquals(expected, dhcpInfo.toString());
- }
-
- private boolean dhcpInfoEquals(@Nullable DhcpInfo left, @Nullable DhcpInfo right) {
- if (left == null && right == null) return true;
-
- if (left == null || right == null) return false;
-
- return left.ipAddress == right.ipAddress
- && left.gateway == right.gateway
- && left.netmask == right.netmask
- && left.dns1 == right.dns1
- && left.dns2 == right.dns2
- && left.serverAddress == right.serverAddress
- && left.leaseDuration == right.leaseDuration;
- }
-
- @Test
- public void testParcelDhcpInfo() throws Exception {
- // Cannot use assertParcelSane() here because this requires .equals() to work as
- // defined, but DhcpInfo has a different legacy behavior that we cannot change.
- final DhcpInfo dhcpInfo = createDhcpInfoObject();
- assertFieldCountEquals(7, DhcpInfo.class);
-
- final DhcpInfo dhcpInfoRoundTrip = parcelingRoundTrip(dhcpInfo);
- assertTrue(dhcpInfoEquals(null, null));
- assertFalse(dhcpInfoEquals(null, dhcpInfoRoundTrip));
- assertFalse(dhcpInfoEquals(dhcpInfo, null));
- assertTrue(dhcpInfoEquals(dhcpInfo, dhcpInfoRoundTrip));
- }
-}
diff --git a/tests/net/common/java/android/net/IpPrefixTest.java b/tests/net/common/java/android/net/IpPrefixTest.java
deleted file mode 100644
index 985e10df3961..000000000000
--- a/tests/net/common/java/android/net/IpPrefixTest.java
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static com.android.testutils.MiscAssertsKt.assertEqualBothWays;
-import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
-import static com.android.testutils.MiscAssertsKt.assertNotEqualEitherWay;
-import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.util.Random;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpPrefixTest {
-
- private static InetAddress address(String addr) {
- return InetAddress.parseNumericAddress(addr);
- }
-
- // Explicitly cast everything to byte because "error: possible loss of precision".
- private static final byte[] IPV4_BYTES = { (byte) 192, (byte) 0, (byte) 2, (byte) 4};
- private static final byte[] IPV6_BYTES = {
- (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8,
- (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
- (byte) 0x0f, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xa0
- };
-
- @Test
- public void testConstructor() {
- IpPrefix p;
- try {
- p = new IpPrefix((byte[]) null, 9);
- fail("Expected NullPointerException: null byte array");
- } catch (RuntimeException expected) { }
-
- try {
- p = new IpPrefix((InetAddress) null, 10);
- fail("Expected NullPointerException: null InetAddress");
- } catch (RuntimeException expected) { }
-
- try {
- p = new IpPrefix((String) null);
- fail("Expected NullPointerException: null String");
- } catch (RuntimeException expected) { }
-
-
- try {
- byte[] b2 = {1, 2, 3, 4, 5};
- p = new IpPrefix(b2, 29);
- fail("Expected IllegalArgumentException: invalid array length");
- } catch (IllegalArgumentException expected) { }
-
- try {
- p = new IpPrefix("1.2.3.4");
- fail("Expected IllegalArgumentException: no prefix length");
- } catch (IllegalArgumentException expected) { }
-
- try {
- p = new IpPrefix("1.2.3.4/");
- fail("Expected IllegalArgumentException: empty prefix length");
- } catch (IllegalArgumentException expected) { }
-
- try {
- p = new IpPrefix("foo/32");
- fail("Expected IllegalArgumentException: invalid address");
- } catch (IllegalArgumentException expected) { }
-
- try {
- p = new IpPrefix("1/32");
- fail("Expected IllegalArgumentException: deprecated IPv4 format");
- } catch (IllegalArgumentException expected) { }
-
- try {
- p = new IpPrefix("1.2.3.256/32");
- fail("Expected IllegalArgumentException: invalid IPv4 address");
- } catch (IllegalArgumentException expected) { }
-
- try {
- p = new IpPrefix("foo/32");
- fail("Expected IllegalArgumentException: non-address");
- } catch (IllegalArgumentException expected) { }
-
- try {
- p = new IpPrefix("f00:::/32");
- fail("Expected IllegalArgumentException: invalid IPv6 address");
- } catch (IllegalArgumentException expected) { }
- }
-
- @Test
- public void testTruncation() {
- IpPrefix p;
-
- p = new IpPrefix(IPV4_BYTES, 32);
- assertEquals("192.0.2.4/32", p.toString());
-
- p = new IpPrefix(IPV4_BYTES, 29);
- assertEquals("192.0.2.0/29", p.toString());
-
- p = new IpPrefix(IPV4_BYTES, 8);
- assertEquals("192.0.0.0/8", p.toString());
-
- p = new IpPrefix(IPV4_BYTES, 0);
- assertEquals("0.0.0.0/0", p.toString());
-
- try {
- p = new IpPrefix(IPV4_BYTES, 33);
- fail("Expected IllegalArgumentException: invalid prefix length");
- } catch (RuntimeException expected) { }
-
- try {
- p = new IpPrefix(IPV4_BYTES, 128);
- fail("Expected IllegalArgumentException: invalid prefix length");
- } catch (RuntimeException expected) { }
-
- try {
- p = new IpPrefix(IPV4_BYTES, -1);
- fail("Expected IllegalArgumentException: negative prefix length");
- } catch (RuntimeException expected) { }
-
- p = new IpPrefix(IPV6_BYTES, 128);
- assertEquals("2001:db8:dead:beef:f00::a0/128", p.toString());
-
- p = new IpPrefix(IPV6_BYTES, 122);
- assertEquals("2001:db8:dead:beef:f00::80/122", p.toString());
-
- p = new IpPrefix(IPV6_BYTES, 64);
- assertEquals("2001:db8:dead:beef::/64", p.toString());
-
- p = new IpPrefix(IPV6_BYTES, 3);
- assertEquals("2000::/3", p.toString());
-
- p = new IpPrefix(IPV6_BYTES, 0);
- assertEquals("::/0", p.toString());
-
- try {
- p = new IpPrefix(IPV6_BYTES, -1);
- fail("Expected IllegalArgumentException: negative prefix length");
- } catch (RuntimeException expected) { }
-
- try {
- p = new IpPrefix(IPV6_BYTES, 129);
- fail("Expected IllegalArgumentException: negative prefix length");
- } catch (RuntimeException expected) { }
-
- }
-
- @Test
- public void testEquals() {
- IpPrefix p1, p2;
-
- p1 = new IpPrefix("192.0.2.251/23");
- p2 = new IpPrefix(new byte[]{(byte) 192, (byte) 0, (byte) 2, (byte) 251}, 23);
- assertEqualBothWays(p1, p2);
-
- p1 = new IpPrefix("192.0.2.5/23");
- assertEqualBothWays(p1, p2);
-
- p1 = new IpPrefix("192.0.2.5/24");
- assertNotEqualEitherWay(p1, p2);
-
- p1 = new IpPrefix("192.0.4.5/23");
- assertNotEqualEitherWay(p1, p2);
-
-
- p1 = new IpPrefix("2001:db8:dead:beef:f00::80/122");
- p2 = new IpPrefix(IPV6_BYTES, 122);
- assertEquals("2001:db8:dead:beef:f00::80/122", p2.toString());
- assertEqualBothWays(p1, p2);
-
- p1 = new IpPrefix("2001:db8:dead:beef:f00::bf/122");
- assertEqualBothWays(p1, p2);
-
- p1 = new IpPrefix("2001:db8:dead:beef:f00::8:0/123");
- assertNotEqualEitherWay(p1, p2);
-
- p1 = new IpPrefix("2001:db8:dead:beef::/122");
- assertNotEqualEitherWay(p1, p2);
-
- // 192.0.2.4/32 != c000:0204::/32.
- byte[] ipv6bytes = new byte[16];
- System.arraycopy(IPV4_BYTES, 0, ipv6bytes, 0, IPV4_BYTES.length);
- p1 = new IpPrefix(ipv6bytes, 32);
- assertEqualBothWays(p1, new IpPrefix("c000:0204::/32"));
-
- p2 = new IpPrefix(IPV4_BYTES, 32);
- assertNotEqualEitherWay(p1, p2);
- }
-
- @Test
- public void testContainsInetAddress() {
- IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127");
- assertTrue(p.contains(address("2001:db8:f00::ace:d00c")));
- assertTrue(p.contains(address("2001:db8:f00::ace:d00d")));
- assertFalse(p.contains(address("2001:db8:f00::ace:d00e")));
- assertFalse(p.contains(address("2001:db8:f00::bad:d00d")));
- assertFalse(p.contains(address("2001:4868:4860::8888")));
- assertFalse(p.contains(address("8.8.8.8")));
-
- p = new IpPrefix("192.0.2.0/23");
- assertTrue(p.contains(address("192.0.2.43")));
- assertTrue(p.contains(address("192.0.3.21")));
- assertFalse(p.contains(address("192.0.0.21")));
- assertFalse(p.contains(address("8.8.8.8")));
- assertFalse(p.contains(address("2001:4868:4860::8888")));
-
- IpPrefix ipv6Default = new IpPrefix("::/0");
- assertTrue(ipv6Default.contains(address("2001:db8::f00")));
- assertFalse(ipv6Default.contains(address("192.0.2.1")));
-
- IpPrefix ipv4Default = new IpPrefix("0.0.0.0/0");
- assertTrue(ipv4Default.contains(address("255.255.255.255")));
- assertTrue(ipv4Default.contains(address("192.0.2.1")));
- assertFalse(ipv4Default.contains(address("2001:db8::f00")));
- }
-
- @Test
- public void testContainsIpPrefix() {
- assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("0.0.0.0/0")));
- assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/0")));
- assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/8")));
- assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/24")));
- assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/23")));
-
- assertTrue(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("1.2.3.4/8")));
- assertTrue(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("1.254.12.9/8")));
- assertTrue(new IpPrefix("1.2.3.4/21").containsPrefix(new IpPrefix("1.2.3.4/21")));
- assertTrue(new IpPrefix("1.2.3.4/32").containsPrefix(new IpPrefix("1.2.3.4/32")));
-
- assertTrue(new IpPrefix("1.2.3.4/20").containsPrefix(new IpPrefix("1.2.3.0/24")));
-
- assertFalse(new IpPrefix("1.2.3.4/32").containsPrefix(new IpPrefix("1.2.3.5/32")));
- assertFalse(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("2.2.3.4/8")));
- assertFalse(new IpPrefix("0.0.0.0/16").containsPrefix(new IpPrefix("0.0.0.0/15")));
- assertFalse(new IpPrefix("100.0.0.0/8").containsPrefix(new IpPrefix("99.0.0.0/8")));
-
- assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("::/0")));
- assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/1")));
- assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("3d8a:661:a0::770/8")));
- assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/8")));
- assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/64")));
- assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/113")));
- assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/128")));
-
- assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
- new IpPrefix("2001:db8:f00::ace:d00d/64")));
- assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
- new IpPrefix("2001:db8:f00::ace:d00d/120")));
- assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
- new IpPrefix("2001:db8:f00::ace:d00d/32")));
- assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
- new IpPrefix("2006:db8:f00::ace:d00d/96")));
-
- assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/128").containsPrefix(
- new IpPrefix("2001:db8:f00::ace:d00d/128")));
- assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/100").containsPrefix(
- new IpPrefix("2001:db8:f00::ace:ccaf/110")));
-
- assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/128").containsPrefix(
- new IpPrefix("2001:db8:f00::ace:d00e/128")));
- assertFalse(new IpPrefix("::/30").containsPrefix(new IpPrefix("::/29")));
- }
-
- @Test
- public void testHashCode() {
- IpPrefix p = new IpPrefix(new byte[4], 0);
- Random random = new Random();
- for (int i = 0; i < 100; i++) {
- final IpPrefix oldP = p;
- if (random.nextBoolean()) {
- // IPv4.
- byte[] b = new byte[4];
- random.nextBytes(b);
- p = new IpPrefix(b, random.nextInt(33));
- } else {
- // IPv6.
- byte[] b = new byte[16];
- random.nextBytes(b);
- p = new IpPrefix(b, random.nextInt(129));
- }
- if (p.equals(oldP)) {
- assertEquals(p.hashCode(), oldP.hashCode());
- }
- if (p.hashCode() != oldP.hashCode()) {
- assertNotEquals(p, oldP);
- }
- }
- }
-
- @Test
- public void testHashCodeIsNotConstant() {
- IpPrefix[] prefixes = {
- new IpPrefix("2001:db8:f00::ace:d00d/127"),
- new IpPrefix("192.0.2.0/23"),
- new IpPrefix("::/0"),
- new IpPrefix("0.0.0.0/0"),
- };
- for (int i = 0; i < prefixes.length; i++) {
- for (int j = i + 1; j < prefixes.length; j++) {
- assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode());
- }
- }
- }
-
- @Test
- public void testMappedAddressesAreBroken() {
- // 192.0.2.0/24 != ::ffff:c000:0204/120, but because we use InetAddress,
- // we are unable to comprehend that.
- byte[] ipv6bytes = {
- (byte) 0, (byte) 0, (byte) 0, (byte) 0,
- (byte) 0, (byte) 0, (byte) 0, (byte) 0,
- (byte) 0, (byte) 0, (byte) 0xff, (byte) 0xff,
- (byte) 192, (byte) 0, (byte) 2, (byte) 0};
- IpPrefix p = new IpPrefix(ipv6bytes, 120);
- assertEquals(16, p.getRawAddress().length); // Fine.
- assertArrayEquals(ipv6bytes, p.getRawAddress()); // Fine.
-
- // Broken.
- assertEquals("192.0.2.0/120", p.toString());
- assertEquals(InetAddress.parseNumericAddress("192.0.2.0"), p.getAddress());
- }
-
- @Test
- public void testParceling() {
- IpPrefix p;
-
- p = new IpPrefix("2001:4860:db8::/64");
- assertParcelingIsLossless(p);
- assertTrue(p.isIPv6());
-
- p = new IpPrefix("192.0.2.0/25");
- assertParcelingIsLossless(p);
- assertTrue(p.isIPv4());
-
- assertFieldCountEquals(2, IpPrefix.class);
- }
-}
diff --git a/tests/net/common/java/android/net/KeepalivePacketDataTest.kt b/tests/net/common/java/android/net/KeepalivePacketDataTest.kt
deleted file mode 100644
index f464ec6cf0e5..000000000000
--- a/tests/net/common/java/android/net/KeepalivePacketDataTest.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net
-
-import android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS
-import android.net.InvalidPacketException.ERROR_INVALID_PORT
-import android.os.Build
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import java.net.InetAddress
-import java.util.Arrays
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
-import org.junit.Assert.fail
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class KeepalivePacketDataTest {
- @Rule @JvmField
- val ignoreRule: DevSdkIgnoreRule = DevSdkIgnoreRule()
-
- private val INVALID_PORT = 65537
- private val TEST_DST_PORT = 4244
- private val TEST_SRC_PORT = 4243
-
- private val TESTBYTES = byteArrayOf(12, 31, 22, 44)
- private val TEST_SRC_ADDRV4 = "198.168.0.2".address()
- private val TEST_DST_ADDRV4 = "198.168.0.1".address()
- private val TEST_ADDRV6 = "2001:db8::1".address()
-
- private fun String.address() = InetAddresses.parseNumericAddress(this)
-
- // Add for test because constructor of KeepalivePacketData is protected.
- private inner class TestKeepalivePacketData(
- srcAddress: InetAddress? = TEST_SRC_ADDRV4,
- srcPort: Int = TEST_SRC_PORT,
- dstAddress: InetAddress? = TEST_DST_ADDRV4,
- dstPort: Int = TEST_DST_PORT,
- data: ByteArray = TESTBYTES
- ) : KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, data)
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testConstructor() {
- var data: TestKeepalivePacketData
-
- try {
- data = TestKeepalivePacketData(srcAddress = null)
- fail("Null src address should cause exception")
- } catch (e: InvalidPacketException) {
- assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
- }
-
- try {
- data = TestKeepalivePacketData(dstAddress = null)
- fail("Null dst address should cause exception")
- } catch (e: InvalidPacketException) {
- assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
- }
-
- try {
- data = TestKeepalivePacketData(dstAddress = TEST_ADDRV6)
- fail("Ip family mismatched should cause exception")
- } catch (e: InvalidPacketException) {
- assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
- }
-
- try {
- data = TestKeepalivePacketData(srcPort = INVALID_PORT)
- fail("Invalid srcPort should cause exception")
- } catch (e: InvalidPacketException) {
- assertEquals(e.error, ERROR_INVALID_PORT)
- }
-
- try {
- data = TestKeepalivePacketData(dstPort = INVALID_PORT)
- fail("Invalid dstPort should cause exception")
- } catch (e: InvalidPacketException) {
- assertEquals(e.error, ERROR_INVALID_PORT)
- }
- }
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testSrcAddress() = assertEquals(TEST_SRC_ADDRV4, TestKeepalivePacketData().srcAddress)
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testDstAddress() = assertEquals(TEST_DST_ADDRV4, TestKeepalivePacketData().dstAddress)
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testSrcPort() = assertEquals(TEST_SRC_PORT, TestKeepalivePacketData().srcPort)
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testDstPort() = assertEquals(TEST_DST_PORT, TestKeepalivePacketData().dstPort)
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testPacket() = assertTrue(Arrays.equals(TESTBYTES, TestKeepalivePacketData().packet))
-} \ No newline at end of file
diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java
deleted file mode 100644
index c74c112490f8..000000000000
--- a/tests/net/common/java/android/net/LinkAddressTest.java
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.system.OsConstants.IFA_F_DADFAILED;
-import static android.system.OsConstants.IFA_F_DEPRECATED;
-import static android.system.OsConstants.IFA_F_OPTIMISTIC;
-import static android.system.OsConstants.IFA_F_PERMANENT;
-import static android.system.OsConstants.IFA_F_TEMPORARY;
-import static android.system.OsConstants.IFA_F_TENTATIVE;
-import static android.system.OsConstants.RT_SCOPE_HOST;
-import static android.system.OsConstants.RT_SCOPE_LINK;
-import static android.system.OsConstants.RT_SCOPE_SITE;
-import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
-
-import static com.android.testutils.MiscAssertsKt.assertEqualBothWays;
-import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
-import static com.android.testutils.MiscAssertsKt.assertNotEqualEitherWay;
-import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.os.Build;
-import android.os.SystemClock;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.net.InterfaceAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.util.Arrays;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class LinkAddressTest {
- @Rule
- public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
-
- private static final String V4 = "192.0.2.1";
- private static final String V6 = "2001:db8::1";
- private static final InetAddress V4_ADDRESS = NetworkUtils.numericToInetAddress(V4);
- private static final InetAddress V6_ADDRESS = NetworkUtils.numericToInetAddress(V6);
-
- @Test
- public void testConstants() {
- // RT_SCOPE_UNIVERSE = 0, but all the other constants should be nonzero.
- assertNotEquals(0, RT_SCOPE_HOST);
- assertNotEquals(0, RT_SCOPE_LINK);
- assertNotEquals(0, RT_SCOPE_SITE);
-
- assertNotEquals(0, IFA_F_DEPRECATED);
- assertNotEquals(0, IFA_F_PERMANENT);
- assertNotEquals(0, IFA_F_TENTATIVE);
- }
-
- @Test
- public void testConstructors() throws SocketException {
- LinkAddress address;
-
- // Valid addresses work as expected.
- address = new LinkAddress(V4_ADDRESS, 25);
- assertEquals(V4_ADDRESS, address.getAddress());
- assertEquals(25, address.getPrefixLength());
- assertEquals(0, address.getFlags());
- assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
- assertTrue(address.isIpv4());
-
- address = new LinkAddress(V6_ADDRESS, 127);
- assertEquals(V6_ADDRESS, address.getAddress());
- assertEquals(127, address.getPrefixLength());
- assertEquals(0, address.getFlags());
- assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
- assertTrue(address.isIpv6());
-
- // Nonsensical flags/scopes or combinations thereof are acceptable.
- address = new LinkAddress(V6 + "/64", IFA_F_DEPRECATED | IFA_F_PERMANENT, RT_SCOPE_LINK);
- assertEquals(V6_ADDRESS, address.getAddress());
- assertEquals(64, address.getPrefixLength());
- assertEquals(IFA_F_DEPRECATED | IFA_F_PERMANENT, address.getFlags());
- assertEquals(RT_SCOPE_LINK, address.getScope());
- assertTrue(address.isIpv6());
-
- address = new LinkAddress(V4 + "/23", 123, 456);
- assertEquals(V4_ADDRESS, address.getAddress());
- assertEquals(23, address.getPrefixLength());
- assertEquals(123, address.getFlags());
- assertEquals(456, address.getScope());
- assertTrue(address.isIpv4());
-
- // InterfaceAddress doesn't have a constructor. Fetch some from an interface.
- List<InterfaceAddress> addrs = NetworkInterface.getByName("lo").getInterfaceAddresses();
-
- // We expect to find 127.0.0.1/8 and ::1/128, in any order.
- LinkAddress ipv4Loopback, ipv6Loopback;
- assertEquals(2, addrs.size());
- if (addrs.get(0).getAddress() instanceof Inet4Address) {
- ipv4Loopback = new LinkAddress(addrs.get(0));
- ipv6Loopback = new LinkAddress(addrs.get(1));
- } else {
- ipv4Loopback = new LinkAddress(addrs.get(1));
- ipv6Loopback = new LinkAddress(addrs.get(0));
- }
-
- assertEquals(NetworkUtils.numericToInetAddress("127.0.0.1"), ipv4Loopback.getAddress());
- assertEquals(8, ipv4Loopback.getPrefixLength());
-
- assertEquals(NetworkUtils.numericToInetAddress("::1"), ipv6Loopback.getAddress());
- assertEquals(128, ipv6Loopback.getPrefixLength());
-
- // Null addresses are rejected.
- try {
- address = new LinkAddress(null, 24);
- fail("Null InetAddress should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
- try {
- address = new LinkAddress((String) null, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
- fail("Null string should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
- try {
- address = new LinkAddress((InterfaceAddress) null);
- fail("Null string should cause NullPointerException");
- } catch(NullPointerException expected) {}
-
- // Invalid prefix lengths are rejected.
- try {
- address = new LinkAddress(V4_ADDRESS, -1);
- fail("Negative IPv4 prefix length should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
- try {
- address = new LinkAddress(V6_ADDRESS, -1);
- fail("Negative IPv6 prefix length should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
- try {
- address = new LinkAddress(V4_ADDRESS, 33);
- fail("/33 IPv4 prefix length should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
- try {
- address = new LinkAddress(V4 + "/33", IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
- fail("/33 IPv4 prefix length should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
-
- try {
- address = new LinkAddress(V6_ADDRESS, 129, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
- fail("/129 IPv6 prefix length should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
- try {
- address = new LinkAddress(V6 + "/129", IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
- fail("/129 IPv6 prefix length should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
- // Multicast addresses are rejected.
- try {
- address = new LinkAddress("224.0.0.2/32");
- fail("IPv4 multicast address should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
- try {
- address = new LinkAddress("ff02::1/128");
- fail("IPv6 multicast address should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
- }
-
- @Test
- public void testAddressScopes() {
- assertEquals(RT_SCOPE_HOST, new LinkAddress("::/128").getScope());
- assertEquals(RT_SCOPE_HOST, new LinkAddress("0.0.0.0/32").getScope());
-
- assertEquals(RT_SCOPE_LINK, new LinkAddress("::1/128").getScope());
- assertEquals(RT_SCOPE_LINK, new LinkAddress("127.0.0.5/8").getScope());
- assertEquals(RT_SCOPE_LINK, new LinkAddress("fe80::ace:d00d/64").getScope());
- assertEquals(RT_SCOPE_LINK, new LinkAddress("169.254.5.12/16").getScope());
-
- assertEquals(RT_SCOPE_SITE, new LinkAddress("fec0::dead/64").getScope());
-
- assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("10.1.2.3/21").getScope());
- assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("192.0.2.1/25").getScope());
- assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("2001:db8::/64").getScope());
- assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("5000::/127").getScope());
- }
-
- private void assertIsSameAddressAs(LinkAddress l1, LinkAddress l2) {
- assertTrue(l1 + " unexpectedly does not have same address as " + l2,
- l1.isSameAddressAs(l2));
- assertTrue(l2 + " unexpectedly does not have same address as " + l1,
- l2.isSameAddressAs(l1));
- }
-
- private void assertIsNotSameAddressAs(LinkAddress l1, LinkAddress l2) {
- assertFalse(l1 + " unexpectedly has same address as " + l2,
- l1.isSameAddressAs(l2));
- assertFalse(l2 + " unexpectedly has same address as " + l1,
- l1.isSameAddressAs(l2));
- }
-
- @Test
- public void testEqualsAndSameAddressAs() {
- LinkAddress l1, l2, l3;
-
- l1 = new LinkAddress("2001:db8::1/64");
- l2 = new LinkAddress("2001:db8::1/64");
- assertEqualBothWays(l1, l2);
- assertIsSameAddressAs(l1, l2);
-
- l2 = new LinkAddress("2001:db8::1/65");
- assertNotEqualEitherWay(l1, l2);
- assertIsNotSameAddressAs(l1, l2);
-
- l2 = new LinkAddress("2001:db8::2/64");
- assertNotEqualEitherWay(l1, l2);
- assertIsNotSameAddressAs(l1, l2);
-
-
- l1 = new LinkAddress("192.0.2.1/24");
- l2 = new LinkAddress("192.0.2.1/24");
- assertEqualBothWays(l1, l2);
- assertIsSameAddressAs(l1, l2);
-
- l2 = new LinkAddress("192.0.2.1/23");
- assertNotEqualEitherWay(l1, l2);
- assertIsNotSameAddressAs(l1, l2);
-
- l2 = new LinkAddress("192.0.2.2/24");
- assertNotEqualEitherWay(l1, l2);
- assertIsNotSameAddressAs(l1, l2);
-
-
- // Check equals() and isSameAddressAs() on identical addresses with different flags.
- l1 = new LinkAddress(V6_ADDRESS, 64);
- l2 = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_UNIVERSE);
- assertEqualBothWays(l1, l2);
- assertIsSameAddressAs(l1, l2);
-
- l2 = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_UNIVERSE);
- assertNotEqualEitherWay(l1, l2);
- assertIsSameAddressAs(l1, l2);
-
- // Check equals() and isSameAddressAs() on identical addresses with different scope.
- l1 = new LinkAddress(V4_ADDRESS, 24);
- l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_UNIVERSE);
- assertEqualBothWays(l1, l2);
- assertIsSameAddressAs(l1, l2);
-
- l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_HOST);
- assertNotEqualEitherWay(l1, l2);
- assertIsSameAddressAs(l1, l2);
-
- // Addresses with the same start or end bytes aren't equal between families.
- l1 = new LinkAddress("32.1.13.184/24");
- l2 = new LinkAddress("2001:db8::1/24");
- l3 = new LinkAddress("::2001:db8/24");
-
- byte[] ipv4Bytes = l1.getAddress().getAddress();
- byte[] l2FirstIPv6Bytes = Arrays.copyOf(l2.getAddress().getAddress(), 4);
- byte[] l3LastIPv6Bytes = Arrays.copyOfRange(l3.getAddress().getAddress(), 12, 16);
- assertTrue(Arrays.equals(ipv4Bytes, l2FirstIPv6Bytes));
- assertTrue(Arrays.equals(ipv4Bytes, l3LastIPv6Bytes));
-
- assertNotEqualEitherWay(l1, l2);
- assertIsNotSameAddressAs(l1, l2);
-
- assertNotEqualEitherWay(l1, l3);
- assertIsNotSameAddressAs(l1, l3);
-
- // Because we use InetAddress, an IPv4 address is equal to its IPv4-mapped address.
- // TODO: Investigate fixing this.
- String addressString = V4 + "/24";
- l1 = new LinkAddress(addressString);
- l2 = new LinkAddress("::ffff:" + addressString);
- assertEqualBothWays(l1, l2);
- assertIsSameAddressAs(l1, l2);
- }
-
- @Test
- public void testHashCode() {
- LinkAddress l1, l2;
-
- l1 = new LinkAddress(V4_ADDRESS, 23);
- l2 = new LinkAddress(V4_ADDRESS, 23, 0, RT_SCOPE_HOST);
- assertNotEquals(l1.hashCode(), l2.hashCode());
-
- l1 = new LinkAddress(V6_ADDRESS, 128);
- l2 = new LinkAddress(V6_ADDRESS, 128, IFA_F_TENTATIVE, RT_SCOPE_UNIVERSE);
- assertNotEquals(l1.hashCode(), l2.hashCode());
- }
-
- @Test
- public void testParceling() {
- LinkAddress l;
-
- l = new LinkAddress(V6_ADDRESS, 64, 123, 456);
- assertParcelingIsLossless(l);
-
- l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK);
- assertParcelingIsLossless(l);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testLifetimeParceling() {
- final LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 123, 456, 1L, 3600000L);
- assertParcelingIsLossless(l);
- }
-
- @Test @IgnoreAfter(Build.VERSION_CODES.Q)
- public void testFieldCount_Q() {
- assertFieldCountEquals(4, LinkAddress.class);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testFieldCount() {
- // Make sure any new field is covered by the above parceling tests when changing this number
- assertFieldCountEquals(6, LinkAddress.class);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testDeprecationTime() {
- try {
- new LinkAddress(V6_ADDRESS, 64, 0, 456,
- LinkAddress.LIFETIME_UNKNOWN, 100000L);
- fail("Only one time provided should cause exception");
- } catch (IllegalArgumentException expected) { }
-
- try {
- new LinkAddress(V6_ADDRESS, 64, 0, 456,
- 200000L, 100000L);
- fail("deprecation time later than expiration time should cause exception");
- } catch (IllegalArgumentException expected) { }
-
- try {
- new LinkAddress(V6_ADDRESS, 64, 0, 456,
- -2, 100000L);
- fail("negative deprecation time should cause exception");
- } catch (IllegalArgumentException expected) { }
-
- LinkAddress addr = new LinkAddress(V6_ADDRESS, 64, 0, 456, 100000L, 200000L);
- assertEquals(100000L, addr.getDeprecationTime());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testExpirationTime() {
- try {
- new LinkAddress(V6_ADDRESS, 64, 0, 456,
- 200000L, LinkAddress.LIFETIME_UNKNOWN);
- fail("Only one time provided should cause exception");
- } catch (IllegalArgumentException expected) { }
-
- try {
- new LinkAddress(V6_ADDRESS, 64, 0, 456,
- 100000L, -2);
- fail("negative expiration time should cause exception");
- } catch (IllegalArgumentException expected) { }
-
- LinkAddress addr = new LinkAddress(V6_ADDRESS, 64, 0, 456, 100000L, 200000L);
- assertEquals(200000L, addr.getExpirationTime());
- }
-
- @Test
- public void testGetFlags() {
- LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 123, RT_SCOPE_HOST);
- assertEquals(123, l.getFlags());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testGetFlags_Deprecation() {
- // Test if deprecated bit was added/remove automatically based on the provided deprecation
- // time
- LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_HOST,
- 1L, LinkAddress.LIFETIME_PERMANENT);
- // Check if the flag is added automatically.
- assertTrue((l.getFlags() & IFA_F_DEPRECATED) != 0);
-
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
- SystemClock.elapsedRealtime() + 100000L, LinkAddress.LIFETIME_PERMANENT);
- // Check if the flag is removed automatically.
- assertTrue((l.getFlags() & IFA_F_DEPRECATED) == 0);
-
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
- LinkAddress.LIFETIME_PERMANENT, LinkAddress.LIFETIME_PERMANENT);
- // Check if the permanent flag is added.
- assertTrue((l.getFlags() & IFA_F_PERMANENT) != 0);
-
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_PERMANENT, RT_SCOPE_HOST,
- 1000L, SystemClock.elapsedRealtime() + 100000L);
- // Check if the permanent flag is removed
- assertTrue((l.getFlags() & IFA_F_PERMANENT) == 0);
- }
-
- private void assertGlobalPreferred(LinkAddress l, String msg) {
- assertTrue(msg, l.isGlobalPreferred());
- }
-
- private void assertNotGlobalPreferred(LinkAddress l, String msg) {
- assertFalse(msg, l.isGlobalPreferred());
- }
-
- @Test
- public void testIsGlobalPreferred() {
- LinkAddress l;
-
- l = new LinkAddress(V4_ADDRESS, 32, 0, RT_SCOPE_UNIVERSE);
- assertGlobalPreferred(l, "v4,global,noflags");
-
- l = new LinkAddress("10.10.1.7/23", 0, RT_SCOPE_UNIVERSE);
- assertGlobalPreferred(l, "v4-rfc1918,global,noflags");
-
- l = new LinkAddress("10.10.1.7/23", 0, RT_SCOPE_SITE);
- assertNotGlobalPreferred(l, "v4-rfc1918,site-local,noflags");
-
- l = new LinkAddress("127.0.0.7/8", 0, RT_SCOPE_HOST);
- assertNotGlobalPreferred(l, "v4-localhost,node-local,noflags");
-
- l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_UNIVERSE);
- assertGlobalPreferred(l, "v6,global,noflags");
-
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
- assertGlobalPreferred(l, "v6,global,permanent");
-
- // IPv6 ULAs are not acceptable "global preferred" addresses.
- l = new LinkAddress("fc12::1/64", 0, RT_SCOPE_UNIVERSE);
- assertNotGlobalPreferred(l, "v6,ula1,noflags");
-
- l = new LinkAddress("fd34::1/64", 0, RT_SCOPE_UNIVERSE);
- assertNotGlobalPreferred(l, "v6,ula2,noflags");
-
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_UNIVERSE);
- assertGlobalPreferred(l, "v6,global,tempaddr");
-
- l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_DADFAILED),
- RT_SCOPE_UNIVERSE);
- assertNotGlobalPreferred(l, "v6,global,tempaddr+dadfailed");
-
- l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_DEPRECATED),
- RT_SCOPE_UNIVERSE);
- assertNotGlobalPreferred(l, "v6,global,tempaddr+deprecated");
-
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_SITE);
- assertNotGlobalPreferred(l, "v6,site-local,tempaddr");
-
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_LINK);
- assertNotGlobalPreferred(l, "v6,link-local,tempaddr");
-
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_HOST);
- assertNotGlobalPreferred(l, "v6,node-local,tempaddr");
-
- l = new LinkAddress("::1/128", IFA_F_PERMANENT, RT_SCOPE_HOST);
- assertNotGlobalPreferred(l, "v6-localhost,node-local,permanent");
-
- l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_TENTATIVE),
- RT_SCOPE_UNIVERSE);
- assertNotGlobalPreferred(l, "v6,global,tempaddr+tentative");
-
- l = new LinkAddress(V6_ADDRESS, 64,
- (IFA_F_TEMPORARY|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC),
- RT_SCOPE_UNIVERSE);
- assertGlobalPreferred(l, "v6,global,tempaddr+optimistic");
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testIsGlobalPreferred_DeprecatedInFuture() {
- final LinkAddress l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED,
- RT_SCOPE_UNIVERSE, SystemClock.elapsedRealtime() + 100000,
- SystemClock.elapsedRealtime() + 200000);
- // Although the deprecated bit is set, but the deprecation time is in the future, test
- // if the flag is removed automatically.
- assertGlobalPreferred(l, "v6,global,tempaddr+deprecated in the future");
- }
-}
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
deleted file mode 100644
index 6eba62e63740..000000000000
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ /dev/null
@@ -1,1303 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.RouteInfo.RTN_THROW;
-import static android.net.RouteInfo.RTN_UNICAST;
-import static android.net.RouteInfo.RTN_UNREACHABLE;
-
-import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
-import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
-import static com.android.testutils.ParcelUtilsKt.parcelingRoundTrip;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.LinkProperties.ProvisioningChange;
-import android.net.util.LinkPropertiesUtils.CompareResult;
-import android.os.Build;
-import android.system.OsConstants;
-import android.util.ArraySet;
-
-import androidx.core.os.BuildCompat;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class LinkPropertiesTest {
- @Rule
- public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
-
- private static final InetAddress ADDRV4 = address("75.208.6.1");
- private static final InetAddress ADDRV6 = address("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
- private static final InetAddress DNS1 = address("75.208.7.1");
- private static final InetAddress DNS2 = address("69.78.7.1");
- private static final InetAddress DNS6 = address("2001:4860:4860::8888");
- private static final InetAddress PRIVDNS1 = address("1.1.1.1");
- private static final InetAddress PRIVDNS2 = address("1.0.0.1");
- private static final InetAddress PRIVDNS6 = address("2606:4700:4700::1111");
- private static final InetAddress PCSCFV4 = address("10.77.25.37");
- private static final InetAddress PCSCFV6 = address("2001:0db8:85a3:0000:0000:8a2e:0370:1");
- private static final InetAddress GATEWAY1 = address("75.208.8.1");
- private static final InetAddress GATEWAY2 = address("69.78.8.1");
- private static final InetAddress GATEWAY61 = address("fe80::6:0000:613");
- private static final InetAddress GATEWAY62 = address("fe80::6:22%lo");
- private static final InetAddress TESTIPV4ADDR = address("192.168.47.42");
- private static final InetAddress TESTIPV6ADDR = address("fe80::7:33%43");
- private static final Inet4Address DHCPSERVER = (Inet4Address) address("192.0.2.1");
- private static final String NAME = "qmi0";
- private static final String DOMAINS = "google.com";
- private static final String PRIV_DNS_SERVER_NAME = "private.dns.com";
- private static final String TCP_BUFFER_SIZES = "524288,1048576,2097152,262144,524288,1048576";
- private static final int MTU = 1500;
- private static final LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32);
- private static final LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
- private static final LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64");
- private static final Uri CAPPORT_API_URL = Uri.parse("https://test.example.com/capportapi");
-
- // CaptivePortalData cannot be in a constant as it does not exist on Q.
- // The test runner also crashes when scanning for tests if it is a return type.
- private static Object getCaptivePortalData() {
- return new CaptivePortalData.Builder()
- .setVenueInfoUrl(Uri.parse("https://test.example.com/venue")).build();
- }
-
- private static InetAddress address(String addrString) {
- return InetAddresses.parseNumericAddress(addrString);
- }
-
- private static boolean isAtLeastR() {
- // BuildCompat.isAtLeastR is documented to return false on release SDKs (including R)
- return Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR();
- }
-
- private void checkEmpty(final LinkProperties lp) {
- assertEquals(0, lp.getAllInterfaceNames().size());
- assertEquals(0, lp.getAllAddresses().size());
- assertEquals(0, lp.getDnsServers().size());
- assertEquals(0, lp.getValidatedPrivateDnsServers().size());
- assertEquals(0, lp.getPcscfServers().size());
- assertEquals(0, lp.getAllRoutes().size());
- assertEquals(0, lp.getAllLinkAddresses().size());
- assertEquals(0, lp.getStackedLinks().size());
- assertEquals(0, lp.getMtu());
- assertNull(lp.getPrivateDnsServerName());
- assertNull(lp.getDomains());
- assertNull(lp.getHttpProxy());
- assertNull(lp.getTcpBufferSizes());
- assertNull(lp.getNat64Prefix());
- assertFalse(lp.isProvisioned());
- assertFalse(lp.isIpv4Provisioned());
- assertFalse(lp.isIpv6Provisioned());
- assertFalse(lp.isPrivateDnsActive());
-
- if (isAtLeastR()) {
- assertNull(lp.getDhcpServerAddress());
- assertFalse(lp.isWakeOnLanSupported());
- assertNull(lp.getCaptivePortalApiUrl());
- assertNull(lp.getCaptivePortalData());
- }
- }
-
- private LinkProperties makeTestObject() {
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(NAME);
- lp.addLinkAddress(LINKADDRV4);
- lp.addLinkAddress(LINKADDRV6);
- lp.addDnsServer(DNS1);
- lp.addDnsServer(DNS2);
- lp.addValidatedPrivateDnsServer(PRIVDNS1);
- lp.addValidatedPrivateDnsServer(PRIVDNS2);
- lp.setUsePrivateDns(true);
- lp.setPrivateDnsServerName(PRIV_DNS_SERVER_NAME);
- lp.addPcscfServer(PCSCFV6);
- lp.setDomains(DOMAINS);
- lp.addRoute(new RouteInfo(GATEWAY1));
- lp.addRoute(new RouteInfo(GATEWAY2));
- lp.setHttpProxy(ProxyInfo.buildDirectProxy("test", 8888));
- lp.setMtu(MTU);
- lp.setTcpBufferSizes(TCP_BUFFER_SIZES);
- lp.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96"));
- if (isAtLeastR()) {
- lp.setDhcpServerAddress(DHCPSERVER);
- lp.setWakeOnLanSupported(true);
- lp.setCaptivePortalApiUrl(CAPPORT_API_URL);
- lp.setCaptivePortalData((CaptivePortalData) getCaptivePortalData());
- }
- return lp;
- }
-
- public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) {
- // Check implementation of equals(), element by element.
- assertTrue(source.isIdenticalInterfaceName(target));
- assertTrue(target.isIdenticalInterfaceName(source));
-
- assertTrue(source.isIdenticalAddresses(target));
- assertTrue(target.isIdenticalAddresses(source));
-
- assertTrue(source.isIdenticalDnses(target));
- assertTrue(target.isIdenticalDnses(source));
-
- assertTrue(source.isIdenticalPrivateDns(target));
- assertTrue(target.isIdenticalPrivateDns(source));
-
- assertTrue(source.isIdenticalValidatedPrivateDnses(target));
- assertTrue(target.isIdenticalValidatedPrivateDnses(source));
-
- assertTrue(source.isIdenticalPcscfs(target));
- assertTrue(target.isIdenticalPcscfs(source));
-
- assertTrue(source.isIdenticalRoutes(target));
- assertTrue(target.isIdenticalRoutes(source));
-
- assertTrue(source.isIdenticalHttpProxy(target));
- assertTrue(target.isIdenticalHttpProxy(source));
-
- assertTrue(source.isIdenticalStackedLinks(target));
- assertTrue(target.isIdenticalStackedLinks(source));
-
- assertTrue(source.isIdenticalMtu(target));
- assertTrue(target.isIdenticalMtu(source));
-
- assertTrue(source.isIdenticalTcpBufferSizes(target));
- assertTrue(target.isIdenticalTcpBufferSizes(source));
-
- if (isAtLeastR()) {
- assertTrue(source.isIdenticalDhcpServerAddress(target));
- assertTrue(source.isIdenticalDhcpServerAddress(source));
-
- assertTrue(source.isIdenticalWakeOnLan(target));
- assertTrue(target.isIdenticalWakeOnLan(source));
-
- assertTrue(source.isIdenticalCaptivePortalApiUrl(target));
- assertTrue(target.isIdenticalCaptivePortalApiUrl(source));
-
- assertTrue(source.isIdenticalCaptivePortalData(target));
- assertTrue(target.isIdenticalCaptivePortalData(source));
- }
-
- // Check result of equals().
- assertTrue(source.equals(target));
- assertTrue(target.equals(source));
-
- // Check hashCode.
- assertEquals(source.hashCode(), target.hashCode());
- }
-
- @Test
- public void testEqualsNull() {
- LinkProperties source = new LinkProperties();
- LinkProperties target = new LinkProperties();
-
- assertFalse(source == target);
- assertLinkPropertiesEqual(source, target);
- }
-
- @Test
- public void testEqualsSameOrder() throws Exception {
- LinkProperties source = new LinkProperties();
- source.setInterfaceName(NAME);
- // set 2 link addresses
- source.addLinkAddress(LINKADDRV4);
- source.addLinkAddress(LINKADDRV6);
- // set 2 dnses
- source.addDnsServer(DNS1);
- source.addDnsServer(DNS2);
- // set 1 pcscf
- source.addPcscfServer(PCSCFV6);
- // set 2 gateways
- source.addRoute(new RouteInfo(GATEWAY1));
- source.addRoute(new RouteInfo(GATEWAY2));
- source.setMtu(MTU);
-
- LinkProperties target = new LinkProperties();
-
- // All fields are same
- target.setInterfaceName(NAME);
- target.addLinkAddress(LINKADDRV4);
- target.addLinkAddress(LINKADDRV6);
- target.addDnsServer(DNS1);
- target.addDnsServer(DNS2);
- target.addPcscfServer(PCSCFV6);
- target.addRoute(new RouteInfo(GATEWAY1));
- target.addRoute(new RouteInfo(GATEWAY2));
- target.setMtu(MTU);
-
- assertLinkPropertiesEqual(source, target);
-
- target.clear();
- // change Interface Name
- target.setInterfaceName("qmi1");
- target.addLinkAddress(LINKADDRV4);
- target.addLinkAddress(LINKADDRV6);
- target.addDnsServer(DNS1);
- target.addDnsServer(DNS2);
- target.addPcscfServer(PCSCFV6);
- target.addRoute(new RouteInfo(GATEWAY1));
- target.addRoute(new RouteInfo(GATEWAY2));
- target.setMtu(MTU);
- assertFalse(source.equals(target));
-
- target.clear();
- target.setInterfaceName(NAME);
- // change link addresses
- target.addLinkAddress(new LinkAddress(address("75.208.6.2"), 32));
- target.addLinkAddress(LINKADDRV6);
- target.addDnsServer(DNS1);
- target.addDnsServer(DNS2);
- target.addPcscfServer(PCSCFV6);
- target.addRoute(new RouteInfo(GATEWAY1));
- target.addRoute(new RouteInfo(GATEWAY2));
- target.setMtu(MTU);
- assertFalse(source.equals(target));
-
- target.clear();
- target.setInterfaceName(NAME);
- target.addLinkAddress(LINKADDRV4);
- target.addLinkAddress(LINKADDRV6);
- // change dnses
- target.addDnsServer(address("75.208.7.2"));
- target.addDnsServer(DNS2);
- target.addPcscfServer(PCSCFV6);
- target.addRoute(new RouteInfo(GATEWAY1));
- target.addRoute(new RouteInfo(GATEWAY2));
- target.setMtu(MTU);
- assertFalse(source.equals(target));
-
- target.clear();
- target.setInterfaceName(NAME);
- target.addLinkAddress(LINKADDRV4);
- target.addLinkAddress(LINKADDRV6);
- target.addDnsServer(address("75.208.7.2"));
- target.addDnsServer(DNS2);
- // change pcscf
- target.addPcscfServer(address("2001::1"));
- target.addRoute(new RouteInfo(GATEWAY1));
- target.addRoute(new RouteInfo(GATEWAY2));
- target.setMtu(MTU);
- assertFalse(source.equals(target));
-
- target.clear();
- target.setInterfaceName(NAME);
- target.addLinkAddress(LINKADDRV4);
- target.addLinkAddress(LINKADDRV6);
- target.addDnsServer(DNS1);
- target.addDnsServer(DNS2);
- // change gateway
- target.addRoute(new RouteInfo(address("75.208.8.2")));
- target.setMtu(MTU);
- target.addRoute(new RouteInfo(GATEWAY2));
- assertFalse(source.equals(target));
-
- target.clear();
- target.setInterfaceName(NAME);
- target.addLinkAddress(LINKADDRV4);
- target.addLinkAddress(LINKADDRV6);
- target.addDnsServer(DNS1);
- target.addDnsServer(DNS2);
- target.addRoute(new RouteInfo(GATEWAY1));
- target.addRoute(new RouteInfo(GATEWAY2));
- // change mtu
- target.setMtu(1440);
- assertFalse(source.equals(target));
- }
-
- @Test
- public void testEqualsDifferentOrder() throws Exception {
- LinkProperties source = new LinkProperties();
- source.setInterfaceName(NAME);
- // set 2 link addresses
- source.addLinkAddress(LINKADDRV4);
- source.addLinkAddress(LINKADDRV6);
- // set 2 dnses
- source.addDnsServer(DNS1);
- source.addDnsServer(DNS2);
- // set 2 gateways
- source.addRoute(new RouteInfo(LINKADDRV4, GATEWAY1));
- source.addRoute(new RouteInfo(GATEWAY2));
- source.setMtu(MTU);
-
- LinkProperties target = new LinkProperties();
- // Exchange order
- target.setInterfaceName(NAME);
- target.addLinkAddress(LINKADDRV6);
- target.addLinkAddress(LINKADDRV4);
- target.addDnsServer(DNS2);
- target.addDnsServer(DNS1);
- target.addRoute(new RouteInfo(GATEWAY2));
- target.addRoute(new RouteInfo(LINKADDRV4, GATEWAY1));
- target.setMtu(MTU);
-
- assertLinkPropertiesEqual(source, target);
- }
-
- @Test
- public void testEqualsDuplicated() throws Exception {
- LinkProperties source = new LinkProperties();
- // set 3 link addresses, eg, [A, A, B]
- source.addLinkAddress(LINKADDRV4);
- source.addLinkAddress(LINKADDRV4);
- source.addLinkAddress(LINKADDRV6);
-
- LinkProperties target = new LinkProperties();
- // set 3 link addresses, eg, [A, B, B]
- target.addLinkAddress(LINKADDRV4);
- target.addLinkAddress(LINKADDRV6);
- target.addLinkAddress(LINKADDRV6);
-
- assertLinkPropertiesEqual(source, target);
- }
-
- private void assertAllRoutesHaveInterface(String iface, LinkProperties lp) {
- for (RouteInfo r : lp.getRoutes()) {
- assertEquals(iface, r.getInterface());
- }
- }
-
- private void assertAllRoutesNotHaveInterface(String iface, LinkProperties lp) {
- for (RouteInfo r : lp.getRoutes()) {
- assertNotEquals(iface, r.getInterface());
- }
- }
-
- @Test
- public void testRouteInterfaces() {
- LinkAddress prefix1 = new LinkAddress(address("2001:db8:1::"), 48);
- LinkAddress prefix2 = new LinkAddress(address("2001:db8:2::"), 48);
- InetAddress address = ADDRV6;
-
- // Add a route with no interface to a LinkProperties with no interface. No errors.
- LinkProperties lp = new LinkProperties();
- RouteInfo r = new RouteInfo(prefix1, address, null);
- assertTrue(lp.addRoute(r));
- assertEquals(1, lp.getRoutes().size());
- assertAllRoutesHaveInterface(null, lp);
-
- // Adding the same route twice has no effect.
- assertFalse(lp.addRoute(r));
- assertEquals(1, lp.getRoutes().size());
-
- // Add a route with an interface. Expect an exception.
- r = new RouteInfo(prefix2, address, "wlan0");
- try {
- lp.addRoute(r);
- fail("Adding wlan0 route to LP with no interface, expect exception");
- } catch (IllegalArgumentException expected) {}
-
- // Change the interface name. All the routes should change their interface name too.
- lp.setInterfaceName("rmnet0");
- assertAllRoutesHaveInterface("rmnet0", lp);
- assertAllRoutesNotHaveInterface(null, lp);
- assertAllRoutesNotHaveInterface("wlan0", lp);
-
- // Now add a route with the wrong interface. This causes an exception too.
- try {
- lp.addRoute(r);
- fail("Adding wlan0 route to rmnet0 LP, expect exception");
- } catch (IllegalArgumentException expected) {}
-
- // If the interface name matches, the route is added.
- r = new RouteInfo(prefix2, null, "wlan0");
- lp.setInterfaceName("wlan0");
- lp.addRoute(r);
- assertEquals(2, lp.getRoutes().size());
- assertAllRoutesHaveInterface("wlan0", lp);
- assertAllRoutesNotHaveInterface("rmnet0", lp);
-
- // Routes with null interfaces are converted to wlan0.
- r = RouteInfo.makeHostRoute(ADDRV6, null);
- lp.addRoute(r);
- assertEquals(3, lp.getRoutes().size());
- assertAllRoutesHaveInterface("wlan0", lp);
-
- // Check comparisons work.
- LinkProperties lp2 = new LinkProperties(lp);
- assertAllRoutesHaveInterface("wlan0", lp2);
- // LinkProperties#compareAllRoutes exists both in R and before R, but the return type
- // changed in R, so a test compiled with the R version of LinkProperties cannot run on Q.
- if (isAtLeastR()) {
- assertEquals(0, lp.compareAllRoutes(lp2).added.size());
- assertEquals(0, lp.compareAllRoutes(lp2).removed.size());
- }
-
- lp2.setInterfaceName("p2p0");
- assertAllRoutesHaveInterface("p2p0", lp2);
- assertAllRoutesNotHaveInterface("wlan0", lp2);
- if (isAtLeastR()) {
- assertEquals(3, lp.compareAllRoutes(lp2).added.size());
- assertEquals(3, lp.compareAllRoutes(lp2).removed.size());
- }
-
- // Remove route with incorrect interface, no route removed.
- lp.removeRoute(new RouteInfo(prefix2, null, null));
- assertEquals(3, lp.getRoutes().size());
-
- // Check remove works when interface is correct.
- lp.removeRoute(new RouteInfo(prefix2, null, "wlan0"));
- assertEquals(2, lp.getRoutes().size());
- assertAllRoutesHaveInterface("wlan0", lp);
- assertAllRoutesNotHaveInterface("p2p0", lp);
- }
-
- @Test
- public void testStackedInterfaces() {
- LinkProperties rmnet0 = new LinkProperties();
- rmnet0.setInterfaceName("rmnet0");
- rmnet0.addLinkAddress(LINKADDRV6);
-
- LinkProperties clat4 = new LinkProperties();
- clat4.setInterfaceName("clat4");
- clat4.addLinkAddress(LINKADDRV4);
-
- assertEquals(0, rmnet0.getStackedLinks().size());
- assertEquals(1, rmnet0.getAddresses().size());
- assertEquals(1, rmnet0.getLinkAddresses().size());
- assertEquals(1, rmnet0.getAllAddresses().size());
- assertEquals(1, rmnet0.getAllLinkAddresses().size());
- assertEquals(1, rmnet0.getAllInterfaceNames().size());
- assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
-
- rmnet0.addStackedLink(clat4);
- assertEquals(1, rmnet0.getStackedLinks().size());
- assertEquals(1, rmnet0.getAddresses().size());
- assertEquals(1, rmnet0.getLinkAddresses().size());
- assertEquals(2, rmnet0.getAllAddresses().size());
- assertEquals(2, rmnet0.getAllLinkAddresses().size());
- assertEquals(2, rmnet0.getAllInterfaceNames().size());
- assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
- assertEquals("clat4", rmnet0.getAllInterfaceNames().get(1));
-
- rmnet0.addStackedLink(clat4);
- assertEquals(1, rmnet0.getStackedLinks().size());
- assertEquals(1, rmnet0.getAddresses().size());
- assertEquals(1, rmnet0.getLinkAddresses().size());
- assertEquals(2, rmnet0.getAllAddresses().size());
- assertEquals(2, rmnet0.getAllLinkAddresses().size());
- assertEquals(2, rmnet0.getAllInterfaceNames().size());
- assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
- assertEquals("clat4", rmnet0.getAllInterfaceNames().get(1));
-
- assertEquals(0, clat4.getStackedLinks().size());
-
- // Modify an item in the returned collection to see what happens.
- for (LinkProperties link : rmnet0.getStackedLinks()) {
- if (link.getInterfaceName().equals("clat4")) {
- link.setInterfaceName("newname");
- }
- }
- for (LinkProperties link : rmnet0.getStackedLinks()) {
- assertFalse("newname".equals(link.getInterfaceName()));
- }
-
- assertTrue(rmnet0.removeStackedLink("clat4"));
- assertEquals(0, rmnet0.getStackedLinks().size());
- assertEquals(1, rmnet0.getAddresses().size());
- assertEquals(1, rmnet0.getLinkAddresses().size());
- assertEquals(1, rmnet0.getAllAddresses().size());
- assertEquals(1, rmnet0.getAllLinkAddresses().size());
- assertEquals(1, rmnet0.getAllInterfaceNames().size());
- assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
-
- assertFalse(rmnet0.removeStackedLink("clat4"));
- }
-
- private LinkAddress getFirstLinkAddress(LinkProperties lp) {
- return lp.getLinkAddresses().iterator().next();
- }
-
- @Test
- public void testAddressMethods() {
- LinkProperties lp = new LinkProperties();
-
- // No addresses.
- assertFalse(lp.hasIpv4Address());
- assertFalse(lp.hasGlobalIpv6Address());
-
- // Addresses on stacked links don't count.
- LinkProperties stacked = new LinkProperties();
- stacked.setInterfaceName("stacked");
- lp.addStackedLink(stacked);
- stacked.addLinkAddress(LINKADDRV4);
- stacked.addLinkAddress(LINKADDRV6);
- assertTrue(stacked.hasIpv4Address());
- assertTrue(stacked.hasGlobalIpv6Address());
- assertFalse(lp.hasIpv4Address());
- assertFalse(lp.hasGlobalIpv6Address());
- lp.removeStackedLink("stacked");
- assertFalse(lp.hasIpv4Address());
- assertFalse(lp.hasGlobalIpv6Address());
-
- // Addresses on the base link.
- // Check the return values of hasIpvXAddress and ensure the add/remove methods return true
- // iff something changes.
- assertEquals(0, lp.getLinkAddresses().size());
- assertTrue(lp.addLinkAddress(LINKADDRV6));
- assertEquals(1, lp.getLinkAddresses().size());
- assertFalse(lp.hasIpv4Address());
- assertTrue(lp.hasGlobalIpv6Address());
-
- assertTrue(lp.removeLinkAddress(LINKADDRV6));
- assertEquals(0, lp.getLinkAddresses().size());
-
- assertTrue(lp.addLinkAddress(LINKADDRV6LINKLOCAL));
- assertEquals(1, lp.getLinkAddresses().size());
- assertFalse(lp.hasGlobalIpv6Address());
-
- assertTrue(lp.addLinkAddress(LINKADDRV4));
- assertEquals(2, lp.getLinkAddresses().size());
- assertTrue(lp.hasIpv4Address());
- assertFalse(lp.hasGlobalIpv6Address());
-
- assertTrue(lp.addLinkAddress(LINKADDRV6));
- assertEquals(3, lp.getLinkAddresses().size());
- assertTrue(lp.hasIpv4Address());
- assertTrue(lp.hasGlobalIpv6Address());
-
- assertTrue(lp.removeLinkAddress(LINKADDRV6LINKLOCAL));
- assertEquals(2, lp.getLinkAddresses().size());
- assertTrue(lp.hasIpv4Address());
- assertTrue(lp.hasGlobalIpv6Address());
-
- // Adding an address twice has no effect.
- // Removing an address that's not present has no effect.
- assertFalse(lp.addLinkAddress(LINKADDRV4));
- assertEquals(2, lp.getLinkAddresses().size());
- assertTrue(lp.hasIpv4Address());
- assertTrue(lp.removeLinkAddress(LINKADDRV4));
- assertEquals(1, lp.getLinkAddresses().size());
- assertFalse(lp.hasIpv4Address());
- assertFalse(lp.removeLinkAddress(LINKADDRV4));
- assertEquals(1, lp.getLinkAddresses().size());
-
- // Adding an address that's already present but with different properties causes the
- // existing address to be updated and returns true.
- // Start with only LINKADDRV6.
- assertEquals(1, lp.getLinkAddresses().size());
- assertEquals(LINKADDRV6, getFirstLinkAddress(lp));
-
- // Create a LinkAddress object for the same address, but with different flags.
- LinkAddress deprecated = new LinkAddress(ADDRV6, 128,
- OsConstants.IFA_F_DEPRECATED, OsConstants.RT_SCOPE_UNIVERSE);
- assertTrue(deprecated.isSameAddressAs(LINKADDRV6));
- assertFalse(deprecated.equals(LINKADDRV6));
-
- // Check that adding it updates the existing address instead of adding a new one.
- assertTrue(lp.addLinkAddress(deprecated));
- assertEquals(1, lp.getLinkAddresses().size());
- assertEquals(deprecated, getFirstLinkAddress(lp));
- assertFalse(LINKADDRV6.equals(getFirstLinkAddress(lp)));
-
- // Removing LINKADDRV6 removes deprecated, because removing addresses ignores properties.
- assertTrue(lp.removeLinkAddress(LINKADDRV6));
- assertEquals(0, lp.getLinkAddresses().size());
- }
-
- @Test
- public void testLinkAddresses() {
- final LinkProperties lp = new LinkProperties();
- lp.addLinkAddress(LINKADDRV4);
- lp.addLinkAddress(LINKADDRV6);
-
- final LinkProperties lp2 = new LinkProperties();
- lp2.addLinkAddress(LINKADDRV6);
-
- final LinkProperties lp3 = new LinkProperties();
- final List<LinkAddress> linkAddresses = Arrays.asList(LINKADDRV4);
- lp3.setLinkAddresses(linkAddresses);
-
- assertFalse(lp.equals(lp2));
- assertFalse(lp2.equals(lp3));
-
- lp.removeLinkAddress(LINKADDRV4);
- assertTrue(lp.equals(lp2));
-
- lp2.setLinkAddresses(lp3.getLinkAddresses());
- assertTrue(lp2.equals(lp3));
- }
-
- @Test
- public void testNat64Prefix() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.addLinkAddress(LINKADDRV4);
- lp.addLinkAddress(LINKADDRV6);
-
- assertNull(lp.getNat64Prefix());
-
- IpPrefix p = new IpPrefix("64:ff9b::/96");
- lp.setNat64Prefix(p);
- assertEquals(p, lp.getNat64Prefix());
-
- p = new IpPrefix("2001:db8:a:b:1:2:3::/96");
- lp.setNat64Prefix(p);
- assertEquals(p, lp.getNat64Prefix());
-
- p = new IpPrefix("2001:db8:a:b:1:2::/80");
- try {
- lp.setNat64Prefix(p);
- } catch (IllegalArgumentException expected) {
- }
-
- p = new IpPrefix("64:ff9b::/64");
- try {
- lp.setNat64Prefix(p);
- } catch (IllegalArgumentException expected) {
- }
-
- assertEquals(new IpPrefix("2001:db8:a:b:1:2:3::/96"), lp.getNat64Prefix());
-
- lp.setNat64Prefix(null);
- assertNull(lp.getNat64Prefix());
- }
-
- @Test
- public void testIsProvisioned() {
- LinkProperties lp4 = new LinkProperties();
- assertFalse("v4only:empty", lp4.isProvisioned());
- lp4.addLinkAddress(LINKADDRV4);
- assertFalse("v4only:addr-only", lp4.isProvisioned());
- lp4.addDnsServer(DNS1);
- assertFalse("v4only:addr+dns", lp4.isProvisioned());
- lp4.addRoute(new RouteInfo(GATEWAY1));
- assertTrue("v4only:addr+dns+route", lp4.isProvisioned());
- assertTrue("v4only:addr+dns+route", lp4.isIpv4Provisioned());
- assertFalse("v4only:addr+dns+route", lp4.isIpv6Provisioned());
-
- LinkProperties lp6 = new LinkProperties();
- assertFalse("v6only:empty", lp6.isProvisioned());
- lp6.addLinkAddress(LINKADDRV6LINKLOCAL);
- assertFalse("v6only:fe80-only", lp6.isProvisioned());
- lp6.addDnsServer(DNS6);
- assertFalse("v6only:fe80+dns", lp6.isProvisioned());
- lp6.addRoute(new RouteInfo(GATEWAY61));
- assertFalse("v6only:fe80+dns+route", lp6.isProvisioned());
- lp6.addLinkAddress(LINKADDRV6);
- assertTrue("v6only:fe80+global+dns+route", lp6.isIpv6Provisioned());
- assertTrue("v6only:fe80+global+dns+route", lp6.isProvisioned());
- lp6.removeLinkAddress(LINKADDRV6LINKLOCAL);
- assertFalse("v6only:global+dns+route", lp6.isIpv4Provisioned());
- assertTrue("v6only:global+dns+route", lp6.isIpv6Provisioned());
- assertTrue("v6only:global+dns+route", lp6.isProvisioned());
-
- LinkProperties lp46 = new LinkProperties();
- lp46.addLinkAddress(LINKADDRV4);
- lp46.addLinkAddress(LINKADDRV6);
- lp46.addDnsServer(DNS1);
- lp46.addDnsServer(DNS6);
- assertFalse("dualstack:missing-routes", lp46.isProvisioned());
- lp46.addRoute(new RouteInfo(GATEWAY1));
- assertTrue("dualstack:v4-provisioned", lp46.isIpv4Provisioned());
- assertFalse("dualstack:v4-provisioned", lp46.isIpv6Provisioned());
- assertTrue("dualstack:v4-provisioned", lp46.isProvisioned());
- lp46.addRoute(new RouteInfo(GATEWAY61));
- assertTrue("dualstack:both-provisioned", lp46.isIpv4Provisioned());
- assertTrue("dualstack:both-provisioned", lp46.isIpv6Provisioned());
- assertTrue("dualstack:both-provisioned", lp46.isProvisioned());
-
- // A link with an IPv6 address and default route, but IPv4 DNS server.
- LinkProperties mixed = new LinkProperties();
- mixed.addLinkAddress(LINKADDRV6);
- mixed.addDnsServer(DNS1);
- mixed.addRoute(new RouteInfo(GATEWAY61));
- assertFalse("mixed:addr6+route6+dns4", mixed.isIpv4Provisioned());
- assertFalse("mixed:addr6+route6+dns4", mixed.isIpv6Provisioned());
- assertFalse("mixed:addr6+route6+dns4", mixed.isProvisioned());
- }
-
- @Test
- public void testCompareProvisioning() {
- LinkProperties v4lp = new LinkProperties();
- v4lp.addLinkAddress(LINKADDRV4);
- v4lp.addRoute(new RouteInfo(GATEWAY1));
- v4lp.addDnsServer(DNS1);
- assertTrue(v4lp.isProvisioned());
-
- LinkProperties v4r = new LinkProperties(v4lp);
- v4r.removeDnsServer(DNS1);
- assertFalse(v4r.isProvisioned());
-
- assertEquals(ProvisioningChange.STILL_NOT_PROVISIONED,
- LinkProperties.compareProvisioning(v4r, v4r));
- assertEquals(ProvisioningChange.LOST_PROVISIONING,
- LinkProperties.compareProvisioning(v4lp, v4r));
- assertEquals(ProvisioningChange.GAINED_PROVISIONING,
- LinkProperties.compareProvisioning(v4r, v4lp));
- assertEquals(ProvisioningChange.STILL_PROVISIONED,
- LinkProperties.compareProvisioning(v4lp, v4lp));
-
- // Check that losing IPv4 provisioning on a dualstack network is
- // seen as a total loss of provisioning.
- LinkProperties v6lp = new LinkProperties();
- v6lp.addLinkAddress(LINKADDRV6);
- v6lp.addRoute(new RouteInfo(GATEWAY61));
- v6lp.addDnsServer(DNS6);
- assertFalse(v6lp.isIpv4Provisioned());
- assertTrue(v6lp.isIpv6Provisioned());
- assertTrue(v6lp.isProvisioned());
-
- LinkProperties v46lp = new LinkProperties(v6lp);
- v46lp.addLinkAddress(LINKADDRV4);
- v46lp.addRoute(new RouteInfo(GATEWAY1));
- v46lp.addDnsServer(DNS1);
- assertTrue(v46lp.isIpv4Provisioned());
- assertTrue(v46lp.isIpv6Provisioned());
- assertTrue(v46lp.isProvisioned());
-
- assertEquals(ProvisioningChange.STILL_PROVISIONED,
- LinkProperties.compareProvisioning(v4lp, v46lp));
- assertEquals(ProvisioningChange.STILL_PROVISIONED,
- LinkProperties.compareProvisioning(v6lp, v46lp));
- assertEquals(ProvisioningChange.LOST_PROVISIONING,
- LinkProperties.compareProvisioning(v46lp, v6lp));
- assertEquals(ProvisioningChange.LOST_PROVISIONING,
- LinkProperties.compareProvisioning(v46lp, v4lp));
-
- // Check that losing and gaining a secondary router does not change
- // the provisioning status.
- LinkProperties v6lp2 = new LinkProperties(v6lp);
- v6lp2.addRoute(new RouteInfo(GATEWAY62));
- assertTrue(v6lp2.isProvisioned());
-
- assertEquals(ProvisioningChange.STILL_PROVISIONED,
- LinkProperties.compareProvisioning(v6lp2, v6lp));
- assertEquals(ProvisioningChange.STILL_PROVISIONED,
- LinkProperties.compareProvisioning(v6lp, v6lp2));
- }
-
- @Test
- public void testIsReachable() {
- final LinkProperties v4lp = new LinkProperties();
- assertFalse(v4lp.isReachable(DNS1));
- assertFalse(v4lp.isReachable(DNS2));
-
- // Add an on-link route, making the on-link DNS server reachable,
- // but there is still no IPv4 address.
- assertTrue(v4lp.addRoute(new RouteInfo(new IpPrefix(address("75.208.0.0"), 16))));
- assertFalse(v4lp.isReachable(DNS1));
- assertFalse(v4lp.isReachable(DNS2));
-
- // Adding an IPv4 address (right now, any IPv4 address) means we use
- // the routes to compute likely reachability.
- assertTrue(v4lp.addLinkAddress(new LinkAddress(ADDRV4, 16)));
- assertTrue(v4lp.isReachable(DNS1));
- assertFalse(v4lp.isReachable(DNS2));
-
- // Adding a default route makes the off-link DNS server reachable.
- assertTrue(v4lp.addRoute(new RouteInfo(GATEWAY1)));
- assertTrue(v4lp.isReachable(DNS1));
- assertTrue(v4lp.isReachable(DNS2));
-
- final LinkProperties v6lp = new LinkProperties();
- final InetAddress kLinkLocalDns = address("fe80::6:1");
- final InetAddress kLinkLocalDnsWithScope = address("fe80::6:2%43");
- final InetAddress kOnLinkDns = address("2001:db8:85a3::53");
- assertFalse(v6lp.isReachable(kLinkLocalDns));
- assertFalse(v6lp.isReachable(kLinkLocalDnsWithScope));
- assertFalse(v6lp.isReachable(kOnLinkDns));
- assertFalse(v6lp.isReachable(DNS6));
-
- // Add a link-local route, making the link-local DNS servers reachable. Because
- // we assume the presence of an IPv6 link-local address, link-local DNS servers
- // are considered reachable, but only those with a non-zero scope identifier.
- assertTrue(v6lp.addRoute(new RouteInfo(new IpPrefix(address("fe80::"), 64))));
- assertFalse(v6lp.isReachable(kLinkLocalDns));
- assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
- assertFalse(v6lp.isReachable(kOnLinkDns));
- assertFalse(v6lp.isReachable(DNS6));
-
- // Add a link-local address--nothing changes.
- assertTrue(v6lp.addLinkAddress(LINKADDRV6LINKLOCAL));
- assertFalse(v6lp.isReachable(kLinkLocalDns));
- assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
- assertFalse(v6lp.isReachable(kOnLinkDns));
- assertFalse(v6lp.isReachable(DNS6));
-
- // Add a global route on link, but no global address yet. DNS servers reachable
- // via a route that doesn't require a gateway: give them the benefit of the
- // doubt and hope the link-local source address suffices for communication.
- assertTrue(v6lp.addRoute(new RouteInfo(new IpPrefix(address("2001:db8:85a3::"), 64))));
- assertFalse(v6lp.isReachable(kLinkLocalDns));
- assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
- assertTrue(v6lp.isReachable(kOnLinkDns));
- assertFalse(v6lp.isReachable(DNS6));
-
- // Add a global address; the on-link global address DNS server is (still)
- // presumed reachable.
- assertTrue(v6lp.addLinkAddress(new LinkAddress(ADDRV6, 64)));
- assertFalse(v6lp.isReachable(kLinkLocalDns));
- assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
- assertTrue(v6lp.isReachable(kOnLinkDns));
- assertFalse(v6lp.isReachable(DNS6));
-
- // Adding a default route makes the off-link DNS server reachable.
- assertTrue(v6lp.addRoute(new RouteInfo(GATEWAY62)));
- assertFalse(v6lp.isReachable(kLinkLocalDns));
- assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
- assertTrue(v6lp.isReachable(kOnLinkDns));
- assertTrue(v6lp.isReachable(DNS6));
-
- // Check isReachable on stacked links. This requires that the source IP address be assigned
- // on the interface returned by the route lookup.
- LinkProperties stacked = new LinkProperties();
-
- // Can't add a stacked link without an interface name.
- stacked.setInterfaceName("v4-test0");
- v6lp.addStackedLink(stacked);
-
- InetAddress stackedAddress = address("192.0.0.4");
- LinkAddress stackedLinkAddress = new LinkAddress(stackedAddress, 32);
- assertFalse(v6lp.isReachable(stackedAddress));
- stacked.addLinkAddress(stackedLinkAddress);
- assertFalse(v6lp.isReachable(stackedAddress));
- stacked.addRoute(new RouteInfo(stackedLinkAddress));
- assertTrue(stacked.isReachable(stackedAddress));
- assertTrue(v6lp.isReachable(stackedAddress));
-
- assertFalse(v6lp.isReachable(DNS1));
- stacked.addRoute(new RouteInfo((IpPrefix) null, stackedAddress));
- assertTrue(v6lp.isReachable(DNS1));
- }
-
- @Test
- public void testLinkPropertiesEnsureDirectlyConnectedRoutes() {
- // IPv4 case: no route added initially
- LinkProperties rmnet0 = new LinkProperties();
- rmnet0.setInterfaceName("rmnet0");
- rmnet0.addLinkAddress(new LinkAddress("10.0.0.2/8"));
- RouteInfo directRoute0 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
- rmnet0.getInterfaceName());
-
- // Since no routes is added explicitly, getAllRoutes() should return empty.
- assertTrue(rmnet0.getAllRoutes().isEmpty());
- rmnet0.ensureDirectlyConnectedRoutes();
- // ensureDirectlyConnectedRoutes() should have added the missing local route.
- assertEqualRoutes(Collections.singletonList(directRoute0), rmnet0.getAllRoutes());
-
- // IPv4 case: both direct and default routes added initially
- LinkProperties rmnet1 = new LinkProperties();
- rmnet1.setInterfaceName("rmnet1");
- rmnet1.addLinkAddress(new LinkAddress("10.0.0.3/8"));
- RouteInfo defaultRoute1 = new RouteInfo((IpPrefix) null, address("10.0.0.1"),
- rmnet1.getInterfaceName());
- RouteInfo directRoute1 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
- rmnet1.getInterfaceName());
- rmnet1.addRoute(defaultRoute1);
- rmnet1.addRoute(directRoute1);
-
- // Check added routes
- assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes());
- // ensureDirectlyConnectedRoutes() shouldn't change the routes since direct connected
- // route is already part of the configuration.
- rmnet1.ensureDirectlyConnectedRoutes();
- assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes());
-
- // IPv6 case: only default routes added initially
- LinkProperties rmnet2 = new LinkProperties();
- rmnet2.setInterfaceName("rmnet2");
- rmnet2.addLinkAddress(new LinkAddress("fe80::cafe/64"));
- rmnet2.addLinkAddress(new LinkAddress("2001:db8::2/64"));
- RouteInfo defaultRoute2 = new RouteInfo((IpPrefix) null, address("2001:db8::1"),
- rmnet2.getInterfaceName());
- RouteInfo directRoute2 = new RouteInfo(new IpPrefix("2001:db8::/64"), null,
- rmnet2.getInterfaceName());
- RouteInfo linkLocalRoute2 = new RouteInfo(new IpPrefix("fe80::/64"), null,
- rmnet2.getInterfaceName());
- rmnet2.addRoute(defaultRoute2);
-
- assertEqualRoutes(Arrays.asList(defaultRoute2), rmnet2.getAllRoutes());
- rmnet2.ensureDirectlyConnectedRoutes();
- assertEqualRoutes(Arrays.asList(defaultRoute2, directRoute2, linkLocalRoute2),
- rmnet2.getAllRoutes());
-
- // Corner case: no interface name
- LinkProperties rmnet3 = new LinkProperties();
- rmnet3.addLinkAddress(new LinkAddress("192.168.0.2/24"));
- RouteInfo directRoute3 = new RouteInfo(new IpPrefix("192.168.0.0/24"), null,
- rmnet3.getInterfaceName());
-
- assertTrue(rmnet3.getAllRoutes().isEmpty());
- rmnet3.ensureDirectlyConnectedRoutes();
- assertEqualRoutes(Collections.singletonList(directRoute3), rmnet3.getAllRoutes());
-
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testCompareResult() {
- // Either adding or removing items
- compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(1),
- Arrays.asList(2, 3, 4), new ArrayList<>());
- compareResult(Arrays.asList(1, 2), Arrays.asList(3, 2, 1, 4),
- new ArrayList<>(), Arrays.asList(3, 4));
-
-
- // adding and removing items at the same time
- compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(2, 3, 4, 5),
- Arrays.asList(1), Arrays.asList(5));
- compareResult(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6),
- Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6));
-
- // null cases
- compareResult(Arrays.asList(1, 2, 3), null, Arrays.asList(1, 2, 3), new ArrayList<>());
- compareResult(null, Arrays.asList(3, 2, 1), new ArrayList<>(), Arrays.asList(1, 2, 3));
- compareResult(null, null, new ArrayList<>(), new ArrayList<>());
- }
-
- private void assertEqualRoutes(Collection<RouteInfo> expected, Collection<RouteInfo> actual) {
- Set<RouteInfo> expectedSet = new ArraySet<>(expected);
- Set<RouteInfo> actualSet = new ArraySet<>(actual);
- // Duplicated entries in actual routes are considered failures
- assertEquals(actual.size(), actualSet.size());
-
- assertEquals(expectedSet, actualSet);
- }
-
- private <T> void compareResult(List<T> oldItems, List<T> newItems, List<T> expectRemoved,
- List<T> expectAdded) {
- CompareResult<T> result = new CompareResult<>(oldItems, newItems);
- assertEquals(new ArraySet<>(expectAdded), new ArraySet<>(result.added));
- assertEquals(new ArraySet<>(expectRemoved), (new ArraySet<>(result.removed)));
- }
-
- private static LinkProperties makeLinkPropertiesForParceling() {
- LinkProperties source = new LinkProperties();
- source.setInterfaceName(NAME);
-
- source.addLinkAddress(LINKADDRV4);
- source.addLinkAddress(LINKADDRV6);
-
- source.addDnsServer(DNS1);
- source.addDnsServer(DNS2);
- source.addDnsServer(GATEWAY62);
-
- source.addPcscfServer(TESTIPV4ADDR);
- source.addPcscfServer(TESTIPV6ADDR);
-
- source.setUsePrivateDns(true);
- source.setPrivateDnsServerName(PRIV_DNS_SERVER_NAME);
-
- source.setDomains(DOMAINS);
-
- source.addRoute(new RouteInfo(GATEWAY1));
- source.addRoute(new RouteInfo(GATEWAY2));
-
- source.addValidatedPrivateDnsServer(DNS6);
- source.addValidatedPrivateDnsServer(GATEWAY61);
- source.addValidatedPrivateDnsServer(TESTIPV6ADDR);
-
- source.setHttpProxy(ProxyInfo.buildDirectProxy("test", 8888));
-
- source.setMtu(MTU);
-
- source.setTcpBufferSizes(TCP_BUFFER_SIZES);
-
- source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96"));
-
- final LinkProperties stacked = new LinkProperties();
- stacked.setInterfaceName("test-stacked");
- source.addStackedLink(stacked);
-
- return source;
- }
-
- @Test @IgnoreAfter(Build.VERSION_CODES.Q)
- public void testLinkPropertiesParcelable_Q() throws Exception {
- final LinkProperties source = makeLinkPropertiesForParceling();
- assertParcelSane(source, 14 /* fieldCount */);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testLinkPropertiesParcelable() throws Exception {
- final LinkProperties source = makeLinkPropertiesForParceling();
-
- source.setWakeOnLanSupported(true);
- source.setCaptivePortalApiUrl(CAPPORT_API_URL);
- source.setCaptivePortalData((CaptivePortalData) getCaptivePortalData());
- source.setDhcpServerAddress((Inet4Address) GATEWAY1);
- assertParcelSane(new LinkProperties(source, true /* parcelSensitiveFields */),
- 18 /* fieldCount */);
-
- // Verify that without using a sensitiveFieldsParcelingCopy, sensitive fields are cleared.
- final LinkProperties sanitized = new LinkProperties(source);
- sanitized.setCaptivePortalApiUrl(null);
- sanitized.setCaptivePortalData(null);
- assertEquals(sanitized, parcelingRoundTrip(source));
- }
-
- // Parceling of the scope was broken until Q-QPR2
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testLinkLocalDnsServerParceling() throws Exception {
- final String strAddress = "fe80::1%lo";
- final LinkProperties lp = new LinkProperties();
- lp.addDnsServer(address(strAddress));
- final LinkProperties unparceled = parcelingRoundTrip(lp);
- // Inet6Address#equals does not test for the scope id
- assertEquals(strAddress, unparceled.getDnsServers().get(0).getHostAddress());
- }
-
- @Test
- public void testParcelUninitialized() throws Exception {
- LinkProperties empty = new LinkProperties();
- assertParcelingIsLossless(empty);
- }
-
- @Test
- public void testConstructor() {
- LinkProperties lp = new LinkProperties();
- checkEmpty(lp);
- assertLinkPropertiesEqual(lp, new LinkProperties(lp));
- assertLinkPropertiesEqual(lp, new LinkProperties());
-
- lp = makeTestObject();
- assertLinkPropertiesEqual(lp, new LinkProperties(lp));
- }
-
- @Test
- public void testDnsServers() {
- final LinkProperties lp = new LinkProperties();
- final List<InetAddress> dnsServers = Arrays.asList(DNS1, DNS2);
- lp.setDnsServers(dnsServers);
- assertEquals(2, lp.getDnsServers().size());
- assertEquals(DNS1, lp.getDnsServers().get(0));
- assertEquals(DNS2, lp.getDnsServers().get(1));
-
- lp.removeDnsServer(DNS1);
- assertEquals(1, lp.getDnsServers().size());
- assertEquals(DNS2, lp.getDnsServers().get(0));
-
- lp.addDnsServer(DNS6);
- assertEquals(2, lp.getDnsServers().size());
- assertEquals(DNS2, lp.getDnsServers().get(0));
- assertEquals(DNS6, lp.getDnsServers().get(1));
- }
-
- @Test
- public void testValidatedPrivateDnsServers() {
- final LinkProperties lp = new LinkProperties();
- final List<InetAddress> privDnsServers = Arrays.asList(PRIVDNS1, PRIVDNS2);
- lp.setValidatedPrivateDnsServers(privDnsServers);
- assertEquals(2, lp.getValidatedPrivateDnsServers().size());
- assertEquals(PRIVDNS1, lp.getValidatedPrivateDnsServers().get(0));
- assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(1));
-
- lp.removeValidatedPrivateDnsServer(PRIVDNS1);
- assertEquals(1, lp.getValidatedPrivateDnsServers().size());
- assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(0));
-
- lp.addValidatedPrivateDnsServer(PRIVDNS6);
- assertEquals(2, lp.getValidatedPrivateDnsServers().size());
- assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(0));
- assertEquals(PRIVDNS6, lp.getValidatedPrivateDnsServers().get(1));
- }
-
- @Test
- public void testPcscfServers() {
- final LinkProperties lp = new LinkProperties();
- final List<InetAddress> pcscfServers = Arrays.asList(PCSCFV4);
- lp.setPcscfServers(pcscfServers);
- assertEquals(1, lp.getPcscfServers().size());
- assertEquals(PCSCFV4, lp.getPcscfServers().get(0));
-
- lp.removePcscfServer(PCSCFV4);
- assertEquals(0, lp.getPcscfServers().size());
-
- lp.addPcscfServer(PCSCFV6);
- assertEquals(1, lp.getPcscfServers().size());
- assertEquals(PCSCFV6, lp.getPcscfServers().get(0));
- }
-
- @Test
- public void testTcpBufferSizes() {
- final LinkProperties lp = makeTestObject();
- assertEquals(TCP_BUFFER_SIZES, lp.getTcpBufferSizes());
-
- lp.setTcpBufferSizes(null);
- assertNull(lp.getTcpBufferSizes());
- }
-
- @Test
- public void testHasIpv6DefaultRoute() {
- final LinkProperties lp = makeTestObject();
- assertFalse(lp.hasIPv6DefaultRoute());
-
- lp.addRoute(new RouteInfo(GATEWAY61));
- assertTrue(lp.hasIPv6DefaultRoute());
- }
-
- @Test
- public void testHttpProxy() {
- final LinkProperties lp = makeTestObject();
- assertTrue(lp.getHttpProxy().equals(ProxyInfo.buildDirectProxy("test", 8888)));
- }
-
- @Test
- public void testPrivateDnsServerName() {
- final LinkProperties lp = makeTestObject();
- assertEquals(PRIV_DNS_SERVER_NAME, lp.getPrivateDnsServerName());
-
- lp.setPrivateDnsServerName(null);
- assertNull(lp.getPrivateDnsServerName());
- }
-
- @Test
- public void testUsePrivateDns() {
- final LinkProperties lp = makeTestObject();
- assertTrue(lp.isPrivateDnsActive());
-
- lp.clear();
- assertFalse(lp.isPrivateDnsActive());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testDhcpServerAddress() {
- final LinkProperties lp = makeTestObject();
- assertEquals(DHCPSERVER, lp.getDhcpServerAddress());
-
- lp.clear();
- assertNull(lp.getDhcpServerAddress());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testWakeOnLanSupported() {
- final LinkProperties lp = makeTestObject();
- assertTrue(lp.isWakeOnLanSupported());
-
- lp.clear();
- assertFalse(lp.isWakeOnLanSupported());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testCaptivePortalApiUrl() {
- final LinkProperties lp = makeTestObject();
- assertEquals(CAPPORT_API_URL, lp.getCaptivePortalApiUrl());
-
- lp.clear();
- assertNull(lp.getCaptivePortalApiUrl());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testCaptivePortalData() {
- final LinkProperties lp = makeTestObject();
- assertEquals(getCaptivePortalData(), lp.getCaptivePortalData());
-
- lp.clear();
- assertNull(lp.getCaptivePortalData());
- }
-
- private LinkProperties makeIpv4LinkProperties() {
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setInterfaceName(NAME);
- linkProperties.addLinkAddress(LINKADDRV4);
- linkProperties.addDnsServer(DNS1);
- linkProperties.addRoute(new RouteInfo(GATEWAY1));
- linkProperties.addRoute(new RouteInfo(GATEWAY2));
- return linkProperties;
- }
-
- private LinkProperties makeIpv6LinkProperties() {
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setInterfaceName(NAME);
- linkProperties.addLinkAddress(LINKADDRV6);
- linkProperties.addDnsServer(DNS6);
- linkProperties.addRoute(new RouteInfo(GATEWAY61));
- linkProperties.addRoute(new RouteInfo(GATEWAY62));
- return linkProperties;
- }
-
- @Test
- public void testHasIpv4DefaultRoute() {
- final LinkProperties Ipv4 = makeIpv4LinkProperties();
- assertTrue(Ipv4.hasIpv4DefaultRoute());
- final LinkProperties Ipv6 = makeIpv6LinkProperties();
- assertFalse(Ipv6.hasIpv4DefaultRoute());
- }
-
- @Test
- public void testHasIpv4DnsServer() {
- final LinkProperties Ipv4 = makeIpv4LinkProperties();
- assertTrue(Ipv4.hasIpv4DnsServer());
- final LinkProperties Ipv6 = makeIpv6LinkProperties();
- assertFalse(Ipv6.hasIpv4DnsServer());
- }
-
- @Test
- public void testHasIpv6DnsServer() {
- final LinkProperties Ipv4 = makeIpv4LinkProperties();
- assertFalse(Ipv4.hasIpv6DnsServer());
- final LinkProperties Ipv6 = makeIpv6LinkProperties();
- assertTrue(Ipv6.hasIpv6DnsServer());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testHasIpv4UnreachableDefaultRoute() {
- final LinkProperties lp = makeTestObject();
- assertFalse(lp.hasIpv4UnreachableDefaultRoute());
- assertFalse(lp.hasIpv6UnreachableDefaultRoute());
-
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
- assertTrue(lp.hasIpv4UnreachableDefaultRoute());
- assertFalse(lp.hasIpv6UnreachableDefaultRoute());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testHasIpv6UnreachableDefaultRoute() {
- final LinkProperties lp = makeTestObject();
- assertFalse(lp.hasIpv6UnreachableDefaultRoute());
- assertFalse(lp.hasIpv4UnreachableDefaultRoute());
-
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
- assertTrue(lp.hasIpv6UnreachableDefaultRoute());
- assertFalse(lp.hasIpv4UnreachableDefaultRoute());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testRouteAddWithSameKey() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("wlan0");
- final IpPrefix v6 = new IpPrefix("64:ff9b::/96");
- lp.addRoute(new RouteInfo(v6, address("fe80::1"), "wlan0", RTN_UNICAST, 1280));
- assertEquals(1, lp.getRoutes().size());
- lp.addRoute(new RouteInfo(v6, address("fe80::1"), "wlan0", RTN_UNICAST, 1500));
- assertEquals(1, lp.getRoutes().size());
- final IpPrefix v4 = new IpPrefix("192.0.2.128/25");
- lp.addRoute(new RouteInfo(v4, address("192.0.2.1"), "wlan0", RTN_UNICAST, 1460));
- assertEquals(2, lp.getRoutes().size());
- lp.addRoute(new RouteInfo(v4, address("192.0.2.1"), "wlan0", RTN_THROW, 1460));
- assertEquals(2, lp.getRoutes().size());
- }
-}
diff --git a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
deleted file mode 100644
index ef15b668e24c..000000000000
--- a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net
-
-import android.net.wifi.aware.DiscoverySession
-import android.net.wifi.aware.PeerHandle
-import android.net.wifi.aware.WifiAwareNetworkSpecifier
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-
-import com.android.testutils.assertParcelSane
-
-import java.lang.IllegalStateException
-
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class MatchAllNetworkSpecifierTest {
- @Test
- fun testParcel() {
- assertParcelSane(MatchAllNetworkSpecifier(), 0)
- }
-
- @Test(expected = IllegalStateException::class)
- fun testSatisfiedBy() {
- val specifier = MatchAllNetworkSpecifier()
- val discoverySession = Mockito.mock(DiscoverySession::class.java)
- val peerHandle = Mockito.mock(PeerHandle::class.java)
- val wifiAwareNetworkSpecifier = WifiAwareNetworkSpecifier.Builder(discoverySession,
- peerHandle).build()
- specifier.satisfiedBy(wifiAwareNetworkSpecifier)
- }
-}
diff --git a/tests/net/common/java/android/net/NattKeepalivePacketDataTest.kt b/tests/net/common/java/android/net/NattKeepalivePacketDataTest.kt
deleted file mode 100644
index 46f39dd016fd..000000000000
--- a/tests/net/common/java/android/net/NattKeepalivePacketDataTest.kt
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net
-
-import android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS
-import android.net.InvalidPacketException.ERROR_INVALID_PORT
-import android.net.NattSocketKeepalive.NATT_PORT
-import android.os.Build
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertEqualBothWays
-import com.android.testutils.assertFieldCountEquals
-import com.android.testutils.assertParcelSane
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import com.android.testutils.parcelingRoundTrip
-import java.net.InetAddress
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNotEquals
-import org.junit.Assert.fail
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class NattKeepalivePacketDataTest {
- @Rule @JvmField
- val ignoreRule: DevSdkIgnoreRule = DevSdkIgnoreRule()
-
- /* Refer to the definition in {@code NattKeepalivePacketData} */
- private val IPV4_HEADER_LENGTH = 20
- private val UDP_HEADER_LENGTH = 8
-
- private val TEST_PORT = 4243
- private val TEST_PORT2 = 4244
- private val TEST_SRC_ADDRV4 = "198.168.0.2".address()
- private val TEST_DST_ADDRV4 = "198.168.0.1".address()
- private val TEST_ADDRV6 = "2001:db8::1".address()
-
- private fun String.address() = InetAddresses.parseNumericAddress(this)
- private fun nattKeepalivePacket(
- srcAddress: InetAddress? = TEST_SRC_ADDRV4,
- srcPort: Int = TEST_PORT,
- dstAddress: InetAddress? = TEST_DST_ADDRV4,
- dstPort: Int = NATT_PORT
- ) = NattKeepalivePacketData.nattKeepalivePacket(srcAddress, srcPort, dstAddress, dstPort)
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testConstructor() {
- try {
- nattKeepalivePacket(dstPort = TEST_PORT)
- fail("Dst port is not NATT port should cause exception")
- } catch (e: InvalidPacketException) {
- assertEquals(e.error, ERROR_INVALID_PORT)
- }
-
- try {
- nattKeepalivePacket(srcAddress = TEST_ADDRV6)
- fail("A v6 srcAddress should cause exception")
- } catch (e: InvalidPacketException) {
- assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
- }
-
- try {
- nattKeepalivePacket(dstAddress = TEST_ADDRV6)
- fail("A v6 dstAddress should cause exception")
- } catch (e: InvalidPacketException) {
- assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
- }
-
- try {
- parcelingRoundTrip(
- NattKeepalivePacketData(TEST_SRC_ADDRV4, TEST_PORT, TEST_DST_ADDRV4, TEST_PORT,
- byteArrayOf(12, 31, 22, 44)))
- fail("Invalid data should cause exception")
- } catch (e: IllegalArgumentException) { }
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testParcel() {
- assertParcelSane(nattKeepalivePacket(), 0)
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testEquals() {
- assertEqualBothWays(nattKeepalivePacket(), nattKeepalivePacket())
- assertNotEquals(nattKeepalivePacket(dstAddress = TEST_SRC_ADDRV4), nattKeepalivePacket())
- assertNotEquals(nattKeepalivePacket(srcAddress = TEST_DST_ADDRV4), nattKeepalivePacket())
- // Test src port only because dst port have to be NATT_PORT
- assertNotEquals(nattKeepalivePacket(srcPort = TEST_PORT2), nattKeepalivePacket())
- // Make sure the parceling test is updated if fields are added in the base class.
- assertFieldCountEquals(5, KeepalivePacketData::class.java)
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testHashCode() {
- assertEquals(nattKeepalivePacket().hashCode(), nattKeepalivePacket().hashCode())
- }
-} \ No newline at end of file
diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
deleted file mode 100644
index a4d8353d1253..000000000000
--- a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net
-
-import android.os.Build
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class NetworkAgentConfigTest {
- @Rule @JvmField
- val ignoreRule = DevSdkIgnoreRule()
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testParcelNetworkAgentConfig() {
- val config = NetworkAgentConfig.Builder().apply {
- setExplicitlySelected(true)
- setLegacyType(ConnectivityManager.TYPE_ETHERNET)
- setSubscriberId("MySubId")
- setPartialConnectivityAcceptable(false)
- setUnvalidatedConnectivityAcceptable(true)
- }.build()
- assertParcelSane(config, 10)
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testBuilder() {
- val config = NetworkAgentConfig.Builder().apply {
- setExplicitlySelected(true)
- setLegacyType(ConnectivityManager.TYPE_ETHERNET)
- setSubscriberId("MySubId")
- setPartialConnectivityAcceptable(false)
- setUnvalidatedConnectivityAcceptable(true)
- setLegacyTypeName("TEST_NETWORK")
- disableNat64Detection()
- disableProvisioningNotification()
- }.build()
-
- assertTrue(config.isExplicitlySelected())
- assertEquals(ConnectivityManager.TYPE_ETHERNET, config.getLegacyType())
- assertEquals("MySubId", config.getSubscriberId())
- assertFalse(config.isPartialConnectivityAcceptable())
- assertTrue(config.isUnvalidatedConnectivityAcceptable())
- assertEquals("TEST_NETWORK", config.getLegacyTypeName())
- assertFalse(config.isNat64DetectionEnabled())
- assertFalse(config.isProvisioningNotificationEnabled())
- }
-}
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
deleted file mode 100644
index 3f8261d5ad7f..000000000000
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ /dev/null
@@ -1,935 +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 android.net;
-
-import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
-import static android.net.NetworkCapabilities.MAX_TRANSPORT;
-import static android.net.NetworkCapabilities.MIN_TRANSPORT;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
-import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
-import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_TEST;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
-import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
-
-import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
-import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.wifi.aware.DiscoverySession;
-import android.net.wifi.aware.PeerHandle;
-import android.net.wifi.aware.WifiAwareNetworkSpecifier;
-import android.os.Build;
-import android.os.Process;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.ArraySet;
-
-import androidx.core.os.BuildCompat;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-
-import java.util.Arrays;
-import java.util.Set;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkCapabilitiesTest {
- private static final String TEST_SSID = "TEST_SSID";
- private static final String DIFFERENT_TEST_SSID = "DIFFERENT_TEST_SSID";
-
- @Rule
- public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule();
-
- private DiscoverySession mDiscoverySession = Mockito.mock(DiscoverySession.class);
- private PeerHandle mPeerHandle = Mockito.mock(PeerHandle.class);
-
- private boolean isAtLeastR() {
- // BuildCompat.isAtLeastR() is used to check the Android version before releasing Android R.
- // Build.VERSION.SDK_INT > Build.VERSION_CODES.Q is used to check the Android version after
- // releasing Android R.
- return BuildCompat.isAtLeastR() || Build.VERSION.SDK_INT > Build.VERSION_CODES.Q;
- }
-
- @Test
- public void testMaybeMarkCapabilitiesRestricted() {
- // verify EIMS is restricted
- assertEquals((1 << NET_CAPABILITY_EIMS) & RESTRICTED_CAPABILITIES,
- (1 << NET_CAPABILITY_EIMS));
-
- // verify CBS is also restricted
- assertEquals((1 << NET_CAPABILITY_CBS) & RESTRICTED_CAPABILITIES,
- (1 << NET_CAPABILITY_CBS));
-
- // verify default is not restricted
- assertEquals((1 << NET_CAPABILITY_INTERNET) & RESTRICTED_CAPABILITIES, 0);
-
- // just to see
- assertEquals(RESTRICTED_CAPABILITIES & UNRESTRICTED_CAPABILITIES, 0);
-
- // check that internet does not get restricted
- NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.maybeMarkCapabilitiesRestricted();
- assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // metered-ness shouldn't matter
- netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.addCapability(NET_CAPABILITY_NOT_METERED);
- netCap.maybeMarkCapabilitiesRestricted();
- assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
- netCap.maybeMarkCapabilitiesRestricted();
- assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // add EIMS - bundled with unrestricted means it's unrestricted
- netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.addCapability(NET_CAPABILITY_EIMS);
- netCap.addCapability(NET_CAPABILITY_NOT_METERED);
- netCap.maybeMarkCapabilitiesRestricted();
- assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.addCapability(NET_CAPABILITY_EIMS);
- netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
- netCap.maybeMarkCapabilitiesRestricted();
- assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // just a restricted cap should be restricted regardless of meteredness
- netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_EIMS);
- netCap.addCapability(NET_CAPABILITY_NOT_METERED);
- netCap.maybeMarkCapabilitiesRestricted();
- assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_EIMS);
- netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
- netCap.maybeMarkCapabilitiesRestricted();
- assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // try 2 restricted caps
- netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_CBS);
- netCap.addCapability(NET_CAPABILITY_EIMS);
- netCap.addCapability(NET_CAPABILITY_NOT_METERED);
- netCap.maybeMarkCapabilitiesRestricted();
- assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_CBS);
- netCap.addCapability(NET_CAPABILITY_EIMS);
- netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
- netCap.maybeMarkCapabilitiesRestricted();
- assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- }
-
- @Test
- public void testDescribeImmutableDifferences() {
- NetworkCapabilities nc1;
- NetworkCapabilities nc2;
-
- // Transports changing
- nc1 = new NetworkCapabilities().addTransportType(TRANSPORT_CELLULAR);
- nc2 = new NetworkCapabilities().addTransportType(TRANSPORT_WIFI);
- assertNotEquals("", nc1.describeImmutableDifferences(nc2));
- assertEquals("", nc1.describeImmutableDifferences(nc1));
-
- // Mutable capability changing
- nc1 = new NetworkCapabilities().addCapability(NET_CAPABILITY_VALIDATED);
- nc2 = new NetworkCapabilities();
- assertEquals("", nc1.describeImmutableDifferences(nc2));
- assertEquals("", nc1.describeImmutableDifferences(nc1));
-
- // NOT_METERED changing (http://b/63326103)
- nc1 = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_NOT_METERED)
- .addCapability(NET_CAPABILITY_INTERNET);
- nc2 = new NetworkCapabilities().addCapability(NET_CAPABILITY_INTERNET);
- assertEquals("", nc1.describeImmutableDifferences(nc2));
- assertEquals("", nc1.describeImmutableDifferences(nc1));
-
- // Immutable capability changing
- nc1 = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- nc2 = new NetworkCapabilities().addCapability(NET_CAPABILITY_INTERNET);
- assertNotEquals("", nc1.describeImmutableDifferences(nc2));
- assertEquals("", nc1.describeImmutableDifferences(nc1));
-
- // Specifier changing
- nc1 = new NetworkCapabilities().addTransportType(TRANSPORT_WIFI);
- nc2 = new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .setNetworkSpecifier(new StringNetworkSpecifier("specs"));
- assertNotEquals("", nc1.describeImmutableDifferences(nc2));
- assertEquals("", nc1.describeImmutableDifferences(nc1));
- }
-
- @Test
- public void testLinkBandwidthUtils() {
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, NetworkCapabilities
- .minBandwidth(LINK_BANDWIDTH_UNSPECIFIED, LINK_BANDWIDTH_UNSPECIFIED));
- assertEquals(10, NetworkCapabilities
- .minBandwidth(LINK_BANDWIDTH_UNSPECIFIED, 10));
- assertEquals(10, NetworkCapabilities
- .minBandwidth(10, LINK_BANDWIDTH_UNSPECIFIED));
- assertEquals(10, NetworkCapabilities
- .minBandwidth(10, 20));
-
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, NetworkCapabilities
- .maxBandwidth(LINK_BANDWIDTH_UNSPECIFIED, LINK_BANDWIDTH_UNSPECIFIED));
- assertEquals(10, NetworkCapabilities
- .maxBandwidth(LINK_BANDWIDTH_UNSPECIFIED, 10));
- assertEquals(10, NetworkCapabilities
- .maxBandwidth(10, LINK_BANDWIDTH_UNSPECIFIED));
- assertEquals(20, NetworkCapabilities
- .maxBandwidth(10, 20));
- }
-
- @Test
- public void testSetUids() {
- final NetworkCapabilities netCap = new NetworkCapabilities();
- final Set<UidRange> uids = new ArraySet<>();
- uids.add(new UidRange(50, 100));
- uids.add(new UidRange(3000, 4000));
- netCap.setUids(uids);
- assertTrue(netCap.appliesToUid(50));
- assertTrue(netCap.appliesToUid(80));
- assertTrue(netCap.appliesToUid(100));
- assertTrue(netCap.appliesToUid(3000));
- assertTrue(netCap.appliesToUid(3001));
- assertFalse(netCap.appliesToUid(10));
- assertFalse(netCap.appliesToUid(25));
- assertFalse(netCap.appliesToUid(49));
- assertFalse(netCap.appliesToUid(101));
- assertFalse(netCap.appliesToUid(2000));
- assertFalse(netCap.appliesToUid(100000));
-
- assertTrue(netCap.appliesToUidRange(new UidRange(50, 100)));
- assertTrue(netCap.appliesToUidRange(new UidRange(70, 72)));
- assertTrue(netCap.appliesToUidRange(new UidRange(3500, 3912)));
- assertFalse(netCap.appliesToUidRange(new UidRange(1, 100)));
- assertFalse(netCap.appliesToUidRange(new UidRange(49, 100)));
- assertFalse(netCap.appliesToUidRange(new UidRange(1, 10)));
- assertFalse(netCap.appliesToUidRange(new UidRange(60, 101)));
- assertFalse(netCap.appliesToUidRange(new UidRange(60, 3400)));
-
- NetworkCapabilities netCap2 = new NetworkCapabilities();
- // A new netcap object has null UIDs, so anything will satisfy it.
- assertTrue(netCap2.satisfiedByUids(netCap));
- // Still not equal though.
- assertFalse(netCap2.equalsUids(netCap));
- netCap2.setUids(uids);
- assertTrue(netCap2.satisfiedByUids(netCap));
- assertTrue(netCap.equalsUids(netCap2));
- assertTrue(netCap2.equalsUids(netCap));
-
- uids.add(new UidRange(600, 700));
- netCap2.setUids(uids);
- assertFalse(netCap2.satisfiedByUids(netCap));
- assertFalse(netCap.appliesToUid(650));
- assertTrue(netCap2.appliesToUid(650));
- netCap.combineCapabilities(netCap2);
- assertTrue(netCap2.satisfiedByUids(netCap));
- assertTrue(netCap.appliesToUid(650));
- assertFalse(netCap.appliesToUid(500));
-
- assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
- netCap.combineCapabilities(new NetworkCapabilities());
- assertTrue(netCap.appliesToUid(500));
- assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000)));
- assertFalse(netCap2.appliesToUid(500));
- assertFalse(netCap2.appliesToUidRange(new UidRange(1, 100000)));
- assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
- }
-
- @Test
- public void testParcelNetworkCapabilities() {
- final Set<UidRange> uids = new ArraySet<>();
- uids.add(new UidRange(50, 100));
- uids.add(new UidRange(3000, 4000));
- final NetworkCapabilities netCap = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .setUids(uids)
- .addCapability(NET_CAPABILITY_EIMS)
- .addCapability(NET_CAPABILITY_NOT_METERED);
- if (isAtLeastR()) {
- netCap.setOwnerUid(123);
- netCap.setAdministratorUids(new int[] {5, 11});
- }
- assertParcelingIsLossless(netCap);
- netCap.setSSID(TEST_SSID);
- testParcelSane(netCap);
- }
-
- @Test
- public void testParcelNetworkCapabilitiesWithRequestorUidAndPackageName() {
- final NetworkCapabilities netCap = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_EIMS)
- .addCapability(NET_CAPABILITY_NOT_METERED);
- if (isAtLeastR()) {
- netCap.setRequestorPackageName("com.android.test");
- netCap.setRequestorUid(9304);
- }
- assertParcelingIsLossless(netCap);
- netCap.setSSID(TEST_SSID);
- testParcelSane(netCap);
- }
-
- private void testParcelSane(NetworkCapabilities cap) {
- if (isAtLeastR()) {
- assertParcelSane(cap, 15);
- } else {
- assertParcelSane(cap, 11);
- }
- }
-
- @Test
- public void testOemPaid() {
- NetworkCapabilities nc = new NetworkCapabilities();
- // By default OEM_PAID is neither in the unwanted or required lists and the network is not
- // restricted.
- assertFalse(nc.hasUnwantedCapability(NET_CAPABILITY_OEM_PAID));
- assertFalse(nc.hasCapability(NET_CAPABILITY_OEM_PAID));
- nc.maybeMarkCapabilitiesRestricted();
- assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // Adding OEM_PAID to capability list should make network restricted.
- nc.addCapability(NET_CAPABILITY_OEM_PAID);
- nc.addCapability(NET_CAPABILITY_INTERNET); // Combine with unrestricted capability.
- nc.maybeMarkCapabilitiesRestricted();
- assertTrue(nc.hasCapability(NET_CAPABILITY_OEM_PAID));
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // Now let's make request for OEM_PAID network.
- NetworkCapabilities nr = new NetworkCapabilities();
- nr.addCapability(NET_CAPABILITY_OEM_PAID);
- nr.maybeMarkCapabilitiesRestricted();
- assertTrue(nr.satisfiedByNetworkCapabilities(nc));
-
- // Request fails for network with the default capabilities.
- assertFalse(nr.satisfiedByNetworkCapabilities(new NetworkCapabilities()));
- }
-
- @Test
- public void testUnwantedCapabilities() {
- NetworkCapabilities network = new NetworkCapabilities();
-
- NetworkCapabilities request = new NetworkCapabilities();
- assertTrue("Request: " + request + ", Network:" + network,
- request.satisfiedByNetworkCapabilities(network));
-
- // Requesting absence of capabilities that network doesn't have. Request should satisfy.
- request.addUnwantedCapability(NET_CAPABILITY_WIFI_P2P);
- request.addUnwantedCapability(NET_CAPABILITY_NOT_METERED);
- assertTrue(request.satisfiedByNetworkCapabilities(network));
- assertArrayEquals(new int[] {NET_CAPABILITY_WIFI_P2P,
- NET_CAPABILITY_NOT_METERED},
- request.getUnwantedCapabilities());
-
- // This is a default capability, just want to make sure its there because we use it below.
- assertTrue(network.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // Verify that adding unwanted capability will effectively remove it from capability list.
- request.addUnwantedCapability(NET_CAPABILITY_NOT_RESTRICTED);
- assertTrue(request.hasUnwantedCapability(NET_CAPABILITY_NOT_RESTRICTED));
- assertFalse(request.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // Now this request won't be satisfied because network contains NOT_RESTRICTED.
- assertFalse(request.satisfiedByNetworkCapabilities(network));
- network.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- assertTrue(request.satisfiedByNetworkCapabilities(network));
-
- // Verify that adding capability will effectively remove it from unwanted list
- request.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
- assertTrue(request.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- assertFalse(request.hasUnwantedCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- assertFalse(request.satisfiedByNetworkCapabilities(network));
- network.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
- assertTrue(request.satisfiedByNetworkCapabilities(network));
- }
-
- @Test
- public void testConnectivityManagedCapabilities() {
- NetworkCapabilities nc = new NetworkCapabilities();
- assertFalse(nc.hasConnectivityManagedCapability());
- // Check every single system managed capability.
- nc.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
- assertTrue(nc.hasConnectivityManagedCapability());
- nc.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
- nc.addCapability(NET_CAPABILITY_FOREGROUND);
- assertTrue(nc.hasConnectivityManagedCapability());
- nc.removeCapability(NET_CAPABILITY_FOREGROUND);
- nc.addCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY);
- assertTrue(nc.hasConnectivityManagedCapability());
- nc.removeCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY);
- nc.addCapability(NET_CAPABILITY_VALIDATED);
- assertTrue(nc.hasConnectivityManagedCapability());
- }
-
- @Test
- public void testEqualsNetCapabilities() {
- NetworkCapabilities nc1 = new NetworkCapabilities();
- NetworkCapabilities nc2 = new NetworkCapabilities();
- assertTrue(nc1.equalsNetCapabilities(nc2));
- assertEquals(nc1, nc2);
-
- nc1.addCapability(NET_CAPABILITY_MMS);
- assertFalse(nc1.equalsNetCapabilities(nc2));
- assertNotEquals(nc1, nc2);
- nc2.addCapability(NET_CAPABILITY_MMS);
- assertTrue(nc1.equalsNetCapabilities(nc2));
- assertEquals(nc1, nc2);
-
- nc1.addUnwantedCapability(NET_CAPABILITY_INTERNET);
- assertFalse(nc1.equalsNetCapabilities(nc2));
- nc2.addUnwantedCapability(NET_CAPABILITY_INTERNET);
- assertTrue(nc1.equalsNetCapabilities(nc2));
-
- nc1.removeCapability(NET_CAPABILITY_INTERNET);
- assertFalse(nc1.equalsNetCapabilities(nc2));
- nc2.removeCapability(NET_CAPABILITY_INTERNET);
- assertTrue(nc1.equalsNetCapabilities(nc2));
- }
-
- @Test
- public void testSSID() {
- NetworkCapabilities nc1 = new NetworkCapabilities();
- NetworkCapabilities nc2 = new NetworkCapabilities();
- assertTrue(nc2.satisfiedBySSID(nc1));
-
- nc1.setSSID(TEST_SSID);
- assertTrue(nc2.satisfiedBySSID(nc1));
- nc2.setSSID("different " + TEST_SSID);
- assertFalse(nc2.satisfiedBySSID(nc1));
-
- assertTrue(nc1.satisfiedByImmutableNetworkCapabilities(nc2));
- assertFalse(nc1.satisfiedByNetworkCapabilities(nc2));
- }
-
- private ArraySet<UidRange> uidRange(int from, int to) {
- final ArraySet<UidRange> range = new ArraySet<>(1);
- range.add(new UidRange(from, to));
- return range;
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testSetAdministratorUids() {
- NetworkCapabilities nc =
- new NetworkCapabilities().setAdministratorUids(new int[] {2, 1, 3});
-
- assertArrayEquals(new int[] {1, 2, 3}, nc.getAdministratorUids());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testSetAdministratorUidsWithDuplicates() {
- try {
- new NetworkCapabilities().setAdministratorUids(new int[] {1, 1});
- fail("Expected IllegalArgumentException for duplicate uids");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testCombineCapabilities() {
- NetworkCapabilities nc1 = new NetworkCapabilities();
- NetworkCapabilities nc2 = new NetworkCapabilities();
-
- nc1.addUnwantedCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
- nc1.addCapability(NET_CAPABILITY_NOT_ROAMING);
- assertNotEquals(nc1, nc2);
- nc2.combineCapabilities(nc1);
- assertEquals(nc1, nc2);
- assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_CAPTIVE_PORTAL));
-
- // This will effectively move NOT_ROAMING capability from required to unwanted for nc1.
- nc1.addUnwantedCapability(NET_CAPABILITY_NOT_ROAMING);
-
- nc2.combineCapabilities(nc1);
- // We will get this capability in both requested and unwanted lists thus this request
- // will never be satisfied.
- assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
-
- nc1.setSSID(TEST_SSID);
- nc2.combineCapabilities(nc1);
- if (isAtLeastR()) {
- assertTrue(TEST_SSID.equals(nc2.getSsid()));
- }
-
- // Because they now have the same SSID, the following call should not throw
- nc2.combineCapabilities(nc1);
-
- nc1.setSSID(DIFFERENT_TEST_SSID);
- try {
- nc2.combineCapabilities(nc1);
- fail("Expected IllegalStateException: can't combine different SSIDs");
- } catch (IllegalStateException expected) {}
- nc1.setSSID(TEST_SSID);
-
- nc1.setUids(uidRange(10, 13));
- assertNotEquals(nc1, nc2);
- nc2.combineCapabilities(nc1); // Everything + 10~13 is still everything.
- assertNotEquals(nc1, nc2);
- nc1.combineCapabilities(nc2); // 10~13 + everything is everything.
- assertEquals(nc1, nc2);
- nc1.setUids(uidRange(10, 13));
- nc2.setUids(uidRange(20, 23));
- assertNotEquals(nc1, nc2);
- nc1.combineCapabilities(nc2);
- assertTrue(nc1.appliesToUid(12));
- assertFalse(nc2.appliesToUid(12));
- assertTrue(nc1.appliesToUid(22));
- assertTrue(nc2.appliesToUid(22));
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testCombineCapabilities_AdministratorUids() {
- final NetworkCapabilities nc1 = new NetworkCapabilities();
- final NetworkCapabilities nc2 = new NetworkCapabilities();
-
- final int[] adminUids = {3, 6, 12};
- nc1.setAdministratorUids(adminUids);
- nc2.combineCapabilities(nc1);
- assertTrue(nc2.equalsAdministratorUids(nc1));
- assertArrayEquals(nc2.getAdministratorUids(), adminUids);
-
- final int[] adminUidsOtherOrder = {3, 12, 6};
- nc1.setAdministratorUids(adminUidsOtherOrder);
- assertTrue(nc2.equalsAdministratorUids(nc1));
-
- final int[] adminUids2 = {11, 1, 12, 3, 6};
- nc1.setAdministratorUids(adminUids2);
- assertFalse(nc2.equalsAdministratorUids(nc1));
- assertFalse(Arrays.equals(nc2.getAdministratorUids(), adminUids2));
- try {
- nc2.combineCapabilities(nc1);
- fail("Shouldn't be able to combine different lists of admin UIDs");
- } catch (IllegalStateException expected) { }
- }
-
- @Test
- public void testSetCapabilities() {
- final int[] REQUIRED_CAPABILITIES = new int[] {
- NET_CAPABILITY_INTERNET, NET_CAPABILITY_NOT_VPN };
- final int[] UNWANTED_CAPABILITIES = new int[] {
- NET_CAPABILITY_NOT_RESTRICTED, NET_CAPABILITY_NOT_METERED
- };
-
- NetworkCapabilities nc1 = new NetworkCapabilities();
- NetworkCapabilities nc2 = new NetworkCapabilities();
-
- nc1.setCapabilities(REQUIRED_CAPABILITIES, UNWANTED_CAPABILITIES);
- assertArrayEquals(REQUIRED_CAPABILITIES, nc1.getCapabilities());
-
- // Verify that setting and adding capabilities leads to the same object state.
- nc2.clearAll();
- for (int cap : REQUIRED_CAPABILITIES) {
- nc2.addCapability(cap);
- }
- for (int cap : UNWANTED_CAPABILITIES) {
- nc2.addUnwantedCapability(cap);
- }
- assertEquals(nc1, nc2);
- }
-
- @Test
- public void testSetNetworkSpecifierOnMultiTransportNc() {
- // Sequence 1: Transport + Transport + NetworkSpecifier
- NetworkCapabilities nc1 = new NetworkCapabilities();
- nc1.addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI);
- try {
- nc1.setNetworkSpecifier(new StringNetworkSpecifier("specs"));
- fail("Cannot set NetworkSpecifier on a NetworkCapability with multiple transports!");
- } catch (IllegalStateException expected) {
- // empty
- }
-
- // Sequence 2: Transport + NetworkSpecifier + Transport
- NetworkCapabilities nc2 = new NetworkCapabilities();
- nc2.addTransportType(TRANSPORT_CELLULAR).setNetworkSpecifier(
- new StringNetworkSpecifier("specs"));
- try {
- nc2.addTransportType(TRANSPORT_WIFI);
- fail("Cannot set a second TransportType of a network which has a NetworkSpecifier!");
- } catch (IllegalStateException expected) {
- // empty
- }
- }
-
- @Test
- public void testSetTransportInfoOnMultiTransportNc() {
- // Sequence 1: Transport + Transport + TransportInfo
- NetworkCapabilities nc1 = new NetworkCapabilities();
- nc1.addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI)
- .setTransportInfo(new TransportInfo() {});
-
- // Sequence 2: Transport + NetworkSpecifier + Transport
- NetworkCapabilities nc2 = new NetworkCapabilities();
- nc2.addTransportType(TRANSPORT_CELLULAR).setTransportInfo(new TransportInfo() {})
- .addTransportType(TRANSPORT_WIFI);
- }
-
- @Test
- public void testCombineTransportInfo() {
- NetworkCapabilities nc1 = new NetworkCapabilities();
- nc1.setTransportInfo(new TransportInfo() {
- // empty
- });
- NetworkCapabilities nc2 = new NetworkCapabilities();
- // new TransportInfo so that object is not #equals to nc1's TransportInfo (that's where
- // combine fails)
- nc2.setTransportInfo(new TransportInfo() {
- // empty
- });
-
- try {
- nc1.combineCapabilities(nc2);
- fail("Should not be able to combine NetworkCabilities which contain TransportInfos");
- } catch (IllegalStateException expected) {
- // empty
- }
-
- // verify that can combine with identical TransportInfo objects
- NetworkCapabilities nc3 = new NetworkCapabilities();
- nc3.setTransportInfo(nc1.getTransportInfo());
- nc1.combineCapabilities(nc3);
- }
-
- @Test
- public void testSet() {
- NetworkCapabilities nc1 = new NetworkCapabilities();
- NetworkCapabilities nc2 = new NetworkCapabilities();
-
- nc1.addUnwantedCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
- nc1.addCapability(NET_CAPABILITY_NOT_ROAMING);
- assertNotEquals(nc1, nc2);
- nc2.set(nc1);
- assertEquals(nc1, nc2);
- assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_CAPTIVE_PORTAL));
-
- // This will effectively move NOT_ROAMING capability from required to unwanted for nc1.
- nc1.addUnwantedCapability(NET_CAPABILITY_NOT_ROAMING);
- nc1.setSSID(TEST_SSID);
- nc2.set(nc1);
- assertEquals(nc1, nc2);
- // Contrary to combineCapabilities, set() will have removed the NOT_ROAMING capability
- // from nc2.
- assertFalse(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
- if (isAtLeastR()) {
- assertTrue(TEST_SSID.equals(nc2.getSsid()));
- }
-
- nc1.setSSID(DIFFERENT_TEST_SSID);
- nc2.set(nc1);
- assertEquals(nc1, nc2);
- if (isAtLeastR()) {
- assertTrue(DIFFERENT_TEST_SSID.equals(nc2.getSsid()));
- }
-
- nc1.setUids(uidRange(10, 13));
- nc2.set(nc1); // Overwrites, as opposed to combineCapabilities
- assertEquals(nc1, nc2);
- }
-
- @Test
- public void testGetTransportTypes() {
- final NetworkCapabilities nc = new NetworkCapabilities();
- nc.addTransportType(TRANSPORT_CELLULAR);
- nc.addTransportType(TRANSPORT_WIFI);
- nc.addTransportType(TRANSPORT_VPN);
- nc.addTransportType(TRANSPORT_TEST);
-
- final int[] transportTypes = nc.getTransportTypes();
- assertEquals(4, transportTypes.length);
- assertEquals(TRANSPORT_CELLULAR, transportTypes[0]);
- assertEquals(TRANSPORT_WIFI, transportTypes[1]);
- assertEquals(TRANSPORT_VPN, transportTypes[2]);
- assertEquals(TRANSPORT_TEST, transportTypes[3]);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testTelephonyNetworkSpecifier() {
- final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier(1);
- final NetworkCapabilities nc1 = new NetworkCapabilities.Builder()
- .addTransportType(TRANSPORT_WIFI)
- .setNetworkSpecifier(specifier)
- .build();
- assertEquals(specifier, nc1.getNetworkSpecifier());
- try {
- final NetworkCapabilities nc2 = new NetworkCapabilities.Builder()
- .setNetworkSpecifier(specifier)
- .build();
- fail("Must have a single transport type. Without transport type or multiple transport"
- + " types is invalid.");
- } catch (IllegalStateException expected) { }
- }
-
- @Test
- public void testWifiAwareNetworkSpecifier() {
- final NetworkCapabilities nc = new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI_AWARE);
- // If NetworkSpecifier is not set, the default value is null.
- assertNull(nc.getNetworkSpecifier());
- final WifiAwareNetworkSpecifier specifier = new WifiAwareNetworkSpecifier.Builder(
- mDiscoverySession, mPeerHandle).build();
- nc.setNetworkSpecifier(specifier);
- assertEquals(specifier, nc.getNetworkSpecifier());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testAdministratorUidsAndOwnerUid() {
- // Test default owner uid.
- // If the owner uid is not set, the default value should be Process.INVALID_UID.
- final NetworkCapabilities nc1 = new NetworkCapabilities.Builder().build();
- assertEquals(Process.INVALID_UID, nc1.getOwnerUid());
- // Test setAdministratorUids and getAdministratorUids.
- final int[] administratorUids = {1001, 10001};
- final NetworkCapabilities nc2 = new NetworkCapabilities.Builder()
- .setAdministratorUids(administratorUids)
- .build();
- assertTrue(Arrays.equals(administratorUids, nc2.getAdministratorUids()));
- // Test setOwnerUid and getOwnerUid.
- // The owner UID must be included in administrator UIDs, or throw IllegalStateException.
- try {
- final NetworkCapabilities nc3 = new NetworkCapabilities.Builder()
- .setOwnerUid(1001)
- .build();
- fail("The owner UID must be included in administrator UIDs.");
- } catch (IllegalStateException expected) { }
- final NetworkCapabilities nc4 = new NetworkCapabilities.Builder()
- .setAdministratorUids(administratorUids)
- .setOwnerUid(1001)
- .build();
- assertEquals(1001, nc4.getOwnerUid());
- try {
- final NetworkCapabilities nc5 = new NetworkCapabilities.Builder()
- .setAdministratorUids(null)
- .build();
- fail("Should not set null into setAdministratorUids");
- } catch (NullPointerException expected) { }
- }
-
- @Test
- public void testLinkBandwidthKbps() {
- final NetworkCapabilities nc = new NetworkCapabilities();
- // The default value of LinkDown/UpstreamBandwidthKbps should be LINK_BANDWIDTH_UNSPECIFIED.
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, nc.getLinkDownstreamBandwidthKbps());
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, nc.getLinkUpstreamBandwidthKbps());
- nc.setLinkDownstreamBandwidthKbps(512);
- nc.setLinkUpstreamBandwidthKbps(128);
- assertEquals(512, nc.getLinkDownstreamBandwidthKbps());
- assertNotEquals(128, nc.getLinkDownstreamBandwidthKbps());
- assertEquals(128, nc.getLinkUpstreamBandwidthKbps());
- assertNotEquals(512, nc.getLinkUpstreamBandwidthKbps());
- }
-
- @Test
- public void testSignalStrength() {
- final NetworkCapabilities nc = new NetworkCapabilities();
- // The default value of signal strength should be SIGNAL_STRENGTH_UNSPECIFIED.
- assertEquals(SIGNAL_STRENGTH_UNSPECIFIED, nc.getSignalStrength());
- nc.setSignalStrength(-80);
- assertEquals(-80, nc.getSignalStrength());
- assertNotEquals(-50, nc.getSignalStrength());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testDeduceRestrictedCapability() {
- final NetworkCapabilities nc = new NetworkCapabilities();
- // Default capabilities don't have restricted capability.
- assertFalse(nc.deduceRestrictedCapability());
- // If there is a force restricted capability, then the network capabilities is restricted.
- nc.addCapability(NET_CAPABILITY_OEM_PAID);
- nc.addCapability(NET_CAPABILITY_INTERNET);
- assertTrue(nc.deduceRestrictedCapability());
- // Except for the force restricted capability, if there is any unrestricted capability in
- // capabilities, then the network capabilities is not restricted.
- nc.removeCapability(NET_CAPABILITY_OEM_PAID);
- nc.addCapability(NET_CAPABILITY_CBS);
- assertFalse(nc.deduceRestrictedCapability());
- // Except for the force restricted capability, the network capabilities will only be treated
- // as restricted when there is no any unrestricted capability.
- nc.removeCapability(NET_CAPABILITY_INTERNET);
- assertTrue(nc.deduceRestrictedCapability());
- }
-
- private void assertNoTransport(NetworkCapabilities nc) {
- for (int i = MIN_TRANSPORT; i <= MAX_TRANSPORT; i++) {
- assertFalse(nc.hasTransport(i));
- }
- }
-
- // Checks that all transport types from MIN_TRANSPORT to maxTransportType are set and all
- // transport types from maxTransportType + 1 to MAX_TRANSPORT are not set when positiveSequence
- // is true. If positiveSequence is false, then the check sequence is opposite.
- private void checkCurrentTransportTypes(NetworkCapabilities nc, int maxTransportType,
- boolean positiveSequence) {
- for (int i = MIN_TRANSPORT; i <= maxTransportType; i++) {
- if (positiveSequence) {
- assertTrue(nc.hasTransport(i));
- } else {
- assertFalse(nc.hasTransport(i));
- }
- }
- for (int i = MAX_TRANSPORT; i > maxTransportType; i--) {
- if (positiveSequence) {
- assertFalse(nc.hasTransport(i));
- } else {
- assertTrue(nc.hasTransport(i));
- }
- }
- }
-
- @Test
- public void testMultipleTransportTypes() {
- final NetworkCapabilities nc = new NetworkCapabilities();
- assertNoTransport(nc);
- // Test adding multiple transport types.
- for (int i = MIN_TRANSPORT; i <= MAX_TRANSPORT; i++) {
- nc.addTransportType(i);
- checkCurrentTransportTypes(nc, i, true /* positiveSequence */);
- }
- // Test removing multiple transport types.
- for (int i = MIN_TRANSPORT; i <= MAX_TRANSPORT; i++) {
- nc.removeTransportType(i);
- checkCurrentTransportTypes(nc, i, false /* positiveSequence */);
- }
- assertNoTransport(nc);
- nc.addTransportType(TRANSPORT_WIFI);
- assertTrue(nc.hasTransport(TRANSPORT_WIFI));
- assertFalse(nc.hasTransport(TRANSPORT_VPN));
- nc.addTransportType(TRANSPORT_VPN);
- assertTrue(nc.hasTransport(TRANSPORT_WIFI));
- assertTrue(nc.hasTransport(TRANSPORT_VPN));
- nc.removeTransportType(TRANSPORT_WIFI);
- assertFalse(nc.hasTransport(TRANSPORT_WIFI));
- assertTrue(nc.hasTransport(TRANSPORT_VPN));
- nc.removeTransportType(TRANSPORT_VPN);
- assertFalse(nc.hasTransport(TRANSPORT_WIFI));
- assertFalse(nc.hasTransport(TRANSPORT_VPN));
- assertNoTransport(nc);
- }
-
- @Test
- public void testAddAndRemoveTransportType() {
- final NetworkCapabilities nc = new NetworkCapabilities();
- try {
- nc.addTransportType(-1);
- fail("Should not set invalid transport type into addTransportType");
- } catch (IllegalArgumentException expected) { }
- try {
- nc.removeTransportType(-1);
- fail("Should not set invalid transport type into removeTransportType");
- } catch (IllegalArgumentException e) { }
- }
-
- private class TestTransportInfo implements TransportInfo {
- TestTransportInfo() {
- }
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testBuilder() {
- final int ownerUid = 1001;
- final int signalStrength = -80;
- final int requestUid = 10100;
- final int[] administratorUids = {ownerUid, 10001};
- final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier(1);
- final TestTransportInfo transportInfo = new TestTransportInfo();
- final String ssid = "TEST_SSID";
- final String packageName = "com.google.test.networkcapabilities";
- final NetworkCapabilities nc = new NetworkCapabilities.Builder()
- .addTransportType(TRANSPORT_WIFI)
- .addTransportType(TRANSPORT_CELLULAR)
- .removeTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_EIMS)
- .addCapability(NET_CAPABILITY_CBS)
- .removeCapability(NET_CAPABILITY_CBS)
- .setAdministratorUids(administratorUids)
- .setOwnerUid(ownerUid)
- .setLinkDownstreamBandwidthKbps(512)
- .setLinkUpstreamBandwidthKbps(128)
- .setNetworkSpecifier(specifier)
- .setTransportInfo(transportInfo)
- .setSignalStrength(signalStrength)
- .setSsid(ssid)
- .setRequestorUid(requestUid)
- .setRequestorPackageName(packageName)
- .build();
- assertEquals(1, nc.getTransportTypes().length);
- assertEquals(TRANSPORT_WIFI, nc.getTransportTypes()[0]);
- assertTrue(nc.hasCapability(NET_CAPABILITY_EIMS));
- assertFalse(nc.hasCapability(NET_CAPABILITY_CBS));
- assertTrue(Arrays.equals(administratorUids, nc.getAdministratorUids()));
- assertEquals(ownerUid, nc.getOwnerUid());
- assertEquals(512, nc.getLinkDownstreamBandwidthKbps());
- assertNotEquals(128, nc.getLinkDownstreamBandwidthKbps());
- assertEquals(128, nc.getLinkUpstreamBandwidthKbps());
- assertNotEquals(512, nc.getLinkUpstreamBandwidthKbps());
- assertEquals(specifier, nc.getNetworkSpecifier());
- assertEquals(transportInfo, nc.getTransportInfo());
- assertEquals(signalStrength, nc.getSignalStrength());
- assertNotEquals(-50, nc.getSignalStrength());
- assertEquals(ssid, nc.getSsid());
- assertEquals(requestUid, nc.getRequestorUid());
- assertEquals(packageName, nc.getRequestorPackageName());
- // Cannot assign null into NetworkCapabilities.Builder
- try {
- final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(null);
- fail("Should not set null into NetworkCapabilities.Builder");
- } catch (NullPointerException expected) { }
- assertEquals(nc, new NetworkCapabilities.Builder(nc).build());
- }
-}
diff --git a/tests/net/common/java/android/net/NetworkProviderTest.kt b/tests/net/common/java/android/net/NetworkProviderTest.kt
deleted file mode 100644
index b7c47c2bc223..000000000000
--- a/tests/net/common/java/android/net/NetworkProviderTest.kt
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net
-
-import android.app.Instrumentation
-import android.content.Context
-import android.net.NetworkCapabilities.TRANSPORT_TEST
-import android.os.Build
-import android.os.HandlerThread
-import android.os.Looper
-import android.net.NetworkProviderTest.TestNetworkCallback.CallbackEntry.OnUnavailable
-import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequested
-import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequestWithdrawn
-import androidx.test.InstrumentationRegistry
-import com.android.testutils.ArrayTrackRecord
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import com.android.testutils.DevSdkIgnoreRunner
-import java.util.UUID
-import kotlin.test.assertEquals
-import kotlin.test.assertNotEquals
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-private const val DEFAULT_TIMEOUT_MS = 5000L
-private val instrumentation: Instrumentation
- get() = InstrumentationRegistry.getInstrumentation()
-private val context: Context get() = InstrumentationRegistry.getContext()
-private val PROVIDER_NAME = "NetworkProviderTest"
-
-@RunWith(DevSdkIgnoreRunner::class)
-@IgnoreUpTo(Build.VERSION_CODES.Q)
-class NetworkProviderTest {
- private val mCm = context.getSystemService(ConnectivityManager::class.java)
- private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread")
-
- @Before
- fun setUp() {
- instrumentation.getUiAutomation().adoptShellPermissionIdentity()
- mHandlerThread.start()
- }
-
- @After
- fun tearDown() {
- mHandlerThread.quitSafely()
- instrumentation.getUiAutomation().dropShellPermissionIdentity()
- }
-
- private class TestNetworkProvider(context: Context, looper: Looper) :
- NetworkProvider(context, looper, PROVIDER_NAME) {
- private val seenEvents = ArrayTrackRecord<CallbackEntry>().newReadHead()
-
- sealed class CallbackEntry {
- data class OnNetworkRequested(
- val request: NetworkRequest,
- val score: Int,
- val id: Int
- ) : CallbackEntry()
- data class OnNetworkRequestWithdrawn(val request: NetworkRequest) : CallbackEntry()
- }
-
- override fun onNetworkRequested(request: NetworkRequest, score: Int, id: Int) {
- seenEvents.add(OnNetworkRequested(request, score, id))
- }
-
- override fun onNetworkRequestWithdrawn(request: NetworkRequest) {
- seenEvents.add(OnNetworkRequestWithdrawn(request))
- }
-
- inline fun <reified T : CallbackEntry> expectCallback(
- crossinline predicate: (T) -> Boolean
- ) = seenEvents.poll(DEFAULT_TIMEOUT_MS) { it is T && predicate(it) }
- }
-
- private fun createNetworkProvider(): TestNetworkProvider {
- return TestNetworkProvider(context, mHandlerThread.looper)
- }
-
- @Test
- fun testOnNetworkRequested() {
- val provider = createNetworkProvider()
- assertEquals(provider.getProviderId(), NetworkProvider.ID_NONE)
- mCm.registerNetworkProvider(provider)
- assertNotEquals(provider.getProviderId(), NetworkProvider.ID_NONE)
-
- val specifier = StringNetworkSpecifier(UUID.randomUUID().toString())
- val nr: NetworkRequest = NetworkRequest.Builder()
- .addTransportType(TRANSPORT_TEST)
- .setNetworkSpecifier(specifier)
- .build()
- val cb = ConnectivityManager.NetworkCallback()
- mCm.requestNetwork(nr, cb)
- provider.expectCallback<OnNetworkRequested>() { callback ->
- callback.request.getNetworkSpecifier() == specifier &&
- callback.request.hasTransport(TRANSPORT_TEST)
- }
-
- val initialScore = 40
- val updatedScore = 60
- val nc = NetworkCapabilities().apply {
- addTransportType(NetworkCapabilities.TRANSPORT_TEST)
- removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
- removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
- addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
- addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- setNetworkSpecifier(specifier)
- }
- val lp = LinkProperties()
- val config = NetworkAgentConfig.Builder().build()
- val agent = object : NetworkAgent(context, mHandlerThread.looper, "TestAgent", nc, lp,
- initialScore, config, provider) {}
-
- provider.expectCallback<OnNetworkRequested>() { callback ->
- callback.request.getNetworkSpecifier() == specifier &&
- callback.score == initialScore &&
- callback.id == agent.providerId
- }
-
- agent.sendNetworkScore(updatedScore)
- provider.expectCallback<OnNetworkRequested>() { callback ->
- callback.request.getNetworkSpecifier() == specifier &&
- callback.score == updatedScore &&
- callback.id == agent.providerId
- }
-
- mCm.unregisterNetworkCallback(cb)
- provider.expectCallback<OnNetworkRequestWithdrawn>() { callback ->
- callback.request.getNetworkSpecifier() == specifier &&
- callback.request.hasTransport(TRANSPORT_TEST)
- }
- mCm.unregisterNetworkProvider(provider)
- // Provider id should be ID_NONE after unregister network provider
- assertEquals(provider.getProviderId(), NetworkProvider.ID_NONE)
- // unregisterNetworkProvider should not crash even if it's called on an
- // already unregistered provider.
- mCm.unregisterNetworkProvider(provider)
- }
-
- private class TestNetworkCallback : ConnectivityManager.NetworkCallback() {
- private val seenEvents = ArrayTrackRecord<CallbackEntry>().newReadHead()
- sealed class CallbackEntry {
- object OnUnavailable : CallbackEntry()
- }
-
- override fun onUnavailable() {
- seenEvents.add(OnUnavailable)
- }
-
- inline fun <reified T : CallbackEntry> expectCallback(
- crossinline predicate: (T) -> Boolean
- ) = seenEvents.poll(DEFAULT_TIMEOUT_MS) { it is T && predicate(it) }
- }
-
- @Test
- fun testDeclareNetworkRequestUnfulfillable() {
- val provider = createNetworkProvider()
- mCm.registerNetworkProvider(provider)
-
- val specifier = StringNetworkSpecifier(UUID.randomUUID().toString())
- val nr: NetworkRequest = NetworkRequest.Builder()
- .addTransportType(TRANSPORT_TEST)
- .setNetworkSpecifier(specifier)
- .build()
-
- val cb = TestNetworkCallback()
- mCm.requestNetwork(nr, cb)
- provider.declareNetworkRequestUnfulfillable(nr)
- cb.expectCallback<OnUnavailable>() { nr.getNetworkSpecifier() == specifier }
- mCm.unregisterNetworkProvider(provider)
- }
-} \ No newline at end of file
diff --git a/tests/net/common/java/android/net/NetworkSpecifierTest.kt b/tests/net/common/java/android/net/NetworkSpecifierTest.kt
deleted file mode 100644
index f3409f53596f..000000000000
--- a/tests/net/common/java/android/net/NetworkSpecifierTest.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net
-
-import android.os.Build
-import androidx.test.filters.SmallTest
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import com.android.testutils.DevSdkIgnoreRunner
-import kotlin.test.assertTrue
-import kotlin.test.assertEquals
-import kotlin.test.assertFalse
-import kotlin.test.assertNotEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(DevSdkIgnoreRunner::class)
-@IgnoreUpTo(Build.VERSION_CODES.Q)
-class NetworkSpecifierTest {
- private class TestNetworkSpecifier(
- val intData: Int = 123,
- val stringData: String = "init"
- ) : NetworkSpecifier() {
- override fun canBeSatisfiedBy(other: NetworkSpecifier?): Boolean =
- other != null &&
- other is TestNetworkSpecifier &&
- other.intData >= intData &&
- stringData.equals(other.stringData)
-
- override fun redact(): NetworkSpecifier = TestNetworkSpecifier(intData, "redact")
- }
-
- @Test
- fun testRedact() {
- val ns: TestNetworkSpecifier = TestNetworkSpecifier()
- val redactNs = ns.redact()
- assertTrue(redactNs is TestNetworkSpecifier)
- assertEquals(ns.intData, redactNs.intData)
- assertNotEquals(ns.stringData, redactNs.stringData)
- assertTrue("redact".equals(redactNs.stringData))
- }
-
- @Test
- fun testcanBeSatisfiedBy() {
- val target: TestNetworkSpecifier = TestNetworkSpecifier()
- assertFalse(target.canBeSatisfiedBy(null))
- assertTrue(target.canBeSatisfiedBy(TestNetworkSpecifier()))
- val otherNs = TelephonyNetworkSpecifier.Builder().setSubscriptionId(123).build()
- assertFalse(target.canBeSatisfiedBy(otherNs))
- assertTrue(target.canBeSatisfiedBy(TestNetworkSpecifier(intData = 999)))
- assertFalse(target.canBeSatisfiedBy(TestNetworkSpecifier(intData = 1)))
- assertFalse(target.canBeSatisfiedBy(TestNetworkSpecifier(stringData = "diff")))
- }
-} \ No newline at end of file
diff --git a/tests/net/common/java/android/net/NetworkStackTest.java b/tests/net/common/java/android/net/NetworkStackTest.java
deleted file mode 100644
index a99aa0106655..000000000000
--- a/tests/net/common/java/android/net/NetworkStackTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net;
-
-import static android.Manifest.permission.NETWORK_STACK;
-import static android.content.pm.PackageManager.PERMISSION_DENIED;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
-import static android.net.NetworkStack.checkNetworkStackPermission;
-import static android.net.NetworkStack.checkNetworkStackPermissionOr;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.os.Build;
-import android.os.IBinder;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-public class NetworkStackTest {
- private static final String [] OTHER_PERMISSION = {"otherpermission1", "otherpermission2"};
-
- @Rule
- public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule();
-
- @Mock Context mCtx;
- @Mock private IBinder mConnectorBinder;
-
- @Before public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- }
-
- @Test
- public void testCheckNetworkStackPermission() throws Exception {
- when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_GRANTED);
- when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK)))
- .thenReturn(PERMISSION_DENIED);
- checkNetworkStackPermission(mCtx);
- checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
-
- when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_DENIED);
- when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK)))
- .thenReturn(PERMISSION_GRANTED);
- checkNetworkStackPermission(mCtx);
- checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
-
- when(mCtx.checkCallingOrSelfPermission(any())).thenReturn(PERMISSION_DENIED);
-
- try {
- checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
- } catch (SecurityException e) {
- // Expect to get a SecurityException
- return;
- }
-
- fail("Expect fail but permission granted.");
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testGetService() {
- NetworkStack.setServiceForTest(mConnectorBinder);
- assertEquals(NetworkStack.getService(), mConnectorBinder);
- }
-}
diff --git a/tests/net/common/java/android/net/NetworkTest.java b/tests/net/common/java/android/net/NetworkTest.java
deleted file mode 100644
index 11d44b86bc50..000000000000
--- a/tests/net/common/java/android/net/NetworkTest.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.platform.test.annotations.AppModeFull;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.net.DatagramSocket;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.SocketException;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkTest {
- final Network mNetwork = new Network(99);
-
- @Test
- public void testBindSocketOfInvalidFdThrows() throws Exception {
-
- final FileDescriptor fd = new FileDescriptor();
- assertFalse(fd.valid());
-
- try {
- mNetwork.bindSocket(fd);
- fail("SocketException not thrown");
- } catch (SocketException expected) {}
- }
-
- @Test
- public void testBindSocketOfNonSocketFdThrows() throws Exception {
- final File devNull = new File("/dev/null");
- assertTrue(devNull.canRead());
-
- final FileInputStream fis = new FileInputStream(devNull);
- assertTrue(null != fis.getFD());
- assertTrue(fis.getFD().valid());
-
- try {
- mNetwork.bindSocket(fis.getFD());
- fail("SocketException not thrown");
- } catch (SocketException expected) {}
- }
-
- @Test
- @AppModeFull(reason = "Socket cannot bind in instant app mode")
- public void testBindSocketOfConnectedDatagramSocketThrows() throws Exception {
- final DatagramSocket mDgramSocket = new DatagramSocket(0, (InetAddress) Inet6Address.ANY);
- mDgramSocket.connect((InetAddress) Inet6Address.LOOPBACK, 53);
- assertTrue(mDgramSocket.isConnected());
-
- try {
- mNetwork.bindSocket(mDgramSocket);
- fail("SocketException not thrown");
- } catch (SocketException expected) {}
- }
-
- @Test
- public void testBindSocketOfLocalSocketThrows() throws Exception {
- final LocalSocket mLocalClient = new LocalSocket();
- mLocalClient.bind(new LocalSocketAddress("testClient"));
- assertTrue(mLocalClient.getFileDescriptor().valid());
-
- try {
- mNetwork.bindSocket(mLocalClient.getFileDescriptor());
- fail("SocketException not thrown");
- } catch (SocketException expected) {}
-
- final LocalServerSocket mLocalServer = new LocalServerSocket("testServer");
- mLocalClient.connect(mLocalServer.getLocalSocketAddress());
- assertTrue(mLocalClient.isConnected());
-
- try {
- mNetwork.bindSocket(mLocalClient.getFileDescriptor());
- fail("SocketException not thrown");
- } catch (SocketException expected) {}
- }
-
- @Test
- public void testZeroIsObviousForDebugging() {
- Network zero = new Network(0);
- assertEquals(0, zero.hashCode());
- assertEquals(0, zero.getNetworkHandle());
- assertEquals("0", zero.toString());
- }
-
- @Test
- public void testGetNetworkHandle() {
- Network one = new Network(1);
- Network two = new Network(2);
- Network three = new Network(3);
-
- // None of the hashcodes are zero.
- assertNotEquals(0, one.hashCode());
- assertNotEquals(0, two.hashCode());
- assertNotEquals(0, three.hashCode());
-
- // All the hashcodes are distinct.
- assertNotEquals(one.hashCode(), two.hashCode());
- assertNotEquals(one.hashCode(), three.hashCode());
- assertNotEquals(two.hashCode(), three.hashCode());
-
- // None of the handles are zero.
- assertNotEquals(0, one.getNetworkHandle());
- assertNotEquals(0, two.getNetworkHandle());
- assertNotEquals(0, three.getNetworkHandle());
-
- // All the handles are distinct.
- assertNotEquals(one.getNetworkHandle(), two.getNetworkHandle());
- assertNotEquals(one.getNetworkHandle(), three.getNetworkHandle());
- assertNotEquals(two.getNetworkHandle(), three.getNetworkHandle());
-
- // The handles are not equal to the hashcodes.
- assertNotEquals(one.hashCode(), one.getNetworkHandle());
- assertNotEquals(two.hashCode(), two.getNetworkHandle());
- assertNotEquals(three.hashCode(), three.getNetworkHandle());
-
- // Adjust as necessary to test an implementation's specific constants.
- // When running with runtest, "adb logcat -s TestRunner" can be useful.
- assertEquals(7700664333L, one.getNetworkHandle());
- assertEquals(11995631629L, two.getNetworkHandle());
- assertEquals(16290598925L, three.getNetworkHandle());
- }
-
- @Test
- public void testGetPrivateDnsBypassingCopy() {
- final Network copy = mNetwork.getPrivateDnsBypassingCopy();
- assertEquals(mNetwork.netId, copy.netId);
- assertNotEquals(copy.netId, copy.getNetIdForResolv());
- assertNotEquals(mNetwork.getNetIdForResolv(), copy.getNetIdForResolv());
- }
-}
diff --git a/tests/net/common/java/android/net/RouteInfoTest.java b/tests/net/common/java/android/net/RouteInfoTest.java
deleted file mode 100644
index 60cac0b6b0f5..000000000000
--- a/tests/net/common/java/android/net/RouteInfoTest.java
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.RouteInfo.RTN_UNREACHABLE;
-
-import static com.android.testutils.MiscAssertsKt.assertEqualBothWays;
-import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
-import static com.android.testutils.MiscAssertsKt.assertNotEqualEitherWay;
-import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.os.Build;
-
-import androidx.core.os.BuildCompat;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class RouteInfoTest {
- @Rule
- public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
-
- private static final int INVALID_ROUTE_TYPE = -1;
-
- private InetAddress Address(String addr) {
- return InetAddresses.parseNumericAddress(addr);
- }
-
- private IpPrefix Prefix(String prefix) {
- return new IpPrefix(prefix);
- }
-
- private static boolean isAtLeastR() {
- // BuildCompat.isAtLeastR is documented to return false on release SDKs (including R)
- return Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR();
- }
-
- @Test
- public void testConstructor() {
- RouteInfo r;
- // Invalid input.
- try {
- r = new RouteInfo((IpPrefix) null, null, "rmnet0");
- fail("Expected RuntimeException: destination and gateway null");
- } catch (RuntimeException e) { }
-
- try {
- r = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("2001:db8::1"), "rmnet0",
- INVALID_ROUTE_TYPE);
- fail("Invalid route type should cause exception");
- } catch (IllegalArgumentException e) { }
-
- try {
- r = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("192.0.2.1"), "rmnet0",
- RTN_UNREACHABLE);
- fail("Address family mismatch should cause exception");
- } catch (IllegalArgumentException e) { }
-
- try {
- r = new RouteInfo(Prefix("0.0.0.0/0"), Address("2001:db8::1"), "rmnet0",
- RTN_UNREACHABLE);
- fail("Address family mismatch should cause exception");
- } catch (IllegalArgumentException e) { }
-
- // Null destination is default route.
- r = new RouteInfo((IpPrefix) null, Address("2001:db8::1"), null);
- assertEquals(Prefix("::/0"), r.getDestination());
- assertEquals(Address("2001:db8::1"), r.getGateway());
- assertNull(r.getInterface());
-
- r = new RouteInfo((IpPrefix) null, Address("192.0.2.1"), "wlan0");
- assertEquals(Prefix("0.0.0.0/0"), r.getDestination());
- assertEquals(Address("192.0.2.1"), r.getGateway());
- assertEquals("wlan0", r.getInterface());
-
- // Null gateway sets gateway to unspecified address (why?).
- r = new RouteInfo(Prefix("2001:db8:beef:cafe::/48"), null, "lo");
- assertEquals(Prefix("2001:db8:beef::/48"), r.getDestination());
- assertEquals(Address("::"), r.getGateway());
- assertEquals("lo", r.getInterface());
-
- r = new RouteInfo(Prefix("192.0.2.5/24"), null);
- assertEquals(Prefix("192.0.2.0/24"), r.getDestination());
- assertEquals(Address("0.0.0.0"), r.getGateway());
- assertNull(r.getInterface());
- }
-
- @Test
- public void testMatches() {
- class PatchedRouteInfo {
- private final RouteInfo mRouteInfo;
-
- public PatchedRouteInfo(IpPrefix destination, InetAddress gateway, String iface) {
- mRouteInfo = new RouteInfo(destination, gateway, iface);
- }
-
- public boolean matches(InetAddress destination) {
- return mRouteInfo.matches(destination);
- }
- }
-
- PatchedRouteInfo r;
-
- r = new PatchedRouteInfo(Prefix("2001:db8:f00::ace:d00d/127"), null, "rmnet0");
- assertTrue(r.matches(Address("2001:db8:f00::ace:d00c")));
- assertTrue(r.matches(Address("2001:db8:f00::ace:d00d")));
- assertFalse(r.matches(Address("2001:db8:f00::ace:d00e")));
- assertFalse(r.matches(Address("2001:db8:f00::bad:d00d")));
- assertFalse(r.matches(Address("2001:4868:4860::8888")));
- assertFalse(r.matches(Address("8.8.8.8")));
-
- r = new PatchedRouteInfo(Prefix("192.0.2.0/23"), null, "wlan0");
- assertTrue(r.matches(Address("192.0.2.43")));
- assertTrue(r.matches(Address("192.0.3.21")));
- assertFalse(r.matches(Address("192.0.0.21")));
- assertFalse(r.matches(Address("8.8.8.8")));
-
- PatchedRouteInfo ipv6Default = new PatchedRouteInfo(Prefix("::/0"), null, "rmnet0");
- assertTrue(ipv6Default.matches(Address("2001:db8::f00")));
- assertFalse(ipv6Default.matches(Address("192.0.2.1")));
-
- PatchedRouteInfo ipv4Default = new PatchedRouteInfo(Prefix("0.0.0.0/0"), null, "rmnet0");
- assertTrue(ipv4Default.matches(Address("255.255.255.255")));
- assertTrue(ipv4Default.matches(Address("192.0.2.1")));
- assertFalse(ipv4Default.matches(Address("2001:db8::f00")));
- }
-
- @Test
- public void testEquals() {
- // IPv4
- RouteInfo r1 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
- RouteInfo r2 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
- assertEqualBothWays(r1, r2);
-
- RouteInfo r3 = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("2001:db8::1"), "wlan0");
- RouteInfo r4 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::2"), "wlan0");
- RouteInfo r5 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "rmnet0");
- assertNotEqualEitherWay(r1, r3);
- assertNotEqualEitherWay(r1, r4);
- assertNotEqualEitherWay(r1, r5);
-
- // IPv6
- r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0");
- r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0");
- assertEqualBothWays(r1, r2);
-
- r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0");
- r4 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.2"), "wlan0");
- r5 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "rmnet0");
- assertNotEqualEitherWay(r1, r3);
- assertNotEqualEitherWay(r1, r4);
- assertNotEqualEitherWay(r1, r5);
-
- // Interfaces (but not destinations or gateways) can be null.
- r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null);
- r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null);
- r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0");
- assertEqualBothWays(r1, r2);
- assertNotEqualEitherWay(r1, r3);
- }
-
- @Test
- public void testHostAndDefaultRoutes() {
- RouteInfo r;
-
- r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0");
- assertFalse(r.isHostRoute());
- assertTrue(r.isDefaultRoute());
- assertTrue(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("::/0"), Address("::"), "wlan0");
- assertFalse(r.isHostRoute());
- assertTrue(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertTrue(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
- assertFalse(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("2001:db8::/48"), null, "wlan0");
- assertFalse(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("192.0.2.0/32"), Address("0.0.0.0"), "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("2001:db8::/128"), Address("::"), "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("192.0.2.0/32"), null, "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("2001:db8::/128"), null, "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("::/128"), Address("fe80::"), "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE);
- assertFalse(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertTrue(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE);
- assertFalse(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertTrue(r.isIPv6UnreachableDefault());
- }
- }
-
- @Test
- public void testTruncation() {
- LinkAddress l;
- RouteInfo r;
-
- l = new LinkAddress("192.0.2.5/30");
- r = new RouteInfo(l, Address("192.0.2.1"), "wlan0");
- assertEquals("192.0.2.4", r.getDestination().getAddress().getHostAddress());
-
- l = new LinkAddress("2001:db8:1:f::5/63");
- r = new RouteInfo(l, Address("2001:db8:5::1"), "wlan0");
- assertEquals("2001:db8:1:e::", r.getDestination().getAddress().getHostAddress());
- }
-
- // Make sure that creating routes to multicast addresses doesn't throw an exception. Even though
- // there's nothing we can do with them, we don't want to crash if, e.g., someone calls
- // requestRouteToHostAddress("230.0.0.0", MOBILE_HIPRI);
- @Test
- public void testMulticastRoute() {
- RouteInfo r;
- r = new RouteInfo(Prefix("230.0.0.0/32"), Address("192.0.2.1"), "wlan0");
- r = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::1"), "wlan0");
- // No exceptions? Good.
- }
-
- @Test
- public void testParceling() {
- RouteInfo r;
- r = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), null);
- assertParcelingIsLossless(r);
- r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
- assertParcelingIsLossless(r);
- r = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0", RTN_UNREACHABLE);
- assertParcelingIsLossless(r);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testMtuParceling() {
- final RouteInfo r = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::"), "testiface",
- RTN_UNREACHABLE, 1450 /* mtu */);
- assertParcelingIsLossless(r);
- }
-
- @Test @IgnoreAfter(Build.VERSION_CODES.Q)
- public void testFieldCount_Q() {
- assertFieldCountEquals(6, RouteInfo.class);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testFieldCount() {
- // Make sure any new field is covered by the above parceling tests when changing this number
- assertFieldCountEquals(7, RouteInfo.class);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testMtu() {
- RouteInfo r;
- r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0",
- RouteInfo.RTN_UNICAST, 1500);
- assertEquals(1500, r.getMtu());
-
- r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0");
- assertEquals(0, r.getMtu());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testRouteKey() {
- RouteInfo.RouteKey k1, k2;
- // Only prefix, null gateway and null interface
- k1 = new RouteInfo(Prefix("2001:db8::/128"), null).getRouteKey();
- k2 = new RouteInfo(Prefix("2001:db8::/128"), null).getRouteKey();
- assertEquals(k1, k2);
- assertEquals(k1.hashCode(), k2.hashCode());
-
- // With prefix, gateway and interface. Type and MTU does not affect RouteKey equality
- k1 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0",
- RTN_UNREACHABLE, 1450).getRouteKey();
- k2 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0",
- RouteInfo.RTN_UNICAST, 1400).getRouteKey();
- assertEquals(k1, k2);
- assertEquals(k1.hashCode(), k2.hashCode());
-
- // Different scope IDs are ignored by the kernel, so we consider them equal here too.
- k1 = new RouteInfo(Prefix("2001:db8::/64"), Address("fe80::1%1"), "wlan0").getRouteKey();
- k2 = new RouteInfo(Prefix("2001:db8::/64"), Address("fe80::1%2"), "wlan0").getRouteKey();
- assertEquals(k1, k2);
- assertEquals(k1.hashCode(), k2.hashCode());
-
- // Different prefix
- k1 = new RouteInfo(Prefix("192.0.2.0/24"), null).getRouteKey();
- k2 = new RouteInfo(Prefix("192.0.3.0/24"), null).getRouteKey();
- assertNotEquals(k1, k2);
-
- // Different gateway
- k1 = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::1"), null).getRouteKey();
- k2 = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::2"), null).getRouteKey();
- assertNotEquals(k1, k2);
-
- // Different interface
- k1 = new RouteInfo(Prefix("ff02::1/128"), null, "tun0").getRouteKey();
- k2 = new RouteInfo(Prefix("ff02::1/128"), null, "tun1").getRouteKey();
- assertNotEquals(k1, k2);
- }
-}
diff --git a/tests/net/common/java/android/net/StaticIpConfigurationTest.java b/tests/net/common/java/android/net/StaticIpConfigurationTest.java
deleted file mode 100644
index b5f23bf19a3c..000000000000
--- a/tests/net/common/java/android/net/StaticIpConfigurationTest.java
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.os.Parcel;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class StaticIpConfigurationTest {
-
- private static final String ADDRSTR = "192.0.2.2/25";
- private static final LinkAddress ADDR = new LinkAddress(ADDRSTR);
- private static final InetAddress GATEWAY = IpAddress("192.0.2.1");
- private static final InetAddress OFFLINKGATEWAY = IpAddress("192.0.2.129");
- private static final InetAddress DNS1 = IpAddress("8.8.8.8");
- private static final InetAddress DNS2 = IpAddress("8.8.4.4");
- private static final InetAddress DNS3 = IpAddress("4.2.2.2");
- private static final String IFACE = "eth0";
- private static final String FAKE_DOMAINS = "google.com";
-
- private static InetAddress IpAddress(String addr) {
- return InetAddress.parseNumericAddress(addr);
- }
-
- private void checkEmpty(StaticIpConfiguration s) {
- assertNull(s.ipAddress);
- assertNull(s.gateway);
- assertNull(s.domains);
- assertEquals(0, s.dnsServers.size());
- }
-
- private StaticIpConfiguration makeTestObject() {
- StaticIpConfiguration s = new StaticIpConfiguration();
- s.ipAddress = ADDR;
- s.gateway = GATEWAY;
- s.dnsServers.add(DNS1);
- s.dnsServers.add(DNS2);
- s.dnsServers.add(DNS3);
- s.domains = FAKE_DOMAINS;
- return s;
- }
-
- @Test
- public void testConstructor() {
- StaticIpConfiguration s = new StaticIpConfiguration();
- checkEmpty(s);
- }
-
- @Test
- public void testCopyAndClear() {
- StaticIpConfiguration empty = new StaticIpConfiguration((StaticIpConfiguration) null);
- checkEmpty(empty);
-
- StaticIpConfiguration s1 = makeTestObject();
- StaticIpConfiguration s2 = new StaticIpConfiguration(s1);
- assertEquals(s1, s2);
- s2.clear();
- assertEquals(empty, s2);
- }
-
- @Test
- public void testHashCodeAndEquals() {
- HashSet<Integer> hashCodes = new HashSet();
- hashCodes.add(0);
-
- StaticIpConfiguration s = new StaticIpConfiguration();
- // Check that this hash code is nonzero and different from all the ones seen so far.
- assertTrue(hashCodes.add(s.hashCode()));
-
- s.ipAddress = ADDR;
- assertTrue(hashCodes.add(s.hashCode()));
-
- s.gateway = GATEWAY;
- assertTrue(hashCodes.add(s.hashCode()));
-
- s.dnsServers.add(DNS1);
- assertTrue(hashCodes.add(s.hashCode()));
-
- s.dnsServers.add(DNS2);
- assertTrue(hashCodes.add(s.hashCode()));
-
- s.dnsServers.add(DNS3);
- assertTrue(hashCodes.add(s.hashCode()));
-
- s.domains = "example.com";
- assertTrue(hashCodes.add(s.hashCode()));
-
- assertFalse(s.equals(null));
- assertEquals(s, s);
-
- StaticIpConfiguration s2 = new StaticIpConfiguration(s);
- assertEquals(s, s2);
-
- s.ipAddress = new LinkAddress(DNS1, 32);
- assertNotEquals(s, s2);
-
- s2 = new StaticIpConfiguration(s);
- s.domains = "foo";
- assertNotEquals(s, s2);
-
- s2 = new StaticIpConfiguration(s);
- s.gateway = DNS2;
- assertNotEquals(s, s2);
-
- s2 = new StaticIpConfiguration(s);
- s.dnsServers.add(DNS3);
- assertNotEquals(s, s2);
- }
-
- @Test
- public void testToLinkProperties() {
- LinkProperties expected = new LinkProperties();
- expected.setInterfaceName(IFACE);
-
- StaticIpConfiguration s = new StaticIpConfiguration();
- assertEquals(expected, s.toLinkProperties(IFACE));
-
- final RouteInfo connectedRoute = new RouteInfo(new IpPrefix(ADDRSTR), null, IFACE);
- s.ipAddress = ADDR;
- expected.addLinkAddress(ADDR);
- expected.addRoute(connectedRoute);
- assertEquals(expected, s.toLinkProperties(IFACE));
-
- s.gateway = GATEWAY;
- RouteInfo defaultRoute = new RouteInfo(new IpPrefix("0.0.0.0/0"), GATEWAY, IFACE);
- expected.addRoute(defaultRoute);
- assertEquals(expected, s.toLinkProperties(IFACE));
-
- s.gateway = OFFLINKGATEWAY;
- expected.removeRoute(defaultRoute);
- defaultRoute = new RouteInfo(new IpPrefix("0.0.0.0/0"), OFFLINKGATEWAY, IFACE);
- expected.addRoute(defaultRoute);
-
- RouteInfo gatewayRoute = new RouteInfo(new IpPrefix("192.0.2.129/32"), null, IFACE);
- expected.addRoute(gatewayRoute);
- assertEquals(expected, s.toLinkProperties(IFACE));
-
- s.dnsServers.add(DNS1);
- expected.addDnsServer(DNS1);
- assertEquals(expected, s.toLinkProperties(IFACE));
-
- s.dnsServers.add(DNS2);
- s.dnsServers.add(DNS3);
- expected.addDnsServer(DNS2);
- expected.addDnsServer(DNS3);
- assertEquals(expected, s.toLinkProperties(IFACE));
-
- s.domains = FAKE_DOMAINS;
- expected.setDomains(FAKE_DOMAINS);
- assertEquals(expected, s.toLinkProperties(IFACE));
-
- s.gateway = null;
- expected.removeRoute(defaultRoute);
- expected.removeRoute(gatewayRoute);
- assertEquals(expected, s.toLinkProperties(IFACE));
-
- // Without knowing the IP address, we don't have a directly-connected route, so we can't
- // tell if the gateway is off-link or not and we don't add a host route. This isn't a real
- // configuration, but we should at least not crash.
- s.gateway = OFFLINKGATEWAY;
- s.ipAddress = null;
- expected.removeLinkAddress(ADDR);
- expected.removeRoute(connectedRoute);
- expected.addRoute(defaultRoute);
- assertEquals(expected, s.toLinkProperties(IFACE));
- }
-
- private StaticIpConfiguration passThroughParcel(StaticIpConfiguration s) {
- Parcel p = Parcel.obtain();
- StaticIpConfiguration s2 = null;
- try {
- s.writeToParcel(p, 0);
- p.setDataPosition(0);
- s2 = StaticIpConfiguration.readFromParcel(p);
- } finally {
- p.recycle();
- }
- assertNotNull(s2);
- return s2;
- }
-
- @Test
- public void testParceling() {
- StaticIpConfiguration s = makeTestObject();
- StaticIpConfiguration s2 = passThroughParcel(s);
- assertEquals(s, s2);
- }
-
- @Test
- public void testBuilder() {
- final ArrayList<InetAddress> dnsServers = new ArrayList<>();
- dnsServers.add(DNS1);
-
- final StaticIpConfiguration s = new StaticIpConfiguration.Builder()
- .setIpAddress(ADDR)
- .setGateway(GATEWAY)
- .setDomains(FAKE_DOMAINS)
- .setDnsServers(dnsServers)
- .build();
-
- assertEquals(s.ipAddress, s.getIpAddress());
- assertEquals(ADDR, s.getIpAddress());
- assertEquals(s.gateway, s.getGateway());
- assertEquals(GATEWAY, s.getGateway());
- assertEquals(s.domains, s.getDomains());
- assertEquals(FAKE_DOMAINS, s.getDomains());
- assertTrue(s.dnsServers.equals(s.getDnsServers()));
- assertEquals(1, s.getDnsServers().size());
- assertEquals(DNS1, s.getDnsServers().get(0));
- }
-
- @Test
- public void testAddDnsServers() {
- final StaticIpConfiguration s = new StaticIpConfiguration((StaticIpConfiguration) null);
- checkEmpty(s);
-
- s.addDnsServer(DNS1);
- assertEquals(1, s.getDnsServers().size());
- assertEquals(DNS1, s.getDnsServers().get(0));
-
- s.addDnsServer(DNS2);
- s.addDnsServer(DNS3);
- assertEquals(3, s.getDnsServers().size());
- assertEquals(DNS2, s.getDnsServers().get(1));
- assertEquals(DNS3, s.getDnsServers().get(2));
- }
-
- @Test
- public void testGetRoutes() {
- final StaticIpConfiguration s = makeTestObject();
- final List<RouteInfo> routeInfoList = s.getRoutes(IFACE);
-
- assertEquals(2, routeInfoList.size());
- assertEquals(new RouteInfo(ADDR, (InetAddress) null, IFACE), routeInfoList.get(0));
- assertEquals(new RouteInfo((IpPrefix) null, GATEWAY, IFACE), routeInfoList.get(1));
- }
-}
diff --git a/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java b/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java
deleted file mode 100644
index 84805442e5c7..000000000000
--- a/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.apf;
-
-import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ApfCapabilitiesTest {
- private Context mContext;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getContext();
- }
-
- @Test
- public void testConstructAndParcel() {
- final ApfCapabilities caps = new ApfCapabilities(123, 456, 789);
- assertEquals(123, caps.apfVersionSupported);
- assertEquals(456, caps.maximumApfProgramSize);
- assertEquals(789, caps.apfPacketFormat);
-
- assertParcelSane(caps, 3);
- }
-
- @Test
- public void testEquals() {
- assertEquals(new ApfCapabilities(1, 2, 3), new ApfCapabilities(1, 2, 3));
- assertNotEquals(new ApfCapabilities(2, 2, 3), new ApfCapabilities(1, 2, 3));
- assertNotEquals(new ApfCapabilities(1, 3, 3), new ApfCapabilities(1, 2, 3));
- assertNotEquals(new ApfCapabilities(1, 2, 4), new ApfCapabilities(1, 2, 3));
- }
-
- @Test
- public void testHasDataAccess() {
- //hasDataAccess is only supported starting at apf version 4.
- ApfCapabilities caps = new ApfCapabilities(1 /* apfVersionSupported */, 2, 3);
- assertFalse(caps.hasDataAccess());
-
- caps = new ApfCapabilities(4 /* apfVersionSupported */, 5, 6);
- assertTrue(caps.hasDataAccess());
- }
-
- @Test
- public void testGetApfDrop8023Frames() {
- // Get com.android.internal.R.bool.config_apfDrop802_3Frames. The test cannot directly
- // use R.bool.config_apfDrop802_3Frames because that is not a stable resource ID.
- final int resId = mContext.getResources().getIdentifier("config_apfDrop802_3Frames",
- "bool", "android");
- final boolean shouldDrop8023Frames = mContext.getResources().getBoolean(resId);
- final boolean actual = ApfCapabilities.getApfDrop8023Frames();
- assertEquals(shouldDrop8023Frames, actual);
- }
-
- @Test
- public void testGetApfEtherTypeBlackList() {
- // Get com.android.internal.R.array.config_apfEthTypeBlackList. The test cannot directly
- // use R.array.config_apfEthTypeBlackList because that is not a stable resource ID.
- final int resId = mContext.getResources().getIdentifier("config_apfEthTypeBlackList",
- "array", "android");
- final int[] blacklistedEtherTypeArray = mContext.getResources().getIntArray(resId);
- final int[] actual = ApfCapabilities.getApfEtherTypeBlackList();
- assertNotNull(actual);
- assertTrue(Arrays.equals(blacklistedEtherTypeArray, actual));
- }
-}
diff --git a/tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt b/tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt
deleted file mode 100644
index 0b7b74097cc6..000000000000
--- a/tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.metrics;
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class ApfProgramEventTest {
- private infix fun Int.hasFlag(flag: Int) = (this and (1 shl flag)) != 0
-
- @Test
- fun testBuilderAndParcel() {
- val apfProgramEvent = ApfProgramEvent.Builder()
- .setLifetime(1)
- .setActualLifetime(2)
- .setFilteredRas(3)
- .setCurrentRas(4)
- .setProgramLength(5)
- .setFlags(true, true)
- .build()
-
- assertEquals(1, apfProgramEvent.lifetime)
- assertEquals(2, apfProgramEvent.actualLifetime)
- assertEquals(3, apfProgramEvent.filteredRas)
- assertEquals(4, apfProgramEvent.currentRas)
- assertEquals(5, apfProgramEvent.programLength)
- assertEquals(ApfProgramEvent.flagsFor(true, true), apfProgramEvent.flags)
-
- assertParcelSane(apfProgramEvent, 6)
- }
-
- @Test
- fun testFlagsFor() {
- var flags = ApfProgramEvent.flagsFor(false, false)
- assertFalse(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
- assertFalse(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
-
- flags = ApfProgramEvent.flagsFor(true, false)
- assertTrue(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
- assertFalse(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
-
- flags = ApfProgramEvent.flagsFor(false, true)
- assertFalse(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
- assertTrue(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
-
- flags = ApfProgramEvent.flagsFor(true, true)
- assertTrue(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
- assertTrue(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
- }
-}
diff --git a/tests/net/common/java/android/net/metrics/ApfStatsTest.kt b/tests/net/common/java/android/net/metrics/ApfStatsTest.kt
deleted file mode 100644
index 46a8c8e5b509..000000000000
--- a/tests/net/common/java/android/net/metrics/ApfStatsTest.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.metrics
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class ApfStatsTest {
- @Test
- fun testBuilderAndParcel() {
- val apfStats = ApfStats.Builder()
- .setDurationMs(Long.MAX_VALUE)
- .setReceivedRas(1)
- .setMatchingRas(2)
- .setDroppedRas(3)
- .setZeroLifetimeRas(4)
- .setParseErrors(5)
- .setProgramUpdates(6)
- .setProgramUpdatesAll(7)
- .setProgramUpdatesAllowingMulticast(8)
- .setMaxProgramSize(9)
- .build()
-
- assertEquals(Long.MAX_VALUE, apfStats.durationMs)
- assertEquals(1, apfStats.receivedRas)
- assertEquals(2, apfStats.matchingRas)
- assertEquals(3, apfStats.droppedRas)
- assertEquals(4, apfStats.zeroLifetimeRas)
- assertEquals(5, apfStats.parseErrors)
- assertEquals(6, apfStats.programUpdates)
- assertEquals(7, apfStats.programUpdatesAll)
- assertEquals(8, apfStats.programUpdatesAllowingMulticast)
- assertEquals(9, apfStats.maxProgramSize)
-
- assertParcelSane(apfStats, 10)
- }
-}
diff --git a/tests/net/common/java/android/net/metrics/DhcpClientEventTest.kt b/tests/net/common/java/android/net/metrics/DhcpClientEventTest.kt
deleted file mode 100644
index 8d7a9c405024..000000000000
--- a/tests/net/common/java/android/net/metrics/DhcpClientEventTest.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.metrics
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-private const val FAKE_MESSAGE = "test"
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class DhcpClientEventTest {
- @Test
- fun testBuilderAndParcel() {
- val dhcpClientEvent = DhcpClientEvent.Builder()
- .setMsg(FAKE_MESSAGE)
- .setDurationMs(Integer.MAX_VALUE)
- .build()
-
- assertEquals(FAKE_MESSAGE, dhcpClientEvent.msg)
- assertEquals(Integer.MAX_VALUE, dhcpClientEvent.durationMs)
-
- assertParcelSane(dhcpClientEvent, 2)
- }
-}
diff --git a/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt b/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt
deleted file mode 100644
index 236f72eafbdc..000000000000
--- a/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-package android.net.metrics
-
-import android.net.metrics.DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH
-import android.net.metrics.DhcpErrorEvent.errorCodeWithOption
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.parcelingRoundTrip
-import java.lang.reflect.Modifier
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNotNull
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-
-private const val TEST_ERROR_CODE = 12345
-//DHCP Optional Type: DHCP Subnet Mask (Copy from DhcpPacket.java due to it's protected)
-private const val DHCP_SUBNET_MASK = 1
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class DhcpErrorEventTest {
-
- @Test
- fun testConstructor() {
- val event = DhcpErrorEvent(TEST_ERROR_CODE)
- assertEquals(TEST_ERROR_CODE, event.errorCode)
- }
-
- @Test
- fun testParcelUnparcel() {
- val event = DhcpErrorEvent(TEST_ERROR_CODE)
- val parceled = parcelingRoundTrip(event)
- assertEquals(TEST_ERROR_CODE, parceled.errorCode)
- }
-
- @Test
- fun testErrorCodeWithOption() {
- val errorCode = errorCodeWithOption(DHCP_INVALID_OPTION_LENGTH, DHCP_SUBNET_MASK);
- assertTrue((DHCP_INVALID_OPTION_LENGTH and errorCode) == DHCP_INVALID_OPTION_LENGTH);
- assertTrue((DHCP_SUBNET_MASK and errorCode) == DHCP_SUBNET_MASK);
- }
-
- @Test
- fun testToString() {
- val names = listOf("L2_ERROR", "L3_ERROR", "L4_ERROR", "DHCP_ERROR", "MISC_ERROR")
- val errorFields = DhcpErrorEvent::class.java.declaredFields.filter {
- it.type == Int::class.javaPrimitiveType
- && Modifier.isPublic(it.modifiers) && Modifier.isStatic(it.modifiers)
- && it.name !in names
- }
-
- errorFields.forEach {
- val intValue = it.getInt(null)
- val stringValue = DhcpErrorEvent(intValue).toString()
- assertTrue("Invalid string for error 0x%08X (field %s): %s".format(intValue, it.name,
- stringValue),
- stringValue.contains(it.name))
- }
- }
-
- @Test
- fun testToString_InvalidErrorCode() {
- assertNotNull(DhcpErrorEvent(TEST_ERROR_CODE).toString())
- }
-}
diff --git a/tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java b/tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java
deleted file mode 100644
index d4780d3a5d7b..000000000000
--- a/tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.metrics;
-
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-
-import android.net.ConnectivityMetricsEvent;
-import android.net.IIpConnectivityMetrics;
-import android.net.Network;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.BitUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpConnectivityLogTest {
- private static final int FAKE_NET_ID = 100;
- private static final int[] FAKE_TRANSPORT_TYPES = BitUtils.unpackBits(TRANSPORT_WIFI);
- private static final long FAKE_TIME_STAMP = System.currentTimeMillis();
- private static final String FAKE_INTERFACE_NAME = "test";
- private static final IpReachabilityEvent FAKE_EV =
- new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED);
-
- @Mock IIpConnectivityMetrics mMockService;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- }
-
- @Test
- public void testLoggingEvents() throws Exception {
- IpConnectivityLog logger = new IpConnectivityLog(mMockService);
-
- assertTrue(logger.log(FAKE_EV));
- assertTrue(logger.log(FAKE_TIME_STAMP, FAKE_EV));
- assertTrue(logger.log(FAKE_NET_ID, FAKE_TRANSPORT_TYPES, FAKE_EV));
- assertTrue(logger.log(new Network(FAKE_NET_ID), FAKE_TRANSPORT_TYPES, FAKE_EV));
- assertTrue(logger.log(FAKE_INTERFACE_NAME, FAKE_EV));
- assertTrue(logger.log(makeExpectedEvent(FAKE_TIME_STAMP, FAKE_NET_ID, TRANSPORT_WIFI,
- FAKE_INTERFACE_NAME)));
-
- List<ConnectivityMetricsEvent> got = verifyEvents(6);
- assertEventsEqual(makeExpectedEvent(got.get(0).timestamp, 0, 0, null), got.get(0));
- assertEventsEqual(makeExpectedEvent(FAKE_TIME_STAMP, 0, 0, null), got.get(1));
- assertEventsEqual(makeExpectedEvent(got.get(2).timestamp, FAKE_NET_ID,
- TRANSPORT_WIFI, null), got.get(2));
- assertEventsEqual(makeExpectedEvent(got.get(3).timestamp, FAKE_NET_ID,
- TRANSPORT_WIFI, null), got.get(3));
- assertEventsEqual(makeExpectedEvent(got.get(4).timestamp, 0, 0, FAKE_INTERFACE_NAME),
- got.get(4));
- assertEventsEqual(makeExpectedEvent(FAKE_TIME_STAMP, FAKE_NET_ID,
- TRANSPORT_WIFI, FAKE_INTERFACE_NAME), got.get(5));
- }
-
- @Test
- public void testLoggingEventsWithMultipleCallers() throws Exception {
- IpConnectivityLog logger = new IpConnectivityLog(mMockService);
-
- final int nCallers = 10;
- final int nEvents = 10;
- for (int n = 0; n < nCallers; n++) {
- final int i = n;
- new Thread() {
- public void run() {
- for (int j = 0; j < nEvents; j++) {
- assertTrue(logger.log(makeExpectedEvent(
- FAKE_TIME_STAMP + i * 100 + j,
- FAKE_NET_ID + i * 100 + j,
- ((i + j) % 2 == 0) ? TRANSPORT_WIFI : TRANSPORT_CELLULAR,
- FAKE_INTERFACE_NAME)));
- }
- }
- }.start();
- }
-
- List<ConnectivityMetricsEvent> got = verifyEvents(nCallers * nEvents, 200);
- Collections.sort(got, EVENT_COMPARATOR);
- Iterator<ConnectivityMetricsEvent> iter = got.iterator();
- for (int i = 0; i < nCallers; i++) {
- for (int j = 0; j < nEvents; j++) {
- final long expectedTimestamp = FAKE_TIME_STAMP + i * 100 + j;
- final int expectedNetId = FAKE_NET_ID + i * 100 + j;
- final long expectedTransports =
- ((i + j) % 2 == 0) ? TRANSPORT_WIFI : TRANSPORT_CELLULAR;
- assertEventsEqual(makeExpectedEvent(expectedTimestamp, expectedNetId,
- expectedTransports, FAKE_INTERFACE_NAME), iter.next());
- }
- }
- }
-
- private List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
- ArgumentCaptor<ConnectivityMetricsEvent> captor =
- ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
- verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture());
- return captor.getAllValues();
- }
-
- private List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
- return verifyEvents(n, 10);
- }
-
-
- private ConnectivityMetricsEvent makeExpectedEvent(long timestamp, int netId, long transports,
- String ifname) {
- ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
- ev.timestamp = timestamp;
- ev.data = FAKE_EV;
- ev.netId = netId;
- ev.transports = transports;
- ev.ifname = ifname;
- return ev;
- }
-
- /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
- private void assertEventsEqual(ConnectivityMetricsEvent expected,
- ConnectivityMetricsEvent got) {
- assertEquals(expected.data, got.data);
- assertEquals(expected.timestamp, got.timestamp);
- assertEquals(expected.netId, got.netId);
- assertEquals(expected.transports, got.transports);
- assertEquals(expected.ifname, got.ifname);
- }
-
- static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
- Comparator.comparingLong((ev) -> ev.timestamp);
-}
diff --git a/tests/net/common/java/android/net/metrics/IpManagerEventTest.kt b/tests/net/common/java/android/net/metrics/IpManagerEventTest.kt
deleted file mode 100644
index 64be50837fc9..000000000000
--- a/tests/net/common/java/android/net/metrics/IpManagerEventTest.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.metrics
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class IpManagerEventTest {
- @Test
- fun testConstructorAndParcel() {
- (IpManagerEvent.PROVISIONING_OK..IpManagerEvent.ERROR_INTERFACE_NOT_FOUND).forEach {
- val ipManagerEvent = IpManagerEvent(it, Long.MAX_VALUE)
- assertEquals(it, ipManagerEvent.eventType)
- assertEquals(Long.MAX_VALUE, ipManagerEvent.durationMs)
-
- assertParcelSane(ipManagerEvent, 2)
- }
- }
-}
diff --git a/tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt b/tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt
deleted file mode 100644
index 55b5e492dd47..000000000000
--- a/tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.metrics
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class IpReachabilityEventTest {
- @Test
- fun testConstructorAndParcel() {
- (IpReachabilityEvent.PROBE..IpReachabilityEvent.PROVISIONING_LOST_ORGANIC).forEach {
- val ipReachabilityEvent = IpReachabilityEvent(it)
- assertEquals(it, ipReachabilityEvent.eventType)
-
- assertParcelSane(ipReachabilityEvent, 1)
- }
- }
-}
diff --git a/tests/net/common/java/android/net/metrics/NetworkEventTest.kt b/tests/net/common/java/android/net/metrics/NetworkEventTest.kt
deleted file mode 100644
index 41430b03a1eb..000000000000
--- a/tests/net/common/java/android/net/metrics/NetworkEventTest.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.metrics
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class NetworkEventTest {
- @Test
- fun testConstructorAndParcel() {
- (NetworkEvent.NETWORK_CONNECTED..NetworkEvent.NETWORK_PARTIAL_CONNECTIVITY).forEach {
- var networkEvent = NetworkEvent(it)
- assertEquals(it, networkEvent.eventType)
- assertEquals(0, networkEvent.durationMs)
-
- networkEvent = NetworkEvent(it, Long.MAX_VALUE)
- assertEquals(it, networkEvent.eventType)
- assertEquals(Long.MAX_VALUE, networkEvent.durationMs)
-
- assertParcelSane(networkEvent, 2)
- }
- }
-}
diff --git a/tests/net/common/java/android/net/metrics/RaEventTest.kt b/tests/net/common/java/android/net/metrics/RaEventTest.kt
deleted file mode 100644
index d9b720332fbe..000000000000
--- a/tests/net/common/java/android/net/metrics/RaEventTest.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.metrics
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-private const val NO_LIFETIME: Long = -1L
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class RaEventTest {
- @Test
- fun testConstructorAndParcel() {
- var raEvent = RaEvent.Builder().build()
- assertEquals(NO_LIFETIME, raEvent.routerLifetime)
- assertEquals(NO_LIFETIME, raEvent.prefixValidLifetime)
- assertEquals(NO_LIFETIME, raEvent.prefixPreferredLifetime)
- assertEquals(NO_LIFETIME, raEvent.routeInfoLifetime)
- assertEquals(NO_LIFETIME, raEvent.rdnssLifetime)
- assertEquals(NO_LIFETIME, raEvent.dnsslLifetime)
-
- raEvent = RaEvent.Builder()
- .updateRouterLifetime(1)
- .updatePrefixValidLifetime(2)
- .updatePrefixPreferredLifetime(3)
- .updateRouteInfoLifetime(4)
- .updateRdnssLifetime(5)
- .updateDnsslLifetime(6)
- .build()
- assertEquals(1, raEvent.routerLifetime)
- assertEquals(2, raEvent.prefixValidLifetime)
- assertEquals(3, raEvent.prefixPreferredLifetime)
- assertEquals(4, raEvent.routeInfoLifetime)
- assertEquals(5, raEvent.rdnssLifetime)
- assertEquals(6, raEvent.dnsslLifetime)
-
- raEvent = RaEvent.Builder()
- .updateRouterLifetime(Long.MIN_VALUE)
- .updateRouterLifetime(Long.MAX_VALUE)
- .build()
- assertEquals(Long.MIN_VALUE, raEvent.routerLifetime)
-
- raEvent = RaEvent(1, 2, 3, 4, 5, 6)
- assertEquals(1, raEvent.routerLifetime)
- assertEquals(2, raEvent.prefixValidLifetime)
- assertEquals(3, raEvent.prefixPreferredLifetime)
- assertEquals(4, raEvent.routeInfoLifetime)
- assertEquals(5, raEvent.rdnssLifetime)
- assertEquals(6, raEvent.dnsslLifetime)
-
- assertParcelSane(raEvent, 6)
- }
-}
diff --git a/tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt b/tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt
deleted file mode 100644
index 51c0d41bf4d5..000000000000
--- a/tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.metrics
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import java.lang.reflect.Modifier
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-
-private const val FIRST_VALIDATION: Int = 1 shl 8
-private const val REVALIDATION: Int = 2 shl 8
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class ValidationProbeEventTest {
- private infix fun Int.hasType(type: Int) = (type and this) == type
-
- @Test
- fun testBuilderAndParcel() {
- var validationProbeEvent = ValidationProbeEvent.Builder()
- .setProbeType(ValidationProbeEvent.PROBE_DNS, false).build()
-
- assertTrue(validationProbeEvent.probeType hasType REVALIDATION)
-
- validationProbeEvent = ValidationProbeEvent.Builder()
- .setDurationMs(Long.MAX_VALUE)
- .setProbeType(ValidationProbeEvent.PROBE_DNS, true)
- .setReturnCode(ValidationProbeEvent.DNS_SUCCESS)
- .build()
-
- assertEquals(Long.MAX_VALUE, validationProbeEvent.durationMs)
- assertTrue(validationProbeEvent.probeType hasType ValidationProbeEvent.PROBE_DNS)
- assertTrue(validationProbeEvent.probeType hasType FIRST_VALIDATION)
- assertEquals(ValidationProbeEvent.DNS_SUCCESS, validationProbeEvent.returnCode)
-
- assertParcelSane(validationProbeEvent, 3)
- }
-
- @Test
- fun testGetProbeName() {
- val probeFields = ValidationProbeEvent::class.java.declaredFields.filter {
- it.type == Int::class.javaPrimitiveType
- && Modifier.isPublic(it.modifiers) && Modifier.isStatic(it.modifiers)
- && it.name.contains("PROBE")
- }
-
- probeFields.forEach {
- val intValue = it.getInt(null)
- val stringValue = ValidationProbeEvent.getProbeName(intValue)
- assertEquals(it.name, stringValue)
- }
-
- }
-}
diff --git a/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt b/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt
deleted file mode 100644
index 7b22e45db90a..000000000000
--- a/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netstats
-
-import android.net.NetworkStats
-import android.net.NetworkStats.DEFAULT_NETWORK_NO
-import android.net.NetworkStats.DEFAULT_NETWORK_YES
-import android.net.NetworkStats.Entry
-import android.net.NetworkStats.IFACE_VT
-import android.net.NetworkStats.METERED_NO
-import android.net.NetworkStats.METERED_YES
-import android.net.NetworkStats.ROAMING_NO
-import android.net.NetworkStats.ROAMING_YES
-import android.net.NetworkStats.SET_DEFAULT
-import android.net.NetworkStats.SET_FOREGROUND
-import android.net.NetworkStats.TAG_NONE
-import android.os.Build
-import androidx.test.filters.SmallTest
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.assertFieldCountEquals
-import com.android.testutils.assertNetworkStatsEquals
-import com.android.testutils.assertParcelingIsLossless
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import kotlin.test.assertEquals
-
-@RunWith(JUnit4::class)
-@SmallTest
-class NetworkStatsApiTest {
- @Rule
- @JvmField
- val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q)
-
- private val testStatsEmpty = NetworkStats(0L, 0)
-
- // Note that these variables need to be initialized outside of constructor, initialize
- // here with methods that don't exist in Q devices will result in crash.
-
- // stats1 and stats2 will have some entries with common keys, which are expected to
- // be merged if performing add on these 2 stats.
- private lateinit var testStats1: NetworkStats
- private lateinit var testStats2: NetworkStats
-
- // This is a result of adding stats1 and stats2, while the merging of common key items is
- // subject to test later, this should not be initialized with for a loop to add stats1
- // and stats2 above.
- private lateinit var testStats3: NetworkStats
-
- companion object {
- private const val TEST_IFACE = "test0"
- private const val TEST_UID1 = 1001
- private const val TEST_UID2 = 1002
- }
-
- @Before
- fun setUp() {
- testStats1 = NetworkStats(0L, 0)
- // Entries which only appear in set1.
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 37, 52, 1, 10, 4))
- // Entries which are common for set1 and set2.
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 17, 2, 11, 1, 0))
- .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 40, 1, 0, 0, 8))
- .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 1, 6, 2, 0))
- assertEquals(8, testStats1.size())
-
- testStats2 = NetworkStats(0L, 0)
- // Entries which are common for set1 and set2.
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45))
- .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7))
- .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0))
- // Entry which only appears in set2.
- .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
- assertEquals(5, testStats2.size())
-
- testStats3 = NetworkStats(0L, 9)
- // Entries which are unique either in stats1 or stats2.
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2))
- .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
- // Entries which are common for stats1 and stats2 are being merged.
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 20, 17, 13, 32, 1))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 50, 113, 11, 11, 49))
- .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 51, 3, 3, 4, 15))
- .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 7, 4, 8, 3, 0))
- assertEquals(9, testStats3.size())
- }
-
- @Test
- fun testAddEntry() {
- val expectedEntriesInStats2 = arrayOf(
- Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1),
- Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45),
- Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7),
- Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0),
- Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
-
- // While testStats* are already initialized with addEntry, verify content added
- // matches expectation.
- for (i in expectedEntriesInStats2.indices) {
- val entry = testStats2.getValues(i, null)
- assertEquals(expectedEntriesInStats2[i], entry)
- }
-
- // Verify entry updated with addEntry.
- val stats = testStats2.addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12, -5, 7, 0, 9))
- assertEquals(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 16, -2, 9, 1, 9),
- stats.getValues(3, null))
- }
-
- @Test
- fun testAdd() {
- var stats = NetworkStats(0L, 0)
- assertNetworkStatsEquals(testStatsEmpty, stats)
- stats = stats.add(testStats2)
- assertNetworkStatsEquals(testStats2, stats)
- stats = stats.add(testStats1)
- // EMPTY + STATS2 + STATS1 = STATS3
- assertNetworkStatsEquals(testStats3, stats)
- }
-
- @Test
- fun testParcelUnparcel() {
- assertParcelingIsLossless(testStatsEmpty)
- assertParcelingIsLossless(testStats1)
- assertParcelingIsLossless(testStats2)
- assertFieldCountEquals(15, NetworkStats::class.java)
- }
-
- @Test
- fun testDescribeContents() {
- assertEquals(0, testStatsEmpty.describeContents())
- assertEquals(0, testStats1.describeContents())
- assertEquals(0, testStats2.describeContents())
- assertEquals(0, testStats3.describeContents())
- }
-
- @Test
- fun testSubtract() {
- // STATS3 - STATS2 = STATS1
- assertNetworkStatsEquals(testStats1, testStats3.subtract(testStats2))
- // STATS3 - STATS1 = STATS2
- assertNetworkStatsEquals(testStats2, testStats3.subtract(testStats1))
- }
-
- @Test
- fun testMethodsDontModifyReceiver() {
- listOf(testStatsEmpty, testStats1, testStats2, testStats3).forEach {
- val origStats = it.clone()
- it.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45))
- it.add(testStats3)
- it.subtract(testStats1)
- assertNetworkStatsEquals(origStats, it)
- }
- }
-} \ No newline at end of file
diff --git a/tests/net/common/java/android/net/util/SocketUtilsTest.kt b/tests/net/common/java/android/net/util/SocketUtilsTest.kt
deleted file mode 100644
index aaf97f36889b..000000000000
--- a/tests/net/common/java/android/net/util/SocketUtilsTest.kt
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.util
-
-import android.os.Build
-import android.system.NetlinkSocketAddress
-import android.system.Os
-import android.system.OsConstants.AF_INET
-import android.system.OsConstants.ETH_P_ALL
-import android.system.OsConstants.IPPROTO_UDP
-import android.system.OsConstants.RTMGRP_NEIGH
-import android.system.OsConstants.SOCK_DGRAM
-import android.system.PacketSocketAddress
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
-import org.junit.Assert.fail
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-private const val TEST_INDEX = 123
-private const val TEST_PORT = 555
-private const val FF_BYTE = 0xff.toByte()
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class SocketUtilsTest {
- @Rule @JvmField
- val ignoreRule = DevSdkIgnoreRule()
-
- @Test
- fun testMakeNetlinkSocketAddress() {
- val nlAddress = SocketUtils.makeNetlinkSocketAddress(TEST_PORT, RTMGRP_NEIGH)
- if (nlAddress is NetlinkSocketAddress) {
- assertEquals(TEST_PORT, nlAddress.getPortId())
- assertEquals(RTMGRP_NEIGH, nlAddress.getGroupsMask())
- } else {
- fail("Not NetlinkSocketAddress object")
- }
- }
-
- @Test
- fun testMakePacketSocketAddress_Q() {
- val pkAddress = SocketUtils.makePacketSocketAddress(ETH_P_ALL, TEST_INDEX)
- assertTrue("Not PacketSocketAddress object", pkAddress is PacketSocketAddress)
-
- val pkAddress2 = SocketUtils.makePacketSocketAddress(TEST_INDEX, ByteArray(6) { FF_BYTE })
- assertTrue("Not PacketSocketAddress object", pkAddress2 is PacketSocketAddress)
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testMakePacketSocketAddress() {
- val pkAddress = SocketUtils.makePacketSocketAddress(
- ETH_P_ALL, TEST_INDEX, ByteArray(6) { FF_BYTE })
- assertTrue("Not PacketSocketAddress object", pkAddress is PacketSocketAddress)
- }
-
- @Test
- fun testCloseSocket() {
- // Expect no exception happening with null object.
- SocketUtils.closeSocket(null)
-
- val fd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
- assertTrue(fd.valid())
- SocketUtils.closeSocket(fd)
- assertFalse(fd.valid())
- // Expecting socket should be still invalid even closed socket again.
- SocketUtils.closeSocket(fd)
- assertFalse(fd.valid())
- }
-}
diff --git a/tests/net/deflake/src/com/android/server/net/FrameworksNetDeflakeTest.kt b/tests/net/deflake/src/com/android/server/net/FrameworksNetDeflakeTest.kt
deleted file mode 100644
index 62855255fec2..000000000000
--- a/tests/net/deflake/src/com/android/server/net/FrameworksNetDeflakeTest.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.net
-
-import com.android.testutils.host.DeflakeHostTestBase
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
-import org.junit.runner.RunWith
-
-@RunWith(DeviceJUnit4ClassRunner::class)
-class FrameworksNetDeflakeTest: DeflakeHostTestBase() {
- override val runCount = 20
- override val testApkFilename = "FrameworksNetTests.apk"
- override val testClasses = listOf("com.android.server.ConnectivityServiceTest")
-} \ No newline at end of file
diff --git a/tests/net/integration/Android.bp b/tests/net/integration/Android.bp
deleted file mode 100644
index 874bd4b97df1..000000000000
--- a/tests/net/integration/Android.bp
+++ /dev/null
@@ -1,65 +0,0 @@
-//
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-android_test {
- name: "FrameworksNetIntegrationTests",
- platform_apis: true,
- certificate: "platform",
- srcs: [
- "src/**/*.kt",
- "src/**/*.aidl",
- ],
- libs: [
- "android.test.mock",
- ],
- static_libs: [
- "TestNetworkStackLib",
- "androidx.test.ext.junit",
- "frameworks-net-integration-testutils",
- "kotlin-reflect",
- "mockito-target-extended-minus-junit4",
- "net-tests-utils",
- "services.core",
- "services.net",
- "testables",
- ],
- test_suites: ["device-tests"],
- use_embedded_native_libs: true,
- jni_libs: [
- // For mockito extended
- "libdexmakerjvmtiagent",
- "libstaticjvmtiagent",
- // android_library does not include JNI libs: include NetworkStack dependencies here
- "libnativehelper_compat_libc++",
- "libnetworkstackutilsjni",
- ],
-}
-
-// Utilities for testing framework code both in integration and unit tests.
-java_library {
- name: "frameworks-net-integration-testutils",
- srcs: ["util/**/*.java", "util/**/*.kt"],
- static_libs: [
- "androidx.annotation_annotation",
- "androidx.test.rules",
- "junit",
- "net-tests-utils",
- ],
- libs: [
- "services.core",
- "services.net",
- ],
-}
diff --git a/tests/net/integration/AndroidManifest.xml b/tests/net/integration/AndroidManifest.xml
deleted file mode 100644
index 09c0e4826075..000000000000
--- a/tests/net/integration/AndroidManifest.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.net.integrationtests">
-
- <!-- For ConnectivityService registerReceiverAsUser (receiving broadcasts) -->
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
- <!-- PermissionMonitor sets network permissions for each user -->
- <uses-permission android:name="android.permission.MANAGE_USERS" />
- <!-- ConnectivityService sends notifications to BatteryStats -->
- <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
- <!-- Reading network status -->
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.NETWORK_FACTORY" />
- <uses-permission android:name="android.permission.NETWORK_STACK" />
- <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
- <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
- <!-- Reading DeviceConfig flags -->
- <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
- <application android:debuggable="true">
- <uses-library android:name="android.test.runner" />
-
- <!-- This manifest is merged with the base manifest of the real NetworkStack app.
- Remove the NetworkStackService from the base (real) manifest, and replace with a test
- service that responds to the same intent -->
- <service android:name=".TestNetworkStackService"
- android:process="com.android.server.net.integrationtests.testnetworkstack">
- <intent-filter>
- <action android:name="android.net.INetworkStackConnector.Test"/>
- </intent-filter>
- </service>
- <service android:name=".NetworkStackInstrumentationService"
- android:process="com.android.server.net.integrationtests.testnetworkstack">
- <intent-filter>
- <action android:name=".INetworkStackInstrumentation"/>
- </intent-filter>
- </service>
- <service android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService"
- android:process="com.android.server.net.integrationtests.testnetworkstack"
- android:permission="android.permission.BIND_JOB_SERVICE"/>
-
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.net.integrationtests"
- android:label="Frameworks Net Integration Tests" />
-
-</manifest>
diff --git a/tests/net/integration/res/values/config.xml b/tests/net/integration/res/values/config.xml
deleted file mode 100644
index 2c8046ffd781..000000000000
--- a/tests/net/integration/res/values/config.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <!--
- Override configuration for testing. The below settings use the config_ variants, which are
- normally used by RROs to override the setting with highest priority. -->
- <integer name="config_captive_portal_dns_probe_timeout">12500</integer>
- <string name="config_captive_portal_http_url" translatable="false">http://test.android.com</string>
- <string name="config_captive_portal_https_url" translatable="false">https://secure.test.android.com</string>
- <string-array name="config_captive_portal_fallback_urls" translatable="false">
- <item>http://fallback1.android.com</item>
- <item>http://fallback2.android.com</item>
- </string-array>
- <string-array name="config_captive_portal_fallback_probe_specs" translatable="false">
- </string-array>
-</resources>
diff --git a/tests/net/integration/src/android/net/TestNetworkStackClient.kt b/tests/net/integration/src/android/net/TestNetworkStackClient.kt
deleted file mode 100644
index 01eb514a1c81..000000000000
--- a/tests/net/integration/src/android/net/TestNetworkStackClient.kt
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net
-
-import android.content.ComponentName
-import android.content.Context
-import android.content.Intent
-import android.os.IBinder
-import com.android.server.net.integrationtests.TestNetworkStackService
-import org.mockito.Mockito.any
-import org.mockito.Mockito.spy
-import org.mockito.Mockito.timeout
-import org.mockito.Mockito.verify
-import kotlin.test.fail
-
-const val TEST_ACTION_SUFFIX = ".Test"
-
-class TestNetworkStackClient(context: Context) : NetworkStackClient(TestDependencies(context)) {
- // TODO: consider switching to TrackRecord for more expressive checks
- private val lastCallbacks = HashMap<Network, INetworkMonitorCallbacks>()
-
- private class TestDependencies(private val context: Context) : Dependencies {
- override fun addToServiceManager(service: IBinder) = Unit
- override fun checkCallerUid() = Unit
-
- override fun getConnectivityModuleConnector(): ConnectivityModuleConnector {
- return ConnectivityModuleConnector { _, _, _, inSystemProcess ->
- getNetworkStackIntent(inSystemProcess)
- }.also { it.init(context) }
- }
-
- private fun getNetworkStackIntent(inSystemProcess: Boolean): Intent? {
- // Simulate out-of-system-process config: in-process service not found (null intent)
- if (inSystemProcess) return null
- val intent = Intent(INetworkStackConnector::class.qualifiedName + TEST_ACTION_SUFFIX)
- val serviceName = TestNetworkStackService::class.qualifiedName
- ?: fail("TestNetworkStackService name not found")
- intent.component = ComponentName(context.packageName, serviceName)
- return intent
- }
- }
-
- // base may be an instance of an inaccessible subclass, so non-spyable.
- // Use a known open class that delegates to the original instance for all methods except
- // asBinder. asBinder needs to use its own non-delegated implementation as otherwise it would
- // return a binder token to a class that is not spied on.
- open class NetworkMonitorCallbacksWrapper(private val base: INetworkMonitorCallbacks) :
- INetworkMonitorCallbacks.Stub(), INetworkMonitorCallbacks by base {
- // asBinder is implemented by both base class and delegate: specify explicitly
- override fun asBinder(): IBinder {
- return super.asBinder()
- }
- }
-
- override fun makeNetworkMonitor(network: Network, name: String?, cb: INetworkMonitorCallbacks) {
- val cbSpy = spy(NetworkMonitorCallbacksWrapper(cb))
- lastCallbacks[network] = cbSpy
- super.makeNetworkMonitor(network, name, cbSpy)
- }
-
- fun verifyNetworkMonitorCreated(network: Network, timeoutMs: Long) {
- val cb = lastCallbacks[network]
- ?: fail("NetworkMonitor for network $network not requested")
- verify(cb, timeout(timeoutMs)).onNetworkMonitorCreated(any())
- }
-} \ No newline at end of file
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
deleted file mode 100644
index 344d0c3260c9..000000000000
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.net.integrationtests
-
-import android.content.ComponentName
-import android.content.Context
-import android.content.Context.BIND_AUTO_CREATE
-import android.content.Context.BIND_IMPORTANT
-import android.content.Intent
-import android.content.ServiceConnection
-import android.net.ConnectivityManager
-import android.net.IDnsResolver
-import android.net.INetd
-import android.net.INetworkPolicyManager
-import android.net.INetworkStatsService
-import android.net.LinkProperties
-import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
-import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
-import android.net.NetworkRequest
-import android.net.TestNetworkStackClient
-import android.net.metrics.IpConnectivityLog
-import android.os.ConditionVariable
-import android.os.IBinder
-import android.os.INetworkManagementService
-import android.testing.TestableContext
-import android.util.Log
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.ConnectivityService
-import com.android.server.LocalServices
-import com.android.server.NetworkAgentWrapper
-import com.android.server.TestNetIdManager
-import com.android.server.connectivity.DefaultNetworkMetrics
-import com.android.server.connectivity.IpConnectivityMetrics
-import com.android.server.connectivity.MockableSystemProperties
-import com.android.server.connectivity.ProxyTracker
-import com.android.server.net.NetworkPolicyManagerInternal
-import com.android.testutils.TestableNetworkCallback
-import org.junit.After
-import org.junit.Before
-import org.junit.BeforeClass
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.any
-import org.mockito.Mockito.doNothing
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.spy
-import org.mockito.MockitoAnnotations
-import org.mockito.Spy
-import kotlin.test.assertEquals
-import kotlin.test.assertTrue
-import kotlin.test.fail
-
-const val SERVICE_BIND_TIMEOUT_MS = 5_000L
-const val TEST_TIMEOUT_MS = 1_000L
-
-/**
- * Test that exercises an instrumented version of ConnectivityService against an instrumented
- * NetworkStack in a different test process.
- */
-@RunWith(AndroidJUnit4::class)
-class ConnectivityServiceIntegrationTest {
- // lateinit used here for mocks as they need to be reinitialized between each test and the test
- // should crash if they are used before being initialized.
- @Mock
- private lateinit var netManager: INetworkManagementService
- @Mock
- private lateinit var statsService: INetworkStatsService
- @Mock
- private lateinit var policyManager: INetworkPolicyManager
- @Mock
- private lateinit var log: IpConnectivityLog
- @Mock
- private lateinit var netd: INetd
- @Mock
- private lateinit var dnsResolver: IDnsResolver
- @Mock
- private lateinit var metricsLogger: IpConnectivityMetrics.Logger
- @Mock
- private lateinit var defaultMetrics: DefaultNetworkMetrics
- @Spy
- private var context = TestableContext(realContext)
-
- // lateinit for these three classes under test, as they should be reset to a different instance
- // for every test but should always be initialized before use (or the test should crash).
- private lateinit var networkStackClient: TestNetworkStackClient
- private lateinit var service: ConnectivityService
- private lateinit var cm: ConnectivityManager
-
- companion object {
- // lateinit for this binder token, as it must be initialized before any test code is run
- // and use of it before init should crash the test.
- private lateinit var nsInstrumentation: INetworkStackInstrumentation
- private val bindingCondition = ConditionVariable(false)
-
- private val realContext get() = InstrumentationRegistry.getInstrumentation().context
-
- private class InstrumentationServiceConnection : ServiceConnection {
- override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
- Log.i("TestNetworkStack", "Service connected")
- try {
- if (service == null) fail("Error binding to NetworkStack instrumentation")
- if (::nsInstrumentation.isInitialized) fail("Service already connected")
- nsInstrumentation = INetworkStackInstrumentation.Stub.asInterface(service)
- } finally {
- bindingCondition.open()
- }
- }
-
- override fun onServiceDisconnected(name: ComponentName?) = Unit
- }
-
- @BeforeClass
- @JvmStatic
- fun setUpClass() {
- val intent = Intent(realContext, NetworkStackInstrumentationService::class.java)
- intent.action = INetworkStackInstrumentation::class.qualifiedName
- assertTrue(realContext.bindService(intent, InstrumentationServiceConnection(),
- BIND_AUTO_CREATE or BIND_IMPORTANT),
- "Error binding to instrumentation service")
- assertTrue(bindingCondition.block(SERVICE_BIND_TIMEOUT_MS),
- "Timed out binding to instrumentation service " +
- "after $SERVICE_BIND_TIMEOUT_MS ms")
- }
- }
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- doReturn(defaultMetrics).`when`(metricsLogger).defaultNetworkMetrics()
- doNothing().`when`(context).sendStickyBroadcastAsUser(any(), any(), any())
-
- networkStackClient = TestNetworkStackClient(realContext)
- networkStackClient.init()
- networkStackClient.start()
-
- LocalServices.removeServiceForTest(NetworkPolicyManagerInternal::class.java)
- LocalServices.addService(NetworkPolicyManagerInternal::class.java,
- mock(NetworkPolicyManagerInternal::class.java))
-
- service = TestConnectivityService(makeDependencies())
- cm = ConnectivityManager(context, service)
- context.addMockSystemService(Context.CONNECTIVITY_SERVICE, cm)
-
- service.systemReady()
- }
-
- private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService(
- context, netManager, statsService, policyManager, dnsResolver, log, netd, deps)
-
- private fun makeDependencies(): ConnectivityService.Dependencies {
- val deps = spy(ConnectivityService.Dependencies())
- doReturn(networkStackClient).`when`(deps).networkStack
- doReturn(metricsLogger).`when`(deps).metricsLogger
- doReturn(mock(ProxyTracker::class.java)).`when`(deps).makeProxyTracker(any(), any())
- doReturn(mock(MockableSystemProperties::class.java)).`when`(deps).systemProperties
- doReturn(TestNetIdManager()).`when`(deps).makeNetIdManager()
- return deps
- }
-
- @After
- fun tearDown() {
- nsInstrumentation.clearAllState()
- }
-
- @Test
- fun testValidation() {
- val request = NetworkRequest.Builder()
- .clearCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .build()
- val testCallback = TestableNetworkCallback()
-
- cm.registerNetworkCallback(request, testCallback)
- nsInstrumentation.addHttpResponse(HttpResponse(
- "http://test.android.com",
- responseCode = 204, contentLength = 42, redirectUrl = null))
- nsInstrumentation.addHttpResponse(HttpResponse(
- "https://secure.test.android.com",
- responseCode = 204, contentLength = 42, redirectUrl = null))
-
- val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, LinkProperties(), null /* ncTemplate */,
- context)
- networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS)
-
- na.addCapability(NET_CAPABILITY_INTERNET)
- na.connect()
-
- testCallback.expectAvailableThenValidatedCallbacks(na.network, TEST_TIMEOUT_MS)
- assertEquals(2, nsInstrumentation.getRequestUrls().size)
- }
-}
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl b/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl
deleted file mode 100644
index 9a2bcfea7641..000000000000
--- a/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.net.integrationtests;
-
-parcelable HttpResponse; \ No newline at end of file
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt b/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt
deleted file mode 100644
index 45073d8df3f7..000000000000
--- a/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.net.integrationtests
-
-import android.os.Parcel
-import android.os.Parcelable
-
-data class HttpResponse(
- val requestUrl: String,
- val responseCode: Int,
- val contentLength: Long,
- val redirectUrl: String?
-) : Parcelable {
- constructor(p: Parcel): this(p.readString(), p.readInt(), p.readLong(), p.readString())
-
- override fun writeToParcel(dest: Parcel, flags: Int) {
- with(dest) {
- writeString(requestUrl)
- writeInt(responseCode)
- writeLong(contentLength)
- writeString(redirectUrl)
- }
- }
-
- override fun describeContents() = 0
- companion object CREATOR : Parcelable.Creator<HttpResponse> {
- override fun createFromParcel(source: Parcel) = HttpResponse(source)
- override fun newArray(size: Int) = arrayOfNulls<HttpResponse?>(size)
- }
-} \ No newline at end of file
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/INetworkStackInstrumentation.aidl b/tests/net/integration/src/com/android/server/net/integrationtests/INetworkStackInstrumentation.aidl
deleted file mode 100644
index efc58add9cf5..000000000000
--- a/tests/net/integration/src/com/android/server/net/integrationtests/INetworkStackInstrumentation.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.net.integrationtests;
-
-import com.android.server.net.integrationtests.HttpResponse;
-
-interface INetworkStackInstrumentation {
- void clearAllState();
- void addHttpResponse(in HttpResponse response);
- List<String> getRequestUrls();
-} \ No newline at end of file
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt
deleted file mode 100644
index 4827d2997d93..000000000000
--- a/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.net.integrationtests
-
-import android.app.Service
-import android.content.Intent
-import java.net.URL
-import java.util.Collections
-import java.util.concurrent.ConcurrentHashMap
-import java.util.concurrent.ConcurrentLinkedQueue
-import kotlin.collections.ArrayList
-import kotlin.test.fail
-
-/**
- * An instrumentation interface for the NetworkStack that allows controlling behavior to
- * facilitate integration tests.
- */
-class NetworkStackInstrumentationService : Service() {
- override fun onBind(intent: Intent) = InstrumentationConnector.asBinder()
-
- object InstrumentationConnector : INetworkStackInstrumentation.Stub() {
- private val httpResponses = ConcurrentHashMap<String, ConcurrentLinkedQueue<HttpResponse>>()
- .run {
- withDefault { key -> getOrPut(key) { ConcurrentLinkedQueue() } }
- }
- private val httpRequestUrls = Collections.synchronizedList(ArrayList<String>())
-
- /**
- * Called when an HTTP request is being processed by NetworkMonitor. Returns the response
- * that should be simulated.
- */
- fun processRequest(url: URL): HttpResponse {
- val strUrl = url.toString()
- httpRequestUrls.add(strUrl)
- return httpResponses[strUrl]?.poll()
- ?: fail("No mocked response for request: $strUrl. " +
- "Mocked URL keys are: ${httpResponses.keys}")
- }
-
- /**
- * Clear all state of this connector. This is intended for use between two tests, so all
- * state should be reset as if the connector was just created.
- */
- override fun clearAllState() {
- httpResponses.clear()
- httpRequestUrls.clear()
- }
-
- /**
- * Add a response to a future HTTP request.
- *
- * <p>For any subsequent HTTP/HTTPS query, the first response with a matching URL will be
- * used to mock the query response.
- */
- override fun addHttpResponse(response: HttpResponse) {
- httpResponses.getValue(response.requestUrl).add(response)
- }
-
- /**
- * Get the ordered list of request URLs that have been sent by NetworkMonitor, and were
- * answered based on mock responses.
- */
- override fun getRequestUrls(): List<String> {
- return ArrayList(httpRequestUrls)
- }
- }
-} \ No newline at end of file
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
deleted file mode 100644
index 649f71d4293f..000000000000
--- a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.net.integrationtests
-
-import android.app.Service
-import android.content.Context
-import android.content.Intent
-import android.net.INetworkMonitorCallbacks
-import android.net.Network
-import android.net.metrics.IpConnectivityLog
-import android.net.util.SharedLog
-import android.os.IBinder
-import com.android.networkstack.netlink.TcpSocketTracker
-import com.android.server.NetworkStackService
-import com.android.server.NetworkStackService.NetworkMonitorConnector
-import com.android.server.NetworkStackService.NetworkStackConnector
-import com.android.server.connectivity.NetworkMonitor
-import com.android.server.net.integrationtests.NetworkStackInstrumentationService.InstrumentationConnector
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.spy
-import java.net.HttpURLConnection
-import java.net.URL
-import java.net.URLConnection
-
-private const val TEST_NETID = 42
-
-/**
- * Android service that can return an [android.net.INetworkStackConnector] which can be instrumented
- * through [NetworkStackInstrumentationService].
- * Useful in tests to create test instrumented NetworkStack components that can receive
- * instrumentation commands through [NetworkStackInstrumentationService].
- */
-class TestNetworkStackService : Service() {
- override fun onBind(intent: Intent): IBinder = TestNetworkStackConnector(makeTestContext())
-
- private fun makeTestContext() = spy(applicationContext).also {
- doReturn(mock(IBinder::class.java)).`when`(it).getSystemService(Context.NETD_SERVICE)
- }
-
- private class TestPermissionChecker : NetworkStackService.PermissionChecker() {
- override fun enforceNetworkStackCallingPermission() = Unit
- }
-
- private class NetworkMonitorDeps(private val privateDnsBypassNetwork: Network) :
- NetworkMonitor.Dependencies() {
- override fun getPrivateDnsBypassNetwork(network: Network?) = privateDnsBypassNetwork
- }
-
- private inner class TestNetworkStackConnector(context: Context) : NetworkStackConnector(
- context, TestPermissionChecker(), NetworkStackService.Dependencies()) {
-
- private val network = Network(TEST_NETID)
- private val privateDnsBypassNetwork = TestNetwork(TEST_NETID)
-
- private inner class TestNetwork(netId: Int) : Network(netId) {
- override fun openConnection(url: URL): URLConnection {
- val response = InstrumentationConnector.processRequest(url)
-
- val connection = mock(HttpURLConnection::class.java)
- doReturn(response.responseCode).`when`(connection).responseCode
- doReturn(response.contentLength).`when`(connection).contentLengthLong
- doReturn(response.redirectUrl).`when`(connection).getHeaderField("location")
- return connection
- }
- }
-
- override fun makeNetworkMonitor(
- network: Network,
- name: String?,
- cb: INetworkMonitorCallbacks
- ) {
- val nm = NetworkMonitor(this@TestNetworkStackService, cb,
- this.network,
- mock(IpConnectivityLog::class.java), mock(SharedLog::class.java),
- mock(NetworkStackService.NetworkStackServiceManager::class.java),
- NetworkMonitorDeps(privateDnsBypassNetwork),
- mock(TcpSocketTracker::class.java))
- cb.onNetworkMonitorCreated(NetworkMonitorConnector(nm, TestPermissionChecker()))
- }
- }
-}
diff --git a/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt b/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt
deleted file mode 100644
index fa2b99ce5cc6..000000000000
--- a/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server
-
-import android.net.ConnectivityManager.TYPE_BLUETOOTH
-import android.net.ConnectivityManager.TYPE_ETHERNET
-import android.net.ConnectivityManager.TYPE_MOBILE
-import android.net.ConnectivityManager.TYPE_NONE
-import android.net.ConnectivityManager.TYPE_TEST
-import android.net.ConnectivityManager.TYPE_VPN
-import android.net.ConnectivityManager.TYPE_WIFI
-import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH
-import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
-import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
-import android.net.NetworkCapabilities.TRANSPORT_TEST
-import android.net.NetworkCapabilities.TRANSPORT_VPN
-import android.net.NetworkCapabilities.TRANSPORT_WIFI
-
-fun transportToLegacyType(transport: Int) = when (transport) {
- TRANSPORT_BLUETOOTH -> TYPE_BLUETOOTH
- TRANSPORT_CELLULAR -> TYPE_MOBILE
- TRANSPORT_ETHERNET -> TYPE_ETHERNET
- TRANSPORT_TEST -> TYPE_TEST
- TRANSPORT_VPN -> TYPE_VPN
- TRANSPORT_WIFI -> TYPE_WIFI
- else -> TYPE_NONE
-} \ No newline at end of file
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
deleted file mode 100644
index 03954de98438..000000000000
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
-
-import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType;
-
-import static junit.framework.Assert.assertTrue;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkAgent;
-import android.net.NetworkAgentConfig;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkProvider;
-import android.net.NetworkSpecifier;
-import android.net.SocketKeepalive;
-import android.net.UidRange;
-import android.os.ConditionVariable;
-import android.os.HandlerThread;
-import android.os.Message;
-import android.util.Log;
-
-import com.android.server.connectivity.ConnectivityConstants;
-import com.android.testutils.HandlerUtilsKt;
-import com.android.testutils.TestableNetworkCallback;
-
-import java.util.Set;
-
-public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
- private final NetworkInfo mNetworkInfo;
- private final NetworkCapabilities mNetworkCapabilities;
- private final HandlerThread mHandlerThread;
- private final Context mContext;
- private final String mLogTag;
-
- private final ConditionVariable mDisconnected = new ConditionVariable();
- private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
- private int mScore;
- private NetworkAgent mNetworkAgent;
- private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED;
- private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE;
- private Integer mExpectedKeepaliveSlot = null;
-
- public NetworkAgentWrapper(int transport, LinkProperties linkProperties,
- NetworkCapabilities ncTemplate, Context context) throws Exception {
- final int type = transportToLegacyType(transport);
- final String typeName = ConnectivityManager.getNetworkTypeName(type);
- mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");
- mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
- mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- mNetworkCapabilities.addTransportType(transport);
- switch (transport) {
- case TRANSPORT_ETHERNET:
- mScore = 70;
- break;
- case TRANSPORT_WIFI:
- mScore = 60;
- break;
- case TRANSPORT_CELLULAR:
- mScore = 50;
- break;
- case TRANSPORT_WIFI_AWARE:
- mScore = 20;
- break;
- case TRANSPORT_VPN:
- mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
- // VPNs deduce the SUSPENDED capability from their underlying networks and there
- // is no public API to let VPN services set it.
- mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
- mScore = ConnectivityConstants.VPN_DEFAULT_SCORE;
- break;
- default:
- throw new UnsupportedOperationException("unimplemented network type");
- }
- mContext = context;
- mLogTag = "Mock-" + typeName;
- mHandlerThread = new HandlerThread(mLogTag);
- mHandlerThread.start();
-
- mNetworkAgent = makeNetworkAgent(linkProperties);
- }
-
- protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties)
- throws Exception {
- return new InstrumentedNetworkAgent(this, linkProperties);
- }
-
- public static class InstrumentedNetworkAgent extends NetworkAgent {
- private final NetworkAgentWrapper mWrapper;
-
- public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp) {
- super(wrapper.mHandlerThread.getLooper(), wrapper.mContext, wrapper.mLogTag,
- wrapper.mNetworkInfo, wrapper.mNetworkCapabilities, lp, wrapper.mScore,
- new NetworkAgentConfig(), NetworkProvider.ID_NONE);
- mWrapper = wrapper;
- }
-
- @Override
- public void unwanted() {
- mWrapper.mDisconnected.open();
- }
-
- @Override
- public void startSocketKeepalive(Message msg) {
- int slot = msg.arg1;
- if (mWrapper.mExpectedKeepaliveSlot != null) {
- assertEquals((int) mWrapper.mExpectedKeepaliveSlot, slot);
- }
- onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError);
- }
-
- @Override
- public void stopSocketKeepalive(Message msg) {
- onSocketKeepaliveEvent(msg.arg1, mWrapper.mStopKeepaliveError);
- }
-
- @Override
- protected void preventAutomaticReconnect() {
- mWrapper.mPreventReconnectReceived.open();
- }
-
- @Override
- protected void addKeepalivePacketFilter(Message msg) {
- Log.i(mWrapper.mLogTag, "Add keepalive packet filter.");
- }
-
- @Override
- protected void removeKeepalivePacketFilter(Message msg) {
- Log.i(mWrapper.mLogTag, "Remove keepalive packet filter.");
- }
- }
-
- public void adjustScore(int change) {
- mScore += change;
- mNetworkAgent.sendNetworkScore(mScore);
- }
-
- public int getScore() {
- return mScore;
- }
-
- public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) {
- mNetworkAgent.explicitlySelected(explicitlySelected, acceptUnvalidated);
- }
-
- public void addCapability(int capability) {
- mNetworkCapabilities.addCapability(capability);
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
-
- public void removeCapability(int capability) {
- mNetworkCapabilities.removeCapability(capability);
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
-
- public void setUids(Set<UidRange> uids) {
- mNetworkCapabilities.setUids(uids);
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
-
- public void setSignalStrength(int signalStrength) {
- mNetworkCapabilities.setSignalStrength(signalStrength);
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
-
- public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
- mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
-
- public void setNetworkCapabilities(NetworkCapabilities nc, boolean sendToConnectivityService) {
- mNetworkCapabilities.set(nc);
- if (sendToConnectivityService) {
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
- }
-
- public void connect() {
- assertNotEquals("MockNetworkAgents can only be connected once",
- getNetworkInfo().getDetailedState(), NetworkInfo.DetailedState.CONNECTED);
- mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
- mNetworkAgent.sendNetworkInfo(mNetworkInfo);
- }
-
- public void suspend() {
- removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
- }
-
- public void resume() {
- addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- }
-
- public void disconnect() {
- mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
- mNetworkAgent.sendNetworkInfo(mNetworkInfo);
- }
-
- @Override
- public Network getNetwork() {
- return mNetworkAgent.getNetwork();
- }
-
- public void expectPreventReconnectReceived(long timeoutMs) {
- assertTrue(mPreventReconnectReceived.block(timeoutMs));
- }
-
- public void expectDisconnected(long timeoutMs) {
- assertTrue(mDisconnected.block(timeoutMs));
- }
-
- public void sendLinkProperties(LinkProperties lp) {
- mNetworkAgent.sendLinkProperties(lp);
- }
-
- public void setStartKeepaliveEvent(int reason) {
- mStartKeepaliveError = reason;
- }
-
- public void setStopKeepaliveEvent(int reason) {
- mStopKeepaliveError = reason;
- }
-
- public void setExpectedKeepaliveSlot(Integer slot) {
- mExpectedKeepaliveSlot = slot;
- }
-
- public NetworkAgent getNetworkAgent() {
- return mNetworkAgent;
- }
-
- public NetworkInfo getNetworkInfo() {
- return mNetworkInfo;
- }
-
- public NetworkCapabilities getNetworkCapabilities() {
- return mNetworkCapabilities;
- }
-
- public void waitForIdle(long timeoutMs) {
- HandlerUtilsKt.waitForIdle(mHandlerThread, timeoutMs);
- }
-}
diff --git a/tests/net/integration/util/com/android/server/TestNetIdManager.kt b/tests/net/integration/util/com/android/server/TestNetIdManager.kt
deleted file mode 100644
index 938a694e8ba9..000000000000
--- a/tests/net/integration/util/com/android/server/TestNetIdManager.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server
-
-import java.util.concurrent.atomic.AtomicInteger
-
-/**
- * A [NetIdManager] that generates ID starting from [NetIdManager.MAX_NET_ID] and decreasing, rather
- * than starting from [NetIdManager.MIN_NET_ID] and increasing.
- *
- * Useful for testing ConnectivityService, to minimize the risk of test ConnectivityService netIDs
- * overlapping with netIDs used by the real ConnectivityService on the device.
- *
- * IDs may still overlap if many networks have been used on the device (so the "real" netIDs
- * are close to MAX_NET_ID), but this is typically not the case when running unit tests. Also, there
- * is no way to fully solve the overlap issue without altering ID allocation in non-test code, as
- * the real ConnectivityService could start using netIds that have been used by the test in the
- * past.
- */
-class TestNetIdManager : NetIdManager() {
- private val nextId = AtomicInteger(MAX_NET_ID)
- override fun reserveNetId() = nextId.decrementAndGet()
- override fun releaseNetId(id: Int) = Unit
- fun peekNextNetId() = nextId.get() - 1
-}
diff --git a/tests/net/java/android/app/usage/NetworkStatsManagerTest.java b/tests/net/java/android/app/usage/NetworkStatsManagerTest.java
deleted file mode 100644
index 899295a019d2..000000000000
--- a/tests/net/java/android/app/usage/NetworkStatsManagerTest.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.usage;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.net.ConnectivityManager;
-import android.net.INetworkStatsService;
-import android.net.INetworkStatsSession;
-import android.net.NetworkStats.Entry;
-import android.net.NetworkStatsHistory;
-import android.net.NetworkTemplate;
-import android.os.RemoteException;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkStatsManagerTest {
-
- private @Mock INetworkStatsService mService;
- private @Mock INetworkStatsSession mStatsSession;
-
- private NetworkStatsManager mManager;
-
- // TODO: change to NetworkTemplate.MATCH_MOBILE once internal constant rename is merged to aosp.
- private static final int MATCH_MOBILE_ALL = 1;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mManager = new NetworkStatsManager(InstrumentationRegistry.getContext(), mService);
- }
-
- @Test
- public void testQueryDetails() throws RemoteException {
- final String subscriberId = "subid";
- final long startTime = 1;
- final long endTime = 100;
- final int uid1 = 10001;
- final int uid2 = 10002;
- final int uid3 = 10003;
-
- Entry uid1Entry1 = new Entry("if1", uid1,
- android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
- 100, 10, 200, 20, 0);
-
- Entry uid1Entry2 = new Entry(
- "if2", uid1,
- android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
- 100, 10, 200, 20, 0);
-
- Entry uid2Entry1 = new Entry("if1", uid2,
- android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
- 150, 10, 250, 20, 0);
-
- Entry uid2Entry2 = new Entry(
- "if2", uid2,
- android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
- 150, 10, 250, 20, 0);
-
- NetworkStatsHistory history1 = new NetworkStatsHistory(10, 2);
- history1.recordData(10, 20, uid1Entry1);
- history1.recordData(20, 30, uid1Entry2);
-
- NetworkStatsHistory history2 = new NetworkStatsHistory(10, 2);
- history1.recordData(30, 40, uid2Entry1);
- history1.recordData(35, 45, uid2Entry2);
-
-
- when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession);
- when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2, uid3 });
-
- when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
- eq(uid1), eq(android.net.NetworkStats.SET_ALL),
- eq(android.net.NetworkStats.TAG_NONE),
- eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime)))
- .then((InvocationOnMock inv) -> {
- NetworkTemplate template = inv.getArgument(0);
- assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
- assertEquals(subscriberId, template.getSubscriberId());
- return history1;
- });
-
- when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
- eq(uid2), eq(android.net.NetworkStats.SET_ALL),
- eq(android.net.NetworkStats.TAG_NONE),
- eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime)))
- .then((InvocationOnMock inv) -> {
- NetworkTemplate template = inv.getArgument(0);
- assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
- assertEquals(subscriberId, template.getSubscriberId());
- return history2;
- });
-
-
- NetworkStats stats = mManager.queryDetails(
- ConnectivityManager.TYPE_MOBILE, subscriberId, startTime, endTime);
-
- NetworkStats.Bucket bucket = new NetworkStats.Bucket();
-
- // First 2 buckets exactly match entry timings
- assertTrue(stats.getNextBucket(bucket));
- assertEquals(10, bucket.getStartTimeStamp());
- assertEquals(20, bucket.getEndTimeStamp());
- assertBucketMatches(uid1Entry1, bucket);
-
- assertTrue(stats.getNextBucket(bucket));
- assertEquals(20, bucket.getStartTimeStamp());
- assertEquals(30, bucket.getEndTimeStamp());
- assertBucketMatches(uid1Entry2, bucket);
-
- // 30 -> 40: contains uid2Entry1 and half of uid2Entry2
- assertTrue(stats.getNextBucket(bucket));
- assertEquals(30, bucket.getStartTimeStamp());
- assertEquals(40, bucket.getEndTimeStamp());
- assertEquals(225, bucket.getRxBytes());
- assertEquals(15, bucket.getRxPackets());
- assertEquals(375, bucket.getTxBytes());
- assertEquals(30, bucket.getTxPackets());
-
- // 40 -> 50: contains half of uid2Entry2
- assertTrue(stats.getNextBucket(bucket));
- assertEquals(40, bucket.getStartTimeStamp());
- assertEquals(50, bucket.getEndTimeStamp());
- assertEquals(75, bucket.getRxBytes());
- assertEquals(5, bucket.getRxPackets());
- assertEquals(125, bucket.getTxBytes());
- assertEquals(10, bucket.getTxPackets());
-
- assertFalse(stats.hasNextBucket());
- }
-
- @Test
- public void testQueryDetails_NoSubscriberId() throws RemoteException {
- final long startTime = 1;
- final long endTime = 100;
- final int uid1 = 10001;
- final int uid2 = 10002;
-
- when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession);
- when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2 });
-
- NetworkStats stats = mManager.queryDetails(
- ConnectivityManager.TYPE_MOBILE, null, startTime, endTime);
-
- when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
- anyInt(), anyInt(), anyInt(), anyInt(), anyLong(), anyLong()))
- .thenReturn(new NetworkStatsHistory(10, 0));
-
- verify(mStatsSession, times(1)).getHistoryIntervalForUid(
- argThat((NetworkTemplate t) ->
- // No subscriberId: MATCH_MOBILE_WILDCARD template
- t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD),
- eq(uid1), eq(android.net.NetworkStats.SET_ALL),
- eq(android.net.NetworkStats.TAG_NONE),
- eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
-
- verify(mStatsSession, times(1)).getHistoryIntervalForUid(
- argThat((NetworkTemplate t) ->
- // No subscriberId: MATCH_MOBILE_WILDCARD template
- t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD),
- eq(uid2), eq(android.net.NetworkStats.SET_ALL),
- eq(android.net.NetworkStats.TAG_NONE),
- eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
-
- assertFalse(stats.hasNextBucket());
- }
-
- private void assertBucketMatches(Entry expected, NetworkStats.Bucket actual) {
- assertEquals(expected.uid, actual.getUid());
- assertEquals(expected.rxBytes, actual.getRxBytes());
- assertEquals(expected.rxPackets, actual.getRxPackets());
- assertEquals(expected.txBytes, actual.getTxBytes());
- assertEquals(expected.txPackets, actual.getTxPackets());
- }
-}
diff --git a/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java b/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java
deleted file mode 100644
index 1d6c10766792..000000000000
--- a/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsBinder;
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback;
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
-import static android.net.ConnectivityDiagnosticsManager.DataStallReport;
-
-import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import android.content.Context;
-import android.os.PersistableBundle;
-
-import androidx.test.InstrumentationRegistry;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.Mock;
-
-import java.util.concurrent.Executor;
-
-@RunWith(JUnit4.class)
-public class ConnectivityDiagnosticsManagerTest {
- private static final int NET_ID = 1;
- private static final int DETECTION_METHOD = 2;
- private static final long TIMESTAMP = 10L;
- private static final String INTERFACE_NAME = "interface";
- private static final String BUNDLE_KEY = "key";
- private static final String BUNDLE_VALUE = "value";
-
- private static final Executor INLINE_EXECUTOR = x -> x.run();
-
- @Mock private IConnectivityManager mService;
- @Mock private ConnectivityDiagnosticsCallback mCb;
-
- private Context mContext;
- private ConnectivityDiagnosticsBinder mBinder;
- private ConnectivityDiagnosticsManager mManager;
-
- private String mPackageName;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getContext();
-
- mService = mock(IConnectivityManager.class);
- mCb = mock(ConnectivityDiagnosticsCallback.class);
-
- mBinder = new ConnectivityDiagnosticsBinder(mCb, INLINE_EXECUTOR);
- mManager = new ConnectivityDiagnosticsManager(mContext, mService);
-
- mPackageName = mContext.getOpPackageName();
- }
-
- @After
- public void tearDown() {
- // clear ConnectivityDiagnosticsManager callbacks map
- ConnectivityDiagnosticsManager.sCallbacks.clear();
- }
-
- private ConnectivityReport createSampleConnectivityReport() {
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setInterfaceName(INTERFACE_NAME);
-
- final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
- networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
-
- final PersistableBundle bundle = new PersistableBundle();
- bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
-
- return new ConnectivityReport(
- new Network(NET_ID), TIMESTAMP, linkProperties, networkCapabilities, bundle);
- }
-
- private ConnectivityReport createDefaultConnectivityReport() {
- return new ConnectivityReport(
- new Network(0),
- 0L,
- new LinkProperties(),
- new NetworkCapabilities(),
- PersistableBundle.EMPTY);
- }
-
- @Test
- public void testPersistableBundleEquals() {
- assertFalse(
- ConnectivityDiagnosticsManager.persistableBundleEquals(
- null, PersistableBundle.EMPTY));
- assertFalse(
- ConnectivityDiagnosticsManager.persistableBundleEquals(
- PersistableBundle.EMPTY, null));
- assertTrue(
- ConnectivityDiagnosticsManager.persistableBundleEquals(
- PersistableBundle.EMPTY, PersistableBundle.EMPTY));
-
- final PersistableBundle a = new PersistableBundle();
- a.putString(BUNDLE_KEY, BUNDLE_VALUE);
-
- final PersistableBundle b = new PersistableBundle();
- b.putString(BUNDLE_KEY, BUNDLE_VALUE);
-
- final PersistableBundle c = new PersistableBundle();
- c.putString(BUNDLE_KEY, null);
-
- assertFalse(
- ConnectivityDiagnosticsManager.persistableBundleEquals(PersistableBundle.EMPTY, a));
- assertFalse(
- ConnectivityDiagnosticsManager.persistableBundleEquals(a, PersistableBundle.EMPTY));
-
- assertTrue(ConnectivityDiagnosticsManager.persistableBundleEquals(a, b));
- assertTrue(ConnectivityDiagnosticsManager.persistableBundleEquals(b, a));
-
- assertFalse(ConnectivityDiagnosticsManager.persistableBundleEquals(a, c));
- assertFalse(ConnectivityDiagnosticsManager.persistableBundleEquals(c, a));
- }
-
- @Test
- public void testConnectivityReportEquals() {
- final ConnectivityReport defaultReport = createDefaultConnectivityReport();
- final ConnectivityReport sampleReport = createSampleConnectivityReport();
- assertEquals(sampleReport, createSampleConnectivityReport());
- assertEquals(defaultReport, createDefaultConnectivityReport());
-
- final LinkProperties linkProperties = sampleReport.getLinkProperties();
- final NetworkCapabilities networkCapabilities = sampleReport.getNetworkCapabilities();
- final PersistableBundle bundle = sampleReport.getAdditionalInfo();
-
- assertNotEquals(
- createDefaultConnectivityReport(),
- new ConnectivityReport(
- new Network(NET_ID),
- 0L,
- new LinkProperties(),
- new NetworkCapabilities(),
- PersistableBundle.EMPTY));
- assertNotEquals(
- createDefaultConnectivityReport(),
- new ConnectivityReport(
- new Network(0),
- TIMESTAMP,
- new LinkProperties(),
- new NetworkCapabilities(),
- PersistableBundle.EMPTY));
- assertNotEquals(
- createDefaultConnectivityReport(),
- new ConnectivityReport(
- new Network(0),
- 0L,
- linkProperties,
- new NetworkCapabilities(),
- PersistableBundle.EMPTY));
- assertNotEquals(
- createDefaultConnectivityReport(),
- new ConnectivityReport(
- new Network(0),
- TIMESTAMP,
- new LinkProperties(),
- networkCapabilities,
- PersistableBundle.EMPTY));
- assertNotEquals(
- createDefaultConnectivityReport(),
- new ConnectivityReport(
- new Network(0),
- TIMESTAMP,
- new LinkProperties(),
- new NetworkCapabilities(),
- bundle));
- }
-
- @Test
- public void testConnectivityReportParcelUnparcel() {
- assertParcelSane(createSampleConnectivityReport(), 5);
- }
-
- private DataStallReport createSampleDataStallReport() {
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setInterfaceName(INTERFACE_NAME);
-
- final PersistableBundle bundle = new PersistableBundle();
- bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
-
- final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
- networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
-
- return new DataStallReport(
- new Network(NET_ID),
- TIMESTAMP,
- DETECTION_METHOD,
- linkProperties,
- networkCapabilities,
- bundle);
- }
-
- private DataStallReport createDefaultDataStallReport() {
- return new DataStallReport(
- new Network(0),
- 0L,
- 0,
- new LinkProperties(),
- new NetworkCapabilities(),
- PersistableBundle.EMPTY);
- }
-
- @Test
- public void testDataStallReportEquals() {
- final DataStallReport defaultReport = createDefaultDataStallReport();
- final DataStallReport sampleReport = createSampleDataStallReport();
- assertEquals(sampleReport, createSampleDataStallReport());
- assertEquals(defaultReport, createDefaultDataStallReport());
-
- final LinkProperties linkProperties = sampleReport.getLinkProperties();
- final NetworkCapabilities networkCapabilities = sampleReport.getNetworkCapabilities();
- final PersistableBundle bundle = sampleReport.getStallDetails();
-
- assertNotEquals(
- defaultReport,
- new DataStallReport(
- new Network(NET_ID),
- 0L,
- 0,
- new LinkProperties(),
- new NetworkCapabilities(),
- PersistableBundle.EMPTY));
- assertNotEquals(
- defaultReport,
- new DataStallReport(
- new Network(0),
- TIMESTAMP,
- 0,
- new LinkProperties(),
- new NetworkCapabilities(),
- PersistableBundle.EMPTY));
- assertNotEquals(
- defaultReport,
- new DataStallReport(
- new Network(0),
- 0L,
- DETECTION_METHOD,
- new LinkProperties(),
- new NetworkCapabilities(),
- PersistableBundle.EMPTY));
- assertNotEquals(
- defaultReport,
- new DataStallReport(
- new Network(0),
- 0L,
- 0,
- linkProperties,
- new NetworkCapabilities(),
- PersistableBundle.EMPTY));
- assertNotEquals(
- defaultReport,
- new DataStallReport(
- new Network(0),
- 0L,
- 0,
- new LinkProperties(),
- networkCapabilities,
- PersistableBundle.EMPTY));
- assertNotEquals(
- defaultReport,
- new DataStallReport(
- new Network(0),
- 0L,
- 0,
- new LinkProperties(),
- new NetworkCapabilities(),
- bundle));
- }
-
- @Test
- public void testDataStallReportParcelUnparcel() {
- assertParcelSane(createSampleDataStallReport(), 6);
- }
-
- @Test
- public void testConnectivityDiagnosticsCallbackOnConnectivityReportAvailable() {
- mBinder.onConnectivityReportAvailable(createSampleConnectivityReport());
-
- // The callback will be invoked synchronously by inline executor. Immediately check the
- // latch without waiting.
- verify(mCb).onConnectivityReportAvailable(eq(createSampleConnectivityReport()));
- }
-
- @Test
- public void testConnectivityDiagnosticsCallbackOnDataStallSuspected() {
- mBinder.onDataStallSuspected(createSampleDataStallReport());
-
- // The callback will be invoked synchronously by inline executor. Immediately check the
- // latch without waiting.
- verify(mCb).onDataStallSuspected(eq(createSampleDataStallReport()));
- }
-
- @Test
- public void testConnectivityDiagnosticsCallbackOnNetworkConnectivityReported() {
- final Network n = new Network(NET_ID);
- final boolean connectivity = true;
-
- mBinder.onNetworkConnectivityReported(n, connectivity);
-
- // The callback will be invoked synchronously by inline executor. Immediately check the
- // latch without waiting.
- verify(mCb).onNetworkConnectivityReported(eq(n), eq(connectivity));
- }
-
- @Test
- public void testRegisterConnectivityDiagnosticsCallback() throws Exception {
- final NetworkRequest request = new NetworkRequest.Builder().build();
-
- mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
-
- verify(mService).registerConnectivityDiagnosticsCallback(
- any(ConnectivityDiagnosticsBinder.class), eq(request), eq(mPackageName));
- assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
- }
-
- @Test
- public void testRegisterDuplicateConnectivityDiagnosticsCallback() throws Exception {
- final NetworkRequest request = new NetworkRequest.Builder().build();
-
- mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
-
- try {
- mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
- fail("Duplicate callback registration should fail");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testUnregisterConnectivityDiagnosticsCallback() throws Exception {
- final NetworkRequest request = new NetworkRequest.Builder().build();
- mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
-
- mManager.unregisterConnectivityDiagnosticsCallback(mCb);
-
- verify(mService).unregisterConnectivityDiagnosticsCallback(
- any(ConnectivityDiagnosticsBinder.class));
- assertFalse(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
-
- // verify that re-registering is successful
- mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
- verify(mService, times(2)).registerConnectivityDiagnosticsCallback(
- any(ConnectivityDiagnosticsBinder.class), eq(request), eq(mPackageName));
- assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
- }
-
- @Test
- public void testUnregisterUnknownConnectivityDiagnosticsCallback() throws Exception {
- mManager.unregisterConnectivityDiagnosticsCallback(mCb);
-
- verifyNoMoreInteractions(mService);
- }
-}
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
deleted file mode 100644
index d6bf334ee56a..000000000000
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ /dev/null
@@ -1,372 +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 android.net;
-
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
-import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.NetworkCapabilities;
-import android.os.Build.VERSION_CODES;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ConnectivityManagerTest {
-
- @Mock Context mCtx;
- @Mock IConnectivityManager mService;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- }
-
- static NetworkCapabilities verifyNetworkCapabilities(
- int legacyType, int transportType, int... capabilities) {
- final NetworkCapabilities nc = ConnectivityManager.networkCapabilitiesForType(legacyType);
- assertNotNull(nc);
- assertTrue(nc.hasTransport(transportType));
- for (int capability : capabilities) {
- assertTrue(nc.hasCapability(capability));
- }
-
- return nc;
- }
-
- static void verifyUnrestrictedNetworkCapabilities(int legacyType, int transportType) {
- verifyNetworkCapabilities(
- legacyType,
- transportType,
- NET_CAPABILITY_INTERNET,
- NET_CAPABILITY_NOT_RESTRICTED,
- NET_CAPABILITY_NOT_VPN,
- NET_CAPABILITY_TRUSTED);
- }
-
- static void verifyRestrictedMobileNetworkCapabilities(int legacyType, int capability) {
- final NetworkCapabilities nc = verifyNetworkCapabilities(
- legacyType,
- TRANSPORT_CELLULAR,
- capability,
- NET_CAPABILITY_NOT_VPN,
- NET_CAPABILITY_TRUSTED);
-
- assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeMobile() {
- verifyUnrestrictedNetworkCapabilities(
- ConnectivityManager.TYPE_MOBILE, TRANSPORT_CELLULAR);
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeMobileCbs() {
- verifyRestrictedMobileNetworkCapabilities(
- ConnectivityManager.TYPE_MOBILE_CBS, NET_CAPABILITY_CBS);
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeMobileDun() {
- verifyRestrictedMobileNetworkCapabilities(
- ConnectivityManager.TYPE_MOBILE_DUN, NET_CAPABILITY_DUN);
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeMobileFota() {
- verifyRestrictedMobileNetworkCapabilities(
- ConnectivityManager.TYPE_MOBILE_FOTA, NET_CAPABILITY_FOTA);
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeMobileHipri() {
- verifyUnrestrictedNetworkCapabilities(
- ConnectivityManager.TYPE_MOBILE_HIPRI, TRANSPORT_CELLULAR);
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeMobileIms() {
- verifyRestrictedMobileNetworkCapabilities(
- ConnectivityManager.TYPE_MOBILE_IMS, NET_CAPABILITY_IMS);
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeMobileMms() {
- final NetworkCapabilities nc = verifyNetworkCapabilities(
- ConnectivityManager.TYPE_MOBILE_MMS,
- TRANSPORT_CELLULAR,
- NET_CAPABILITY_MMS,
- NET_CAPABILITY_NOT_VPN,
- NET_CAPABILITY_TRUSTED);
-
- assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeMobileSupl() {
- final NetworkCapabilities nc = verifyNetworkCapabilities(
- ConnectivityManager.TYPE_MOBILE_SUPL,
- TRANSPORT_CELLULAR,
- NET_CAPABILITY_SUPL,
- NET_CAPABILITY_NOT_VPN,
- NET_CAPABILITY_TRUSTED);
-
- assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeWifi() {
- verifyUnrestrictedNetworkCapabilities(
- ConnectivityManager.TYPE_WIFI, TRANSPORT_WIFI);
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeWifiP2p() {
- final NetworkCapabilities nc = verifyNetworkCapabilities(
- ConnectivityManager.TYPE_WIFI_P2P,
- TRANSPORT_WIFI,
- NET_CAPABILITY_NOT_RESTRICTED, NET_CAPABILITY_NOT_VPN,
- NET_CAPABILITY_TRUSTED, NET_CAPABILITY_WIFI_P2P);
-
- assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeBluetooth() {
- verifyUnrestrictedNetworkCapabilities(
- ConnectivityManager.TYPE_BLUETOOTH, TRANSPORT_BLUETOOTH);
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeEthernet() {
- verifyUnrestrictedNetworkCapabilities(
- ConnectivityManager.TYPE_ETHERNET, TRANSPORT_ETHERNET);
- }
-
- @Test
- public void testCallbackRelease() throws Exception {
- ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
- NetworkRequest request = makeRequest(1);
- NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class);
- Handler handler = new Handler(Looper.getMainLooper());
- ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
-
- // register callback
- when(mService.requestNetwork(
- any(), captor.capture(), anyInt(), any(), anyInt(), any()))
- .thenReturn(request);
- manager.requestNetwork(request, callback, handler);
-
- // callback triggers
- captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_AVAILABLE));
- verify(callback, timeout(500).times(1)).onAvailable(any(Network.class),
- any(NetworkCapabilities.class), any(LinkProperties.class), anyBoolean());
-
- // unregister callback
- manager.unregisterNetworkCallback(callback);
- verify(mService, times(1)).releaseNetworkRequest(request);
-
- // callback does not trigger anymore.
- captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_LOSING));
- verify(callback, timeout(500).times(0)).onLosing(any(), anyInt());
- }
-
- @Test
- public void testCallbackRecycling() throws Exception {
- ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
- NetworkRequest req1 = makeRequest(1);
- NetworkRequest req2 = makeRequest(2);
- NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class);
- Handler handler = new Handler(Looper.getMainLooper());
- ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
-
- // register callback
- when(mService.requestNetwork(
- any(), captor.capture(), anyInt(), any(), anyInt(), any()))
- .thenReturn(req1);
- manager.requestNetwork(req1, callback, handler);
-
- // callback triggers
- captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_AVAILABLE));
- verify(callback, timeout(100).times(1)).onAvailable(any(Network.class),
- any(NetworkCapabilities.class), any(LinkProperties.class), anyBoolean());
-
- // unregister callback
- manager.unregisterNetworkCallback(callback);
- verify(mService, times(1)).releaseNetworkRequest(req1);
-
- // callback does not trigger anymore.
- captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_LOSING));
- verify(callback, timeout(100).times(0)).onLosing(any(), anyInt());
-
- // callback can be registered again
- when(mService.requestNetwork(
- any(), captor.capture(), anyInt(), any(), anyInt(), any()))
- .thenReturn(req2);
- manager.requestNetwork(req2, callback, handler);
-
- // callback triggers
- captor.getValue().send(makeMessage(req2, ConnectivityManager.CALLBACK_LOST));
- verify(callback, timeout(100).times(1)).onLost(any());
-
- // unregister callback
- manager.unregisterNetworkCallback(callback);
- verify(mService, times(1)).releaseNetworkRequest(req2);
- }
-
- // TODO: turn on this test when request callback 1:1 mapping is enforced
- //@Test
- private void noDoubleCallbackRegistration() throws Exception {
- ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
- NetworkRequest request = makeRequest(1);
- NetworkCallback callback = new ConnectivityManager.NetworkCallback();
- ApplicationInfo info = new ApplicationInfo();
- // TODO: update version when starting to enforce 1:1 mapping
- info.targetSdkVersion = VERSION_CODES.N_MR1 + 1;
-
- when(mCtx.getApplicationInfo()).thenReturn(info);
- when(mService.requestNetwork(any(), any(), anyInt(), any(), anyInt(), any()))
- .thenReturn(request);
-
- Handler handler = new Handler(Looper.getMainLooper());
- manager.requestNetwork(request, callback, handler);
-
- // callback is already registered, reregistration should fail.
- Class<IllegalArgumentException> wantException = IllegalArgumentException.class;
- expectThrowable(() -> manager.requestNetwork(request, callback), wantException);
-
- manager.unregisterNetworkCallback(callback);
- verify(mService, times(1)).releaseNetworkRequest(request);
-
- // unregistering the callback should make it registrable again.
- manager.requestNetwork(request, callback);
- }
-
- @Test
- public void testArgumentValidation() throws Exception {
- ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
-
- NetworkRequest request = mock(NetworkRequest.class);
- NetworkCallback callback = mock(NetworkCallback.class);
- Handler handler = mock(Handler.class);
- NetworkCallback nullCallback = null;
- PendingIntent nullIntent = null;
-
- mustFail(() -> { manager.requestNetwork(null, callback); });
- mustFail(() -> { manager.requestNetwork(request, nullCallback); });
- mustFail(() -> { manager.requestNetwork(request, callback, null); });
- mustFail(() -> { manager.requestNetwork(request, callback, -1); });
- mustFail(() -> { manager.requestNetwork(request, nullIntent); });
-
- mustFail(() -> { manager.registerNetworkCallback(null, callback, handler); });
- mustFail(() -> { manager.registerNetworkCallback(request, null, handler); });
- mustFail(() -> { manager.registerNetworkCallback(request, callback, null); });
- mustFail(() -> { manager.registerNetworkCallback(request, nullIntent); });
-
- mustFail(() -> { manager.registerDefaultNetworkCallback(null, handler); });
- mustFail(() -> { manager.registerDefaultNetworkCallback(callback, null); });
-
- mustFail(() -> { manager.unregisterNetworkCallback(nullCallback); });
- mustFail(() -> { manager.unregisterNetworkCallback(nullIntent); });
- mustFail(() -> { manager.releaseNetworkRequest(nullIntent); });
- }
-
- static void mustFail(Runnable fn) {
- try {
- fn.run();
- fail();
- } catch (Exception expected) {
- }
- }
-
- static Message makeMessage(NetworkRequest req, int messageType) {
- Bundle bundle = new Bundle();
- bundle.putParcelable(NetworkRequest.class.getSimpleName(), req);
- // Pass default objects as we don't care which get passed here
- bundle.putParcelable(Network.class.getSimpleName(), new Network(1));
- bundle.putParcelable(NetworkCapabilities.class.getSimpleName(), new NetworkCapabilities());
- bundle.putParcelable(LinkProperties.class.getSimpleName(), new LinkProperties());
- Message msg = Message.obtain();
- msg.what = messageType;
- msg.setData(bundle);
- return msg;
- }
-
- static NetworkRequest makeRequest(int requestId) {
- NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
- return new NetworkRequest(request.networkCapabilities, ConnectivityManager.TYPE_NONE,
- requestId, NetworkRequest.Type.NONE);
- }
-
- static void expectThrowable(Runnable block, Class<? extends Throwable> throwableType) {
- try {
- block.run();
- } catch (Throwable t) {
- if (t.getClass().equals(throwableType)) {
- return;
- }
- fail("expected exception of type " + throwableType + ", but was " + t.getClass());
- }
- fail("expected exception of type " + throwableType);
- }
-}
diff --git a/tests/net/java/android/net/Ikev2VpnProfileTest.java b/tests/net/java/android/net/Ikev2VpnProfileTest.java
deleted file mode 100644
index ada5494efd60..000000000000
--- a/tests/net/java/android/net/Ikev2VpnProfileTest.java
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.test.mock.MockContext;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.net.VpnProfile;
-import com.android.org.bouncycastle.x509.X509V1CertificateGenerator;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.math.BigInteger;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import javax.security.auth.x500.X500Principal;
-
-/** Unit tests for {@link Ikev2VpnProfile.Builder}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class Ikev2VpnProfileTest {
- private static final String SERVER_ADDR_STRING = "1.2.3.4";
- private static final String IDENTITY_STRING = "Identity";
- private static final String USERNAME_STRING = "username";
- private static final String PASSWORD_STRING = "pa55w0rd";
- private static final String EXCL_LIST = "exclList";
- private static final byte[] PSK_BYTES = "preSharedKey".getBytes();
- private static final int TEST_MTU = 1300;
-
- private final MockContext mMockContext =
- new MockContext() {
- @Override
- public String getOpPackageName() {
- return "fooPackage";
- }
- };
- private final ProxyInfo mProxy = new ProxyInfo(SERVER_ADDR_STRING, -1, EXCL_LIST);
-
- private X509Certificate mUserCert;
- private X509Certificate mServerRootCa;
- private PrivateKey mPrivateKey;
-
- @Before
- public void setUp() throws Exception {
- mServerRootCa = generateRandomCertAndKeyPair().cert;
-
- final CertificateAndKey userCertKey = generateRandomCertAndKeyPair();
- mUserCert = userCertKey.cert;
- mPrivateKey = userCertKey.key;
- }
-
- private Ikev2VpnProfile.Builder getBuilderWithDefaultOptions() {
- final Ikev2VpnProfile.Builder builder =
- new Ikev2VpnProfile.Builder(SERVER_ADDR_STRING, IDENTITY_STRING);
-
- builder.setBypassable(true);
- builder.setProxy(mProxy);
- builder.setMaxMtu(TEST_MTU);
- builder.setMetered(true);
-
- return builder;
- }
-
- @Test
- public void testBuildValidProfileWithOptions() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
- final Ikev2VpnProfile profile = builder.build();
- assertNotNull(profile);
-
- // Check non-auth parameters correctly stored
- assertEquals(SERVER_ADDR_STRING, profile.getServerAddr());
- assertEquals(IDENTITY_STRING, profile.getUserIdentity());
- assertEquals(mProxy, profile.getProxyInfo());
- assertTrue(profile.isBypassable());
- assertTrue(profile.isMetered());
- assertEquals(TEST_MTU, profile.getMaxMtu());
- assertEquals(Ikev2VpnProfile.DEFAULT_ALGORITHMS, profile.getAllowedAlgorithms());
- }
-
- @Test
- public void testBuildUsernamePasswordProfile() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
- final Ikev2VpnProfile profile = builder.build();
- assertNotNull(profile);
-
- assertEquals(USERNAME_STRING, profile.getUsername());
- assertEquals(PASSWORD_STRING, profile.getPassword());
- assertEquals(mServerRootCa, profile.getServerRootCaCert());
-
- assertNull(profile.getPresharedKey());
- assertNull(profile.getRsaPrivateKey());
- assertNull(profile.getUserCert());
- }
-
- @Test
- public void testBuildDigitalSignatureProfile() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
- final Ikev2VpnProfile profile = builder.build();
- assertNotNull(profile);
-
- assertEquals(profile.getUserCert(), mUserCert);
- assertEquals(mPrivateKey, profile.getRsaPrivateKey());
- assertEquals(profile.getServerRootCaCert(), mServerRootCa);
-
- assertNull(profile.getPresharedKey());
- assertNull(profile.getUsername());
- assertNull(profile.getPassword());
- }
-
- @Test
- public void testBuildPresharedKeyProfile() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthPsk(PSK_BYTES);
- final Ikev2VpnProfile profile = builder.build();
- assertNotNull(profile);
-
- assertArrayEquals(PSK_BYTES, profile.getPresharedKey());
-
- assertNull(profile.getServerRootCaCert());
- assertNull(profile.getUsername());
- assertNull(profile.getPassword());
- assertNull(profile.getRsaPrivateKey());
- assertNull(profile.getUserCert());
- }
-
- @Test
- public void testBuildWithAllowedAlgorithmsAead() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
- builder.setAuthPsk(PSK_BYTES);
-
- List<String> allowedAlgorithms = Arrays.asList(IpSecAlgorithm.AUTH_CRYPT_AES_GCM);
- builder.setAllowedAlgorithms(allowedAlgorithms);
-
- final Ikev2VpnProfile profile = builder.build();
- assertEquals(allowedAlgorithms, profile.getAllowedAlgorithms());
- }
-
- @Test
- public void testBuildWithAllowedAlgorithmsNormal() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
- builder.setAuthPsk(PSK_BYTES);
-
- List<String> allowedAlgorithms =
- Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA512, IpSecAlgorithm.CRYPT_AES_CBC);
- builder.setAllowedAlgorithms(allowedAlgorithms);
-
- final Ikev2VpnProfile profile = builder.build();
- assertEquals(allowedAlgorithms, profile.getAllowedAlgorithms());
- }
-
- @Test
- public void testSetAllowedAlgorithmsEmptyList() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- try {
- builder.setAllowedAlgorithms(new ArrayList<>());
- fail("Expected exception due to no valid algorithm set");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testSetAllowedAlgorithmsInvalidList() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
- List<String> allowedAlgorithms = new ArrayList<>();
-
- try {
- builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA256));
- fail("Expected exception due to missing encryption");
- } catch (IllegalArgumentException expected) {
- }
-
- try {
- builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.CRYPT_AES_CBC));
- fail("Expected exception due to missing authentication");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testSetAllowedAlgorithmsInsecureAlgorithm() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
- List<String> allowedAlgorithms = new ArrayList<>();
-
- try {
- builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_MD5));
- fail("Expected exception due to insecure algorithm");
- } catch (IllegalArgumentException expected) {
- }
-
- try {
- builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA1));
- fail("Expected exception due to insecure algorithm");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testBuildNoAuthMethodSet() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- try {
- builder.build();
- fail("Expected exception due to lack of auth method");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testBuildInvalidMtu() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- try {
- builder.setMaxMtu(500);
- fail("Expected exception due to too-small MTU");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- private void verifyVpnProfileCommon(VpnProfile profile) {
- assertEquals(SERVER_ADDR_STRING, profile.server);
- assertEquals(IDENTITY_STRING, profile.ipsecIdentifier);
- assertEquals(mProxy, profile.proxy);
- assertTrue(profile.isBypassable);
- assertTrue(profile.isMetered);
- assertEquals(TEST_MTU, profile.maxMtu);
- }
-
- @Test
- public void testPskConvertToVpnProfile() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthPsk(PSK_BYTES);
- final VpnProfile profile = builder.build().toVpnProfile();
-
- verifyVpnProfileCommon(profile);
- assertEquals(Ikev2VpnProfile.encodeForIpsecSecret(PSK_BYTES), profile.ipsecSecret);
-
- // Check nothing else is set
- assertEquals("", profile.username);
- assertEquals("", profile.password);
- assertEquals("", profile.ipsecUserCert);
- assertEquals("", profile.ipsecCaCert);
- }
-
- @Test
- public void testUsernamePasswordConvertToVpnProfile() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
- final VpnProfile profile = builder.build().toVpnProfile();
-
- verifyVpnProfileCommon(profile);
- assertEquals(USERNAME_STRING, profile.username);
- assertEquals(PASSWORD_STRING, profile.password);
- assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert);
-
- // Check nothing else is set
- assertEquals("", profile.ipsecUserCert);
- assertEquals("", profile.ipsecSecret);
- }
-
- @Test
- public void testRsaConvertToVpnProfile() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
- final VpnProfile profile = builder.build().toVpnProfile();
-
- final String expectedSecret = Ikev2VpnProfile.PREFIX_INLINE
- + Ikev2VpnProfile.encodeForIpsecSecret(mPrivateKey.getEncoded());
- verifyVpnProfileCommon(profile);
- assertEquals(Ikev2VpnProfile.certificateToPemString(mUserCert), profile.ipsecUserCert);
- assertEquals(
- expectedSecret,
- profile.ipsecSecret);
- assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert);
-
- // Check nothing else is set
- assertEquals("", profile.username);
- assertEquals("", profile.password);
- }
-
- @Test
- public void testPskFromVpnProfileDiscardsIrrelevantValues() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthPsk(PSK_BYTES);
- final VpnProfile profile = builder.build().toVpnProfile();
- profile.username = USERNAME_STRING;
- profile.password = PASSWORD_STRING;
- profile.ipsecCaCert = Ikev2VpnProfile.certificateToPemString(mServerRootCa);
- profile.ipsecUserCert = Ikev2VpnProfile.certificateToPemString(mUserCert);
-
- final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
- assertNull(result.getUsername());
- assertNull(result.getPassword());
- assertNull(result.getUserCert());
- assertNull(result.getRsaPrivateKey());
- assertNull(result.getServerRootCaCert());
- }
-
- @Test
- public void testUsernamePasswordFromVpnProfileDiscardsIrrelevantValues() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
- final VpnProfile profile = builder.build().toVpnProfile();
- profile.ipsecSecret = new String(PSK_BYTES);
- profile.ipsecUserCert = Ikev2VpnProfile.certificateToPemString(mUserCert);
-
- final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
- assertNull(result.getPresharedKey());
- assertNull(result.getUserCert());
- assertNull(result.getRsaPrivateKey());
- }
-
- @Test
- public void testRsaFromVpnProfileDiscardsIrrelevantValues() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
- final VpnProfile profile = builder.build().toVpnProfile();
- profile.username = USERNAME_STRING;
- profile.password = PASSWORD_STRING;
-
- final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
- assertNull(result.getUsername());
- assertNull(result.getPassword());
- assertNull(result.getPresharedKey());
- }
-
- @Test
- public void testPskConversionIsLossless() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthPsk(PSK_BYTES);
- final Ikev2VpnProfile ikeProfile = builder.build();
-
- assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
- }
-
- @Test
- public void testUsernamePasswordConversionIsLossless() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
- final Ikev2VpnProfile ikeProfile = builder.build();
-
- assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
- }
-
- @Test
- public void testRsaConversionIsLossless() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
- final Ikev2VpnProfile ikeProfile = builder.build();
-
- assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
- }
-
- private static class CertificateAndKey {
- public final X509Certificate cert;
- public final PrivateKey key;
-
- CertificateAndKey(X509Certificate cert, PrivateKey key) {
- this.cert = cert;
- this.key = key;
- }
- }
-
- private static CertificateAndKey generateRandomCertAndKeyPair() throws Exception {
- final Date validityBeginDate =
- new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1L));
- final Date validityEndDate =
- new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1L));
-
- // Generate a keypair
- final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
- keyPairGenerator.initialize(512);
- final KeyPair keyPair = keyPairGenerator.generateKeyPair();
-
- final X500Principal dnName = new X500Principal("CN=test.android.com");
- final X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
- certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
- certGen.setSubjectDN(dnName);
- certGen.setIssuerDN(dnName);
- certGen.setNotBefore(validityBeginDate);
- certGen.setNotAfter(validityEndDate);
- certGen.setPublicKey(keyPair.getPublic());
- certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
-
- final X509Certificate cert = certGen.generate(keyPair.getPrivate(), "AndroidOpenSSL");
- return new CertificateAndKey(cert, keyPair.getPrivate());
- }
-}
diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java
deleted file mode 100644
index 0b13800bc5c9..000000000000
--- a/tests/net/java/android/net/IpMemoryStoreTest.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.net.ipmemorystore.Blob;
-import android.net.ipmemorystore.IOnStatusListener;
-import android.net.ipmemorystore.NetworkAttributes;
-import android.net.ipmemorystore.NetworkAttributesParcelable;
-import android.net.ipmemorystore.Status;
-import android.net.networkstack.ModuleNetworkStackClient;
-import android.os.RemoteException;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.net.UnknownHostException;
-import java.util.Arrays;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpMemoryStoreTest {
- private static final String TAG = IpMemoryStoreTest.class.getSimpleName();
- private static final String TEST_CLIENT_ID = "testClientId";
- private static final String TEST_DATA_NAME = "testData";
- private static final String TEST_OTHER_DATA_NAME = TEST_DATA_NAME + "Other";
- private static final byte[] TEST_BLOB_DATA = new byte[] { -3, 6, 8, -9, 12,
- -128, 0, 89, 112, 91, -34 };
- private static final NetworkAttributes TEST_NETWORK_ATTRIBUTES = buildTestNetworkAttributes(
- "hint", 219);
-
- @Mock
- Context mMockContext;
- @Mock
- ModuleNetworkStackClient mModuleNetworkStackClient;
- @Mock
- IIpMemoryStore mMockService;
- @Mock
- IOnStatusListener mIOnStatusListener;
- IpMemoryStore mStore;
-
- @Captor
- ArgumentCaptor<IIpMemoryStoreCallbacks> mCbCaptor;
- @Captor
- ArgumentCaptor<NetworkAttributesParcelable> mNapCaptor;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- }
-
- private void startIpMemoryStore(boolean supplyService) {
- if (supplyService) {
- doAnswer(invocation -> {
- ((IIpMemoryStoreCallbacks) invocation.getArgument(0))
- .onIpMemoryStoreFetched(mMockService);
- return null;
- }).when(mModuleNetworkStackClient).fetchIpMemoryStore(any());
- } else {
- doNothing().when(mModuleNetworkStackClient).fetchIpMemoryStore(mCbCaptor.capture());
- }
- mStore = new IpMemoryStore(mMockContext) {
- @Override
- protected ModuleNetworkStackClient getModuleNetworkStackClient(Context ctx) {
- return mModuleNetworkStackClient;
- }
- };
- }
-
- private static NetworkAttributes buildTestNetworkAttributes(String hint, int mtu) {
- return new NetworkAttributes.Builder()
- .setCluster(hint)
- .setMtu(mtu)
- .build();
- }
-
- @Test
- public void testNetworkAttributes() throws Exception {
- startIpMemoryStore(true /* supplyService */);
- final String l2Key = "fakeKey";
-
- mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
- status -> assertTrue("Store not successful : " + status.resultCode,
- status.isSuccess()));
- verify(mMockService, times(1)).storeNetworkAttributes(eq(l2Key),
- mNapCaptor.capture(), any());
- assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
-
- mStore.retrieveNetworkAttributes(l2Key,
- (status, key, attr) -> {
- assertTrue("Retrieve network attributes not successful : "
- + status.resultCode, status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
- });
-
- verify(mMockService, times(1)).retrieveNetworkAttributes(eq(l2Key), any());
- }
-
- @Test
- public void testPrivateData() throws RemoteException {
- startIpMemoryStore(true /* supplyService */);
- final Blob b = new Blob();
- b.data = TEST_BLOB_DATA;
- final String l2Key = "fakeKey";
-
- mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
- status -> {
- assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
- });
- verify(mMockService, times(1)).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
- eq(b), any());
-
- mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
- (status, key, name, data) -> {
- assertTrue("Retrieve blob status not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(name, TEST_DATA_NAME);
- assertTrue(Arrays.equals(b.data, data.data));
- });
- verify(mMockService, times(1)).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
- eq(TEST_OTHER_DATA_NAME), any());
- }
-
- @Test
- public void testFindL2Key()
- throws UnknownHostException, RemoteException, Exception {
- startIpMemoryStore(true /* supplyService */);
- final String l2Key = "fakeKey";
-
- mStore.findL2Key(TEST_NETWORK_ATTRIBUTES,
- (status, key) -> {
- assertTrue("Retrieve network sameness not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(l2Key, key);
- });
- verify(mMockService, times(1)).findL2Key(mNapCaptor.capture(), any());
- assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
- }
-
- @Test
- public void testIsSameNetwork() throws UnknownHostException, RemoteException {
- startIpMemoryStore(true /* supplyService */);
- final String l2Key1 = "fakeKey1";
- final String l2Key2 = "fakeKey2";
-
- mStore.isSameNetwork(l2Key1, l2Key2,
- (status, answer) -> {
- assertFalse("Retrieve network sameness suspiciously successful : "
- + status.resultCode, status.isSuccess());
- assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
- assertNull(answer);
- });
- verify(mMockService, times(1)).isSameNetwork(eq(l2Key1), eq(l2Key2), any());
- }
-
- @Test
- public void testEnqueuedIpMsRequests() throws Exception {
- startIpMemoryStore(false /* supplyService */);
-
- final Blob b = new Blob();
- b.data = TEST_BLOB_DATA;
- final String l2Key = "fakeKey";
-
- // enqueue multiple ipms requests
- mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
- status -> assertTrue("Store not successful : " + status.resultCode,
- status.isSuccess()));
- mStore.retrieveNetworkAttributes(l2Key,
- (status, key, attr) -> {
- assertTrue("Retrieve network attributes not successful : "
- + status.resultCode, status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
- });
- mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
- status -> assertTrue("Store not successful : " + status.resultCode,
- status.isSuccess()));
- mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
- (status, key, name, data) -> {
- assertTrue("Retrieve blob status not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(name, TEST_DATA_NAME);
- assertTrue(Arrays.equals(b.data, data.data));
- });
-
- // get ipms service ready
- mCbCaptor.getValue().onIpMemoryStoreFetched(mMockService);
-
- InOrder inOrder = inOrder(mMockService);
-
- inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any());
- inOrder.verify(mMockService).retrieveNetworkAttributes(eq(l2Key), any());
- inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
- eq(b), any());
- inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
- eq(TEST_OTHER_DATA_NAME), any());
- assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
- }
-
- @Test
- public void testEnqueuedIpMsRequestsWithException() throws Exception {
- startIpMemoryStore(true /* supplyService */);
- doThrow(RemoteException.class).when(mMockService).retrieveNetworkAttributes(any(), any());
-
- final Blob b = new Blob();
- b.data = TEST_BLOB_DATA;
- final String l2Key = "fakeKey";
-
- // enqueue multiple ipms requests
- mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
- status -> assertTrue("Store not successful : " + status.resultCode,
- status.isSuccess()));
- mStore.retrieveNetworkAttributes(l2Key,
- (status, key, attr) -> {
- assertTrue("Retrieve network attributes not successful : "
- + status.resultCode, status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
- });
- mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
- status -> assertTrue("Store not successful : " + status.resultCode,
- status.isSuccess()));
- mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
- (status, key, name, data) -> {
- assertTrue("Retrieve blob status not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(name, TEST_DATA_NAME);
- assertTrue(Arrays.equals(b.data, data.data));
- });
-
- // verify the rest of the queue is still processed in order even if the remote exception
- // occurs when calling one or more requests
- InOrder inOrder = inOrder(mMockService);
-
- inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any());
- inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
- eq(b), any());
- inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
- eq(TEST_OTHER_DATA_NAME), any());
- assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
- }
-
- @Test
- public void testEnqueuedIpMsRequestsCallbackFunctionWithException() throws Exception {
- startIpMemoryStore(true /* supplyService */);
-
- final Blob b = new Blob();
- b.data = TEST_BLOB_DATA;
- final String l2Key = "fakeKey";
-
- // enqueue multiple ipms requests
- mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
- status -> assertTrue("Store not successful : " + status.resultCode,
- status.isSuccess()));
- mStore.retrieveNetworkAttributes(l2Key,
- (status, key, attr) -> {
- throw new RuntimeException("retrieveNetworkAttributes test");
- });
- mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
- status -> {
- throw new RuntimeException("storeBlob test");
- });
- mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
- (status, key, name, data) -> {
- assertTrue("Retrieve blob status not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(name, TEST_DATA_NAME);
- assertTrue(Arrays.equals(b.data, data.data));
- });
-
- // verify the rest of the queue is still processed in order even if when one or more
- // callback throw the remote exception
- InOrder inOrder = inOrder(mMockService);
-
- inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(),
- any());
- inOrder.verify(mMockService).retrieveNetworkAttributes(eq(l2Key), any());
- inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
- eq(b), any());
- inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
- eq(TEST_OTHER_DATA_NAME), any());
- assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
- }
-
- @Test
- public void testFactoryReset() throws RemoteException {
- startIpMemoryStore(true /* supplyService */);
- mStore.factoryReset();
- verify(mMockService, times(1)).factoryReset();
- }
-}
diff --git a/tests/net/java/android/net/IpSecAlgorithmTest.java b/tests/net/java/android/net/IpSecAlgorithmTest.java
deleted file mode 100644
index 8e9d08c705f3..000000000000
--- a/tests/net/java/android/net/IpSecAlgorithmTest.java
+++ /dev/null
@@ -1,130 +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 android.net;
-
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.os.Parcel;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.AbstractMap.SimpleEntry;
-import java.util.Arrays;
-import java.util.Map.Entry;
-import java.util.Random;
-
-/** Unit tests for {@link IpSecAlgorithm}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class IpSecAlgorithmTest {
-
- private static final byte[] KEY_MATERIAL;
-
- static {
- KEY_MATERIAL = new byte[128];
- new Random().nextBytes(KEY_MATERIAL);
- };
-
- @Test
- public void testNoTruncLen() throws Exception {
- Entry<String, Integer>[] authAndAeadList =
- new Entry[] {
- new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_MD5, 128),
- new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA1, 160),
- new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA256, 256),
- new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA384, 384),
- new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA512, 512),
- new SimpleEntry<>(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, 224)
- };
-
- // Expect auth and aead algorithms to throw errors if trunclen is omitted.
- for (Entry<String, Integer> algData : authAndAeadList) {
- try {
- new IpSecAlgorithm(
- algData.getKey(), Arrays.copyOf(KEY_MATERIAL, algData.getValue() / 8));
- fail("Expected exception on unprovided auth trunclen");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- // Ensure crypt works with no truncation length supplied.
- new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, 256 / 8));
- }
-
- @Test
- public void testTruncLenValidation() throws Exception {
- for (int truncLen : new int[] {256, 512}) {
- new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA512,
- Arrays.copyOf(KEY_MATERIAL, 512 / 8),
- truncLen);
- }
-
- for (int truncLen : new int[] {255, 513}) {
- try {
- new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA512,
- Arrays.copyOf(KEY_MATERIAL, 512 / 8),
- truncLen);
- fail("Invalid truncation length not validated");
- } catch (IllegalArgumentException pass) {
- }
- }
- }
-
- @Test
- public void testLenValidation() throws Exception {
- for (int len : new int[] {128, 192, 256}) {
- new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, len / 8));
- }
- try {
- new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, 384 / 8));
- fail("Invalid key length not validated");
- } catch (IllegalArgumentException pass) {
- }
- }
-
- @Test
- public void testAlgoNameValidation() throws Exception {
- try {
- new IpSecAlgorithm("rot13", Arrays.copyOf(KEY_MATERIAL, 128 / 8));
- fail("Invalid algorithm name not validated");
- } catch (IllegalArgumentException pass) {
- }
- }
-
- @Test
- public void testParcelUnparcel() throws Exception {
- IpSecAlgorithm init =
- new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA512, Arrays.copyOf(KEY_MATERIAL, 512 / 8), 256);
-
- Parcel p = Parcel.obtain();
- p.setDataPosition(0);
- init.writeToParcel(p, 0);
-
- p.setDataPosition(0);
- IpSecAlgorithm fin = IpSecAlgorithm.CREATOR.createFromParcel(p);
- assertTrue("Parcel/Unparcel failed!", IpSecAlgorithm.equals(init, fin));
- p.recycle();
- }
-}
diff --git a/tests/net/java/android/net/IpSecConfigTest.java b/tests/net/java/android/net/IpSecConfigTest.java
deleted file mode 100644
index c9888b24b6da..000000000000
--- a/tests/net/java/android/net/IpSecConfigTest.java
+++ /dev/null
@@ -1,103 +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 android.net;
-
-import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
-import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Unit tests for {@link IpSecConfig}. */
-@SmallTest
-@RunWith(JUnit4.class)
-public class IpSecConfigTest {
-
- @Test
- public void testDefaults() throws Exception {
- IpSecConfig c = new IpSecConfig();
- assertEquals(IpSecTransform.MODE_TRANSPORT, c.getMode());
- assertEquals("", c.getSourceAddress());
- assertEquals("", c.getDestinationAddress());
- assertNull(c.getNetwork());
- assertEquals(IpSecTransform.ENCAP_NONE, c.getEncapType());
- assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getEncapSocketResourceId());
- assertEquals(0, c.getEncapRemotePort());
- assertEquals(0, c.getNattKeepaliveInterval());
- assertNull(c.getEncryption());
- assertNull(c.getAuthentication());
- assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getSpiResourceId());
- assertEquals(0, c.getXfrmInterfaceId());
- }
-
- private IpSecConfig getSampleConfig() {
- IpSecConfig c = new IpSecConfig();
- c.setMode(IpSecTransform.MODE_TUNNEL);
- c.setSourceAddress("0.0.0.0");
- c.setDestinationAddress("1.2.3.4");
- c.setSpiResourceId(1984);
- c.setEncryption(
- new IpSecAlgorithm(
- IpSecAlgorithm.CRYPT_AES_CBC,
- new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}));
- c.setAuthentication(
- new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_MD5,
- new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0},
- 128));
- c.setAuthenticatedEncryption(
- new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
- new byte[] {
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0, 1, 2, 3, 4
- },
- 128));
- c.setEncapType(android.system.OsConstants.UDP_ENCAP_ESPINUDP);
- c.setEncapSocketResourceId(7);
- c.setEncapRemotePort(22);
- c.setNattKeepaliveInterval(42);
- c.setMarkValue(12);
- c.setMarkMask(23);
- c.setXfrmInterfaceId(34);
-
- return c;
- }
-
- @Test
- public void testCopyConstructor() {
- IpSecConfig original = getSampleConfig();
- IpSecConfig copy = new IpSecConfig(original);
-
- assertEquals(original, copy);
- assertNotSame(original, copy);
- }
-
- @Test
- public void testParcelUnparcel() {
- assertParcelingIsLossless(new IpSecConfig());
-
- IpSecConfig c = getSampleConfig();
- assertParcelSane(c, 15);
- }
-}
diff --git a/tests/net/java/android/net/IpSecManagerTest.java b/tests/net/java/android/net/IpSecManagerTest.java
deleted file mode 100644
index 730e2d56bd78..000000000000
--- a/tests/net/java/android/net/IpSecManagerTest.java
+++ /dev/null
@@ -1,305 +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 android.net;
-
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_DGRAM;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.system.Os;
-import android.test.mock.MockContext;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.IpSecService;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.net.Socket;
-import java.net.UnknownHostException;
-
-/** Unit tests for {@link IpSecManager}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class IpSecManagerTest {
-
- private static final int TEST_UDP_ENCAP_PORT = 34567;
- private static final int DROID_SPI = 0xD1201D;
- private static final int DUMMY_RESOURCE_ID = 0x1234;
-
- private static final InetAddress GOOGLE_DNS_4;
- private static final String VTI_INTF_NAME = "ipsec_test";
- private static final InetAddress VTI_LOCAL_ADDRESS;
- private static final LinkAddress VTI_INNER_ADDRESS = new LinkAddress("10.0.1.1/24");
-
- static {
- try {
- // Google Public DNS Addresses;
- GOOGLE_DNS_4 = InetAddress.getByName("8.8.8.8");
- VTI_LOCAL_ADDRESS = InetAddress.getByName("8.8.4.4");
- } catch (UnknownHostException e) {
- throw new RuntimeException("Could not resolve DNS Addresses", e);
- }
- }
-
- private IpSecService mMockIpSecService;
- private IpSecManager mIpSecManager;
- private MockContext mMockContext = new MockContext() {
- @Override
- public String getOpPackageName() {
- return "fooPackage";
- }
- };
-
- @Before
- public void setUp() throws Exception {
- mMockIpSecService = mock(IpSecService.class);
- mIpSecManager = new IpSecManager(mMockContext, mMockIpSecService);
- }
-
- /*
- * Allocate a specific SPI
- * Close SPIs
- */
- @Test
- public void testAllocSpi() throws Exception {
- IpSecSpiResponse spiResp =
- new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_RESOURCE_ID, DROID_SPI);
- when(mMockIpSecService.allocateSecurityParameterIndex(
- eq(GOOGLE_DNS_4.getHostAddress()),
- eq(DROID_SPI),
- anyObject()))
- .thenReturn(spiResp);
-
- IpSecManager.SecurityParameterIndex droidSpi =
- mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4, DROID_SPI);
- assertEquals(DROID_SPI, droidSpi.getSpi());
-
- droidSpi.close();
-
- verify(mMockIpSecService).releaseSecurityParameterIndex(DUMMY_RESOURCE_ID);
- }
-
- @Test
- public void testAllocRandomSpi() throws Exception {
- IpSecSpiResponse spiResp =
- new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_RESOURCE_ID, DROID_SPI);
- when(mMockIpSecService.allocateSecurityParameterIndex(
- eq(GOOGLE_DNS_4.getHostAddress()),
- eq(IpSecManager.INVALID_SECURITY_PARAMETER_INDEX),
- anyObject()))
- .thenReturn(spiResp);
-
- IpSecManager.SecurityParameterIndex randomSpi =
- mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4);
-
- assertEquals(DROID_SPI, randomSpi.getSpi());
-
- randomSpi.close();
-
- verify(mMockIpSecService).releaseSecurityParameterIndex(DUMMY_RESOURCE_ID);
- }
-
- /*
- * Throws resource unavailable exception
- */
- @Test
- public void testAllocSpiResUnavailableException() throws Exception {
- IpSecSpiResponse spiResp =
- new IpSecSpiResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE, 0, 0);
- when(mMockIpSecService.allocateSecurityParameterIndex(
- anyString(), anyInt(), anyObject()))
- .thenReturn(spiResp);
-
- try {
- mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4);
- fail("ResourceUnavailableException was not thrown");
- } catch (IpSecManager.ResourceUnavailableException e) {
- }
- }
-
- /*
- * Throws spi unavailable exception
- */
- @Test
- public void testAllocSpiSpiUnavailableException() throws Exception {
- IpSecSpiResponse spiResp = new IpSecSpiResponse(IpSecManager.Status.SPI_UNAVAILABLE, 0, 0);
- when(mMockIpSecService.allocateSecurityParameterIndex(
- anyString(), anyInt(), anyObject()))
- .thenReturn(spiResp);
-
- try {
- mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4);
- fail("ResourceUnavailableException was not thrown");
- } catch (IpSecManager.ResourceUnavailableException e) {
- }
- }
-
- /*
- * Should throw exception when request spi 0 in IpSecManager
- */
- @Test
- public void testRequestAllocInvalidSpi() throws Exception {
- try {
- mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4, 0);
- fail("Able to allocate invalid spi");
- } catch (IllegalArgumentException e) {
- }
- }
-
- @Test
- public void testOpenEncapsulationSocket() throws Exception {
- IpSecUdpEncapResponse udpEncapResp =
- new IpSecUdpEncapResponse(
- IpSecManager.Status.OK,
- DUMMY_RESOURCE_ID,
- TEST_UDP_ENCAP_PORT,
- Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
- when(mMockIpSecService.openUdpEncapsulationSocket(eq(TEST_UDP_ENCAP_PORT), anyObject()))
- .thenReturn(udpEncapResp);
-
- IpSecManager.UdpEncapsulationSocket encapSocket =
- mIpSecManager.openUdpEncapsulationSocket(TEST_UDP_ENCAP_PORT);
- assertNotNull(encapSocket.getFileDescriptor());
- assertEquals(TEST_UDP_ENCAP_PORT, encapSocket.getPort());
-
- encapSocket.close();
-
- verify(mMockIpSecService).closeUdpEncapsulationSocket(DUMMY_RESOURCE_ID);
- }
-
- @Test
- public void testApplyTransportModeTransformEnsuresSocketCreation() throws Exception {
- Socket socket = new Socket();
- IpSecConfig dummyConfig = new IpSecConfig();
- IpSecTransform dummyTransform = new IpSecTransform(null, dummyConfig);
-
- // Even if underlying SocketImpl is not initalized, this should force the init, and
- // thereby succeed.
- mIpSecManager.applyTransportModeTransform(
- socket, IpSecManager.DIRECTION_IN, dummyTransform);
-
- // Check to make sure the FileDescriptor is non-null
- assertNotNull(socket.getFileDescriptor$());
- }
-
- @Test
- public void testRemoveTransportModeTransformsForcesSocketCreation() throws Exception {
- Socket socket = new Socket();
-
- // Even if underlying SocketImpl is not initalized, this should force the init, and
- // thereby succeed.
- mIpSecManager.removeTransportModeTransforms(socket);
-
- // Check to make sure the FileDescriptor is non-null
- assertNotNull(socket.getFileDescriptor$());
- }
-
- @Test
- public void testOpenEncapsulationSocketOnRandomPort() throws Exception {
- IpSecUdpEncapResponse udpEncapResp =
- new IpSecUdpEncapResponse(
- IpSecManager.Status.OK,
- DUMMY_RESOURCE_ID,
- TEST_UDP_ENCAP_PORT,
- Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
-
- when(mMockIpSecService.openUdpEncapsulationSocket(eq(0), anyObject()))
- .thenReturn(udpEncapResp);
-
- IpSecManager.UdpEncapsulationSocket encapSocket =
- mIpSecManager.openUdpEncapsulationSocket();
-
- assertNotNull(encapSocket.getFileDescriptor());
- assertEquals(TEST_UDP_ENCAP_PORT, encapSocket.getPort());
-
- encapSocket.close();
-
- verify(mMockIpSecService).closeUdpEncapsulationSocket(DUMMY_RESOURCE_ID);
- }
-
- @Test
- public void testOpenEncapsulationSocketWithInvalidPort() throws Exception {
- try {
- mIpSecManager.openUdpEncapsulationSocket(IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
- fail("IllegalArgumentException was not thrown");
- } catch (IllegalArgumentException e) {
- }
- }
-
- // TODO: add test when applicable transform builder interface is available
-
- private IpSecManager.IpSecTunnelInterface createAndValidateVti(int resourceId, String intfName)
- throws Exception {
- IpSecTunnelInterfaceResponse dummyResponse =
- new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
- when(mMockIpSecService.createTunnelInterface(
- eq(VTI_LOCAL_ADDRESS.getHostAddress()), eq(GOOGLE_DNS_4.getHostAddress()),
- anyObject(), anyObject(), anyString()))
- .thenReturn(dummyResponse);
-
- IpSecManager.IpSecTunnelInterface tunnelIntf = mIpSecManager.createIpSecTunnelInterface(
- VTI_LOCAL_ADDRESS, GOOGLE_DNS_4, mock(Network.class));
-
- assertNotNull(tunnelIntf);
- return tunnelIntf;
- }
-
- @Test
- public void testCreateVti() throws Exception {
- IpSecManager.IpSecTunnelInterface tunnelIntf =
- createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);
-
- assertEquals(VTI_INTF_NAME, tunnelIntf.getInterfaceName());
-
- tunnelIntf.close();
- verify(mMockIpSecService).deleteTunnelInterface(eq(DUMMY_RESOURCE_ID), anyString());
- }
-
- @Test
- public void testAddRemoveAddressesFromVti() throws Exception {
- IpSecManager.IpSecTunnelInterface tunnelIntf =
- createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);
-
- tunnelIntf.addAddress(VTI_INNER_ADDRESS.getAddress(),
- VTI_INNER_ADDRESS.getPrefixLength());
- verify(mMockIpSecService)
- .addAddressToTunnelInterface(
- eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
-
- tunnelIntf.removeAddress(VTI_INNER_ADDRESS.getAddress(),
- VTI_INNER_ADDRESS.getPrefixLength());
- verify(mMockIpSecService)
- .addAddressToTunnelInterface(
- eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
- }
-}
diff --git a/tests/net/java/android/net/IpSecTransformTest.java b/tests/net/java/android/net/IpSecTransformTest.java
deleted file mode 100644
index 424f23dbbaf6..000000000000
--- a/tests/net/java/android/net/IpSecTransformTest.java
+++ /dev/null
@@ -1,62 +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 android.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Unit tests for {@link IpSecTransform}. */
-@SmallTest
-@RunWith(JUnit4.class)
-public class IpSecTransformTest {
-
- @Test
- public void testCreateTransformCopiesConfig() {
- // Create a config with a few parameters to make sure it's not empty
- IpSecConfig config = new IpSecConfig();
- config.setSourceAddress("0.0.0.0");
- config.setDestinationAddress("1.2.3.4");
- config.setSpiResourceId(1984);
-
- IpSecTransform preModification = new IpSecTransform(null, config);
-
- config.setSpiResourceId(1985);
- IpSecTransform postModification = new IpSecTransform(null, config);
-
- assertNotEquals(preModification, postModification);
- }
-
- @Test
- public void testCreateTransformsWithSameConfigEqual() {
- // Create a config with a few parameters to make sure it's not empty
- IpSecConfig config = new IpSecConfig();
- config.setSourceAddress("0.0.0.0");
- config.setDestinationAddress("1.2.3.4");
- config.setSpiResourceId(1984);
-
- IpSecTransform config1 = new IpSecTransform(null, config);
- IpSecTransform config2 = new IpSecTransform(null, config);
-
- assertEquals(config1, config2);
- }
-}
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
deleted file mode 100644
index 91c9a2a38036..000000000000
--- a/tests/net/java/android/net/MacAddressTest.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright 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 android.net;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.util.MacAddressUtils;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet6Address;
-import java.util.Arrays;
-import java.util.Random;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class MacAddressTest {
-
- static class AddrTypeTestCase {
- byte[] addr;
- int expectedType;
-
- static AddrTypeTestCase of(int expectedType, int... addr) {
- AddrTypeTestCase t = new AddrTypeTestCase();
- t.expectedType = expectedType;
- t.addr = toByteArray(addr);
- return t;
- }
- }
-
- @Test
- public void testMacAddrTypes() {
- AddrTypeTestCase[] testcases = {
- AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN),
- AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 0),
- AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 1, 2, 3, 4, 5),
- AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 1, 2, 3, 4, 5, 6, 7),
- AddrTypeTestCase.of(MacAddress.TYPE_UNICAST, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0),
- AddrTypeTestCase.of(MacAddress.TYPE_BROADCAST, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
- AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 1, 2, 3, 4, 5, 6),
- AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 11, 22, 33, 44, 55, 66),
- AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 33, 33, 0xaa, 0xbb, 0xcc, 0xdd)
- };
-
- for (AddrTypeTestCase t : testcases) {
- int got = MacAddress.macAddressType(t.addr);
- String msg = String.format("expected type of %s to be %s, but got %s",
- Arrays.toString(t.addr), t.expectedType, got);
- assertEquals(msg, t.expectedType, got);
-
- if (got != MacAddress.TYPE_UNKNOWN) {
- assertEquals(got, MacAddress.fromBytes(t.addr).getAddressType());
- }
- }
- }
-
- @Test
- public void testToOuiString() {
- String[][] macs = {
- {"07:00:d3:56:8a:c4", "07:00:d3"},
- {"33:33:aa:bb:cc:dd", "33:33:aa"},
- {"06:00:00:00:00:00", "06:00:00"},
- {"07:00:d3:56:8a:c4", "07:00:d3"}
- };
-
- for (String[] pair : macs) {
- String mac = pair[0];
- String expected = pair[1];
- assertEquals(expected, MacAddress.fromString(mac).toOuiString());
- }
- }
-
- @Test
- public void testHexPaddingWhenPrinting() {
- String[] macs = {
- "07:00:d3:56:8a:c4",
- "33:33:aa:bb:cc:dd",
- "06:00:00:00:00:00",
- "07:00:d3:56:8a:c4"
- };
-
- for (String mac : macs) {
- assertEquals(mac, MacAddress.fromString(mac).toString());
- assertEquals(mac,
- MacAddress.stringAddrFromByteAddr(MacAddress.byteAddrFromStringAddr(mac)));
- }
- }
-
- @Test
- public void testIsMulticastAddress() {
- MacAddress[] multicastAddresses = {
- MacAddress.BROADCAST_ADDRESS,
- MacAddress.fromString("07:00:d3:56:8a:c4"),
- MacAddress.fromString("33:33:aa:bb:cc:dd"),
- };
- MacAddress[] unicastAddresses = {
- MacAddress.ALL_ZEROS_ADDRESS,
- MacAddress.fromString("00:01:44:55:66:77"),
- MacAddress.fromString("08:00:22:33:44:55"),
- MacAddress.fromString("06:00:00:00:00:00"),
- };
-
- for (MacAddress mac : multicastAddresses) {
- String msg = mac.toString() + " expected to be a multicast address";
- assertTrue(msg, MacAddressUtils.isMulticastAddress(mac));
- }
- for (MacAddress mac : unicastAddresses) {
- String msg = mac.toString() + " expected not to be a multicast address";
- assertFalse(msg, MacAddressUtils.isMulticastAddress(mac));
- }
- }
-
- @Test
- public void testIsLocallyAssignedAddress() {
- MacAddress[] localAddresses = {
- MacAddress.fromString("06:00:00:00:00:00"),
- MacAddress.fromString("07:00:d3:56:8a:c4"),
- MacAddress.fromString("33:33:aa:bb:cc:dd"),
- };
- MacAddress[] universalAddresses = {
- MacAddress.fromString("00:01:44:55:66:77"),
- MacAddress.fromString("08:00:22:33:44:55"),
- };
-
- for (MacAddress mac : localAddresses) {
- String msg = mac.toString() + " expected to be a locally assigned address";
- assertTrue(msg, mac.isLocallyAssigned());
- }
- for (MacAddress mac : universalAddresses) {
- String msg = mac.toString() + " expected not to be globally unique address";
- assertFalse(msg, mac.isLocallyAssigned());
- }
- }
-
- @Test
- public void testMacAddressConversions() {
- final int iterations = 10000;
- for (int i = 0; i < iterations; i++) {
- MacAddress mac = MacAddressUtils.createRandomUnicastAddress();
-
- String stringRepr = mac.toString();
- byte[] bytesRepr = mac.toByteArray();
-
- assertEquals(mac, MacAddress.fromString(stringRepr));
- assertEquals(mac, MacAddress.fromBytes(bytesRepr));
-
- assertEquals(mac, MacAddress.fromString(MacAddress.stringAddrFromByteAddr(bytesRepr)));
- assertEquals(mac, MacAddress.fromBytes(MacAddress.byteAddrFromStringAddr(stringRepr)));
- }
- }
-
- @Test
- public void testMacAddressRandomGeneration() {
- final int iterations = 1000;
- final String expectedAndroidOui = "da:a1:19";
- for (int i = 0; i < iterations; i++) {
- MacAddress mac = MacAddress.createRandomUnicastAddressWithGoogleBase();
- String stringRepr = mac.toString();
-
- assertTrue(stringRepr + " expected to be a locally assigned address",
- mac.isLocallyAssigned());
- assertTrue(stringRepr + " expected to begin with " + expectedAndroidOui,
- stringRepr.startsWith(expectedAndroidOui));
- }
-
- final Random r = new Random();
- final String anotherOui = "24:5f:78";
- final String expectedLocalOui = "26:5f:78";
- final MacAddress base = MacAddress.fromString(anotherOui + ":0:0:0");
- for (int i = 0; i < iterations; i++) {
- MacAddress mac = MacAddressUtils.createRandomUnicastAddress(base, r);
- String stringRepr = mac.toString();
-
- assertTrue(stringRepr + " expected to be a locally assigned address",
- mac.isLocallyAssigned());
- assertEquals(MacAddress.TYPE_UNICAST, mac.getAddressType());
- assertTrue(stringRepr + " expected to begin with " + expectedLocalOui,
- stringRepr.startsWith(expectedLocalOui));
- }
-
- for (int i = 0; i < iterations; i++) {
- MacAddress mac = MacAddressUtils.createRandomUnicastAddress();
- String stringRepr = mac.toString();
-
- assertTrue(stringRepr + " expected to be a locally assigned address",
- mac.isLocallyAssigned());
- assertEquals(MacAddress.TYPE_UNICAST, mac.getAddressType());
- }
- }
-
- @Test
- public void testConstructorInputValidation() {
- String[] invalidStringAddresses = {
- "",
- "abcd",
- "1:2:3:4:5",
- "1:2:3:4:5:6:7",
- "10000:2:3:4:5:6",
- };
-
- for (String s : invalidStringAddresses) {
- try {
- MacAddress mac = MacAddress.fromString(s);
- fail("MacAddress.fromString(" + s + ") should have failed, but returned " + mac);
- } catch (IllegalArgumentException excepted) {
- }
- }
-
- try {
- MacAddress mac = MacAddress.fromString(null);
- fail("MacAddress.fromString(null) should have failed, but returned " + mac);
- } catch (NullPointerException excepted) {
- }
-
- byte[][] invalidBytesAddresses = {
- {},
- {1,2,3,4,5},
- {1,2,3,4,5,6,7},
- };
-
- for (byte[] b : invalidBytesAddresses) {
- try {
- MacAddress mac = MacAddress.fromBytes(b);
- fail("MacAddress.fromBytes(" + Arrays.toString(b)
- + ") should have failed, but returned " + mac);
- } catch (IllegalArgumentException excepted) {
- }
- }
-
- try {
- MacAddress mac = MacAddress.fromBytes(null);
- fail("MacAddress.fromBytes(null) should have failed, but returned " + mac);
- } catch (NullPointerException excepted) {
- }
- }
-
- @Test
- public void testMatches() {
- // match 4 bytes prefix
- assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("aa:bb:cc:dd:00:00"),
- MacAddress.fromString("ff:ff:ff:ff:00:00")));
-
- // match bytes 0,1,2 and 5
- assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("aa:bb:cc:00:00:11"),
- MacAddress.fromString("ff:ff:ff:00:00:ff")));
-
- // match 34 bit prefix
- assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("aa:bb:cc:dd:c0:00"),
- MacAddress.fromString("ff:ff:ff:ff:c0:00")));
-
- // fail to match 36 bit prefix
- assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("aa:bb:cc:dd:40:00"),
- MacAddress.fromString("ff:ff:ff:ff:f0:00")));
-
- // match all 6 bytes
- assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("aa:bb:cc:dd:ee:11"),
- MacAddress.fromString("ff:ff:ff:ff:ff:ff")));
-
- // match none of 6 bytes
- assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("00:00:00:00:00:00"),
- MacAddress.fromString("00:00:00:00:00:00")));
- }
-
- /**
- * Tests that link-local address generation from MAC is valid.
- */
- @Test
- public void testLinkLocalFromMacGeneration() {
- MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f");
- byte[] inet6ll = {(byte) 0xfe, (byte) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x74,
- (byte) 0xf2, (byte) 0xff, (byte) 0xfe, (byte) 0xb1, (byte) 0xa8, 0x7f};
- Inet6Address llv6 = mac.getLinkLocalIpv6FromEui48Mac();
- assertTrue(llv6.isLinkLocalAddress());
- assertArrayEquals(inet6ll, llv6.getAddress());
- }
-
- static byte[] toByteArray(int... in) {
- byte[] out = new byte[in.length];
- for (int i = 0; i < in.length; i++) {
- out[i] = (byte) in[i];
- }
- return out;
- }
-}
diff --git a/tests/net/java/android/net/NetworkStatsHistoryTest.java b/tests/net/java/android/net/NetworkStatsHistoryTest.java
deleted file mode 100644
index 13558cd51c28..000000000000
--- a/tests/net/java/android/net/NetworkStatsHistoryTest.java
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLong;
-import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLong;
-import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
-import static android.net.NetworkStatsHistory.FIELD_ALL;
-import static android.net.NetworkStatsHistory.FIELD_OPERATIONS;
-import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
-import static android.net.NetworkStatsHistory.FIELD_RX_PACKETS;
-import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
-import static android.net.TrafficStats.GB_IN_BYTES;
-import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.text.format.DateUtils.DAY_IN_MILLIS;
-import static android.text.format.DateUtils.HOUR_IN_MILLIS;
-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-import static android.text.format.DateUtils.WEEK_IN_MILLIS;
-import static android.text.format.DateUtils.YEAR_IN_MILLIS;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.frameworks.tests.net.R;
-
-import org.junit.After;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.util.Random;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkStatsHistoryTest {
- private static final String TAG = "NetworkStatsHistoryTest";
-
- private static final long TEST_START = 1194220800000L;
-
- private NetworkStatsHistory stats;
-
- @After
- public void tearDown() throws Exception {
- if (stats != null) {
- assertConsistent(stats);
- }
- }
-
- @Test
- public void testReadOriginalVersion() throws Exception {
- final Context context = InstrumentationRegistry.getContext();
- final DataInputStream in =
- new DataInputStream(context.getResources().openRawResource(R.raw.history_v1));
-
- NetworkStatsHistory.Entry entry = null;
- try {
- final NetworkStatsHistory history = new NetworkStatsHistory(in);
- assertEquals(15 * SECOND_IN_MILLIS, history.getBucketDuration());
-
- entry = history.getValues(0, entry);
- assertEquals(29143L, entry.rxBytes);
- assertEquals(6223L, entry.txBytes);
-
- entry = history.getValues(history.size() - 1, entry);
- assertEquals(1476L, entry.rxBytes);
- assertEquals(838L, entry.txBytes);
-
- entry = history.getValues(Long.MIN_VALUE, Long.MAX_VALUE, entry);
- assertEquals(332401L, entry.rxBytes);
- assertEquals(64314L, entry.txBytes);
-
- } finally {
- in.close();
- }
- }
-
- @Test
- public void testRecordSingleBucket() throws Exception {
- final long BUCKET_SIZE = HOUR_IN_MILLIS;
- stats = new NetworkStatsHistory(BUCKET_SIZE);
-
- // record data into narrow window to get single bucket
- stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
-
- assertEquals(1, stats.size());
- assertValues(stats, 0, SECOND_IN_MILLIS, 1024L, 10L, 2048L, 20L, 2L);
- }
-
- @Test
- public void testRecordEqualBuckets() throws Exception {
- final long bucketDuration = HOUR_IN_MILLIS;
- stats = new NetworkStatsHistory(bucketDuration);
-
- // split equally across two buckets
- final long recordStart = TEST_START + (bucketDuration / 2);
- stats.recordData(recordStart, recordStart + bucketDuration,
- new NetworkStats.Entry(1024L, 10L, 128L, 2L, 2L));
-
- assertEquals(2, stats.size());
- assertValues(stats, 0, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L);
- assertValues(stats, 1, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L);
- }
-
- @Test
- public void testRecordTouchingBuckets() throws Exception {
- final long BUCKET_SIZE = 15 * MINUTE_IN_MILLIS;
- stats = new NetworkStatsHistory(BUCKET_SIZE);
-
- // split almost completely into middle bucket, but with a few minutes
- // overlap into neighboring buckets. total record is 20 minutes.
- final long recordStart = (TEST_START + BUCKET_SIZE) - MINUTE_IN_MILLIS;
- final long recordEnd = (TEST_START + (BUCKET_SIZE * 2)) + (MINUTE_IN_MILLIS * 4);
- stats.recordData(recordStart, recordEnd,
- new NetworkStats.Entry(1000L, 2000L, 5000L, 10000L, 100L));
-
- assertEquals(3, stats.size());
- // first bucket should have (1/20 of value)
- assertValues(stats, 0, MINUTE_IN_MILLIS, 50L, 100L, 250L, 500L, 5L);
- // second bucket should have (15/20 of value)
- assertValues(stats, 1, 15 * MINUTE_IN_MILLIS, 750L, 1500L, 3750L, 7500L, 75L);
- // final bucket should have (4/20 of value)
- assertValues(stats, 2, 4 * MINUTE_IN_MILLIS, 200L, 400L, 1000L, 2000L, 20L);
- }
-
- @Test
- public void testRecordGapBuckets() throws Exception {
- final long BUCKET_SIZE = HOUR_IN_MILLIS;
- stats = new NetworkStatsHistory(BUCKET_SIZE);
-
- // record some data today and next week with large gap
- final long firstStart = TEST_START;
- final long lastStart = TEST_START + WEEK_IN_MILLIS;
- stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS,
- new NetworkStats.Entry(128L, 2L, 256L, 4L, 1L));
- stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS,
- new NetworkStats.Entry(64L, 1L, 512L, 8L, 2L));
-
- // we should have two buckets, far apart from each other
- assertEquals(2, stats.size());
- assertValues(stats, 0, SECOND_IN_MILLIS, 128L, 2L, 256L, 4L, 1L);
- assertValues(stats, 1, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L);
-
- // now record something in middle, spread across two buckets
- final long middleStart = TEST_START + DAY_IN_MILLIS;
- final long middleEnd = middleStart + (HOUR_IN_MILLIS * 2);
- stats.recordData(middleStart, middleEnd,
- new NetworkStats.Entry(2048L, 4L, 2048L, 4L, 2L));
-
- // now should have four buckets, with new record in middle two buckets
- assertEquals(4, stats.size());
- assertValues(stats, 0, SECOND_IN_MILLIS, 128L, 2L, 256L, 4L, 1L);
- assertValues(stats, 1, HOUR_IN_MILLIS, 1024L, 2L, 1024L, 2L, 1L);
- assertValues(stats, 2, HOUR_IN_MILLIS, 1024L, 2L, 1024L, 2L, 1L);
- assertValues(stats, 3, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L);
- }
-
- @Test
- public void testRecordOverlapBuckets() throws Exception {
- final long BUCKET_SIZE = HOUR_IN_MILLIS;
- stats = new NetworkStatsHistory(BUCKET_SIZE);
-
- // record some data in one bucket, and another overlapping buckets
- stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
- new NetworkStats.Entry(256L, 2L, 256L, 2L, 1L));
- final long midStart = TEST_START + (HOUR_IN_MILLIS / 2);
- stats.recordData(midStart, midStart + HOUR_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 1024L, 10L, 10L));
-
- // should have two buckets, with some data mixed together
- assertEquals(2, stats.size());
- assertValues(stats, 0, SECOND_IN_MILLIS + (HOUR_IN_MILLIS / 2), 768L, 7L, 768L, 7L, 6L);
- assertValues(stats, 1, (HOUR_IN_MILLIS / 2), 512L, 5L, 512L, 5L, 5L);
- }
-
- @Test
- public void testRecordEntireGapIdentical() throws Exception {
- // first, create two separate histories far apart
- final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
- stats1.recordData(TEST_START, TEST_START + 2 * HOUR_IN_MILLIS, 2000L, 1000L);
-
- final long TEST_START_2 = TEST_START + DAY_IN_MILLIS;
- final NetworkStatsHistory stats2 = new NetworkStatsHistory(HOUR_IN_MILLIS);
- stats2.recordData(TEST_START_2, TEST_START_2 + 2 * HOUR_IN_MILLIS, 1000L, 500L);
-
- // combine together with identical bucket size
- stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
- stats.recordEntireHistory(stats1);
- stats.recordEntireHistory(stats2);
-
- // first verify that totals match up
- assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 3000L, 1500L);
-
- // now inspect internal buckets
- assertValues(stats, 0, 1000L, 500L);
- assertValues(stats, 1, 1000L, 500L);
- assertValues(stats, 2, 500L, 250L);
- assertValues(stats, 3, 500L, 250L);
- }
-
- @Test
- public void testRecordEntireOverlapVaryingBuckets() throws Exception {
- // create history just over hour bucket boundary
- final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
- stats1.recordData(TEST_START, TEST_START + MINUTE_IN_MILLIS * 60, 600L, 600L);
-
- final long TEST_START_2 = TEST_START + MINUTE_IN_MILLIS;
- final NetworkStatsHistory stats2 = new NetworkStatsHistory(MINUTE_IN_MILLIS);
- stats2.recordData(TEST_START_2, TEST_START_2 + MINUTE_IN_MILLIS * 5, 50L, 50L);
-
- // combine together with minute bucket size
- stats = new NetworkStatsHistory(MINUTE_IN_MILLIS);
- stats.recordEntireHistory(stats1);
- stats.recordEntireHistory(stats2);
-
- // first verify that totals match up
- assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L);
-
- // now inspect internal buckets
- assertValues(stats, 0, 10L, 10L);
- assertValues(stats, 1, 20L, 20L);
- assertValues(stats, 2, 20L, 20L);
- assertValues(stats, 3, 20L, 20L);
- assertValues(stats, 4, 20L, 20L);
- assertValues(stats, 5, 20L, 20L);
- assertValues(stats, 6, 10L, 10L);
-
- // now combine using 15min buckets
- stats = new NetworkStatsHistory(HOUR_IN_MILLIS / 4);
- stats.recordEntireHistory(stats1);
- stats.recordEntireHistory(stats2);
-
- // first verify that totals match up
- assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L);
-
- // and inspect buckets
- assertValues(stats, 0, 200L, 200L);
- assertValues(stats, 1, 150L, 150L);
- assertValues(stats, 2, 150L, 150L);
- assertValues(stats, 3, 150L, 150L);
- }
-
- @Test
- public void testRemove() throws Exception {
- stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
-
- // record some data across 24 buckets
- stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 24L, 24L);
- assertEquals(24, stats.size());
-
- // try removing invalid data; should be no change
- stats.removeBucketsBefore(0 - DAY_IN_MILLIS);
- assertEquals(24, stats.size());
-
- // try removing far before buckets; should be no change
- stats.removeBucketsBefore(TEST_START - YEAR_IN_MILLIS);
- assertEquals(24, stats.size());
-
- // try removing just moments into first bucket; should be no change
- // since that bucket contains data beyond the cutoff
- stats.removeBucketsBefore(TEST_START + SECOND_IN_MILLIS);
- assertEquals(24, stats.size());
-
- // try removing single bucket
- stats.removeBucketsBefore(TEST_START + HOUR_IN_MILLIS);
- assertEquals(23, stats.size());
-
- // try removing multiple buckets
- stats.removeBucketsBefore(TEST_START + (4 * HOUR_IN_MILLIS));
- assertEquals(20, stats.size());
-
- // try removing all buckets
- stats.removeBucketsBefore(TEST_START + YEAR_IN_MILLIS);
- assertEquals(0, stats.size());
- }
-
- @Test
- public void testTotalData() throws Exception {
- final long BUCKET_SIZE = HOUR_IN_MILLIS;
- stats = new NetworkStatsHistory(BUCKET_SIZE);
-
- // record uniform data across day
- stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 2400L, 4800L);
-
- // verify that total outside range is 0
- assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, 0L, 0L);
-
- // verify total in first hour
- assertValues(stats, TEST_START, TEST_START + HOUR_IN_MILLIS, 100L, 200L);
-
- // verify total across 1.5 hours
- assertValues(stats, TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), 150L, 300L);
-
- // verify total beyond end
- assertValues(stats, TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, 100L, 200L);
-
- // verify everything total
- assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 2400L, 4800L);
-
- }
-
- @Test
- public void testFuzzing() throws Exception {
- try {
- // fuzzing with random events, looking for crashes
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- final Random r = new Random();
- for (int i = 0; i < 500; i++) {
- stats = new NetworkStatsHistory(r.nextLong());
- for (int j = 0; j < 10000; j++) {
- if (r.nextBoolean()) {
- // add range
- final long start = r.nextLong();
- final long end = start + r.nextInt();
- entry.rxBytes = nextPositiveLong(r);
- entry.rxPackets = nextPositiveLong(r);
- entry.txBytes = nextPositiveLong(r);
- entry.txPackets = nextPositiveLong(r);
- entry.operations = nextPositiveLong(r);
- stats.recordData(start, end, entry);
- } else {
- // trim something
- stats.removeBucketsBefore(r.nextLong());
- }
- }
- assertConsistent(stats);
- }
- } catch (Throwable e) {
- Log.e(TAG, String.valueOf(stats));
- throw new RuntimeException(e);
- }
- }
-
- private static long nextPositiveLong(Random r) {
- final long value = r.nextLong();
- return value < 0 ? -value : value;
- }
-
- @Test
- public void testIgnoreFields() throws Exception {
- final NetworkStatsHistory history = new NetworkStatsHistory(
- MINUTE_IN_MILLIS, 0, FIELD_RX_BYTES | FIELD_TX_BYTES);
-
- history.recordData(0, MINUTE_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
- history.recordData(0, 2 * MINUTE_IN_MILLIS,
- new NetworkStats.Entry(2L, 2L, 2L, 2L, 2L));
-
- assertFullValues(history, UNKNOWN, 1026L, UNKNOWN, 2050L, UNKNOWN, UNKNOWN);
- }
-
- @Test
- public void testIgnoreFieldsRecordIn() throws Exception {
- final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
- final NetworkStatsHistory partial = new NetworkStatsHistory(
- MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
-
- full.recordData(0, MINUTE_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
- partial.recordEntireHistory(full);
-
- assertFullValues(partial, UNKNOWN, UNKNOWN, 10L, UNKNOWN, UNKNOWN, 4L);
- }
-
- @Test
- public void testIgnoreFieldsRecordOut() throws Exception {
- final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
- final NetworkStatsHistory partial = new NetworkStatsHistory(
- MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
-
- partial.recordData(0, MINUTE_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
- full.recordEntireHistory(partial);
-
- assertFullValues(full, MINUTE_IN_MILLIS, 0L, 10L, 0L, 0L, 4L);
- }
-
- @Test
- public void testSerialize() throws Exception {
- final NetworkStatsHistory before = new NetworkStatsHistory(MINUTE_IN_MILLIS, 40, FIELD_ALL);
- before.recordData(0, 4 * MINUTE_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
- before.recordData(DAY_IN_MILLIS, DAY_IN_MILLIS + MINUTE_IN_MILLIS,
- new NetworkStats.Entry(10L, 20L, 30L, 40L, 50L));
-
- final ByteArrayOutputStream out = new ByteArrayOutputStream();
- before.writeToStream(new DataOutputStream(out));
- out.close();
-
- final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
- final NetworkStatsHistory after = new NetworkStatsHistory(new DataInputStream(in));
-
- // must have identical totals before and after
- assertFullValues(before, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L);
- assertFullValues(after, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L);
- }
-
- @Test
- public void testVarLong() throws Exception {
- assertEquals(0L, performVarLong(0L));
- assertEquals(-1L, performVarLong(-1L));
- assertEquals(1024L, performVarLong(1024L));
- assertEquals(-1024L, performVarLong(-1024L));
- assertEquals(40 * MB_IN_BYTES, performVarLong(40 * MB_IN_BYTES));
- assertEquals(512 * GB_IN_BYTES, performVarLong(512 * GB_IN_BYTES));
- assertEquals(Long.MIN_VALUE, performVarLong(Long.MIN_VALUE));
- assertEquals(Long.MAX_VALUE, performVarLong(Long.MAX_VALUE));
- assertEquals(Long.MIN_VALUE + 40, performVarLong(Long.MIN_VALUE + 40));
- assertEquals(Long.MAX_VALUE - 40, performVarLong(Long.MAX_VALUE - 40));
- }
-
- @Test
- public void testIndexBeforeAfter() throws Exception {
- final long BUCKET_SIZE = HOUR_IN_MILLIS;
- stats = new NetworkStatsHistory(BUCKET_SIZE);
-
- final long FIRST_START = TEST_START;
- final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS);
- final long SECOND_START = TEST_START + WEEK_IN_MILLIS;
- final long SECOND_END = SECOND_START + HOUR_IN_MILLIS;
- final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS);
- final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
-
- stats.recordData(FIRST_START, FIRST_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
- stats.recordData(SECOND_START, SECOND_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
- stats.recordData(THIRD_START, THIRD_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
-
- // should have buckets: 2+1+2
- assertEquals(5, stats.size());
-
- assertIndexBeforeAfter(stats, 0, 0, Long.MIN_VALUE);
- assertIndexBeforeAfter(stats, 0, 1, FIRST_START);
- assertIndexBeforeAfter(stats, 0, 1, FIRST_START + MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 0, 2, FIRST_START + HOUR_IN_MILLIS);
- assertIndexBeforeAfter(stats, 1, 2, FIRST_START + HOUR_IN_MILLIS + MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 1, 2, FIRST_END - MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 1, 2, FIRST_END);
- assertIndexBeforeAfter(stats, 1, 2, FIRST_END + MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 1, 2, SECOND_START - MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 1, 3, SECOND_START);
- assertIndexBeforeAfter(stats, 2, 3, SECOND_END);
- assertIndexBeforeAfter(stats, 2, 3, SECOND_END + MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 2, 3, THIRD_START - MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 2, 4, THIRD_START);
- assertIndexBeforeAfter(stats, 3, 4, THIRD_START + MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 3, 4, THIRD_START + HOUR_IN_MILLIS);
- assertIndexBeforeAfter(stats, 4, 4, THIRD_END);
- assertIndexBeforeAfter(stats, 4, 4, THIRD_END + MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 4, 4, Long.MAX_VALUE);
- }
-
- @Test
- public void testIntersects() throws Exception {
- final long BUCKET_SIZE = HOUR_IN_MILLIS;
- stats = new NetworkStatsHistory(BUCKET_SIZE);
-
- final long FIRST_START = TEST_START;
- final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS);
- final long SECOND_START = TEST_START + WEEK_IN_MILLIS;
- final long SECOND_END = SECOND_START + HOUR_IN_MILLIS;
- final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS);
- final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
-
- stats.recordData(FIRST_START, FIRST_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
- stats.recordData(SECOND_START, SECOND_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
- stats.recordData(THIRD_START, THIRD_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
-
- assertFalse(stats.intersects(10, 20));
- assertFalse(stats.intersects(TEST_START + YEAR_IN_MILLIS, TEST_START + YEAR_IN_MILLIS + 1));
- assertFalse(stats.intersects(Long.MAX_VALUE, Long.MIN_VALUE));
-
- assertTrue(stats.intersects(Long.MIN_VALUE, Long.MAX_VALUE));
- assertTrue(stats.intersects(10, TEST_START + YEAR_IN_MILLIS));
- assertTrue(stats.intersects(TEST_START, TEST_START));
- assertTrue(stats.intersects(TEST_START + DAY_IN_MILLIS, TEST_START + DAY_IN_MILLIS + 1));
- assertTrue(stats.intersects(TEST_START + DAY_IN_MILLIS, Long.MAX_VALUE));
- assertTrue(stats.intersects(TEST_START + 1, Long.MAX_VALUE));
-
- assertFalse(stats.intersects(Long.MIN_VALUE, TEST_START - 1));
- assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START));
- assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START + 1));
- }
-
- @Test
- public void testSetValues() throws Exception {
- stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
- stats.recordData(TEST_START, TEST_START + 1,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
-
- assertEquals(1024L + 2048L, stats.getTotalBytes());
-
- final NetworkStatsHistory.Entry entry = stats.getValues(0, null);
- entry.rxBytes /= 2;
- entry.txBytes *= 2;
- stats.setValues(0, entry);
-
- assertEquals(512L + 4096L, stats.getTotalBytes());
- }
-
- private static void assertIndexBeforeAfter(
- NetworkStatsHistory stats, int before, int after, long time) {
- assertEquals("unexpected before", before, stats.getIndexBefore(time));
- assertEquals("unexpected after", after, stats.getIndexAfter(time));
- }
-
- private static long performVarLong(long before) throws Exception {
- final ByteArrayOutputStream out = new ByteArrayOutputStream();
- writeVarLong(new DataOutputStream(out), before);
-
- final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
- return readVarLong(new DataInputStream(in));
- }
-
- private static void assertConsistent(NetworkStatsHistory stats) {
- // verify timestamps are monotonic
- long lastStart = Long.MIN_VALUE;
- NetworkStatsHistory.Entry entry = null;
- for (int i = 0; i < stats.size(); i++) {
- entry = stats.getValues(i, entry);
- assertTrue(lastStart < entry.bucketStart);
- lastStart = entry.bucketStart;
- }
- }
-
- private static void assertValues(
- NetworkStatsHistory stats, int index, long rxBytes, long txBytes) {
- final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- }
-
- private static void assertValues(
- NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) {
- final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- }
-
- private static void assertValues(NetworkStatsHistory stats, int index, long activeTime,
- long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
- final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
- assertEquals("unexpected activeTime", activeTime, entry.activeTime);
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- assertEquals("unexpected txPackets", txPackets, entry.txPackets);
- assertEquals("unexpected operations", operations, entry.operations);
- }
-
- private static void assertFullValues(NetworkStatsHistory stats, long activeTime, long rxBytes,
- long rxPackets, long txBytes, long txPackets, long operations) {
- assertValues(stats, Long.MIN_VALUE, Long.MAX_VALUE, activeTime, rxBytes, rxPackets, txBytes,
- txPackets, operations);
- }
-
- private static void assertValues(NetworkStatsHistory stats, long start, long end,
- long activeTime, long rxBytes, long rxPackets, long txBytes, long txPackets,
- long operations) {
- final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
- assertEquals("unexpected activeTime", activeTime, entry.activeTime);
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- assertEquals("unexpected txPackets", txPackets, entry.txPackets);
- assertEquals("unexpected operations", operations, entry.operations);
- }
-}
diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java
deleted file mode 100644
index 735fa7cf3751..000000000000
--- a/tests/net/java/android/net/NetworkStatsTest.java
+++ /dev/null
@@ -1,1023 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
-import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
-import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
-import static android.net.NetworkStats.IFACE_ALL;
-import static android.net.NetworkStats.INTERFACES_ALL;
-import static android.net.NetworkStats.METERED_ALL;
-import static android.net.NetworkStats.METERED_NO;
-import static android.net.NetworkStats.METERED_YES;
-import static android.net.NetworkStats.ROAMING_ALL;
-import static android.net.NetworkStats.ROAMING_NO;
-import static android.net.NetworkStats.ROAMING_YES;
-import static android.net.NetworkStats.SET_ALL;
-import static android.net.NetworkStats.SET_DBG_VPN_IN;
-import static android.net.NetworkStats.SET_DBG_VPN_OUT;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.SET_FOREGROUND;
-import static android.net.NetworkStats.TAG_ALL;
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkStats.UID_ALL;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.os.Process;
-import android.util.ArrayMap;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.google.android.collect.Sets;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.HashSet;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkStatsTest {
-
- private static final String TEST_IFACE = "test0";
- private static final String TEST_IFACE2 = "test2";
- private static final int TEST_UID = 1001;
- private static final long TEST_START = 1194220800000L;
-
- @Test
- public void testFindIndex() throws Exception {
- final NetworkStats stats = new NetworkStats(TEST_START, 5)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1024L, 8L, 0L, 0L, 10)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 0L, 0L, 1024L, 8L, 11)
- .insertEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 12)
- .insertEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
- DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12);
-
- assertEquals(4, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES,
- ROAMING_YES, DEFAULT_NETWORK_YES));
- assertEquals(3, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO));
- assertEquals(2, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES,
- ROAMING_NO, DEFAULT_NETWORK_YES));
- assertEquals(1, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO));
- assertEquals(0, stats.findIndex(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_YES));
- assertEquals(-1, stats.findIndex(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO));
- assertEquals(-1, stats.findIndex(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO));
- }
-
- @Test
- public void testFindIndexHinted() {
- final NetworkStats stats = new NetworkStats(TEST_START, 3)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1024L, 8L, 0L, 0L, 10)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11)
- .insertEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12)
- .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1024L, 8L, 0L, 0L, 10)
- .insertEntry(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 0L, 0L, 1024L, 8L, 11)
- .insertEntry(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11)
- .insertEntry(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12)
- .insertEntry(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
- DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 12);
-
- // verify that we correctly find across regardless of hinting
- for (int hint = 0; hint < stats.size(); hint++) {
- assertEquals(0, stats.findIndexHinted(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, hint));
- assertEquals(1, stats.findIndexHinted(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, hint));
- assertEquals(2, stats.findIndexHinted(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, hint));
- assertEquals(3, stats.findIndexHinted(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, hint));
- assertEquals(4, stats.findIndexHinted(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, hint));
- assertEquals(5, stats.findIndexHinted(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D,
- METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, hint));
- assertEquals(6, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, hint));
- assertEquals(7, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
- METERED_YES, ROAMING_YES, DEFAULT_NETWORK_NO, hint));
- assertEquals(-1, stats.findIndexHinted(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, hint));
- assertEquals(-1, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
- METERED_YES, ROAMING_YES, DEFAULT_NETWORK_YES, hint));
- }
- }
-
- @Test
- public void testAddEntryGrow() throws Exception {
- final NetworkStats stats = new NetworkStats(TEST_START, 4);
-
- assertEquals(0, stats.size());
- assertEquals(4, stats.internalSize());
-
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1L, 1L, 2L, 2L, 3);
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 2L, 2L, 2L, 2L, 4);
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
- DEFAULT_NETWORK_YES, 3L, 3L, 2L, 2L, 5);
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
- DEFAULT_NETWORK_NO, 3L, 3L, 2L, 2L, 5);
-
- assertEquals(4, stats.size());
- assertEquals(4, stats.internalSize());
-
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 4L, 40L, 4L, 40L, 7);
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 5L, 50L, 4L, 40L, 8);
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 6L, 60L, 5L, 50L, 10);
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
- DEFAULT_NETWORK_YES, 7L, 70L, 5L, 50L, 11);
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
- DEFAULT_NETWORK_NO, 7L, 70L, 5L, 50L, 11);
-
- assertEquals(9, stats.size());
- assertTrue(stats.internalSize() >= 9);
-
- assertValues(stats, 0, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1L, 1L, 2L, 2L, 3);
- assertValues(stats, 1, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 2L, 2L, 2L, 2L, 4);
- assertValues(stats, 2, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
- DEFAULT_NETWORK_YES, 3L, 3L, 2L, 2L, 5);
- assertValues(stats, 3, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES,
- ROAMING_YES, DEFAULT_NETWORK_NO, 3L, 3L, 2L, 2L, 5);
- assertValues(stats, 4, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 4L, 40L, 4L, 40L, 7);
- assertValues(stats, 5, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 5L, 50L, 4L, 40L, 8);
- assertValues(stats, 6, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 6L, 60L, 5L, 50L, 10);
- assertValues(stats, 7, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
- DEFAULT_NETWORK_YES, 7L, 70L, 5L, 50L, 11);
- assertValues(stats, 8, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES,
- ROAMING_YES, DEFAULT_NETWORK_NO, 7L, 70L, 5L, 50L, 11);
- }
-
- @Test
- public void testCombineExisting() throws Exception {
- final NetworkStats stats = new NetworkStats(TEST_START, 10);
-
- stats.insertEntry(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 10);
- stats.insertEntry(TEST_IFACE, 1001, SET_DEFAULT, 0xff, 128L, 1L, 128L, 1L, 2);
- stats.combineValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, -128L, -1L,
- -128L, -1L, -1);
-
- assertValues(stats, 0, TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 384L, 3L, 128L, 1L, 9);
- assertValues(stats, 1, TEST_IFACE, 1001, SET_DEFAULT, 0xff, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 128L, 1L, 128L, 1L, 2);
-
- // now try combining that should create row
- stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 3);
- assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 128L, 1L, 128L, 1L, 3);
- stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 3);
- assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 256L, 2L, 256L, 2L, 6);
- }
-
- @Test
- public void testSubtractIdenticalData() throws Exception {
- final NetworkStats before = new NetworkStats(TEST_START, 2)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
-
- final NetworkStats after = new NetworkStats(TEST_START, 2)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
-
- final NetworkStats result = after.subtract(before);
-
- // identical data should result in zero delta
- assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0);
- assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0);
- }
-
- @Test
- public void testSubtractIdenticalRows() throws Exception {
- final NetworkStats before = new NetworkStats(TEST_START, 2)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
-
- final NetworkStats after = new NetworkStats(TEST_START, 2)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1025L, 9L, 2L, 1L, 15)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 3L, 1L, 1028L, 9L, 20);
-
- final NetworkStats result = after.subtract(before);
-
- // expect delta between measurements
- assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1L, 1L, 2L, 1L, 4);
- assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 3L, 1L, 4L, 1L, 8);
- }
-
- @Test
- public void testSubtractNewRows() throws Exception {
- final NetworkStats before = new NetworkStats(TEST_START, 2)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
-
- final NetworkStats after = new NetworkStats(TEST_START, 3)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12)
- .insertEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20);
-
- final NetworkStats result = after.subtract(before);
-
- // its okay to have new rows
- assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0);
- assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0);
- assertValues(result, 2, TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 20);
- }
-
- @Test
- public void testSubtractMissingRows() throws Exception {
- final NetworkStats before = new NetworkStats(TEST_START, 2)
- .insertEntry(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0)
- .insertEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2048L, 0L, 0L, 0L, 0);
-
- final NetworkStats after = new NetworkStats(TEST_START, 1)
- .insertEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2049L, 2L, 3L, 4L, 0);
-
- final NetworkStats result = after.subtract(before);
-
- // should silently drop omitted rows
- assertEquals(1, result.size());
- assertValues(result, 0, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 1L, 2L, 3L, 4L, 0);
- assertEquals(4L, result.getTotalBytes());
- }
-
- @Test
- public void testTotalBytes() throws Exception {
- final NetworkStats iface = new NetworkStats(TEST_START, 2)
- .insertEntry(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 256L, 0L, 0L, 0L, 0L);
- assertEquals(384L, iface.getTotalBytes());
-
- final NetworkStats uidSet = new NetworkStats(TEST_START, 3)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L);
- assertEquals(96L, uidSet.getTotalBytes());
-
- final NetworkStats uidTag = new NetworkStats(TEST_START, 6)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L);
- assertEquals(64L, uidTag.getTotalBytes());
-
- final NetworkStats uidMetered = new NetworkStats(TEST_START, 3)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
- assertEquals(96L, uidMetered.getTotalBytes());
-
- final NetworkStats uidRoaming = new NetworkStats(TEST_START, 3)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
- DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
- assertEquals(96L, uidRoaming.getTotalBytes());
- }
-
- @Test
- public void testGroupedByIfaceEmpty() throws Exception {
- final NetworkStats uidStats = new NetworkStats(TEST_START, 3);
- final NetworkStats grouped = uidStats.groupedByIface();
-
- assertEquals(0, uidStats.size());
- assertEquals(0, grouped.size());
- }
-
- @Test
- public void testGroupedByIfaceAll() throws Exception {
- final NetworkStats uidStats = new NetworkStats(TEST_START, 3)
- .insertEntry(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L)
- .insertEntry(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_NO, 128L, 8L, 0L, 2L, 20L)
- .insertEntry(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES,
- DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L);
- final NetworkStats grouped = uidStats.groupedByIface();
-
- assertEquals(3, uidStats.size());
- assertEquals(1, grouped.size());
-
- assertValues(grouped, 0, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 384L, 24L, 0L, 6L, 0L);
- }
-
- @Test
- public void testGroupedByIface() throws Exception {
- final NetworkStats uidStats = new NetworkStats(TEST_START, 7)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 4L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
- DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L);
-
- final NetworkStats grouped = uidStats.groupedByIface();
-
- assertEquals(7, uidStats.size());
-
- assertEquals(2, grouped.size());
- assertValues(grouped, 0, TEST_IFACE, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 384L, 24L, 0L, 2L, 0L);
- assertValues(grouped, 1, TEST_IFACE2, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 1024L, 64L, 0L, 0L, 0L);
- }
-
- @Test
- public void testAddAllValues() {
- final NetworkStats first = new NetworkStats(TEST_START, 5)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
- DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
-
- final NetworkStats second = new NetworkStats(TEST_START, 2)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
- DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
-
- first.combineAllValues(second);
-
- assertEquals(4, first.size());
- assertValues(first, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 0L, 0L, 0L, 0L);
- assertValues(first, 1, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L);
- assertValues(first, 2, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
- DEFAULT_NETWORK_YES, 64L, 0L, 0L, 0L, 0L);
- assertValues(first, 3, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L);
- }
-
- @Test
- public void testGetTotal() {
- final NetworkStats stats = new NetworkStats(TEST_START, 7)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 4L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 512L,32L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
- DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L);
-
- assertValues(stats.getTotal(null), 1408L, 88L, 0L, 2L, 20L);
- assertValues(stats.getTotal(null, 100), 1280L, 80L, 0L, 2L, 20L);
- assertValues(stats.getTotal(null, 101), 128L, 8L, 0L, 0L, 0L);
-
- final HashSet<String> ifaces = Sets.newHashSet();
- assertValues(stats.getTotal(null, ifaces), 0L, 0L, 0L, 0L, 0L);
-
- ifaces.add(TEST_IFACE2);
- assertValues(stats.getTotal(null, ifaces), 1024L, 64L, 0L, 0L, 0L);
- }
-
- @Test
- public void testRemoveUids() throws Exception {
- final NetworkStats before = new NetworkStats(TEST_START, 3);
-
- // Test 0 item stats.
- NetworkStats after = before.clone();
- after.removeUids(new int[0]);
- assertEquals(0, after.size());
- after.removeUids(new int[] {100});
- assertEquals(0, after.size());
-
- // Test 1 item stats.
- before.insertEntry(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, 1L, 128L, 0L, 2L, 20L);
- after = before.clone();
- after.removeUids(new int[0]);
- assertEquals(1, after.size());
- assertValues(after, 0, TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1L, 128L, 0L, 2L, 20L);
- after.removeUids(new int[] {99});
- assertEquals(0, after.size());
-
- // Append remaining test items.
- before.insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 16L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 8L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 4L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 64L, 2L, 0L, 0L, 0L);
- assertEquals(7, before.size());
-
- // Test remove with empty uid list.
- after = before.clone();
- after.removeUids(new int[0]);
- assertValues(after.getTotalIncludingTags(null), 127L, 254L, 0L, 4L, 40L);
-
- // Test remove uids don't exist in stats.
- after.removeUids(new int[] {98, 0, Integer.MIN_VALUE, Integer.MAX_VALUE});
- assertValues(after.getTotalIncludingTags(null), 127L, 254L, 0L, 4L, 40L);
-
- // Test remove all uids.
- after.removeUids(new int[] {99, 100, 100, 101});
- assertEquals(0, after.size());
-
- // Test remove in the middle.
- after = before.clone();
- after.removeUids(new int[] {100});
- assertEquals(3, after.size());
- assertValues(after, 0, TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1L, 128L, 0L, 2L, 20L);
- assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 32L, 4L, 0L, 0L, 0L);
- assertValues(after, 2, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 64L, 2L, 0L, 0L, 0L);
- }
-
- @Test
- public void testRemoveEmptyEntries() throws Exception {
- // Test empty stats.
- final NetworkStats statsEmpty = new NetworkStats(TEST_START, 3);
- assertEquals(0, statsEmpty.removeEmptyEntries().size());
-
- // Test stats with non-zero entry.
- final NetworkStats statsNonZero = new NetworkStats(TEST_START, 1)
- .insertEntry(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 1L, 128L, 0L, 2L, 20L);
- assertEquals(1, statsNonZero.size());
- final NetworkStats expectedNonZero = statsNonZero.removeEmptyEntries();
- assertEquals(1, expectedNonZero.size());
- assertValues(expectedNonZero, 0, TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 1L, 128L, 0L, 2L, 20L);
-
- // Test stats with empty entry.
- final NetworkStats statsZero = new NetworkStats(TEST_START, 1)
- .insertEntry(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
- assertEquals(1, statsZero.size());
- final NetworkStats expectedZero = statsZero.removeEmptyEntries();
- assertEquals(1, statsZero.size()); // Assert immutable.
- assertEquals(0, expectedZero.size());
-
- // Test stats with multiple entries.
- final NetworkStats statsMultiple = new NetworkStats(TEST_START, 0)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 0L, 8L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 4L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 0L, 2L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 0L, 0L, 1L);
- assertEquals(9, statsMultiple.size());
- final NetworkStats expectedMultiple = statsMultiple.removeEmptyEntries();
- assertEquals(9, statsMultiple.size()); // Assert immutable.
- assertEquals(7, expectedMultiple.size());
- assertValues(expectedMultiple.getTotalIncludingTags(null), 14L, 104L, 4L, 4L, 21L);
-
- // Test stats with multiple empty entries.
- assertEquals(statsMultiple.size(), statsMultiple.subtract(statsMultiple).size());
- assertEquals(0, statsMultiple.subtract(statsMultiple).removeEmptyEntries().size());
- }
-
- @Test
- public void testClone() throws Exception {
- final NetworkStats original = new NetworkStats(TEST_START, 5)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L);
-
- // make clone and mutate original
- final NetworkStats clone = original.clone();
- original.insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L);
-
- assertEquals(3, original.size());
- assertEquals(2, clone.size());
-
- assertEquals(128L + 512L + 128L, original.getTotalBytes());
- assertEquals(128L + 512L, clone.getTotalBytes());
- }
-
- @Test
- public void testAddWhenEmpty() throws Exception {
- final NetworkStats red = new NetworkStats(TEST_START, -1);
- final NetworkStats blue = new NetworkStats(TEST_START, 5)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L);
-
- // We're mostly checking that we don't crash
- red.combineAllValues(blue);
- }
-
- @Test
- public void testMigrateTun() throws Exception {
- final int tunUid = 10030;
- final String tunIface = "tun0";
- final String underlyingIface = "wlan0";
- final int testTag1 = 8888;
- NetworkStats delta = new NetworkStats(TEST_START, 17)
- .insertEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 39605L, 46L, 12259L, 55L, 0L)
- .insertEntry(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
- .insertEntry(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 72667L, 197L, 43909L, 241L, 0L)
- .insertEntry(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 9297L, 17L, 4128L, 21L, 0L)
- // VPN package also uses some traffic through unprotected network.
- .insertEntry(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 4983L, 10L, 1801L, 12L, 0L)
- .insertEntry(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
- // Tag entries
- .insertEntry(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 21691L, 41L, 13820L, 51L, 0L)
- .insertEntry(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1281L, 2L, 665L, 2L, 0L)
- // Irrelevant entries
- .insertEntry(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1685L, 5L, 2070L, 6L, 0L)
- // Underlying Iface entries
- .insertEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 5178L, 8L, 2139L, 11L, 0L)
- .insertEntry(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
- .insertEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 149873L, 287L, 59217L /* smaller than sum(tun0) */,
- 299L /* smaller than sum(tun0) */, 0L)
- .insertEntry(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
-
- delta.migrateTun(tunUid, tunIface, new String[]{underlyingIface});
- assertEquals(20, delta.size());
-
- // tunIface and TEST_IFACE entries are not changed.
- assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 39605L, 46L, 12259L, 55L, 0L);
- assertValues(delta, 1, tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
- assertValues(delta, 2, tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 72667L, 197L, 43909L, 241L, 0L);
- assertValues(delta, 3, tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 9297L, 17L, 4128L, 21L, 0L);
- assertValues(delta, 4, tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 4983L, 10L, 1801L, 12L, 0L);
- assertValues(delta, 5, tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
- assertValues(delta, 6, tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 21691L, 41L, 13820L, 51L, 0L);
- assertValues(delta, 7, tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1281L, 2L, 665L, 2L, 0L);
- assertValues(delta, 8, TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1685L, 5L, 2070L, 6L, 0L);
-
- // Existing underlying Iface entries are updated
- assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 44783L, 54L, 14178L, 62L, 0L);
- assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
-
- // VPN underlying Iface entries are updated
- assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 28304L, 27L, 1L, 2L, 0L);
- assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
-
- // New entries are added for new application's underlying Iface traffic
- assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 72667L, 197L, 43123L, 227L, 0L);
- assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 9297L, 17L, 4054, 19L, 0L);
- assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 21691L, 41L, 13572L, 48L, 0L);
- assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 1281L, 2L, 653L, 1L, 0L);
-
- // New entries are added for debug purpose
- assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 39605L, 46L, 12039, 51, 0);
- assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 81964, 214, 47177, 246, 0);
- assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, METERED_ALL,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, 121569, 260, 59216, 297, 0);
-
- }
-
- // Tests a case where all of the data received by the tun0 interface is echo back into the tun0
- // interface by the vpn app before it's sent out of the underlying interface. The VPN app should
- // not be charged for the echoed data but it should still be charged for any extra data it sends
- // via the underlying interface.
- @Test
- public void testMigrateTun_VpnAsLoopback() {
- final int tunUid = 10030;
- final String tunIface = "tun0";
- final String underlyingIface = "wlan0";
- NetworkStats delta = new NetworkStats(TEST_START, 9)
- // 2 different apps sent/receive data via tun0.
- .insertEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L)
- .insertEntry(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L)
- // VPN package resends data through the tunnel (with exaggerated overhead)
- .insertEntry(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 240000, 100L, 120000L, 60L, 0L)
- // 1 app already has some traffic on the underlying interface, the other doesn't yet
- .insertEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1000L, 10L, 2000L, 20L, 0L)
- // Traffic through the underlying interface via the vpn app.
- // This test should redistribute this data correctly.
- .insertEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 75500L, 37L, 130000L, 70L, 0L);
-
- delta.migrateTun(tunUid, tunIface, new String[]{underlyingIface});
- assertEquals(9, delta.size());
-
- // tunIface entries should not be changed.
- assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
- assertValues(delta, 1, tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L);
- assertValues(delta, 2, tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 240000L, 100L, 120000L, 60L, 0L);
-
- // Existing underlying Iface entries are updated
- assertValues(delta, 3, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 51000L, 35L, 102000L, 70L, 0L);
-
- // VPN underlying Iface entries are updated
- assertValues(delta, 4, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 25000L, 10L, 29800L, 15L, 0L);
-
- // New entries are added for new application's underlying Iface traffic
- assertContains(delta, underlyingIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L);
-
- // New entries are added for debug purpose
- assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
- assertContains(delta, underlyingIface, 20100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 500, 2L, 200L, 5L, 0L);
- assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, METERED_ALL,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, 50500L, 27L, 100200L, 55, 0);
- }
-
- @Test
- public void testFilter_NoFilter() {
- NetworkStats.Entry entry1 = new NetworkStats.Entry(
- "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry2 = new NetworkStats.Entry(
- "test2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry3 = new NetworkStats.Entry(
- "test2", 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats stats = new NetworkStats(TEST_START, 3)
- .insertEntry(entry1)
- .insertEntry(entry2)
- .insertEntry(entry3);
-
- stats.filter(UID_ALL, INTERFACES_ALL, TAG_ALL);
- assertEquals(3, stats.size());
- assertEquals(entry1, stats.getValues(0, null));
- assertEquals(entry2, stats.getValues(1, null));
- assertEquals(entry3, stats.getValues(2, null));
- }
-
- @Test
- public void testFilter_UidFilter() {
- final int testUid = 10101;
- NetworkStats.Entry entry1 = new NetworkStats.Entry(
- "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry2 = new NetworkStats.Entry(
- "test2", testUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry3 = new NetworkStats.Entry(
- "test2", testUid, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats stats = new NetworkStats(TEST_START, 3)
- .insertEntry(entry1)
- .insertEntry(entry2)
- .insertEntry(entry3);
-
- stats.filter(testUid, INTERFACES_ALL, TAG_ALL);
- assertEquals(2, stats.size());
- assertEquals(entry2, stats.getValues(0, null));
- assertEquals(entry3, stats.getValues(1, null));
- }
-
- @Test
- public void testFilter_InterfaceFilter() {
- final String testIf1 = "testif1";
- final String testIf2 = "testif2";
- NetworkStats.Entry entry1 = new NetworkStats.Entry(
- testIf1, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry2 = new NetworkStats.Entry(
- "otherif", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry3 = new NetworkStats.Entry(
- testIf1, 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry4 = new NetworkStats.Entry(
- testIf2, 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats stats = new NetworkStats(TEST_START, 4)
- .insertEntry(entry1)
- .insertEntry(entry2)
- .insertEntry(entry3)
- .insertEntry(entry4);
-
- stats.filter(UID_ALL, new String[] { testIf1, testIf2 }, TAG_ALL);
- assertEquals(3, stats.size());
- assertEquals(entry1, stats.getValues(0, null));
- assertEquals(entry3, stats.getValues(1, null));
- assertEquals(entry4, stats.getValues(2, null));
- }
-
- @Test
- public void testFilter_EmptyInterfaceFilter() {
- NetworkStats.Entry entry1 = new NetworkStats.Entry(
- "if1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry2 = new NetworkStats.Entry(
- "if2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats stats = new NetworkStats(TEST_START, 3)
- .insertEntry(entry1)
- .insertEntry(entry2);
-
- stats.filter(UID_ALL, new String[] { }, TAG_ALL);
- assertEquals(0, stats.size());
- }
-
- @Test
- public void testFilter_TagFilter() {
- final int testTag = 123;
- final int otherTag = 456;
- NetworkStats.Entry entry1 = new NetworkStats.Entry(
- "test1", 10100, SET_DEFAULT, testTag, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry2 = new NetworkStats.Entry(
- "test2", 10101, SET_DEFAULT, testTag, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry3 = new NetworkStats.Entry(
- "test2", 10101, SET_DEFAULT, otherTag, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats stats = new NetworkStats(TEST_START, 3)
- .insertEntry(entry1)
- .insertEntry(entry2)
- .insertEntry(entry3);
-
- stats.filter(UID_ALL, INTERFACES_ALL, testTag);
- assertEquals(2, stats.size());
- assertEquals(entry1, stats.getValues(0, null));
- assertEquals(entry2, stats.getValues(1, null));
- }
-
- @Test
- public void testFilterDebugEntries() {
- NetworkStats.Entry entry1 = new NetworkStats.Entry(
- "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry2 = new NetworkStats.Entry(
- "test2", 10101, SET_DBG_VPN_IN, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry3 = new NetworkStats.Entry(
- "test2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry4 = new NetworkStats.Entry(
- "test2", 10101, SET_DBG_VPN_OUT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats stats = new NetworkStats(TEST_START, 4)
- .insertEntry(entry1)
- .insertEntry(entry2)
- .insertEntry(entry3)
- .insertEntry(entry4);
-
- stats.filterDebugEntries();
-
- assertEquals(2, stats.size());
- assertEquals(entry1, stats.getValues(0, null));
- assertEquals(entry3, stats.getValues(1, null));
- }
-
- @Test
- public void testApply464xlatAdjustments() {
- final String v4Iface = "v4-wlan0";
- final String baseIface = "wlan0";
- final String otherIface = "other";
- final int appUid = 10001;
- final int rootUid = Process.ROOT_UID;
- ArrayMap<String, String> stackedIface = new ArrayMap<>();
- stackedIface.put(v4Iface, baseIface);
-
- // Ipv4 traffic sent/received by an app on stacked interface.
- final NetworkStats.Entry appEntry = new NetworkStats.Entry(
- v4Iface, appUid, SET_DEFAULT, TAG_NONE,
- 30501490 /* rxBytes */,
- 22401 /* rxPackets */,
- 876235 /* txBytes */,
- 13805 /* txPackets */,
- 0 /* operations */);
-
- // Traffic measured for the root uid on the base interface.
- final NetworkStats.Entry rootUidEntry = new NetworkStats.Entry(
- baseIface, rootUid, SET_DEFAULT, TAG_NONE,
- 163577 /* rxBytes */,
- 187 /* rxPackets */,
- 17607 /* txBytes */,
- 97 /* txPackets */,
- 0 /* operations */);
-
- final NetworkStats.Entry otherEntry = new NetworkStats.Entry(
- otherIface, appUid, SET_DEFAULT, TAG_NONE,
- 2600 /* rxBytes */,
- 2 /* rxPackets */,
- 3800 /* txBytes */,
- 3 /* txPackets */,
- 0 /* operations */);
-
- final NetworkStats stats = new NetworkStats(TEST_START, 3)
- .insertEntry(appEntry)
- .insertEntry(rootUidEntry)
- .insertEntry(otherEntry);
-
- stats.apply464xlatAdjustments(stackedIface);
-
- assertEquals(3, stats.size());
- final NetworkStats.Entry expectedAppUid = new NetworkStats.Entry(
- v4Iface, appUid, SET_DEFAULT, TAG_NONE,
- 30949510,
- 22401,
- 1152335,
- 13805,
- 0);
- final NetworkStats.Entry expectedRootUid = new NetworkStats.Entry(
- baseIface, 0, SET_DEFAULT, TAG_NONE,
- 163577,
- 187,
- 17607,
- 97,
- 0);
- assertEquals(expectedAppUid, stats.getValues(0, null));
- assertEquals(expectedRootUid, stats.getValues(1, null));
- assertEquals(otherEntry, stats.getValues(2, null));
- }
-
- @Test
- public void testApply464xlatAdjustments_noStackedIface() {
- NetworkStats.Entry firstEntry = new NetworkStats.Entry(
- "if1", 10002, SET_DEFAULT, TAG_NONE,
- 2600 /* rxBytes */,
- 2 /* rxPackets */,
- 3800 /* txBytes */,
- 3 /* txPackets */,
- 0 /* operations */);
- NetworkStats.Entry secondEntry = new NetworkStats.Entry(
- "if2", 10002, SET_DEFAULT, TAG_NONE,
- 5000 /* rxBytes */,
- 3 /* rxPackets */,
- 6000 /* txBytes */,
- 4 /* txPackets */,
- 0 /* operations */);
-
- NetworkStats stats = new NetworkStats(TEST_START, 2)
- .insertEntry(firstEntry)
- .insertEntry(secondEntry);
-
- // Empty map: no adjustment
- stats.apply464xlatAdjustments(new ArrayMap<>());
-
- assertEquals(2, stats.size());
- assertEquals(firstEntry, stats.getValues(0, null));
- assertEquals(secondEntry, stats.getValues(1, null));
- }
-
- private static void assertContains(NetworkStats stats, String iface, int uid, int set,
- int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
- long txBytes, long txPackets, long operations) {
- int index = stats.findIndex(iface, uid, set, tag, metered, roaming, defaultNetwork);
- assertTrue(index != -1);
- assertValues(stats, index, iface, uid, set, tag, metered, roaming, defaultNetwork,
- rxBytes, rxPackets, txBytes, txPackets, operations);
- }
-
- private static void assertValues(NetworkStats stats, int index, String iface, int uid, int set,
- int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
- long txBytes, long txPackets, long operations) {
- final NetworkStats.Entry entry = stats.getValues(index, null);
- assertValues(entry, iface, uid, set, tag, metered, roaming, defaultNetwork);
- assertValues(entry, rxBytes, rxPackets, txBytes, txPackets, operations);
- }
-
- private static void assertValues(
- NetworkStats.Entry entry, String iface, int uid, int set, int tag, int metered,
- int roaming, int defaultNetwork) {
- assertEquals(iface, entry.iface);
- assertEquals(uid, entry.uid);
- assertEquals(set, entry.set);
- assertEquals(tag, entry.tag);
- assertEquals(metered, entry.metered);
- assertEquals(roaming, entry.roaming);
- assertEquals(defaultNetwork, entry.defaultNetwork);
- }
-
- private static void assertValues(NetworkStats.Entry entry, long rxBytes, long rxPackets,
- long txBytes, long txPackets, long operations) {
- assertEquals(rxBytes, entry.rxBytes);
- assertEquals(rxPackets, entry.rxPackets);
- assertEquals(txBytes, entry.txBytes);
- assertEquals(txPackets, entry.txPackets);
- assertEquals(operations, entry.operations);
- }
-
-}
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
deleted file mode 100644
index 9ba56e44fe88..000000000000
--- a/tests/net/java/android/net/NetworkTemplateTest.kt
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net
-
-import android.content.Context
-import android.net.ConnectivityManager.TYPE_MOBILE
-import android.net.ConnectivityManager.TYPE_WIFI
-import android.net.NetworkIdentity.SUBTYPE_COMBINED
-import android.net.NetworkIdentity.buildNetworkIdentity
-import android.net.NetworkStats.DEFAULT_NETWORK_ALL
-import android.net.NetworkStats.METERED_ALL
-import android.net.NetworkStats.ROAMING_ALL
-import android.net.NetworkTemplate.MATCH_MOBILE
-import android.net.NetworkTemplate.MATCH_WIFI
-import android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA
-import android.net.NetworkTemplate.NETWORK_TYPE_ALL
-import android.net.NetworkTemplate.buildTemplateMobileWithRatType
-import android.telephony.TelephonyManager
-import com.android.testutils.assertParcelSane
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.mock
-import org.mockito.MockitoAnnotations
-import kotlin.test.assertFalse
-import kotlin.test.assertNotEquals
-import kotlin.test.assertTrue
-
-private const val TEST_IMSI1 = "imsi1"
-private const val TEST_IMSI2 = "imsi2"
-private const val TEST_SSID1 = "ssid1"
-
-@RunWith(JUnit4::class)
-class NetworkTemplateTest {
- private val mockContext = mock(Context::class.java)
-
- private fun buildMobileNetworkState(subscriberId: String): NetworkState =
- buildNetworkState(TYPE_MOBILE, subscriberId = subscriberId)
- private fun buildWifiNetworkState(ssid: String): NetworkState =
- buildNetworkState(TYPE_WIFI, ssid = ssid)
-
- private fun buildNetworkState(
- type: Int,
- subscriberId: String? = null,
- ssid: String? = null
- ): NetworkState {
- val info = mock(NetworkInfo::class.java)
- doReturn(type).`when`(info).type
- doReturn(NetworkInfo.State.CONNECTED).`when`(info).state
- val lp = LinkProperties()
- val caps = NetworkCapabilities().apply {
- setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
- setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
- }
- return NetworkState(info, lp, caps, mock(Network::class.java), subscriberId, ssid)
- }
-
- private fun NetworkTemplate.assertMatches(ident: NetworkIdentity) =
- assertTrue(matches(ident), "$this does not match $ident")
-
- private fun NetworkTemplate.assertDoesNotMatch(ident: NetworkIdentity) =
- assertFalse(matches(ident), "$this should match $ident")
-
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
- }
-
- @Test
- fun testRatTypeGroupMatches() {
- val stateMobile = buildMobileNetworkState(TEST_IMSI1)
- // Build UMTS template that matches mobile identities with RAT in the same
- // group with any IMSI. See {@link NetworkTemplate#getCollapsedRatType}.
- val templateUmts = buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS)
- // Build normal template that matches mobile identities with any RAT and IMSI.
- val templateAll = buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL)
- // Build template with UNKNOWN RAT that matches mobile identities with RAT that
- // cannot be determined.
- val templateUnknown =
- buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UNKNOWN)
-
- val identUmts = buildNetworkIdentity(
- mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_UMTS)
- val identHsdpa = buildNetworkIdentity(
- mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_HSDPA)
- val identLte = buildNetworkIdentity(
- mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_LTE)
- val identCombined = buildNetworkIdentity(
- mockContext, stateMobile, false, SUBTYPE_COMBINED)
- val identImsi2 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI2),
- false, TelephonyManager.NETWORK_TYPE_UMTS)
- val identWifi = buildNetworkIdentity(
- mockContext, buildWifiNetworkState(TEST_SSID1), true, 0)
-
- // Assert that identity with the same RAT matches.
- templateUmts.assertMatches(identUmts)
- templateAll.assertMatches(identUmts)
- templateUnknown.assertDoesNotMatch(identUmts)
- // Assert that identity with the RAT within the same group matches.
- templateUmts.assertMatches(identHsdpa)
- templateAll.assertMatches(identHsdpa)
- templateUnknown.assertDoesNotMatch(identHsdpa)
- // Assert that identity with the RAT out of the same group only matches template with
- // NETWORK_TYPE_ALL.
- templateUmts.assertDoesNotMatch(identLte)
- templateAll.assertMatches(identLte)
- templateUnknown.assertDoesNotMatch(identLte)
- // Assert that identity with combined RAT only matches with template with NETWORK_TYPE_ALL
- // and NETWORK_TYPE_UNKNOWN.
- templateUmts.assertDoesNotMatch(identCombined)
- templateAll.assertMatches(identCombined)
- templateUnknown.assertMatches(identCombined)
- // Assert that identity with different IMSI matches.
- templateUmts.assertMatches(identImsi2)
- templateAll.assertMatches(identImsi2)
- templateUnknown.assertDoesNotMatch(identImsi2)
- // Assert that wifi identity does not match.
- templateUmts.assertDoesNotMatch(identWifi)
- templateAll.assertDoesNotMatch(identWifi)
- templateUnknown.assertDoesNotMatch(identWifi)
- }
-
- @Test
- fun testParcelUnparcel() {
- val templateMobile = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1, null, null, METERED_ALL,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE)
- val templateWifi = NetworkTemplate(MATCH_WIFI, null, null, TEST_SSID1, METERED_ALL,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, 0)
- assertParcelSane(templateMobile, 8)
- assertParcelSane(templateWifi, 8)
- }
-
- // Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with
- // TelephonyManager#NETWORK_TYPE_* constants.
- @Test
- fun testNetworkTypeConstants() {
- for (ratType in TelephonyManager.getAllNetworkTypes()) {
- assertNotEquals(NETWORK_TYPE_ALL, ratType)
- assertNotEquals(NETWORK_TYPE_5G_NSA, ratType)
- }
- }
-}
diff --git a/tests/net/java/android/net/NetworkUtilsTest.java b/tests/net/java/android/net/NetworkUtilsTest.java
deleted file mode 100644
index 3158cc8637e4..000000000000
--- a/tests/net/java/android/net/NetworkUtilsTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.AF_UNIX;
-import static android.system.OsConstants.EPERM;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOCK_STREAM;
-
-import static junit.framework.Assert.assertEquals;
-
-import static org.junit.Assert.fail;
-
-import android.system.ErrnoException;
-import android.system.Os;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.io.IoUtils;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.math.BigInteger;
-import java.util.TreeSet;
-
-@RunWith(AndroidJUnit4.class)
-@androidx.test.filters.SmallTest
-public class NetworkUtilsTest {
- @Test
- public void testRoutedIPv4AddressCount() {
- final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
- // No routes routes to no addresses.
- assertEquals(0, NetworkUtils.routedIPv4AddressCount(set));
-
- set.add(new IpPrefix("0.0.0.0/0"));
- assertEquals(1l << 32, NetworkUtils.routedIPv4AddressCount(set));
-
- set.add(new IpPrefix("20.18.0.0/16"));
- set.add(new IpPrefix("20.18.0.0/24"));
- set.add(new IpPrefix("20.18.0.0/8"));
- // There is a default route, still covers everything
- assertEquals(1l << 32, NetworkUtils.routedIPv4AddressCount(set));
-
- set.clear();
- set.add(new IpPrefix("20.18.0.0/24"));
- set.add(new IpPrefix("20.18.0.0/8"));
- // The 8-length includes the 24-length prefix
- assertEquals(1l << 24, NetworkUtils.routedIPv4AddressCount(set));
-
- set.add(new IpPrefix("10.10.10.126/25"));
- // The 8-length does not include this 25-length prefix
- assertEquals((1l << 24) + (1 << 7), NetworkUtils.routedIPv4AddressCount(set));
-
- set.clear();
- set.add(new IpPrefix("1.2.3.4/32"));
- set.add(new IpPrefix("1.2.3.4/32"));
- set.add(new IpPrefix("1.2.3.4/32"));
- set.add(new IpPrefix("1.2.3.4/32"));
- assertEquals(1l, NetworkUtils.routedIPv4AddressCount(set));
-
- set.add(new IpPrefix("1.2.3.5/32"));
- set.add(new IpPrefix("1.2.3.6/32"));
-
- set.add(new IpPrefix("1.2.3.7/32"));
- set.add(new IpPrefix("1.2.3.8/32"));
- set.add(new IpPrefix("1.2.3.9/32"));
- set.add(new IpPrefix("1.2.3.0/32"));
- assertEquals(7l, NetworkUtils.routedIPv4AddressCount(set));
-
- // 1.2.3.4/30 eats 1.2.3.{4-7}/32
- set.add(new IpPrefix("1.2.3.4/30"));
- set.add(new IpPrefix("6.2.3.4/28"));
- set.add(new IpPrefix("120.2.3.4/16"));
- assertEquals(7l - 4 + 4 + 16 + 65536, NetworkUtils.routedIPv4AddressCount(set));
- }
-
- @Test
- public void testRoutedIPv6AddressCount() {
- final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
- // No routes routes to no addresses.
- assertEquals(BigInteger.ZERO, NetworkUtils.routedIPv6AddressCount(set));
-
- set.add(new IpPrefix("::/0"));
- assertEquals(BigInteger.ONE.shiftLeft(128), NetworkUtils.routedIPv6AddressCount(set));
-
- set.add(new IpPrefix("1234:622a::18/64"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/96"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/8"));
- // There is a default route, still covers everything
- assertEquals(BigInteger.ONE.shiftLeft(128), NetworkUtils.routedIPv6AddressCount(set));
-
- set.clear();
- set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/96"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/8"));
- // The 8-length includes the 96-length prefix
- assertEquals(BigInteger.ONE.shiftLeft(120), NetworkUtils.routedIPv6AddressCount(set));
-
- set.add(new IpPrefix("10::26/64"));
- // The 8-length does not include this 64-length prefix
- assertEquals(BigInteger.ONE.shiftLeft(120).add(BigInteger.ONE.shiftLeft(64)),
- NetworkUtils.routedIPv6AddressCount(set));
-
- set.clear();
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
- assertEquals(BigInteger.ONE, NetworkUtils.routedIPv6AddressCount(set));
-
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad5/128"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad6/128"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad7/128"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad8/128"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad9/128"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad0/128"));
- assertEquals(BigInteger.valueOf(7), NetworkUtils.routedIPv6AddressCount(set));
-
- // add4:f00:80:f7:1111::6ad4/126 eats add4:f00:8[:f7:1111::6ad{4-7}/128
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/126"));
- set.add(new IpPrefix("d00d:f00:80:f7:1111::6ade/124"));
- set.add(new IpPrefix("f00b:a33::/112"));
- assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536),
- NetworkUtils.routedIPv6AddressCount(set));
- }
-
- private static void expectSocketSuccess(String msg, int domain, int type) {
- try {
- IoUtils.closeQuietly(Os.socket(domain, type, 0));
- } catch (ErrnoException e) {
- fail(msg + e.getMessage());
- }
- }
-
- private static void expectSocketPemissionError(String msg, int domain, int type) {
- try {
- IoUtils.closeQuietly(Os.socket(domain, type, 0));
- fail(msg);
- } catch (ErrnoException e) {
- assertEquals(msg, e.errno, EPERM);
- }
- }
-
- private static void expectHasNetworking() {
- expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
- AF_UNIX, SOCK_STREAM);
- expectSocketSuccess("Creating a AF_INET socket shouldn't have thrown ErrnoException",
- AF_INET, SOCK_DGRAM);
- expectSocketSuccess("Creating a AF_INET6 socket shouldn't have thrown ErrnoException",
- AF_INET6, SOCK_DGRAM);
- }
-
- private static void expectNoNetworking() {
- expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
- AF_UNIX, SOCK_STREAM);
- expectSocketPemissionError(
- "Creating a AF_INET socket should have thrown ErrnoException(EPERM)",
- AF_INET, SOCK_DGRAM);
- expectSocketPemissionError(
- "Creating a AF_INET6 socket should have thrown ErrnoException(EPERM)",
- AF_INET6, SOCK_DGRAM);
- }
-
- @Test
- public void testSetAllowNetworkingForProcess() {
- expectHasNetworking();
- NetworkUtils.setAllowNetworkingForProcess(false);
- expectNoNetworking();
- NetworkUtils.setAllowNetworkingForProcess(true);
- expectHasNetworking();
- }
-}
diff --git a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
deleted file mode 100644
index cea8c5713a6b..000000000000
--- a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-
-@RunWith(JUnit4.class)
-public final class TcpKeepalivePacketDataTest {
- private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 1};
- private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 5};
-
- @Before
- public void setUp() {}
-
- @Test
- public void testV4TcpKeepalivePacket() throws Exception {
- final int srcPort = 1234;
- final int dstPort = 4321;
- final int seq = 0x11111111;
- final int ack = 0x22222222;
- final int wnd = 8000;
- final int wndScale = 2;
- final int tos = 4;
- final int ttl = 64;
- TcpKeepalivePacketData resultData = null;
- final TcpKeepalivePacketDataParcelable testInfo = new TcpKeepalivePacketDataParcelable();
- testInfo.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
- testInfo.srcPort = srcPort;
- testInfo.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
- testInfo.dstPort = dstPort;
- testInfo.seq = seq;
- testInfo.ack = ack;
- testInfo.rcvWnd = wnd;
- testInfo.rcvWndScale = wndScale;
- testInfo.tos = tos;
- testInfo.ttl = ttl;
- try {
- resultData = TcpKeepalivePacketData.tcpKeepalivePacket(testInfo);
- } catch (InvalidPacketException e) {
- fail("InvalidPacketException: " + e);
- }
-
- assertEquals(InetAddress.getByAddress(testInfo.srcAddress), resultData.getSrcAddress());
- assertEquals(InetAddress.getByAddress(testInfo.dstAddress), resultData.getDstAddress());
- assertEquals(testInfo.srcPort, resultData.getSrcPort());
- assertEquals(testInfo.dstPort, resultData.getDstPort());
- assertEquals(testInfo.seq, resultData.tcpSeq);
- assertEquals(testInfo.ack, resultData.tcpAck);
- assertEquals(testInfo.rcvWnd, resultData.tcpWnd);
- assertEquals(testInfo.rcvWndScale, resultData.tcpWndScale);
- assertEquals(testInfo.tos, resultData.ipTos);
- assertEquals(testInfo.ttl, resultData.ipTtl);
-
- assertParcelingIsLossless(resultData);
-
- final byte[] packet = resultData.getPacket();
- // IP version and IHL
- assertEquals(packet[0], 0x45);
- // TOS
- assertEquals(packet[1], tos);
- // TTL
- assertEquals(packet[8], ttl);
- // Source IP address.
- byte[] ip = new byte[4];
- ByteBuffer buf = ByteBuffer.wrap(packet, 12, 4);
- buf.get(ip);
- assertArrayEquals(ip, IPV4_KEEPALIVE_SRC_ADDR);
- // Destination IP address.
- buf = ByteBuffer.wrap(packet, 16, 4);
- buf.get(ip);
- assertArrayEquals(ip, IPV4_KEEPALIVE_DST_ADDR);
-
- buf = ByteBuffer.wrap(packet, 20, 12);
- // Source port.
- assertEquals(buf.getShort(), srcPort);
- // Destination port.
- assertEquals(buf.getShort(), dstPort);
- // Sequence number.
- assertEquals(buf.getInt(), seq);
- // Ack.
- assertEquals(buf.getInt(), ack);
- // Window size.
- buf = ByteBuffer.wrap(packet, 34, 2);
- assertEquals(buf.getShort(), wnd >> wndScale);
- }
-
- //TODO: add ipv6 test when ipv6 supported
-
- @Test
- public void testParcel() throws Exception {
- final int srcPort = 1234;
- final int dstPort = 4321;
- final int sequence = 0x11111111;
- final int ack = 0x22222222;
- final int wnd = 48_000;
- final int wndScale = 2;
- final int tos = 4;
- final int ttl = 64;
- final TcpKeepalivePacketDataParcelable testInfo = new TcpKeepalivePacketDataParcelable();
- testInfo.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
- testInfo.srcPort = srcPort;
- testInfo.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
- testInfo.dstPort = dstPort;
- testInfo.seq = sequence;
- testInfo.ack = ack;
- testInfo.rcvWnd = wnd;
- testInfo.rcvWndScale = wndScale;
- testInfo.tos = tos;
- testInfo.ttl = ttl;
- TcpKeepalivePacketData testData = null;
- TcpKeepalivePacketDataParcelable resultData = null;
- testData = TcpKeepalivePacketData.tcpKeepalivePacket(testInfo);
- resultData = testData.toStableParcelable();
- assertArrayEquals(resultData.srcAddress, IPV4_KEEPALIVE_SRC_ADDR);
- assertArrayEquals(resultData.dstAddress, IPV4_KEEPALIVE_DST_ADDR);
- assertEquals(resultData.srcPort, srcPort);
- assertEquals(resultData.dstPort, dstPort);
- assertEquals(resultData.seq, sequence);
- assertEquals(resultData.ack, ack);
- assertEquals(resultData.rcvWnd, wnd);
- assertEquals(resultData.rcvWndScale, wndScale);
- assertEquals(resultData.tos, tos);
- assertEquals(resultData.ttl, ttl);
- }
-}
diff --git a/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java b/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java
deleted file mode 100644
index efb92033df1e..000000000000
--- a/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.net.wifi.WifiNetworkSpecifier;
-import android.telephony.SubscriptionManager;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-
-/**
- * Unit test for {@link android.net.TelephonyNetworkSpecifier}.
- */
-@SmallTest
-public class TelephonyNetworkSpecifierTest {
- private static final int TEST_SUBID = 5;
- private static final String TEST_SSID = "Test123";
-
- /**
- * Validate that IllegalArgumentException will be thrown if build TelephonyNetworkSpecifier
- * without calling {@link TelephonyNetworkSpecifier.Builder#setSubscriptionId(int)}.
- */
- @Test
- public void testBuilderBuildWithDefault() {
- try {
- new TelephonyNetworkSpecifier.Builder().build();
- } catch (IllegalArgumentException iae) {
- // expected, test pass
- }
- }
-
- /**
- * Validate that no exception will be thrown even if pass invalid subscription id to
- * {@link TelephonyNetworkSpecifier.Builder#setSubscriptionId(int)}.
- */
- @Test
- public void testBuilderBuildWithInvalidSubId() {
- TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
- .setSubscriptionId(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
- .build();
- assertEquals(specifier.getSubscriptionId(), SubscriptionManager.INVALID_SUBSCRIPTION_ID);
- }
-
- /**
- * Validate the correctness of TelephonyNetworkSpecifier when provide valid subId.
- */
- @Test
- public void testBuilderBuildWithValidSubId() {
- final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
- .setSubscriptionId(TEST_SUBID)
- .build();
- assertEquals(TEST_SUBID, specifier.getSubscriptionId());
- }
-
- /**
- * Validate that parcel marshalling/unmarshalling works.
- */
- @Test
- public void testParcel() {
- TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
- .setSubscriptionId(TEST_SUBID)
- .build();
- assertParcelSane(specifier, 1 /* fieldCount */);
- }
-
- /**
- * Validate the behavior of method canBeSatisfiedBy().
- */
- @Test
- public void testCanBeSatisfiedBy() {
- final TelephonyNetworkSpecifier tns1 = new TelephonyNetworkSpecifier.Builder()
- .setSubscriptionId(TEST_SUBID)
- .build();
- final TelephonyNetworkSpecifier tns2 = new TelephonyNetworkSpecifier.Builder()
- .setSubscriptionId(TEST_SUBID)
- .build();
- final WifiNetworkSpecifier wns = new WifiNetworkSpecifier.Builder()
- .setSsid(TEST_SSID)
- .build();
- final MatchAllNetworkSpecifier mans = new MatchAllNetworkSpecifier();
-
- // Test equality
- assertEquals(tns1, tns2);
- assertTrue(tns1.canBeSatisfiedBy(tns1));
- assertTrue(tns1.canBeSatisfiedBy(tns2));
-
- // Test other edge cases.
- assertFalse(tns1.canBeSatisfiedBy(null));
- assertFalse(tns1.canBeSatisfiedBy(wns));
- assertTrue(tns1.canBeSatisfiedBy(mans));
- }
-}
diff --git a/tests/net/java/android/net/UidRangeTest.java b/tests/net/java/android/net/UidRangeTest.java
deleted file mode 100644
index ea1df096e208..000000000000
--- a/tests/net/java/android/net/UidRangeTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static org.junit.Assert.fail;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class UidRangeTest {
-
- /*
- * UidRange is no longer passed to netd. UID ranges between the framework and netd are passed as
- * UidRangeParcel objects.
- */
-
- @Test
- public void testSingleItemUidRangeAllowed() {
- new UidRange(123, 123);
- new UidRange(0, 0);
- new UidRange(Integer.MAX_VALUE, Integer.MAX_VALUE);
- }
-
- @Test
- public void testNegativeUidsDisallowed() {
- try {
- new UidRange(-2, 100);
- fail("Exception not thrown for negative start UID");
- } catch (IllegalArgumentException expected) {
- }
-
- try {
- new UidRange(-200, -100);
- fail("Exception not thrown for negative stop UID");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testStopLessThanStartDisallowed() {
- final int x = 4195000;
- try {
- new UidRange(x, x - 1);
- fail("Exception not thrown for negative-length UID range");
- } catch (IllegalArgumentException expected) {
- }
- }
-} \ No newline at end of file
diff --git a/tests/net/java/android/net/VpnManagerTest.java b/tests/net/java/android/net/VpnManagerTest.java
deleted file mode 100644
index 95a794235a2e..000000000000
--- a/tests/net/java/android/net/VpnManagerTest.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.test.mock.MockContext;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.net.VpnProfile;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Unit tests for {@link VpnManager}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class VpnManagerTest {
- private static final String PKG_NAME = "fooPackage";
-
- private static final String SESSION_NAME_STRING = "testSession";
- private static final String SERVER_ADDR_STRING = "1.2.3.4";
- private static final String IDENTITY_STRING = "Identity";
- private static final byte[] PSK_BYTES = "preSharedKey".getBytes();
-
- private IConnectivityManager mMockCs;
- private VpnManager mVpnManager;
- private final MockContext mMockContext =
- new MockContext() {
- @Override
- public String getOpPackageName() {
- return PKG_NAME;
- }
- };
-
- @Before
- public void setUp() throws Exception {
- mMockCs = mock(IConnectivityManager.class);
- mVpnManager = new VpnManager(mMockContext, mMockCs);
- }
-
- @Test
- public void testProvisionVpnProfilePreconsented() throws Exception {
- final PlatformVpnProfile profile = getPlatformVpnProfile();
- when(mMockCs.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME))).thenReturn(true);
-
- // Expect there to be no intent returned, as consent has already been granted.
- assertNull(mVpnManager.provisionVpnProfile(profile));
- verify(mMockCs).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
- }
-
- @Test
- public void testProvisionVpnProfileNeedsConsent() throws Exception {
- final PlatformVpnProfile profile = getPlatformVpnProfile();
- when(mMockCs.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME))).thenReturn(false);
-
- // Expect intent to be returned, as consent has not already been granted.
- final Intent intent = mVpnManager.provisionVpnProfile(profile);
- assertNotNull(intent);
-
- final ComponentName expectedComponentName =
- ComponentName.unflattenFromString(
- "com.android.vpndialogs/com.android.vpndialogs.PlatformVpnConfirmDialog");
- assertEquals(expectedComponentName, intent.getComponent());
- verify(mMockCs).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
- }
-
- @Test
- public void testDeleteProvisionedVpnProfile() throws Exception {
- mVpnManager.deleteProvisionedVpnProfile();
- verify(mMockCs).deleteVpnProfile(eq(PKG_NAME));
- }
-
- @Test
- public void testStartProvisionedVpnProfile() throws Exception {
- mVpnManager.startProvisionedVpnProfile();
- verify(mMockCs).startVpnProfile(eq(PKG_NAME));
- }
-
- @Test
- public void testStopProvisionedVpnProfile() throws Exception {
- mVpnManager.stopProvisionedVpnProfile();
- verify(mMockCs).stopVpnProfile(eq(PKG_NAME));
- }
-
- private Ikev2VpnProfile getPlatformVpnProfile() throws Exception {
- return new Ikev2VpnProfile.Builder(SERVER_ADDR_STRING, IDENTITY_STRING)
- .setBypassable(true)
- .setMaxMtu(1300)
- .setMetered(true)
- .setAuthPsk(PSK_BYTES)
- .build();
- }
-}
diff --git a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
deleted file mode 100644
index 02f5286506a8..000000000000
--- a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ipmemorystore;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.lang.reflect.Modifier;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.util.Arrays;
-import java.util.Collections;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ParcelableTests {
- @Test
- public void testNetworkAttributesParceling() throws Exception {
- final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
- NetworkAttributes in = builder.build();
- assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
-
- builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
- // lease will expire in two hours
- builder.setAssignedV4AddressExpiry(System.currentTimeMillis() + 7_200_000);
- // groupHint stays null this time around
- builder.setDnsAddresses(Collections.emptyList());
- builder.setMtu(18);
- in = builder.build();
- assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
-
- builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("6.7.8.9"));
- builder.setAssignedV4AddressExpiry(System.currentTimeMillis() + 3_600_000);
- builder.setCluster("groupHint");
- builder.setDnsAddresses(Arrays.asList(
- InetAddress.getByName("ACA1:652B:0911:DE8F:1200:115E:913B:AA2A"),
- InetAddress.getByName("6.7.8.9")));
- builder.setMtu(1_000_000);
- in = builder.build();
- assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
-
- builder.setMtu(null);
- in = builder.build();
- assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
-
- // Verify that this test does not miss any new field added later.
- // If any field is added to NetworkAttributes it must be tested here for parceling
- // roundtrip.
- assertEquals(5, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
- .filter(f -> !Modifier.isStatic(f.getModifiers())).count());
- }
-
- @Test
- public void testPrivateDataParceling() throws Exception {
- final Blob in = new Blob();
- in.data = new byte[] {89, 111, 108, 111};
- final Blob out = parcelingRoundTrip(in);
- // Object.equals on byte[] tests the references
- assertEquals(in.data.length, out.data.length);
- assertTrue(Arrays.equals(in.data, out.data));
- }
-
- @Test
- public void testSameL3NetworkResponseParceling() throws Exception {
- final SameL3NetworkResponseParcelable parcelable = new SameL3NetworkResponseParcelable();
- parcelable.l2Key1 = "key 1";
- parcelable.l2Key2 = "key 2";
- parcelable.confidence = 0.43f;
-
- final SameL3NetworkResponse in = new SameL3NetworkResponse(parcelable);
- assertEquals("key 1", in.l2Key1);
- assertEquals("key 2", in.l2Key2);
- assertEquals(0.43f, in.confidence, 0.01f /* delta */);
-
- final SameL3NetworkResponse out =
- new SameL3NetworkResponse(parcelingRoundTrip(in.toParcelable()));
-
- assertEquals(in, out);
- assertEquals(in.l2Key1, out.l2Key1);
- assertEquals(in.l2Key2, out.l2Key2);
- assertEquals(in.confidence, out.confidence, 0.01f /* delta */);
- }
-
- private <T extends Parcelable> T parcelingRoundTrip(final T in) throws Exception {
- final Parcel p = Parcel.obtain();
- in.writeToParcel(p, /* flags */ 0);
- p.setDataPosition(0);
- final byte[] marshalledData = p.marshall();
- p.recycle();
-
- final Parcel q = Parcel.obtain();
- q.unmarshall(marshalledData, 0, marshalledData.length);
- q.setDataPosition(0);
-
- final Parcelable.Creator<T> creator = (Parcelable.Creator<T>)
- in.getClass().getField("CREATOR").get(null); // static object, so null receiver
- final T unmarshalled = (T) creator.createFromParcel(q);
- q.recycle();
- return unmarshalled;
- }
-}
diff --git a/tests/net/java/android/net/nsd/NsdManagerTest.java b/tests/net/java/android/net/nsd/NsdManagerTest.java
deleted file mode 100644
index cf7587a2039f..000000000000
--- a/tests/net/java/android/net/nsd/NsdManagerTest.java
+++ /dev/null
@@ -1,388 +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 android.net.nsd;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.AsyncChannel;
-import com.android.testutils.HandlerUtilsKt;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NsdManagerTest {
-
- static final int PROTOCOL = NsdManager.PROTOCOL_DNS_SD;
-
- @Mock Context mContext;
- @Mock INsdManager mService;
- MockServiceHandler mServiceHandler;
-
- NsdManager mManager;
-
- long mTimeoutMs = 200; // non-final so that tests can adjust the value.
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- mServiceHandler = spy(MockServiceHandler.create(mContext));
- when(mService.getMessenger()).thenReturn(new Messenger(mServiceHandler));
-
- mManager = makeManager();
- }
-
- @After
- public void tearDown() throws Exception {
- HandlerUtilsKt.waitForIdle(mServiceHandler, mTimeoutMs);
- mServiceHandler.chan.disconnect();
- mServiceHandler.stop();
- if (mManager != null) {
- mManager.disconnect();
- }
- }
-
- @Test
- public void testResolveService() {
- NsdManager manager = mManager;
-
- NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
- NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
- NsdManager.ResolveListener listener = mock(NsdManager.ResolveListener.class);
-
- manager.resolveService(request, listener);
- int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
- int err = 33;
- sendResponse(NsdManager.RESOLVE_SERVICE_FAILED, err, key1, null);
- verify(listener, timeout(mTimeoutMs).times(1)).onResolveFailed(request, err);
-
- manager.resolveService(request, listener);
- int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
- sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
- verify(listener, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
- }
-
- @Test
- public void testParallelResolveService() {
- NsdManager manager = mManager;
-
- NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
- NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
-
- NsdManager.ResolveListener listener1 = mock(NsdManager.ResolveListener.class);
- NsdManager.ResolveListener listener2 = mock(NsdManager.ResolveListener.class);
-
- manager.resolveService(request, listener1);
- int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
-
- manager.resolveService(request, listener2);
- int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
-
- sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
- sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key1, reply);
-
- verify(listener1, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
- verify(listener2, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
- }
-
- @Test
- public void testRegisterService() {
- NsdManager manager = mManager;
-
- NsdServiceInfo request1 = new NsdServiceInfo("a_name", "a_type");
- NsdServiceInfo request2 = new NsdServiceInfo("another_name", "another_type");
- request1.setPort(2201);
- request2.setPort(2202);
- NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
- NsdManager.RegistrationListener listener2 = mock(NsdManager.RegistrationListener.class);
-
- // Register two services
- manager.registerService(request1, PROTOCOL, listener1);
- int key1 = verifyRequest(NsdManager.REGISTER_SERVICE);
-
- manager.registerService(request2, PROTOCOL, listener2);
- int key2 = verifyRequest(NsdManager.REGISTER_SERVICE);
-
- // First reques fails, second request succeeds
- sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key2, request2);
- verify(listener2, timeout(mTimeoutMs).times(1)).onServiceRegistered(request2);
-
- int err = 1;
- sendResponse(NsdManager.REGISTER_SERVICE_FAILED, err, key1, request1);
- verify(listener1, timeout(mTimeoutMs).times(1)).onRegistrationFailed(request1, err);
-
- // Client retries first request, it succeeds
- manager.registerService(request1, PROTOCOL, listener1);
- int key3 = verifyRequest(NsdManager.REGISTER_SERVICE);
-
- sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key3, request1);
- verify(listener1, timeout(mTimeoutMs).times(1)).onServiceRegistered(request1);
-
- // First request is unregistered, it succeeds
- manager.unregisterService(listener1);
- int key3again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
- assertEquals(key3, key3again);
-
- sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key3again, null);
- verify(listener1, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request1);
-
- // Second request is unregistered, it fails
- manager.unregisterService(listener2);
- int key2again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
- assertEquals(key2, key2again);
-
- sendResponse(NsdManager.UNREGISTER_SERVICE_FAILED, err, key2again, null);
- verify(listener2, timeout(mTimeoutMs).times(1)).onUnregistrationFailed(request2, err);
-
- // TODO: do not unregister listener until service is unregistered
- // Client retries unregistration of second request, it succeeds
- //manager.unregisterService(listener2);
- //int key2yetAgain = verifyRequest(NsdManager.UNREGISTER_SERVICE);
- //assertEquals(key2, key2yetAgain);
-
- //sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key2yetAgain, null);
- //verify(listener2, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request2);
- }
-
- @Test
- public void testDiscoverService() {
- NsdManager manager = mManager;
-
- NsdServiceInfo reply1 = new NsdServiceInfo("a_name", "a_type");
- NsdServiceInfo reply2 = new NsdServiceInfo("another_name", "a_type");
- NsdServiceInfo reply3 = new NsdServiceInfo("a_third_name", "a_type");
-
- NsdManager.DiscoveryListener listener = mock(NsdManager.DiscoveryListener.class);
-
- // Client registers for discovery, request fails
- manager.discoverServices("a_type", PROTOCOL, listener);
- int key1 = verifyRequest(NsdManager.DISCOVER_SERVICES);
-
- int err = 1;
- sendResponse(NsdManager.DISCOVER_SERVICES_FAILED, err, key1, null);
- verify(listener, timeout(mTimeoutMs).times(1)).onStartDiscoveryFailed("a_type", err);
-
- // Client retries, request succeeds
- manager.discoverServices("a_type", PROTOCOL, listener);
- int key2 = verifyRequest(NsdManager.DISCOVER_SERVICES);
-
- sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key2, reply1);
- verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
-
-
- // mdns notifies about services
- sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply1);
- verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply1);
-
- sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply2);
- verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply2);
-
- sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply2);
- verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply2);
-
-
- // Client unregisters its listener
- manager.stopServiceDiscovery(listener);
- int key2again = verifyRequest(NsdManager.STOP_DISCOVERY);
- assertEquals(key2, key2again);
-
- // TODO: unregister listener immediately and stop notifying it about services
- // Notifications are still passed to the client's listener
- sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply1);
- verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply1);
-
- // Client is notified of complete unregistration
- sendResponse(NsdManager.STOP_DISCOVERY_SUCCEEDED, 0, key2again, "a_type");
- verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStopped("a_type");
-
- // Notifications are not passed to the client anymore
- sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply3);
- verify(listener, timeout(mTimeoutMs).times(0)).onServiceLost(reply3);
-
-
- // Client registers for service discovery
- reset(listener);
- manager.discoverServices("a_type", PROTOCOL, listener);
- int key3 = verifyRequest(NsdManager.DISCOVER_SERVICES);
-
- sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key3, reply1);
- verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
-
- // Client unregisters immediately, it fails
- manager.stopServiceDiscovery(listener);
- int key3again = verifyRequest(NsdManager.STOP_DISCOVERY);
- assertEquals(key3, key3again);
-
- err = 2;
- sendResponse(NsdManager.STOP_DISCOVERY_FAILED, err, key3again, "a_type");
- verify(listener, timeout(mTimeoutMs).times(1)).onStopDiscoveryFailed("a_type", err);
-
- // New notifications are not passed to the client anymore
- sendResponse(NsdManager.SERVICE_FOUND, 0, key3, reply1);
- verify(listener, timeout(mTimeoutMs).times(0)).onServiceFound(reply1);
- }
-
- @Test
- public void testInvalidCalls() {
- NsdManager manager = mManager;
-
- NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
- NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
- NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
-
- NsdServiceInfo invalidService = new NsdServiceInfo(null, null);
- NsdServiceInfo validService = new NsdServiceInfo("a_name", "a_type");
- validService.setPort(2222);
-
- // Service registration
- // - invalid arguments
- mustFail(() -> { manager.unregisterService(null); });
- mustFail(() -> { manager.registerService(null, -1, null); });
- mustFail(() -> { manager.registerService(null, PROTOCOL, listener1); });
- mustFail(() -> { manager.registerService(invalidService, PROTOCOL, listener1); });
- mustFail(() -> { manager.registerService(validService, -1, listener1); });
- mustFail(() -> { manager.registerService(validService, PROTOCOL, null); });
- manager.registerService(validService, PROTOCOL, listener1);
- // - listener already registered
- mustFail(() -> { manager.registerService(validService, PROTOCOL, listener1); });
- manager.unregisterService(listener1);
- // TODO: make listener immediately reusable
- //mustFail(() -> { manager.unregisterService(listener1); });
- //manager.registerService(validService, PROTOCOL, listener1);
-
- // Discover service
- // - invalid arguments
- mustFail(() -> { manager.stopServiceDiscovery(null); });
- mustFail(() -> { manager.discoverServices(null, -1, null); });
- mustFail(() -> { manager.discoverServices(null, PROTOCOL, listener2); });
- mustFail(() -> { manager.discoverServices("a_service", -1, listener2); });
- mustFail(() -> { manager.discoverServices("a_service", PROTOCOL, null); });
- manager.discoverServices("a_service", PROTOCOL, listener2);
- // - listener already registered
- mustFail(() -> { manager.discoverServices("another_service", PROTOCOL, listener2); });
- manager.stopServiceDiscovery(listener2);
- // TODO: make listener immediately reusable
- //mustFail(() -> { manager.stopServiceDiscovery(listener2); });
- //manager.discoverServices("another_service", PROTOCOL, listener2);
-
- // Resolver service
- // - invalid arguments
- mustFail(() -> { manager.resolveService(null, null); });
- mustFail(() -> { manager.resolveService(null, listener3); });
- mustFail(() -> { manager.resolveService(invalidService, listener3); });
- mustFail(() -> { manager.resolveService(validService, null); });
- manager.resolveService(validService, listener3);
- // - listener already registered:w
- mustFail(() -> { manager.resolveService(validService, listener3); });
- }
-
- public void mustFail(Runnable fn) {
- try {
- fn.run();
- fail();
- } catch (Exception expected) {
- }
- }
-
- NsdManager makeManager() {
- NsdManager manager = new NsdManager(mContext, mService);
- // Acknowledge first two messages connecting the AsyncChannel.
- verify(mServiceHandler, timeout(mTimeoutMs).times(2)).handleMessage(any());
- reset(mServiceHandler);
- assertNotNull(mServiceHandler.chan);
- return manager;
- }
-
- int verifyRequest(int expectedMessageType) {
- HandlerUtilsKt.waitForIdle(mServiceHandler, mTimeoutMs);
- verify(mServiceHandler, timeout(mTimeoutMs)).handleMessage(any());
- reset(mServiceHandler);
- Message received = mServiceHandler.getLastMessage();
- assertEquals(NsdManager.nameOf(expectedMessageType), NsdManager.nameOf(received.what));
- return received.arg2;
- }
-
- void sendResponse(int replyType, int arg, int key, Object obj) {
- mServiceHandler.chan.sendMessage(replyType, arg, key, obj);
- }
-
- // Implements the server side of AsyncChannel connection protocol
- public static class MockServiceHandler extends Handler {
- public final Context context;
- public AsyncChannel chan;
- public Message lastMessage;
-
- MockServiceHandler(Looper l, Context c) {
- super(l);
- context = c;
- }
-
- synchronized Message getLastMessage() {
- return lastMessage;
- }
-
- synchronized void setLastMessage(Message msg) {
- lastMessage = obtainMessage();
- lastMessage.copyFrom(msg);
- }
-
- @Override
- public void handleMessage(Message msg) {
- setLastMessage(msg);
- if (msg.what == AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) {
- chan = new AsyncChannel();
- chan.connect(context, this, msg.replyTo);
- chan.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
- }
- }
-
- void stop() {
- getLooper().quitSafely();
- }
-
- static MockServiceHandler create(Context context) {
- HandlerThread t = new HandlerThread("mock-service-handler");
- t.start();
- return new MockServiceHandler(t.getLooper(), context);
- }
- }
-}
diff --git a/tests/net/java/android/net/nsd/NsdServiceInfoTest.java b/tests/net/java/android/net/nsd/NsdServiceInfoTest.java
deleted file mode 100644
index 94dfc7515c67..000000000000
--- a/tests/net/java/android/net/nsd/NsdServiceInfoTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.nsd;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.StrictMode;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.Map;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NsdServiceInfoTest {
-
- public final static InetAddress LOCALHOST;
- static {
- // Because test.
- StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
- StrictMode.setThreadPolicy(policy);
-
- InetAddress _host = null;
- try {
- _host = InetAddress.getLocalHost();
- } catch (UnknownHostException e) { }
- LOCALHOST = _host;
- }
-
- @Test
- public void testLimits() throws Exception {
- NsdServiceInfo info = new NsdServiceInfo();
-
- // Non-ASCII keys.
- boolean exceptionThrown = false;
- try {
- info.setAttribute("猫", "meow");
- } catch (IllegalArgumentException e) {
- exceptionThrown = true;
- }
- assertTrue(exceptionThrown);
- assertEmptyServiceInfo(info);
-
- // ASCII keys with '=' character.
- exceptionThrown = false;
- try {
- info.setAttribute("kitten=", "meow");
- } catch (IllegalArgumentException e) {
- exceptionThrown = true;
- }
- assertTrue(exceptionThrown);
- assertEmptyServiceInfo(info);
-
- // Single key + value length too long.
- exceptionThrown = false;
- try {
- String longValue = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
- "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
- "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
- "ooooooooooooooooooooooooooooong"; // 248 characters.
- info.setAttribute("longcat", longValue); // Key + value == 255 characters.
- } catch (IllegalArgumentException e) {
- exceptionThrown = true;
- }
- assertTrue(exceptionThrown);
- assertEmptyServiceInfo(info);
-
- // Total TXT record length too long.
- exceptionThrown = false;
- int recordsAdded = 0;
- try {
- for (int i = 100; i < 300; ++i) {
- // 6 char key + 5 char value + 2 bytes overhead = 13 byte record length.
- String key = String.format("key%d", i);
- info.setAttribute(key, "12345");
- recordsAdded++;
- }
- } catch (IllegalArgumentException e) {
- exceptionThrown = true;
- }
- assertTrue(exceptionThrown);
- assertTrue(100 == recordsAdded);
- assertTrue(info.getTxtRecord().length == 1300);
- }
-
- @Test
- public void testParcel() throws Exception {
- NsdServiceInfo emptyInfo = new NsdServiceInfo();
- checkParcelable(emptyInfo);
-
- NsdServiceInfo fullInfo = new NsdServiceInfo();
- fullInfo.setServiceName("kitten");
- fullInfo.setServiceType("_kitten._tcp");
- fullInfo.setPort(4242);
- fullInfo.setHost(LOCALHOST);
- checkParcelable(fullInfo);
-
- NsdServiceInfo noHostInfo = new NsdServiceInfo();
- noHostInfo.setServiceName("kitten");
- noHostInfo.setServiceType("_kitten._tcp");
- noHostInfo.setPort(4242);
- checkParcelable(noHostInfo);
-
- NsdServiceInfo attributedInfo = new NsdServiceInfo();
- attributedInfo.setServiceName("kitten");
- attributedInfo.setServiceType("_kitten._tcp");
- attributedInfo.setPort(4242);
- attributedInfo.setHost(LOCALHOST);
- attributedInfo.setAttribute("color", "pink");
- attributedInfo.setAttribute("sound", (new String("にゃあ")).getBytes("UTF-8"));
- attributedInfo.setAttribute("adorable", (String) null);
- attributedInfo.setAttribute("sticky", "yes");
- attributedInfo.setAttribute("siblings", new byte[] {});
- attributedInfo.setAttribute("edge cases", new byte[] {0, -1, 127, -128});
- attributedInfo.removeAttribute("sticky");
- checkParcelable(attributedInfo);
-
- // Sanity check that we actually wrote attributes to attributedInfo.
- assertTrue(attributedInfo.getAttributes().keySet().contains("adorable"));
- String sound = new String(attributedInfo.getAttributes().get("sound"), "UTF-8");
- assertTrue(sound.equals("にゃあ"));
- byte[] edgeCases = attributedInfo.getAttributes().get("edge cases");
- assertTrue(Arrays.equals(edgeCases, new byte[] {0, -1, 127, -128}));
- assertFalse(attributedInfo.getAttributes().keySet().contains("sticky"));
- }
-
- public void checkParcelable(NsdServiceInfo original) {
- // Write to parcel.
- Parcel p = Parcel.obtain();
- Bundle writer = new Bundle();
- writer.putParcelable("test_info", original);
- writer.writeToParcel(p, 0);
-
- // Extract from parcel.
- p.setDataPosition(0);
- Bundle reader = p.readBundle();
- reader.setClassLoader(NsdServiceInfo.class.getClassLoader());
- NsdServiceInfo result = reader.getParcelable("test_info");
-
- // Assert equality of base fields.
- assertEquals(original.getServiceName(), result.getServiceName());
- assertEquals(original.getServiceType(), result.getServiceType());
- assertEquals(original.getHost(), result.getHost());
- assertTrue(original.getPort() == result.getPort());
-
- // Assert equality of attribute map.
- Map<String, byte[]> originalMap = original.getAttributes();
- Map<String, byte[]> resultMap = result.getAttributes();
- assertEquals(originalMap.keySet(), resultMap.keySet());
- for (String key : originalMap.keySet()) {
- assertTrue(Arrays.equals(originalMap.get(key), resultMap.get(key)));
- }
- }
-
- public void assertEmptyServiceInfo(NsdServiceInfo shouldBeEmpty) {
- byte[] txtRecord = shouldBeEmpty.getTxtRecord();
- if (txtRecord == null || txtRecord.length == 0) {
- return;
- }
- fail("NsdServiceInfo.getTxtRecord did not return null but " + Arrays.toString(txtRecord));
- }
-}
diff --git a/tests/net/java/android/net/util/DnsUtilsTest.java b/tests/net/java/android/net/util/DnsUtilsTest.java
deleted file mode 100644
index b626db8d89e4..000000000000
--- a/tests/net/java/android/net/util/DnsUtilsTest.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.util;
-
-import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_GLOBAL;
-import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_LINKLOCAL;
-import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_SITELOCAL;
-
-import static org.junit.Assert.assertEquals;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.InetAddresses;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DnsUtilsTest {
- private InetAddress stringToAddress(@NonNull String addr) {
- return InetAddresses.parseNumericAddress(addr);
- }
-
- private DnsUtils.SortableAddress makeSortableAddress(@NonNull String addr) {
- return makeSortableAddress(addr, null);
- }
-
- private DnsUtils.SortableAddress makeSortableAddress(@NonNull String addr,
- @Nullable String srcAddr) {
- return new DnsUtils.SortableAddress(stringToAddress(addr),
- srcAddr != null ? stringToAddress(srcAddr) : null);
- }
-
- @Test
- public void testRfc6724Comparator() {
- final List<DnsUtils.SortableAddress> test = Arrays.asList(
- // Ipv4
- makeSortableAddress("216.58.200.36", "192.168.1.1"),
- // global with different scope src
- makeSortableAddress("2404:6800:4008:801::2004", "fe80::1111:2222"),
- // global without src addr
- makeSortableAddress("2404:6800:cafe:801::1"),
- // loop back
- makeSortableAddress("::1", "::1"),
- // link local
- makeSortableAddress("fe80::c46f:1cff:fe04:39b4", "fe80::1"),
- // teredo tunneling
- makeSortableAddress("2001::47c1", "2001::2"),
- // 6bone without src addr
- makeSortableAddress("3ffe::1234:5678"),
- // IPv4-compatible
- makeSortableAddress("::216.58.200.36", "::216.58.200.9"),
- // 6bone
- makeSortableAddress("3ffe::1234:5678", "3ffe::1234:1"),
- // IPv4-mapped IPv6
- makeSortableAddress("::ffff:192.168.95.7", "::ffff:192.168.95.1"));
-
- final List<InetAddress> expected = Arrays.asList(
- stringToAddress("::1"), // loop back
- stringToAddress("fe80::c46f:1cff:fe04:39b4"), // link local
- stringToAddress("216.58.200.36"), // Ipv4
- stringToAddress("::ffff:192.168.95.7"), // IPv4-mapped IPv6
- stringToAddress("2001::47c1"), // teredo tunneling
- stringToAddress("::216.58.200.36"), // IPv4-compatible
- stringToAddress("3ffe::1234:5678"), // 6bone
- stringToAddress("2404:6800:4008:801::2004"), // global with different scope src
- stringToAddress("2404:6800:cafe:801::1"), // global without src addr
- stringToAddress("3ffe::1234:5678")); // 6bone without src addr
-
- Collections.sort(test, new DnsUtils.Rfc6724Comparator());
-
- for (int i = 0; i < test.size(); ++i) {
- assertEquals(test.get(i).address, expected.get(i));
- }
-
- // TODO: add more combinations
- }
-
- @Test
- public void testV4SortableAddress() {
- // Test V4 address
- DnsUtils.SortableAddress test = makeSortableAddress("216.58.200.36");
- assertEquals(test.hasSrcAddr, 0);
- assertEquals(test.prefixMatchLen, 0);
- assertEquals(test.address, stringToAddress("216.58.200.36"));
- assertEquals(test.labelMatch, 0);
- assertEquals(test.scopeMatch, 0);
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.label, 4);
- assertEquals(test.precedence, 35);
-
- // Test V4 loopback address with the same source address
- test = makeSortableAddress("127.1.2.3", "127.1.2.3");
- assertEquals(test.hasSrcAddr, 1);
- assertEquals(test.prefixMatchLen, 0);
- assertEquals(test.address, stringToAddress("127.1.2.3"));
- assertEquals(test.labelMatch, 1);
- assertEquals(test.scopeMatch, 1);
- assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
- assertEquals(test.label, 4);
- assertEquals(test.precedence, 35);
- }
-
- @Test
- public void testV6SortableAddress() {
- // Test global address
- DnsUtils.SortableAddress test = makeSortableAddress("2404:6800:4008:801::2004");
- assertEquals(test.address, stringToAddress("2404:6800:4008:801::2004"));
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.label, 1);
- assertEquals(test.precedence, 40);
-
- // Test global address with global source address
- test = makeSortableAddress("2404:6800:4008:801::2004",
- "2401:fa00:fc:fd00:6d6c:7199:b8e7:41d6");
- assertEquals(test.address, stringToAddress("2404:6800:4008:801::2004"));
- assertEquals(test.hasSrcAddr, 1);
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.labelMatch, 1);
- assertEquals(test.scopeMatch, 1);
- assertEquals(test.label, 1);
- assertEquals(test.precedence, 40);
- assertEquals(test.prefixMatchLen, 13);
-
- // Test global address with linklocal source address
- test = makeSortableAddress("2404:6800:4008:801::2004", "fe80::c46f:1cff:fe04:39b4");
- assertEquals(test.hasSrcAddr, 1);
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.labelMatch, 1);
- assertEquals(test.scopeMatch, 0);
- assertEquals(test.label, 1);
- assertEquals(test.precedence, 40);
- assertEquals(test.prefixMatchLen, 0);
-
- // Test loopback address with the same source address
- test = makeSortableAddress("::1", "::1");
- assertEquals(test.hasSrcAddr, 1);
- assertEquals(test.prefixMatchLen, 16 * 8);
- assertEquals(test.labelMatch, 1);
- assertEquals(test.scopeMatch, 1);
- assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
- assertEquals(test.label, 0);
- assertEquals(test.precedence, 50);
-
- // Test linklocal address
- test = makeSortableAddress("fe80::c46f:1cff:fe04:39b4");
- assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
- assertEquals(test.label, 1);
- assertEquals(test.precedence, 40);
-
- // Test linklocal address
- test = makeSortableAddress("fe80::");
- assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
- assertEquals(test.label, 1);
- assertEquals(test.precedence, 40);
-
- // Test 6to4 address
- test = makeSortableAddress("2002:c000:0204::");
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.label, 2);
- assertEquals(test.precedence, 30);
-
- // Test unique local address
- test = makeSortableAddress("fc00::c000:13ab");
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.label, 13);
- assertEquals(test.precedence, 3);
-
- // Test teredo tunneling address
- test = makeSortableAddress("2001::47c1");
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.label, 5);
- assertEquals(test.precedence, 5);
-
- // Test IPv4-compatible addresses
- test = makeSortableAddress("::216.58.200.36");
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.label, 3);
- assertEquals(test.precedence, 1);
-
- // Test site-local address
- test = makeSortableAddress("fec0::cafe:3ab2");
- assertEquals(test.scope, IPV6_ADDR_SCOPE_SITELOCAL);
- assertEquals(test.label, 11);
- assertEquals(test.precedence, 1);
-
- // Test 6bone address
- test = makeSortableAddress("3ffe::1234:5678");
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.label, 12);
- assertEquals(test.precedence, 1);
- }
-}
diff --git a/tests/net/java/android/net/util/IpUtilsTest.java b/tests/net/java/android/net/util/IpUtilsTest.java
deleted file mode 100644
index 193d85d0013a..000000000000
--- a/tests/net/java/android/net/util/IpUtilsTest.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.util;
-
-import static org.junit.Assert.assertEquals;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.nio.ByteBuffer;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpUtilsTest {
-
- private static final int IPV4_HEADER_LENGTH = 20;
- private static final int IPV6_HEADER_LENGTH = 40;
- private static final int TCP_HEADER_LENGTH = 20;
- private static final int UDP_HEADER_LENGTH = 8;
- private static final int IP_CHECKSUM_OFFSET = 10;
- private static final int TCP_CHECKSUM_OFFSET = 16;
- private static final int UDP_CHECKSUM_OFFSET = 6;
-
- private int getUnsignedByte(ByteBuffer buf, int offset) {
- return buf.get(offset) & 0xff;
- }
-
- private int getChecksum(ByteBuffer buf, int offset) {
- return getUnsignedByte(buf, offset) * 256 + getUnsignedByte(buf, offset + 1);
- }
-
- private void assertChecksumEquals(int expected, short actual) {
- assertEquals(Integer.toHexString(expected), Integer.toHexString(actual & 0xffff));
- }
-
- // Generate test packets using Python code like this::
- //
- // from scapy import all as scapy
- //
- // def JavaPacketDefinition(bytes):
- // out = " ByteBuffer packet = ByteBuffer.wrap(new byte[] {\n "
- // for i in xrange(len(bytes)):
- // out += "(byte) 0x%02x" % ord(bytes[i])
- // if i < len(bytes) - 1:
- // if i % 4 == 3:
- // out += ",\n "
- // else:
- // out += ", "
- // out += "\n });"
- // return out
- //
- // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2") /
- // scapy.UDP(sport=12345, dport=7) /
- // "hello")
- // print JavaPacketDefinition(str(packet))
-
- @Test
- public void testIpv6TcpChecksum() throws Exception {
- // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80) /
- // scapy.TCP(sport=12345, dport=7,
- // seq=1692871236, ack=128376451, flags=16,
- // window=32768) /
- // "hello, world")
- ByteBuffer packet = ByteBuffer.wrap(new byte[] {
- (byte) 0x68, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x20, (byte) 0x06, (byte) 0x40,
- (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01,
- (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02,
- (byte) 0x30, (byte) 0x39, (byte) 0x00, (byte) 0x07,
- (byte) 0x64, (byte) 0xe7, (byte) 0x2a, (byte) 0x44,
- (byte) 0x07, (byte) 0xa6, (byte) 0xde, (byte) 0x83,
- (byte) 0x50, (byte) 0x10, (byte) 0x80, (byte) 0x00,
- (byte) 0xee, (byte) 0x71, (byte) 0x00, (byte) 0x00,
- (byte) 0x68, (byte) 0x65, (byte) 0x6c, (byte) 0x6c,
- (byte) 0x6f, (byte) 0x2c, (byte) 0x20, (byte) 0x77,
- (byte) 0x6f, (byte) 0x72, (byte) 0x6c, (byte) 0x64
- });
-
- // Check that a valid packet has checksum 0.
- int transportLen = packet.limit() - IPV6_HEADER_LENGTH;
- assertEquals(0, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen));
-
- // Check that we can calculate the checksum from scratch.
- int sumOffset = IPV6_HEADER_LENGTH + TCP_CHECKSUM_OFFSET;
- int sum = getUnsignedByte(packet, sumOffset) * 256 + getUnsignedByte(packet, sumOffset + 1);
- assertEquals(0xee71, sum);
-
- packet.put(sumOffset, (byte) 0);
- packet.put(sumOffset + 1, (byte) 0);
- assertChecksumEquals(sum, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen));
-
- // Check that writing the checksum back into the packet results in a valid packet.
- packet.putShort(
- sumOffset,
- IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen));
- assertEquals(0, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen));
- }
-
- @Test
- public void testIpv4UdpChecksum() {
- // packet = (scapy.IP(src="192.0.2.1", dst="192.0.2.2", tos=0x40) /
- // scapy.UDP(sport=32012, dport=4500) /
- // "\xff")
- ByteBuffer packet = ByteBuffer.wrap(new byte[] {
- (byte) 0x45, (byte) 0x40, (byte) 0x00, (byte) 0x1d,
- (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
- (byte) 0x40, (byte) 0x11, (byte) 0xf6, (byte) 0x8b,
- (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01,
- (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x02,
- (byte) 0x7d, (byte) 0x0c, (byte) 0x11, (byte) 0x94,
- (byte) 0x00, (byte) 0x09, (byte) 0xee, (byte) 0x36,
- (byte) 0xff
- });
-
- // Check that a valid packet has IP checksum 0 and UDP checksum 0xffff (0 is not a valid
- // UDP checksum, so the udpChecksum rewrites 0 to 0xffff).
- assertEquals(0, IpUtils.ipChecksum(packet, 0));
- assertEquals((short) 0xffff, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH));
-
- // Check that we can calculate the checksums from scratch.
- final int ipSumOffset = IP_CHECKSUM_OFFSET;
- final int ipSum = getChecksum(packet, ipSumOffset);
- assertEquals(0xf68b, ipSum);
-
- packet.put(ipSumOffset, (byte) 0);
- packet.put(ipSumOffset + 1, (byte) 0);
- assertChecksumEquals(ipSum, IpUtils.ipChecksum(packet, 0));
-
- final int udpSumOffset = IPV4_HEADER_LENGTH + UDP_CHECKSUM_OFFSET;
- final int udpSum = getChecksum(packet, udpSumOffset);
- assertEquals(0xee36, udpSum);
-
- packet.put(udpSumOffset, (byte) 0);
- packet.put(udpSumOffset + 1, (byte) 0);
- assertChecksumEquals(udpSum, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH));
-
- // Check that writing the checksums back into the packet results in a valid packet.
- packet.putShort(ipSumOffset, IpUtils.ipChecksum(packet, 0));
- packet.putShort(udpSumOffset, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH));
- assertEquals(0, IpUtils.ipChecksum(packet, 0));
- assertEquals((short) 0xffff, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH));
- }
-}
diff --git a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt b/tests/net/java/android/net/util/KeepaliveUtilsTest.kt
deleted file mode 100644
index 8ea226db938e..000000000000
--- a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.util
-
-import android.content.Context
-import android.content.res.Resources
-import android.net.NetworkCapabilities
-import android.net.NetworkCapabilities.MAX_TRANSPORT
-import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
-import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
-import android.net.NetworkCapabilities.TRANSPORT_VPN
-import android.net.NetworkCapabilities.TRANSPORT_WIFI
-import androidx.test.filters.SmallTest
-import com.android.internal.R
-import org.junit.Assert.assertArrayEquals
-import org.junit.Assert.assertEquals
-import org.junit.Assert.fail
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import org.mockito.ArgumentMatchers
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.mock
-
-/**
- * Tests for [KeepaliveUtils].
- *
- * Build, install and run with:
- * atest android.net.util.KeepaliveUtilsTest
- */
-@RunWith(JUnit4::class)
-@SmallTest
-class KeepaliveUtilsTest {
-
- // Prepare mocked context with given resource strings.
- private fun getMockedContextWithStringArrayRes(id: Int, res: Array<out String?>?): Context {
- val mockRes = mock(Resources::class.java)
- doReturn(res).`when`(mockRes).getStringArray(ArgumentMatchers.eq(id))
-
- return mock(Context::class.java).apply {
- doReturn(mockRes).`when`(this).getResources()
- }
- }
-
- @Test
- fun testGetSupportedKeepalives() {
- fun assertRunWithException(res: Array<out String?>?) {
- try {
- val mockContext = getMockedContextWithStringArrayRes(
- R.array.config_networkSupportedKeepaliveCount, res)
- KeepaliveUtils.getSupportedKeepalives(mockContext)
- fail("Expected KeepaliveDeviceConfigurationException")
- } catch (expected: KeepaliveUtils.KeepaliveDeviceConfigurationException) {
- }
- }
-
- // Check resource with various invalid format.
- assertRunWithException(null)
- assertRunWithException(arrayOf<String?>(null))
- assertRunWithException(arrayOfNulls<String?>(10))
- assertRunWithException(arrayOf(""))
- assertRunWithException(arrayOf("3,ABC"))
- assertRunWithException(arrayOf("6,3,3"))
- assertRunWithException(arrayOf("5"))
-
- // Check resource with invalid slots value.
- assertRunWithException(arrayOf("3,-1"))
-
- // Check resource with invalid transport type.
- assertRunWithException(arrayOf("-1,3"))
- assertRunWithException(arrayOf("10,3"))
-
- // Check valid customization generates expected array.
- val validRes = arrayOf("0,3", "1,0", "4,4")
- val expectedValidRes = intArrayOf(3, 0, 0, 0, 4, 0, 0, 0)
-
- val mockContext = getMockedContextWithStringArrayRes(
- R.array.config_networkSupportedKeepaliveCount, validRes)
- val actual = KeepaliveUtils.getSupportedKeepalives(mockContext)
- assertArrayEquals(expectedValidRes, actual)
- }
-
- @Test
- fun testGetSupportedKeepalivesForNetworkCapabilities() {
- // Mock customized supported keepalives for each transport type, and assuming:
- // 3 for cellular,
- // 6 for wifi,
- // 0 for others.
- val cust = IntArray(MAX_TRANSPORT + 1).apply {
- this[TRANSPORT_CELLULAR] = 3
- this[TRANSPORT_WIFI] = 6
- }
-
- val nc = NetworkCapabilities()
- // Check supported keepalives with single transport type.
- nc.transportTypes = intArrayOf(TRANSPORT_CELLULAR)
- assertEquals(3, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
-
- // Check supported keepalives with multiple transport types.
- nc.transportTypes = intArrayOf(TRANSPORT_WIFI, TRANSPORT_VPN)
- assertEquals(0, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
-
- // Check supported keepalives with non-customized transport type.
- nc.transportTypes = intArrayOf(TRANSPORT_ETHERNET)
- assertEquals(0, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
-
- // Check supported keepalives with undefined transport type.
- nc.transportTypes = intArrayOf(MAX_TRANSPORT + 1)
- try {
- KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc)
- fail("Expected ArrayIndexOutOfBoundsException")
- } catch (expected: ArrayIndexOutOfBoundsException) {
- }
- }
-}
diff --git a/tests/net/java/com/android/internal/net/VpnProfileTest.java b/tests/net/java/com/android/internal/net/VpnProfileTest.java
deleted file mode 100644
index e5daa71c30ea..000000000000
--- a/tests/net/java/com/android/internal/net/VpnProfileTest.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.net;
-
-import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.IpSecAlgorithm;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/** Unit tests for {@link VpnProfile}. */
-@SmallTest
-@RunWith(JUnit4.class)
-public class VpnProfileTest {
- private static final String DUMMY_PROFILE_KEY = "Test";
-
- private static final int ENCODED_INDEX_AUTH_PARAMS_INLINE = 23;
- private static final int ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS = 24;
-
- @Test
- public void testDefaults() throws Exception {
- final VpnProfile p = new VpnProfile(DUMMY_PROFILE_KEY);
-
- assertEquals(DUMMY_PROFILE_KEY, p.key);
- assertEquals("", p.name);
- assertEquals(VpnProfile.TYPE_PPTP, p.type);
- assertEquals("", p.server);
- assertEquals("", p.username);
- assertEquals("", p.password);
- assertEquals("", p.dnsServers);
- assertEquals("", p.searchDomains);
- assertEquals("", p.routes);
- assertTrue(p.mppe);
- assertEquals("", p.l2tpSecret);
- assertEquals("", p.ipsecIdentifier);
- assertEquals("", p.ipsecSecret);
- assertEquals("", p.ipsecUserCert);
- assertEquals("", p.ipsecCaCert);
- assertEquals("", p.ipsecServerCert);
- assertEquals(null, p.proxy);
- assertTrue(p.getAllowedAlgorithms() != null && p.getAllowedAlgorithms().isEmpty());
- assertFalse(p.isBypassable);
- assertFalse(p.isMetered);
- assertEquals(1360, p.maxMtu);
- assertFalse(p.areAuthParamsInline);
- assertFalse(p.isRestrictedToTestNetworks);
- }
-
- private VpnProfile getSampleIkev2Profile(String key) {
- final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */);
-
- p.name = "foo";
- p.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
- p.server = "bar";
- p.username = "baz";
- p.password = "qux";
- p.dnsServers = "8.8.8.8";
- p.searchDomains = "";
- p.routes = "0.0.0.0/0";
- p.mppe = false;
- p.l2tpSecret = "";
- p.ipsecIdentifier = "quux";
- p.ipsecSecret = "quuz";
- p.ipsecUserCert = "corge";
- p.ipsecCaCert = "grault";
- p.ipsecServerCert = "garply";
- p.proxy = null;
- p.setAllowedAlgorithms(
- Arrays.asList(
- IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
- IpSecAlgorithm.AUTH_HMAC_SHA512,
- IpSecAlgorithm.CRYPT_AES_CBC));
- p.isBypassable = true;
- p.isMetered = true;
- p.maxMtu = 1350;
- p.areAuthParamsInline = true;
-
- // Not saved, but also not compared.
- p.saveLogin = true;
-
- return p;
- }
-
- @Test
- public void testEquals() {
- assertEquals(
- getSampleIkev2Profile(DUMMY_PROFILE_KEY), getSampleIkev2Profile(DUMMY_PROFILE_KEY));
-
- final VpnProfile modified = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
- modified.maxMtu--;
- assertNotEquals(getSampleIkev2Profile(DUMMY_PROFILE_KEY), modified);
- }
-
- @Test
- public void testParcelUnparcel() {
- assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 23);
- }
-
- @Test
- public void testSetInvalidAlgorithmValueDelimiter() {
- final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
-
- try {
- profile.setAllowedAlgorithms(
- Arrays.asList("test" + VpnProfile.VALUE_DELIMITER + "test"));
- fail("Expected failure due to value separator in algorithm name");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testSetInvalidAlgorithmListDelimiter() {
- final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
-
- try {
- profile.setAllowedAlgorithms(
- Arrays.asList("test" + VpnProfile.LIST_DELIMITER + "test"));
- fail("Expected failure due to value separator in algorithm name");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testEncodeDecode() {
- final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
- final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, profile.encode());
- assertEquals(profile, decoded);
- }
-
- @Test
- public void testEncodeDecodeTooManyValues() {
- final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
- final byte[] tooManyValues =
- (new String(profile.encode()) + VpnProfile.VALUE_DELIMITER + "invalid").getBytes();
-
- assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooManyValues));
- }
-
- private String getEncodedDecodedIkev2ProfileMissingValues(int... missingIndices) {
- // Sort to ensure when we remove, we can do it from greatest first.
- Arrays.sort(missingIndices);
-
- final String encoded = new String(getSampleIkev2Profile(DUMMY_PROFILE_KEY).encode());
- final List<String> parts =
- new ArrayList<>(Arrays.asList(encoded.split(VpnProfile.VALUE_DELIMITER)));
-
- // Remove from back first to ensure indexing is consistent.
- for (int i = missingIndices.length - 1; i >= 0; i--) {
- parts.remove(missingIndices[i]);
- }
-
- return String.join(VpnProfile.VALUE_DELIMITER, parts.toArray(new String[0]));
- }
-
- @Test
- public void testEncodeDecodeInvalidNumberOfValues() {
- final String tooFewValues =
- getEncodedDecodedIkev2ProfileMissingValues(
- ENCODED_INDEX_AUTH_PARAMS_INLINE,
- ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */);
-
- assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()));
- }
-
- @Test
- public void testEncodeDecodeMissingIsRestrictedToTestNetworks() {
- final String tooFewValues =
- getEncodedDecodedIkev2ProfileMissingValues(
- ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */);
-
- // Verify decoding without isRestrictedToTestNetworks defaults to false
- final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
- assertFalse(decoded.isRestrictedToTestNetworks);
- }
-
- @Test
- public void testEncodeDecodeLoginsNotSaved() {
- final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
- profile.saveLogin = false;
-
- final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, profile.encode());
- assertNotEquals(profile, decoded);
-
- // Add the username/password back, everything else must be equal.
- decoded.username = profile.username;
- decoded.password = profile.password;
- assertEquals(profile, decoded);
- }
-}
diff --git a/tests/net/java/com/android/internal/util/BitUtilsTest.java b/tests/net/java/com/android/internal/util/BitUtilsTest.java
deleted file mode 100644
index d2fbdce9771a..000000000000
--- a/tests/net/java/com/android/internal/util/BitUtilsTest.java
+++ /dev/null
@@ -1,201 +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.internal.util;
-
-import static com.android.internal.util.BitUtils.bytesToBEInt;
-import static com.android.internal.util.BitUtils.bytesToLEInt;
-import static com.android.internal.util.BitUtils.getUint16;
-import static com.android.internal.util.BitUtils.getUint32;
-import static com.android.internal.util.BitUtils.getUint8;
-import static com.android.internal.util.BitUtils.packBits;
-import static com.android.internal.util.BitUtils.uint16;
-import static com.android.internal.util.BitUtils.uint32;
-import static com.android.internal.util.BitUtils.uint8;
-import static com.android.internal.util.BitUtils.unpackBits;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.Random;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class BitUtilsTest {
-
- @Test
- public void testUnsignedByteWideningConversions() {
- byte b0 = 0;
- byte b1 = 1;
- byte bm1 = -1;
- assertEquals(0, uint8(b0));
- assertEquals(1, uint8(b1));
- assertEquals(127, uint8(Byte.MAX_VALUE));
- assertEquals(128, uint8(Byte.MIN_VALUE));
- assertEquals(255, uint8(bm1));
- assertEquals(255, uint8((byte)255));
- }
-
- @Test
- public void testUnsignedShortWideningConversions() {
- short s0 = 0;
- short s1 = 1;
- short sm1 = -1;
- assertEquals(0, uint16(s0));
- assertEquals(1, uint16(s1));
- assertEquals(32767, uint16(Short.MAX_VALUE));
- assertEquals(32768, uint16(Short.MIN_VALUE));
- assertEquals(65535, uint16(sm1));
- assertEquals(65535, uint16((short)65535));
- }
-
- @Test
- public void testUnsignedShortComposition() {
- byte b0 = 0;
- byte b1 = 1;
- byte b2 = 2;
- byte b10 = 10;
- byte b16 = 16;
- byte b128 = -128;
- byte b224 = -32;
- byte b255 = -1;
- assertEquals(0x0000, uint16(b0, b0));
- assertEquals(0xffff, uint16(b255, b255));
- assertEquals(0x0a01, uint16(b10, b1));
- assertEquals(0x8002, uint16(b128, b2));
- assertEquals(0x01ff, uint16(b1, b255));
- assertEquals(0x80ff, uint16(b128, b255));
- assertEquals(0xe010, uint16(b224, b16));
- }
-
- @Test
- public void testUnsignedIntWideningConversions() {
- assertEquals(0, uint32(0));
- assertEquals(1, uint32(1));
- assertEquals(2147483647L, uint32(Integer.MAX_VALUE));
- assertEquals(2147483648L, uint32(Integer.MIN_VALUE));
- assertEquals(4294967295L, uint32(-1));
- assertEquals(4294967295L, uint32((int)4294967295L));
- }
-
- @Test
- public void testBytesToInt() {
- assertEquals(0x00000000, bytesToBEInt(bytes(0, 0, 0, 0)));
- assertEquals(0xffffffff, bytesToBEInt(bytes(255, 255, 255, 255)));
- assertEquals(0x0a000001, bytesToBEInt(bytes(10, 0, 0, 1)));
- assertEquals(0x0a000002, bytesToBEInt(bytes(10, 0, 0, 2)));
- assertEquals(0x0a001fff, bytesToBEInt(bytes(10, 0, 31, 255)));
- assertEquals(0xe0000001, bytesToBEInt(bytes(224, 0, 0, 1)));
-
- assertEquals(0x00000000, bytesToLEInt(bytes(0, 0, 0, 0)));
- assertEquals(0x01020304, bytesToLEInt(bytes(4, 3, 2, 1)));
- assertEquals(0xffff0000, bytesToLEInt(bytes(0, 0, 255, 255)));
- }
-
- @Test
- public void testUnsignedGetters() {
- ByteBuffer b = ByteBuffer.allocate(4);
- b.putInt(0xffff);
-
- assertEquals(0x0, getUint8(b, 0));
- assertEquals(0x0, getUint8(b, 1));
- assertEquals(0xff, getUint8(b, 2));
- assertEquals(0xff, getUint8(b, 3));
-
- assertEquals(0x0, getUint16(b, 0));
- assertEquals(0xffff, getUint16(b, 2));
-
- b.rewind();
- b.putInt(0xffffffff);
- assertEquals(0xffffffffL, getUint32(b, 0));
- }
-
- @Test
- public void testBitsPacking() {
- BitPackingTestCase[] testCases = {
- new BitPackingTestCase(0, ints()),
- new BitPackingTestCase(1, ints(0)),
- new BitPackingTestCase(2, ints(1)),
- new BitPackingTestCase(3, ints(0, 1)),
- new BitPackingTestCase(4, ints(2)),
- new BitPackingTestCase(6, ints(1, 2)),
- new BitPackingTestCase(9, ints(0, 3)),
- new BitPackingTestCase(~Long.MAX_VALUE, ints(63)),
- new BitPackingTestCase(~Long.MAX_VALUE + 1, ints(0, 63)),
- new BitPackingTestCase(~Long.MAX_VALUE + 2, ints(1, 63)),
- };
- for (BitPackingTestCase tc : testCases) {
- int[] got = unpackBits(tc.packedBits);
- assertTrue(
- "unpackBits("
- + tc.packedBits
- + "): expected "
- + Arrays.toString(tc.bits)
- + " but got "
- + Arrays.toString(got),
- Arrays.equals(tc.bits, got));
- }
- for (BitPackingTestCase tc : testCases) {
- long got = packBits(tc.bits);
- assertEquals(
- "packBits("
- + Arrays.toString(tc.bits)
- + "): expected "
- + tc.packedBits
- + " but got "
- + got,
- tc.packedBits,
- got);
- }
-
- long[] moreTestCases = {
- 0, 1, -1, 23895, -908235, Long.MAX_VALUE, Long.MIN_VALUE, new Random().nextLong(),
- };
- for (long l : moreTestCases) {
- assertEquals(l, packBits(unpackBits(l)));
- }
- }
-
- static byte[] bytes(int b1, int b2, int b3, int b4) {
- return new byte[] {b(b1), b(b2), b(b3), b(b4)};
- }
-
- static byte b(int i) {
- return (byte) i;
- }
-
- static int[] ints(int... array) {
- return array;
- }
-
- static class BitPackingTestCase {
- final int[] bits;
- final long packedBits;
-
- BitPackingTestCase(long packedBits, int[] bits) {
- this.bits = bits;
- this.packedBits = packedBits;
- }
- }
-}
diff --git a/tests/net/java/com/android/internal/util/RingBufferTest.java b/tests/net/java/com/android/internal/util/RingBufferTest.java
deleted file mode 100644
index d06095a690cf..000000000000
--- a/tests/net/java/com/android/internal/util/RingBufferTest.java
+++ /dev/null
@@ -1,178 +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.internal.util;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class RingBufferTest {
-
- @Test
- public void testEmptyRingBuffer() {
- RingBuffer<String> buffer = new RingBuffer<>(String.class, 100);
-
- assertArrayEquals(new String[0], buffer.toArray());
- }
-
- @Test
- public void testIncorrectConstructorArguments() {
- try {
- RingBuffer<String> buffer = new RingBuffer<>(String.class, -10);
- fail("Should not be able to create a negative capacity RingBuffer");
- } catch (IllegalArgumentException expected) {
- }
-
- try {
- RingBuffer<String> buffer = new RingBuffer<>(String.class, 0);
- fail("Should not be able to create a 0 capacity RingBuffer");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testRingBufferWithNoWrapping() {
- RingBuffer<String> buffer = new RingBuffer<>(String.class, 100);
-
- buffer.append("a");
- buffer.append("b");
- buffer.append("c");
- buffer.append("d");
- buffer.append("e");
-
- String[] expected = {"a", "b", "c", "d", "e"};
- assertArrayEquals(expected, buffer.toArray());
- }
-
- @Test
- public void testRingBufferWithCapacity1() {
- RingBuffer<String> buffer = new RingBuffer<>(String.class, 1);
-
- buffer.append("a");
- assertArrayEquals(new String[]{"a"}, buffer.toArray());
-
- buffer.append("b");
- assertArrayEquals(new String[]{"b"}, buffer.toArray());
-
- buffer.append("c");
- assertArrayEquals(new String[]{"c"}, buffer.toArray());
-
- buffer.append("d");
- assertArrayEquals(new String[]{"d"}, buffer.toArray());
-
- buffer.append("e");
- assertArrayEquals(new String[]{"e"}, buffer.toArray());
- }
-
- @Test
- public void testRingBufferWithWrapping() {
- int capacity = 100;
- RingBuffer<String> buffer = new RingBuffer<>(String.class, capacity);
-
- buffer.append("a");
- buffer.append("b");
- buffer.append("c");
- buffer.append("d");
- buffer.append("e");
-
- String[] expected1 = {"a", "b", "c", "d", "e"};
- assertArrayEquals(expected1, buffer.toArray());
-
- String[] expected2 = new String[capacity];
- int firstIndex = 0;
- int lastIndex = capacity - 1;
-
- expected2[firstIndex] = "e";
- for (int i = 1; i < capacity; i++) {
- buffer.append("x");
- expected2[i] = "x";
- }
- assertArrayEquals(expected2, buffer.toArray());
-
- buffer.append("x");
- expected2[firstIndex] = "x";
- assertArrayEquals(expected2, buffer.toArray());
-
- for (int i = 0; i < 10; i++) {
- for (String s : expected2) {
- buffer.append(s);
- }
- }
- assertArrayEquals(expected2, buffer.toArray());
-
- buffer.append("a");
- expected2[lastIndex] = "a";
- assertArrayEquals(expected2, buffer.toArray());
- }
-
- @Test
- public void testGetNextSlot() {
- int capacity = 100;
- RingBuffer<DummyClass1> buffer = new RingBuffer<>(DummyClass1.class, capacity);
-
- final DummyClass1[] actual = new DummyClass1[capacity];
- final DummyClass1[] expected = new DummyClass1[capacity];
- for (int i = 0; i < capacity; ++i) {
- final DummyClass1 obj = buffer.getNextSlot();
- obj.x = capacity * i;
- actual[i] = obj;
- expected[i] = new DummyClass1();
- expected[i].x = capacity * i;
- }
- assertArrayEquals(expected, buffer.toArray());
-
- for (int i = 0; i < capacity; ++i) {
- if (actual[i] != buffer.getNextSlot()) {
- fail("getNextSlot() should re-use objects if available");
- }
- }
-
- RingBuffer<DummyClass2> buffer2 = new RingBuffer<>(DummyClass2.class, capacity);
- assertNull("getNextSlot() should return null if the object can't be initiated "
- + "(No nullary constructor)", buffer2.getNextSlot());
-
- RingBuffer<DummyClass3> buffer3 = new RingBuffer<>(DummyClass3.class, capacity);
- assertNull("getNextSlot() should return null if the object can't be initiated "
- + "(Inaccessible class)", buffer3.getNextSlot());
- }
-
- public static final class DummyClass1 {
- int x;
-
- public boolean equals(Object o) {
- if (o instanceof DummyClass1) {
- final DummyClass1 other = (DummyClass1) o;
- return other.x == this.x;
- }
- return false;
- }
- }
-
- public static final class DummyClass2 {
- public DummyClass2(int x) {}
- }
-
- private static final class DummyClass3 {}
-}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
deleted file mode 100644
index e9301d1dea9d..000000000000
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ /dev/null
@@ -1,7751 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static android.Manifest.permission.CHANGE_NETWORK_STATE;
-import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
-import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
-import static android.content.pm.PackageManager.GET_PERMISSIONS;
-import static android.content.pm.PackageManager.MATCH_ANY_USER;
-import static android.content.pm.PackageManager.PERMISSION_DENIED;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
-import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
-import static android.net.ConnectivityManager.EXTRA_NETWORK_TYPE;
-import static android.net.ConnectivityManager.NETID_UNSET;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
-import static android.net.ConnectivityManager.TYPE_ETHERNET;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
-import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
-import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
-import static android.net.ConnectivityManager.TYPE_VPN;
-import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_IA;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
-import static android.net.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;
-import static android.net.RouteInfo.RTN_UNREACHABLE;
-import static android.os.Process.INVALID_UID;
-import static android.system.OsConstants.IPPROTO_TCP;
-
-import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType;
-import static com.android.testutils.ConcurrentUtilsKt.await;
-import static com.android.testutils.ConcurrentUtilsKt.durationOf;
-import static com.android.testutils.ExceptionUtils.ignoreExceptions;
-import static com.android.testutils.HandlerUtilsKt.waitForIdleSerialExecutor;
-import static com.android.testutils.MiscAssertsKt.assertContainsExactly;
-import static com.android.testutils.MiscAssertsKt.assertEmpty;
-import static com.android.testutils.MiscAssertsKt.assertLength;
-import static com.android.testutils.MiscAssertsKt.assertRunsInAtMost;
-import static com.android.testutils.MiscAssertsKt.assertThrows;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.ArgumentMatchers.startsWith;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.app.AlarmManager;
-import android.app.AppOpsManager;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.ContentProvider;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.location.LocationManager;
-import android.net.CaptivePortalData;
-import android.net.ConnectionInfo;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.ConnectivityManager.PacketKeepalive;
-import android.net.ConnectivityManager.PacketKeepaliveCallback;
-import android.net.ConnectivityManager.TooManyRequestsException;
-import android.net.ConnectivityThread;
-import android.net.DataStallReportParcelable;
-import android.net.IConnectivityDiagnosticsCallback;
-import android.net.IDnsResolver;
-import android.net.IIpConnectivityMetrics;
-import android.net.INetd;
-import android.net.INetworkMonitor;
-import android.net.INetworkMonitorCallbacks;
-import android.net.INetworkPolicyListener;
-import android.net.INetworkPolicyManager;
-import android.net.INetworkStatsService;
-import android.net.InetAddresses;
-import android.net.InterfaceConfiguration;
-import android.net.IpPrefix;
-import android.net.IpSecManager;
-import android.net.IpSecManager.UdpEncapsulationSocket;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.MatchAllNetworkSpecifier;
-import android.net.Network;
-import android.net.NetworkAgent;
-import android.net.NetworkAgentConfig;
-import android.net.NetworkCapabilities;
-import android.net.NetworkFactory;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkRequest;
-import android.net.NetworkSpecifier;
-import android.net.NetworkStack;
-import android.net.NetworkStackClient;
-import android.net.NetworkState;
-import android.net.NetworkTestResultParcelable;
-import android.net.NetworkUtils;
-import android.net.ProxyInfo;
-import android.net.ResolverParamsParcel;
-import android.net.RouteInfo;
-import android.net.RouteInfoParcel;
-import android.net.SocketKeepalive;
-import android.net.UidRange;
-import android.net.Uri;
-import android.net.VpnManager;
-import android.net.metrics.IpConnectivityLog;
-import android.net.shared.NetworkMonitorUtils;
-import android.net.shared.PrivateDnsConfig;
-import android.net.util.MultinetworkPolicyTracker;
-import android.os.BadParcelableException;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.INetworkManagementService;
-import android.os.Looper;
-import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.security.KeyStore;
-import android.system.Os;
-import android.telephony.TelephonyManager;
-import android.test.mock.MockContentResolver;
-import android.text.TextUtils;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.SparseArray;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnInfo;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.WakeupMessage;
-import com.android.internal.util.test.BroadcastInterceptingContext;
-import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
-import com.android.server.connectivity.ConnectivityConstants;
-import com.android.server.connectivity.DefaultNetworkMetrics;
-import com.android.server.connectivity.IpConnectivityMetrics;
-import com.android.server.connectivity.MockableSystemProperties;
-import com.android.server.connectivity.Nat464Xlat;
-import com.android.server.connectivity.NetworkAgentInfo;
-import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
-import com.android.server.connectivity.ProxyTracker;
-import com.android.server.connectivity.Vpn;
-import com.android.server.net.NetworkPinner;
-import com.android.server.net.NetworkPolicyManagerInternal;
-import com.android.testutils.ExceptionUtils;
-import com.android.testutils.HandlerUtilsKt;
-import com.android.testutils.RecorderCallback.CallbackEntry;
-import com.android.testutils.TestableNetworkCallback;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
-import org.mockito.stubbing.Answer;
-
-import java.io.IOException;
-import java.net.DatagramSocket;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-
-import kotlin.reflect.KClass;
-
-/**
- * Tests for {@link ConnectivityService}.
- *
- * Build, install and run with:
- * runtest frameworks-net -c com.android.server.ConnectivityServiceTest
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ConnectivityServiceTest {
- private static final String TAG = "ConnectivityServiceTest";
-
- private static final int TIMEOUT_MS = 500;
- private static final int TEST_LINGER_DELAY_MS = 300;
- // Chosen to be less than the linger timeout. This ensures that we can distinguish between a
- // LOST callback that arrives immediately and a LOST callback that arrives after the linger
- // timeout. For this, our assertions should run fast enough to leave less than
- // (mService.mLingerDelayMs - TEST_CALLBACK_TIMEOUT_MS) between the time callbacks are
- // supposedly fired, and the time we call expectCallback.
- private static final int TEST_CALLBACK_TIMEOUT_MS = 250;
- // Chosen to be less than TEST_CALLBACK_TIMEOUT_MS. This ensures that requests have time to
- // complete before callbacks are verified.
- private static final int TEST_REQUEST_TIMEOUT_MS = 150;
-
- private static final int UNREASONABLY_LONG_ALARM_WAIT_MS = 1000;
-
- private static final long TIMESTAMP = 1234L;
-
- private static final int NET_ID = 110;
-
- private static final String CLAT_PREFIX = "v4-";
- private static final String MOBILE_IFNAME = "test_rmnet_data0";
- private static final String WIFI_IFNAME = "test_wlan0";
- private static final String WIFI_WOL_IFNAME = "test_wlan_wol";
- private static final String VPN_IFNAME = "tun10042";
- private static final String TEST_PACKAGE_NAME = "com.android.test.package";
- private static final String[] EMPTY_STRING_ARRAY = new String[0];
-
- private static final String INTERFACE_NAME = "interface";
-
- private MockContext mServiceContext;
- private HandlerThread mCsHandlerThread;
- private ConnectivityService mService;
- private WrappedConnectivityManager mCm;
- private TestNetworkAgentWrapper mWiFiNetworkAgent;
- private TestNetworkAgentWrapper mCellNetworkAgent;
- private TestNetworkAgentWrapper mEthernetNetworkAgent;
- private MockVpn mMockVpn;
- private Context mContext;
- private INetworkPolicyListener mPolicyListener;
- private WrappedMultinetworkPolicyTracker mPolicyTracker;
- private HandlerThread mAlarmManagerThread;
- private TestNetIdManager mNetIdManager;
-
- @Mock IIpConnectivityMetrics mIpConnectivityMetrics;
- @Mock IpConnectivityMetrics.Logger mMetricsService;
- @Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
- @Mock INetworkManagementService mNetworkManagementService;
- @Mock INetworkStatsService mStatsService;
- @Mock IBatteryStats mBatteryStatsService;
- @Mock INetworkPolicyManager mNpm;
- @Mock IDnsResolver mMockDnsResolver;
- @Mock INetd mMockNetd;
- @Mock NetworkStackClient mNetworkStack;
- @Mock PackageManager mPackageManager;
- @Mock UserManager mUserManager;
- @Mock NotificationManager mNotificationManager;
- @Mock AlarmManager mAlarmManager;
- @Mock IConnectivityDiagnosticsCallback mConnectivityDiagnosticsCallback;
- @Mock IBinder mIBinder;
- @Mock LocationManager mLocationManager;
- @Mock AppOpsManager mAppOpsManager;
- @Mock TelephonyManager mTelephonyManager;
-
- private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
- ArgumentCaptor.forClass(ResolverParamsParcel.class);
-
- // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods
- // do not go through ConnectivityService but talk to netd directly, so they don't automatically
- // reflect the state of our test ConnectivityService.
- private class WrappedConnectivityManager extends ConnectivityManager {
- private Network mFakeBoundNetwork;
-
- public synchronized boolean bindProcessToNetwork(Network network) {
- mFakeBoundNetwork = network;
- return true;
- }
-
- public synchronized Network getBoundNetworkForProcess() {
- return mFakeBoundNetwork;
- }
-
- public WrappedConnectivityManager(Context context, ConnectivityService service) {
- super(context, service);
- }
- }
-
- private class MockContext extends BroadcastInterceptingContext {
- private final MockContentResolver mContentResolver;
-
- @Spy private Resources mResources;
- private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
- // Map of permission name -> PermissionManager.Permission_{GRANTED|DENIED} constant
- private final HashMap<String, Integer> mMockedPermissions = new HashMap<>();
-
- MockContext(Context base, ContentProvider settingsProvider) {
- super(base);
-
- mResources = spy(base.getResources());
- when(mResources.getStringArray(com.android.internal.R.array.networkAttributes)).
- thenReturn(new String[] {
- "wifi,1,1,1,-1,true",
- "mobile,0,0,0,-1,true",
- "mobile_mms,2,0,2,60000,true",
- "mobile_supl,3,0,2,60000,true",
- });
-
- when(mResources.getStringArray(
- com.android.internal.R.array.config_wakeonlan_supported_interfaces))
- .thenReturn(new String[]{
- WIFI_WOL_IFNAME,
- });
-
- mContentResolver = new MockContentResolver();
- mContentResolver.addProvider(Settings.AUTHORITY, settingsProvider);
- }
-
- @Override
- public void startActivityAsUser(Intent intent, UserHandle handle) {
- mStartedActivities.offer(intent);
- }
-
- public Intent expectStartActivityIntent(int timeoutMs) {
- Intent intent = null;
- try {
- intent = mStartedActivities.poll(timeoutMs, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {}
- assertNotNull("Did not receive sign-in intent after " + timeoutMs + "ms", intent);
- return intent;
- }
-
- public void expectNoStartActivityIntent(int timeoutMs) {
- try {
- assertNull("Received unexpected Intent to start activity",
- mStartedActivities.poll(timeoutMs, TimeUnit.MILLISECONDS));
- } catch (InterruptedException e) {}
- }
-
- @Override
- public Object getSystemService(String name) {
- if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
- if (Context.NOTIFICATION_SERVICE.equals(name)) return mNotificationManager;
- if (Context.USER_SERVICE.equals(name)) return mUserManager;
- if (Context.ALARM_SERVICE.equals(name)) return mAlarmManager;
- if (Context.LOCATION_SERVICE.equals(name)) return mLocationManager;
- if (Context.APP_OPS_SERVICE.equals(name)) return mAppOpsManager;
- if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
- return super.getSystemService(name);
- }
-
- @Override
- public ContentResolver getContentResolver() {
- return mContentResolver;
- }
-
- @Override
- public Resources getResources() {
- return mResources;
- }
-
- @Override
- public PackageManager getPackageManager() {
- return mPackageManager;
- }
-
- private int checkMockedPermission(String permission, Supplier<Integer> ifAbsent) {
- final Integer granted = mMockedPermissions.get(permission);
- return granted != null ? granted : ifAbsent.get();
- }
-
- @Override
- public int checkPermission(String permission, int pid, int uid) {
- return checkMockedPermission(
- permission, () -> super.checkPermission(permission, pid, uid));
- }
-
- @Override
- public int checkCallingOrSelfPermission(String permission) {
- return checkMockedPermission(
- permission, () -> super.checkCallingOrSelfPermission(permission));
- }
-
- @Override
- public void enforceCallingOrSelfPermission(String permission, String message) {
- final Integer granted = mMockedPermissions.get(permission);
- if (granted == null) {
- super.enforceCallingOrSelfPermission(permission, message);
- return;
- }
-
- if (!granted.equals(PERMISSION_GRANTED)) {
- throw new SecurityException("[Test] permission denied: " + permission);
- }
- }
-
- /**
- * Mock checks for the specified permission, and have them behave as per {@code granted}.
- *
- * <p>Passing null reverts to default behavior, which does a real permission check on the
- * test package.
- * @param granted One of {@link PackageManager#PERMISSION_GRANTED} or
- * {@link PackageManager#PERMISSION_DENIED}.
- */
- public void setPermission(String permission, Integer granted) {
- mMockedPermissions.put(permission, granted);
- }
- }
-
- private void waitForIdle() {
- HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
- waitForIdle(mCellNetworkAgent, TIMEOUT_MS);
- waitForIdle(mWiFiNetworkAgent, TIMEOUT_MS);
- waitForIdle(mEthernetNetworkAgent, TIMEOUT_MS);
- HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
- HandlerUtilsKt.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS);
- }
-
- private void waitForIdle(TestNetworkAgentWrapper agent, long timeoutMs) {
- if (agent == null) {
- return;
- }
- agent.waitForIdle(timeoutMs);
- }
-
- @Test
- public void testWaitForIdle() throws Exception {
- final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng.
-
- // Tests that waitForIdle returns immediately if the service is already idle.
- for (int i = 0; i < attempts; i++) {
- waitForIdle();
- }
-
- // Bring up a network that we can use to send messages to ConnectivityService.
- ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- Network n = mWiFiNetworkAgent.getNetwork();
- assertNotNull(n);
-
- // Tests that calling waitForIdle waits for messages to be processed.
- for (int i = 0; i < attempts; i++) {
- mWiFiNetworkAgent.setSignalStrength(i);
- waitForIdle();
- assertEquals(i, mCm.getNetworkCapabilities(n).getSignalStrength());
- }
- }
-
- // This test has an inherent race condition in it, and cannot be enabled for continuous testing
- // or presubmit tests. It is kept for manual runs and documentation purposes.
- @Ignore
- public void verifyThatNotWaitingForIdleCausesRaceConditions() throws Exception {
- // Bring up a network that we can use to send messages to ConnectivityService.
- ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- Network n = mWiFiNetworkAgent.getNetwork();
- assertNotNull(n);
-
- // Ensure that not calling waitForIdle causes a race condition.
- final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng.
- for (int i = 0; i < attempts; i++) {
- mWiFiNetworkAgent.setSignalStrength(i);
- if (i != mCm.getNetworkCapabilities(n).getSignalStrength()) {
- // We hit a race condition, as expected. Pass the test.
- return;
- }
- }
-
- // No race? There is a bug in this test.
- fail("expected race condition at least once in " + attempts + " attempts");
- }
-
- private class TestNetworkAgentWrapper extends NetworkAgentWrapper {
- private static final int VALIDATION_RESULT_INVALID = 0;
-
- private static final long DATA_STALL_TIMESTAMP = 10L;
- private static final int DATA_STALL_DETECTION_METHOD = 1;
-
- private INetworkMonitor mNetworkMonitor;
- private INetworkMonitorCallbacks mNmCallbacks;
- private int mNmValidationResult = VALIDATION_RESULT_INVALID;
- private int mProbesCompleted;
- private int mProbesSucceeded;
- private String mNmValidationRedirectUrl = null;
- private boolean mNmProvNotificationRequested = false;
-
- private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
- // Contains the redirectUrl from networkStatus(). Before reading, wait for
- // mNetworkStatusReceived.
- private String mRedirectUrl;
-
- TestNetworkAgentWrapper(int transport) throws Exception {
- this(transport, new LinkProperties(), null);
- }
-
- TestNetworkAgentWrapper(int transport, LinkProperties linkProperties)
- throws Exception {
- this(transport, linkProperties, null);
- }
-
- private TestNetworkAgentWrapper(int transport, LinkProperties linkProperties,
- NetworkCapabilities ncTemplate) throws Exception {
- super(transport, linkProperties, ncTemplate, mServiceContext);
-
- // Waits for the NetworkAgent to be registered, which includes the creation of the
- // NetworkMonitor.
- waitForIdle(TIMEOUT_MS);
- HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
- HandlerUtilsKt.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS);
- }
-
- @Override
- protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties)
- throws Exception {
- mNetworkMonitor = mock(INetworkMonitor.class);
-
- final Answer validateAnswer = inv -> {
- new Thread(ignoreExceptions(this::onValidationRequested)).start();
- return null;
- };
-
- doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected(any(), any());
- doAnswer(validateAnswer).when(mNetworkMonitor).forceReevaluation(anyInt());
-
- final ArgumentCaptor<Network> nmNetworkCaptor = ArgumentCaptor.forClass(Network.class);
- final ArgumentCaptor<INetworkMonitorCallbacks> nmCbCaptor =
- ArgumentCaptor.forClass(INetworkMonitorCallbacks.class);
- doNothing().when(mNetworkStack).makeNetworkMonitor(
- nmNetworkCaptor.capture(),
- any() /* name */,
- nmCbCaptor.capture());
-
- final InstrumentedNetworkAgent na = new InstrumentedNetworkAgent(this, linkProperties) {
- @Override
- public void networkStatus(int status, String redirectUrl) {
- mRedirectUrl = redirectUrl;
- mNetworkStatusReceived.open();
- }
- };
-
- assertEquals(na.getNetwork().netId, nmNetworkCaptor.getValue().netId);
- mNmCallbacks = nmCbCaptor.getValue();
-
- mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor);
-
- return na;
- }
-
- private void onValidationRequested() throws Exception {
- if (mNmProvNotificationRequested
- && ((mNmValidationResult & NETWORK_VALIDATION_RESULT_VALID) != 0)) {
- mNmCallbacks.hideProvisioningNotification();
- mNmProvNotificationRequested = false;
- }
-
- mNmCallbacks.notifyProbeStatusChanged(mProbesCompleted, mProbesSucceeded);
- final NetworkTestResultParcelable p = new NetworkTestResultParcelable();
- p.result = mNmValidationResult;
- p.probesAttempted = mProbesCompleted;
- p.probesSucceeded = mProbesSucceeded;
- p.redirectUrl = mNmValidationRedirectUrl;
- p.timestampMillis = TIMESTAMP;
- mNmCallbacks.notifyNetworkTestedWithExtras(p);
-
- if (mNmValidationRedirectUrl != null) {
- mNmCallbacks.showProvisioningNotification(
- "test_provisioning_notif_action", TEST_PACKAGE_NAME);
- mNmProvNotificationRequested = true;
- }
- }
-
- /**
- * Connect without adding any internet capability.
- */
- public void connectWithoutInternet() {
- super.connect();
- }
-
- /**
- * Transition this NetworkAgent to CONNECTED state with NET_CAPABILITY_INTERNET.
- * @param validated Indicate if network should pretend to be validated.
- */
- public void connect(boolean validated) {
- connect(validated, true, false /* isStrictMode */);
- }
-
- /**
- * Transition this NetworkAgent to CONNECTED state.
- * @param validated Indicate if network should pretend to be validated.
- * @param hasInternet Indicate if network should pretend to have NET_CAPABILITY_INTERNET.
- */
- public void connect(boolean validated, boolean hasInternet, boolean isStrictMode) {
- assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_INTERNET));
-
- ConnectivityManager.NetworkCallback callback = null;
- final ConditionVariable validatedCv = new ConditionVariable();
- if (validated) {
- setNetworkValid(isStrictMode);
- NetworkRequest request = new NetworkRequest.Builder()
- .addTransportType(getNetworkCapabilities().getTransportTypes()[0])
- .clearCapabilities()
- .build();
- callback = new ConnectivityManager.NetworkCallback() {
- public void onCapabilitiesChanged(Network network,
- NetworkCapabilities networkCapabilities) {
- if (network.equals(getNetwork()) &&
- networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
- validatedCv.open();
- }
- }
- };
- mCm.registerNetworkCallback(request, callback);
- }
- if (hasInternet) {
- addCapability(NET_CAPABILITY_INTERNET);
- }
-
- connectWithoutInternet();
-
- if (validated) {
- // Wait for network to validate.
- waitFor(validatedCv);
- setNetworkInvalid(isStrictMode);
- }
-
- if (callback != null) mCm.unregisterNetworkCallback(callback);
- }
-
- public void connectWithCaptivePortal(String redirectUrl, boolean isStrictMode) {
- setNetworkPortal(redirectUrl, isStrictMode);
- connect(false, true /* hasInternet */, isStrictMode);
- }
-
- public void connectWithPartialConnectivity() {
- setNetworkPartial();
- connect(false);
- }
-
- public void connectWithPartialValidConnectivity(boolean isStrictMode) {
- setNetworkPartialValid(isStrictMode);
- connect(false, true /* hasInternet */, isStrictMode);
- }
-
- void setNetworkValid(boolean isStrictMode) {
- mNmValidationResult = NETWORK_VALIDATION_RESULT_VALID;
- mNmValidationRedirectUrl = null;
- int probesSucceeded = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS;
- if (isStrictMode) {
- probesSucceeded |= NETWORK_VALIDATION_PROBE_PRIVDNS;
- }
- // The probesCompleted equals to probesSucceeded for the case of valid network, so put
- // the same value into two different parameter of the method.
- setProbesStatus(probesSucceeded, probesSucceeded);
- }
-
- void setNetworkInvalid(boolean isStrictMode) {
- mNmValidationResult = VALIDATION_RESULT_INVALID;
- mNmValidationRedirectUrl = null;
- int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS
- | NETWORK_VALIDATION_PROBE_HTTP;
- int probesSucceeded = 0;
- // If the isStrictMode is true, it means the network is invalid when NetworkMonitor
- // tried to validate the private DNS but failed.
- if (isStrictMode) {
- probesCompleted &= ~NETWORK_VALIDATION_PROBE_HTTP;
- probesSucceeded = probesCompleted;
- probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS;
- }
- setProbesStatus(probesCompleted, probesSucceeded);
- }
-
- void setNetworkPortal(String redirectUrl, boolean isStrictMode) {
- setNetworkInvalid(isStrictMode);
- mNmValidationRedirectUrl = redirectUrl;
- // Suppose the portal is found when NetworkMonitor probes NETWORK_VALIDATION_PROBE_HTTP
- // in the beginning, so the NETWORK_VALIDATION_PROBE_HTTPS hasn't probed yet.
- int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTP;
- int probesSucceeded = VALIDATION_RESULT_INVALID;
- if (isStrictMode) {
- probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS;
- }
- setProbesStatus(probesCompleted, probesSucceeded);
- }
-
- void setNetworkPartial() {
- mNmValidationResult = NETWORK_VALIDATION_RESULT_PARTIAL;
- mNmValidationRedirectUrl = null;
- int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS
- | NETWORK_VALIDATION_PROBE_FALLBACK;
- int probesSucceeded = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_FALLBACK;
- setProbesStatus(probesCompleted, probesSucceeded);
- }
-
- void setNetworkPartialValid(boolean isStrictMode) {
- setNetworkPartial();
- mNmValidationResult |= NETWORK_VALIDATION_RESULT_VALID;
- int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS
- | NETWORK_VALIDATION_PROBE_HTTP;
- int probesSucceeded = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTP;
- // Suppose the partial network cannot pass the private DNS validation as well, so only
- // add NETWORK_VALIDATION_PROBE_DNS in probesCompleted but not probesSucceeded.
- if (isStrictMode) {
- probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS;
- }
- setProbesStatus(probesCompleted, probesSucceeded);
- }
-
- void setProbesStatus(int probesCompleted, int probesSucceeded) {
- mProbesCompleted = probesCompleted;
- mProbesSucceeded = probesSucceeded;
- }
-
- void notifyCaptivePortalDataChanged(CaptivePortalData data) {
- try {
- mNmCallbacks.notifyCaptivePortalDataChanged(data);
- } catch (RemoteException e) {
- throw new AssertionError("This cannot happen", e);
- }
- }
-
- public String waitForRedirectUrl() {
- assertTrue(mNetworkStatusReceived.block(TIMEOUT_MS));
- return mRedirectUrl;
- }
-
- public void expectDisconnected() {
- expectDisconnected(TIMEOUT_MS);
- }
-
- public void expectPreventReconnectReceived() {
- expectPreventReconnectReceived(TIMEOUT_MS);
- }
-
- void notifyDataStallSuspected() throws Exception {
- final DataStallReportParcelable p = new DataStallReportParcelable();
- p.detectionMethod = DATA_STALL_DETECTION_METHOD;
- p.timestampMillis = DATA_STALL_TIMESTAMP;
- mNmCallbacks.notifyDataStallSuspected(p);
- }
- }
-
- /**
- * A NetworkFactory that allows tests to wait until any in-flight NetworkRequest add or remove
- * operations have been processed. Before ConnectivityService can add or remove any requests,
- * the factory must be told to expect those operations by calling expectAddRequestsWithScores or
- * expectRemoveRequests.
- */
- private static class MockNetworkFactory extends NetworkFactory {
- private final ConditionVariable mNetworkStartedCV = new ConditionVariable();
- private final ConditionVariable mNetworkStoppedCV = new ConditionVariable();
- private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
-
- // Used to expect that requests be removed or added on a separate thread, without sleeping.
- // Callers can call either expectAddRequestsWithScores() or expectRemoveRequests() exactly
- // once, then cause some other thread to add or remove requests, then call
- // waitForRequests().
- // It is not possible to wait for both add and remove requests. When adding, the queue
- // contains the expected score. When removing, the value is unused, all matters is the
- // number of objects in the queue.
- private final LinkedBlockingQueue<Integer> mExpectations;
-
- // Whether we are currently expecting requests to be added or removed. Valid only if
- // mExpectations is non-empty.
- private boolean mExpectingAdditions;
-
- // Used to collect the networks requests managed by this factory. This is a duplicate of
- // the internal information stored in the NetworkFactory (which is private).
- private SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
-
- public MockNetworkFactory(Looper looper, Context context, String logTag,
- NetworkCapabilities filter) {
- super(looper, context, logTag, filter);
- mExpectations = new LinkedBlockingQueue<>();
- }
-
- public int getMyRequestCount() {
- return getRequestCount();
- }
-
- protected void startNetwork() {
- mNetworkStarted.set(true);
- mNetworkStartedCV.open();
- }
-
- protected void stopNetwork() {
- mNetworkStarted.set(false);
- mNetworkStoppedCV.open();
- }
-
- public boolean getMyStartRequested() {
- return mNetworkStarted.get();
- }
-
- public ConditionVariable getNetworkStartedCV() {
- mNetworkStartedCV.close();
- return mNetworkStartedCV;
- }
-
- public ConditionVariable getNetworkStoppedCV() {
- mNetworkStoppedCV.close();
- return mNetworkStoppedCV;
- }
-
- @Override
- protected void handleAddRequest(NetworkRequest request, int score,
- int factorySerialNumber) {
- synchronized (mExpectations) {
- final Integer expectedScore = mExpectations.poll(); // null if the queue is empty
-
- assertNotNull("Added more requests than expected (" + request + " score : "
- + score + ")", expectedScore);
- // If we're expecting anything, we must be expecting additions.
- if (!mExpectingAdditions) {
- fail("Can't add requests while expecting requests to be removed");
- }
- if (expectedScore != score) {
- fail("Expected score was " + expectedScore + " but actual was " + score
- + " in added request");
- }
-
- // Add the request.
- mNetworkRequests.put(request.requestId, request);
- super.handleAddRequest(request, score, factorySerialNumber);
- mExpectations.notify();
- }
- }
-
- @Override
- protected void handleRemoveRequest(NetworkRequest request) {
- synchronized (mExpectations) {
- final Integer expectedScore = mExpectations.poll(); // null if the queue is empty
-
- assertTrue("Removed more requests than expected", expectedScore != null);
- // If we're expecting anything, we must be expecting removals.
- if (mExpectingAdditions) {
- fail("Can't remove requests while expecting requests to be added");
- }
-
- // Remove the request.
- mNetworkRequests.remove(request.requestId);
- super.handleRemoveRequest(request);
- mExpectations.notify();
- }
- }
-
- // Trigger releasing the request as unfulfillable
- public void triggerUnfulfillable(NetworkRequest r) {
- super.releaseRequestAsUnfulfillableByAnyFactory(r);
- }
-
- private void assertNoExpectations() {
- if (mExpectations.size() != 0) {
- fail("Can't add expectation, " + mExpectations.size() + " already pending");
- }
- }
-
- // Expects that requests with the specified scores will be added.
- public void expectAddRequestsWithScores(final int... scores) {
- assertNoExpectations();
- mExpectingAdditions = true;
- for (int score : scores) {
- mExpectations.add(score);
- }
- }
-
- // Expects that count requests will be removed.
- public void expectRemoveRequests(final int count) {
- assertNoExpectations();
- mExpectingAdditions = false;
- for (int i = 0; i < count; ++i) {
- mExpectations.add(0); // For removals the score is ignored so any value will do.
- }
- }
-
- // Waits for the expected request additions or removals to happen within a timeout.
- public void waitForRequests() throws InterruptedException {
- final long deadline = SystemClock.elapsedRealtime() + TIMEOUT_MS;
- synchronized (mExpectations) {
- while (mExpectations.size() > 0 && SystemClock.elapsedRealtime() < deadline) {
- mExpectations.wait(deadline - SystemClock.elapsedRealtime());
- }
- }
- final long count = mExpectations.size();
- final String msg = count + " requests still not " +
- (mExpectingAdditions ? "added" : "removed") +
- " after " + TIMEOUT_MS + " ms";
- assertEquals(msg, 0, count);
- }
-
- public SparseArray<NetworkRequest> waitForNetworkRequests(final int count)
- throws InterruptedException {
- waitForRequests();
- assertEquals(count, getMyRequestCount());
- return mNetworkRequests;
- }
- }
-
- private Set<UidRange> uidRangesForUid(int uid) {
- final ArraySet<UidRange> ranges = new ArraySet<>();
- ranges.add(new UidRange(uid, uid));
- return ranges;
- }
-
- private static Looper startHandlerThreadAndReturnLooper() {
- final HandlerThread handlerThread = new HandlerThread("MockVpnThread");
- handlerThread.start();
- return handlerThread.getLooper();
- }
-
- private class MockVpn extends Vpn implements TestableNetworkCallback.HasNetwork {
- // Careful ! This is different from mNetworkAgent, because MockNetworkAgent does
- // not inherit from NetworkAgent.
- private TestNetworkAgentWrapper mMockNetworkAgent;
- private boolean mAgentRegistered = false;
-
- private int mVpnType = VpnManager.TYPE_VPN_SERVICE;
- private VpnInfo mVpnInfo;
-
- public MockVpn(int userId) {
- super(startHandlerThreadAndReturnLooper(), mServiceContext, mNetworkManagementService,
- userId, mock(KeyStore.class));
- mConfig = new VpnConfig();
- }
-
- public void setUids(Set<UidRange> uids) {
- mNetworkCapabilities.setUids(uids);
- updateCapabilitiesInternal(null /* defaultNetwork */, true);
- }
-
- public void setVpnType(int vpnType) {
- mVpnType = vpnType;
- }
-
- @Override
- public Network getNetwork() {
- return (mMockNetworkAgent == null) ? null : mMockNetworkAgent.getNetwork();
- }
-
- @Override
- public int getNetId() {
- return (mMockNetworkAgent == null) ? NETID_UNSET : mMockNetworkAgent.getNetwork().netId;
- }
-
- @Override
- public int getActiveAppVpnType() {
- return mVpnType;
- }
-
- private void registerAgent(boolean isAlwaysMetered, Set<UidRange> uids, LinkProperties lp)
- throws Exception {
- if (mAgentRegistered) throw new IllegalStateException("already registered");
- setUids(uids);
- mConfig.isMetered = isAlwaysMetered;
- mInterface = VPN_IFNAME;
- mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
- mNetworkCapabilities);
- mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
- mAgentRegistered = true;
- mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
- mNetworkAgent = mMockNetworkAgent.getNetworkAgent();
- }
-
- private void registerAgent(Set<UidRange> uids) throws Exception {
- registerAgent(false /* isAlwaysMetered */, uids, new LinkProperties());
- }
-
- private void connect(boolean validated, boolean hasInternet, boolean isStrictMode) {
- mMockNetworkAgent.connect(validated, hasInternet, isStrictMode);
- }
-
- private void connect(boolean validated) {
- mMockNetworkAgent.connect(validated);
- }
-
- private TestNetworkAgentWrapper getAgent() {
- return mMockNetworkAgent;
- }
-
- public void establish(LinkProperties lp, int uid, Set<UidRange> ranges, boolean validated,
- boolean hasInternet, boolean isStrictMode) throws Exception {
- mNetworkCapabilities.setOwnerUid(uid);
- mNetworkCapabilities.setAdministratorUids(new int[]{uid});
- registerAgent(false, ranges, lp);
- connect(validated, hasInternet, isStrictMode);
- waitForIdle();
- }
-
- public void establish(LinkProperties lp, int uid, Set<UidRange> ranges) throws Exception {
- establish(lp, uid, ranges, true, true, false);
- }
-
- public void establishForMyUid(LinkProperties lp) throws Exception {
- final int uid = Process.myUid();
- establish(lp, uid, uidRangesForUid(uid), true, true, false);
- }
-
- public void establishForMyUid(boolean validated, boolean hasInternet, boolean isStrictMode)
- throws Exception {
- final int uid = Process.myUid();
- establish(new LinkProperties(), uid, uidRangesForUid(uid), validated, hasInternet,
- isStrictMode);
- }
-
- public void establishForMyUid() throws Exception {
- establishForMyUid(new LinkProperties());
- }
-
- public void sendLinkProperties(LinkProperties lp) {
- mMockNetworkAgent.sendLinkProperties(lp);
- }
-
- private NetworkCapabilities updateCapabilitiesInternal(Network defaultNetwork,
- boolean sendToConnectivityService) {
- if (!mAgentRegistered) return null;
- super.updateCapabilities(defaultNetwork);
- // Because super.updateCapabilities will update the capabilities of the agent but
- // not the mock agent, the mock agent needs to know about them.
- copyCapabilitiesToNetworkAgent(sendToConnectivityService);
- return new NetworkCapabilities(mNetworkCapabilities);
- }
-
- private void copyCapabilitiesToNetworkAgent(boolean sendToConnectivityService) {
- if (null != mMockNetworkAgent) {
- mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities,
- sendToConnectivityService);
- }
- }
-
- @Override
- public NetworkCapabilities updateCapabilities(Network defaultNetwork) {
- return updateCapabilitiesInternal(defaultNetwork, false);
- }
-
- public void disconnect() {
- if (mMockNetworkAgent != null) mMockNetworkAgent.disconnect();
- mAgentRegistered = false;
- }
-
- @Override
- public synchronized VpnInfo getVpnInfo() {
- if (mVpnInfo != null) return mVpnInfo;
-
- return super.getVpnInfo();
- }
-
- private synchronized void setVpnInfo(VpnInfo vpnInfo) {
- mVpnInfo = vpnInfo;
- }
- }
-
- private void mockVpn(int uid) {
- synchronized (mService.mVpns) {
- int userId = UserHandle.getUserId(uid);
- mMockVpn = new MockVpn(userId);
- // This has no effect unless the VPN is actually connected, because things like
- // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN
- // netId, and check if that network is actually connected.
- mService.mVpns.put(userId, mMockVpn);
- }
- }
-
- private void setUidRulesChanged(int uidRules) throws RemoteException {
- mPolicyListener.onUidRulesChanged(Process.myUid(), uidRules);
- }
-
- private void setRestrictBackgroundChanged(boolean restrictBackground) throws RemoteException {
- mPolicyListener.onRestrictBackgroundChanged(restrictBackground);
- }
-
- private Nat464Xlat getNat464Xlat(NetworkAgentWrapper mna) {
- return mService.getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
- }
-
- private static class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
- volatile boolean mConfigRestrictsAvoidBadWifi;
- volatile int mConfigMeteredMultipathPreference;
-
- WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
- super(c, h, r);
- }
-
- @Override
- public boolean configRestrictsAvoidBadWifi() {
- return mConfigRestrictsAvoidBadWifi;
- }
-
- @Override
- public int configMeteredMultipathPreference() {
- return mConfigMeteredMultipathPreference;
- }
- }
-
- /**
- * Wait up to TIMEOUT_MS for {@code conditionVariable} to open.
- * Fails if TIMEOUT_MS goes by before {@code conditionVariable} opens.
- */
- static private void waitFor(ConditionVariable conditionVariable) {
- if (conditionVariable.block(TIMEOUT_MS)) {
- return;
- }
- fail("ConditionVariable was blocked for more than " + TIMEOUT_MS + "ms");
- }
-
- private static final int VPN_USER = 0;
- private static final int APP1_UID = UserHandle.getUid(VPN_USER, 10100);
- private static final int APP2_UID = UserHandle.getUid(VPN_USER, 10101);
- private static final int VPN_UID = UserHandle.getUid(VPN_USER, 10043);
-
- @Before
- public void setUp() throws Exception {
- mNetIdManager = new TestNetIdManager();
-
- mContext = InstrumentationRegistry.getContext();
-
- MockitoAnnotations.initMocks(this);
- when(mMetricsService.defaultNetworkMetrics()).thenReturn(mDefaultNetworkMetrics);
-
- when(mUserManager.getUsers(eq(true))).thenReturn(
- Arrays.asList(new UserInfo[] {
- new UserInfo(VPN_USER, "", 0),
- }));
- final int userId = UserHandle.getCallingUserId();
- final UserInfo primaryUser = new UserInfo(userId, "", UserInfo.FLAG_PRIMARY);
- doReturn(primaryUser).when(mUserManager).getUserInfo(eq(userId));
- final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
- when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
- .thenReturn(applicationInfo);
-
- // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
- // http://b/25897652 .
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
- mockDefaultPackages();
-
- FakeSettingsProvider.clearSettingsProvider();
- mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
- new FakeSettingsProvider());
- LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
- LocalServices.addService(
- NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
-
- mAlarmManagerThread = new HandlerThread("TestAlarmManager");
- mAlarmManagerThread.start();
- initAlarmManager(mAlarmManager, mAlarmManagerThread.getThreadHandler());
-
- mCsHandlerThread = new HandlerThread("TestConnectivityService");
- final ConnectivityService.Dependencies deps = makeDependencies();
- mService = new ConnectivityService(mServiceContext,
- mNetworkManagementService,
- mStatsService,
- mNpm,
- mMockDnsResolver,
- mock(IpConnectivityLog.class),
- mMockNetd,
- deps);
- mService.mLingerDelayMs = TEST_LINGER_DELAY_MS;
- verify(deps).makeMultinetworkPolicyTracker(any(), any(), any());
-
- final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
- ArgumentCaptor.forClass(INetworkPolicyListener.class);
- verify(mNpm).registerListener(policyListenerCaptor.capture());
- mPolicyListener = policyListenerCaptor.getValue();
-
- // Create local CM before sending system ready so that we can answer
- // getSystemService() correctly.
- mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
- mService.systemReady();
- mockVpn(Process.myUid());
- mCm.bindProcessToNetwork(null);
-
- // Ensure that the default setting for Captive Portals is used for most tests
- setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
- setAlwaysOnNetworks(false);
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
- }
-
- private ConnectivityService.Dependencies makeDependencies() {
- final MockableSystemProperties systemProperties = spy(new MockableSystemProperties());
- when(systemProperties.getInt("net.tcp.default_init_rwnd", 0)).thenReturn(0);
- when(systemProperties.getBoolean("ro.radio.noril", false)).thenReturn(false);
-
- final ConnectivityService.Dependencies deps = mock(ConnectivityService.Dependencies.class);
- doReturn(mCsHandlerThread).when(deps).makeHandlerThread();
- doReturn(mNetIdManager).when(deps).makeNetIdManager();
- doReturn(mNetworkStack).when(deps).getNetworkStack();
- doReturn(systemProperties).when(deps).getSystemProperties();
- doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
- doReturn(mMetricsService).when(deps).getMetricsLogger();
- doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
- doReturn(mIpConnectivityMetrics).when(deps).getIpConnectivityMetrics();
- doReturn(mBatteryStatsService).when(deps).getBatteryStatsService();
- doReturn(true).when(deps).hasService(Context.ETHERNET_SERVICE);
- doAnswer(inv -> {
- mPolicyTracker = new WrappedMultinetworkPolicyTracker(
- inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
- return mPolicyTracker;
- }).when(deps).makeMultinetworkPolicyTracker(any(), any(), any());
-
- return deps;
- }
-
- private static void initAlarmManager(final AlarmManager am, final Handler alarmHandler) {
- doAnswer(inv -> {
- final long when = inv.getArgument(1);
- final WakeupMessage wakeupMsg = inv.getArgument(3);
- final Handler handler = inv.getArgument(4);
-
- long delayMs = when - SystemClock.elapsedRealtime();
- if (delayMs < 0) delayMs = 0;
- if (delayMs > UNREASONABLY_LONG_ALARM_WAIT_MS) {
- fail("Attempting to send msg more than " + UNREASONABLY_LONG_ALARM_WAIT_MS
- + "ms into the future: " + delayMs);
- }
- alarmHandler.postDelayed(() -> handler.post(wakeupMsg::onAlarm), wakeupMsg /* token */,
- delayMs);
-
- return null;
- }).when(am).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), anyLong(), anyString(),
- any(WakeupMessage.class), any());
-
- doAnswer(inv -> {
- final WakeupMessage wakeupMsg = inv.getArgument(0);
- alarmHandler.removeCallbacksAndMessages(wakeupMsg /* token */);
- return null;
- }).when(am).cancel(any(WakeupMessage.class));
- }
-
- @After
- public void tearDown() throws Exception {
- setAlwaysOnNetworks(false);
- if (mCellNetworkAgent != null) {
- mCellNetworkAgent.disconnect();
- mCellNetworkAgent = null;
- }
- if (mWiFiNetworkAgent != null) {
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent = null;
- }
- if (mEthernetNetworkAgent != null) {
- mEthernetNetworkAgent.disconnect();
- mEthernetNetworkAgent = null;
- }
- mMockVpn.disconnect();
- waitForIdle();
-
- FakeSettingsProvider.clearSettingsProvider();
-
- mCsHandlerThread.quitSafely();
- mAlarmManagerThread.quitSafely();
- }
-
- private void mockDefaultPackages() throws Exception {
- final String testPackageName = mContext.getPackageName();
- final PackageInfo testPackageInfo = mContext.getPackageManager().getPackageInfo(
- testPackageName, PackageManager.GET_PERMISSIONS);
- when(mPackageManager.getPackagesForUid(Binder.getCallingUid())).thenReturn(
- new String[] {testPackageName});
- when(mPackageManager.getPackageInfoAsUser(eq(testPackageName), anyInt(),
- eq(UserHandle.getCallingUserId()))).thenReturn(testPackageInfo);
-
- when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
- Arrays.asList(new PackageInfo[] {
- buildPackageInfo(/* SYSTEM */ false, APP1_UID),
- buildPackageInfo(/* SYSTEM */ false, APP2_UID),
- buildPackageInfo(/* SYSTEM */ false, VPN_UID)
- }));
- final int userId = UserHandle.getCallingUserId();
- when(mPackageManager.getPackageUidAsUser(TEST_PACKAGE_NAME, userId))
- .thenReturn(Process.myUid());
- }
-
- private void verifyActiveNetwork(int transport) {
- // Test getActiveNetworkInfo()
- assertNotNull(mCm.getActiveNetworkInfo());
- assertEquals(transportToLegacyType(transport), mCm.getActiveNetworkInfo().getType());
- // Test getActiveNetwork()
- assertNotNull(mCm.getActiveNetwork());
- assertEquals(mCm.getActiveNetwork(), mCm.getActiveNetworkForUid(Process.myUid()));
- if (!NetworkCapabilities.isValidTransport(transport)) {
- throw new IllegalStateException("Unknown transport " + transport);
- }
- switch (transport) {
- case TRANSPORT_WIFI:
- assertEquals(mCm.getActiveNetwork(), mWiFiNetworkAgent.getNetwork());
- break;
- case TRANSPORT_CELLULAR:
- assertEquals(mCm.getActiveNetwork(), mCellNetworkAgent.getNetwork());
- break;
- default:
- break;
- }
- // Test getNetworkInfo(Network)
- assertNotNull(mCm.getNetworkInfo(mCm.getActiveNetwork()));
- assertEquals(transportToLegacyType(transport),
- mCm.getNetworkInfo(mCm.getActiveNetwork()).getType());
- // Test getNetworkCapabilities(Network)
- assertNotNull(mCm.getNetworkCapabilities(mCm.getActiveNetwork()));
- assertTrue(mCm.getNetworkCapabilities(mCm.getActiveNetwork()).hasTransport(transport));
- }
-
- private void verifyNoNetwork() {
- waitForIdle();
- // Test getActiveNetworkInfo()
- assertNull(mCm.getActiveNetworkInfo());
- // Test getActiveNetwork()
- assertNull(mCm.getActiveNetwork());
- assertNull(mCm.getActiveNetworkForUid(Process.myUid()));
- // Test getAllNetworks()
- assertEmpty(mCm.getAllNetworks());
- }
-
- /**
- * Class to simplify expecting broadcasts using BroadcastInterceptingContext.
- * Ensures that the receiver is unregistered after the expected broadcast is received. This
- * cannot be done in the BroadcastReceiver itself because BroadcastInterceptingContext runs
- * the receivers' receive method while iterating over the list of receivers, and unregistering
- * the receiver during iteration throws ConcurrentModificationException.
- */
- private class ExpectedBroadcast extends CompletableFuture<Intent> {
- private final BroadcastReceiver mReceiver;
-
- ExpectedBroadcast(BroadcastReceiver receiver) {
- mReceiver = receiver;
- }
-
- public Intent expectBroadcast(int timeoutMs) throws Exception {
- try {
- return get(timeoutMs, TimeUnit.MILLISECONDS);
- } catch (TimeoutException e) {
- fail("Expected broadcast not received after " + timeoutMs + " ms");
- return null;
- } finally {
- mServiceContext.unregisterReceiver(mReceiver);
- }
- }
-
- public Intent expectBroadcast() throws Exception {
- return expectBroadcast(TIMEOUT_MS);
- }
-
- public void expectNoBroadcast(int timeoutMs) throws Exception {
- waitForIdle();
- try {
- final Intent intent = get(timeoutMs, TimeUnit.MILLISECONDS);
- fail("Unexpected broadcast: " + intent.getAction());
- } catch (TimeoutException expected) {
- } finally {
- mServiceContext.unregisterReceiver(mReceiver);
- }
- }
- }
-
- /** Expects that {@code count} CONNECTIVITY_ACTION broadcasts are received. */
- private ExpectedBroadcast registerConnectivityBroadcast(final int count) {
- return registerConnectivityBroadcastThat(count, intent -> true);
- }
-
- private ExpectedBroadcast registerConnectivityBroadcastThat(final int count,
- @NonNull final Predicate<Intent> filter) {
- final IntentFilter intentFilter = new IntentFilter(CONNECTIVITY_ACTION);
- // AtomicReference allows receiver to access expected even though it is constructed later.
- final AtomicReference<ExpectedBroadcast> expectedRef = new AtomicReference<>();
- final BroadcastReceiver receiver = new BroadcastReceiver() {
- private int mRemaining = count;
- public void onReceive(Context context, Intent intent) {
- final int type = intent.getIntExtra(EXTRA_NETWORK_TYPE, -1);
- final NetworkInfo ni = intent.getParcelableExtra(EXTRA_NETWORK_INFO);
- Log.d(TAG, "Received CONNECTIVITY_ACTION type=" + type + " ni=" + ni);
- if (!filter.test(intent)) return;
- if (--mRemaining == 0) {
- expectedRef.get().complete(intent);
- }
- }
- };
- final ExpectedBroadcast expected = new ExpectedBroadcast(receiver);
- expectedRef.set(expected);
- mServiceContext.registerReceiver(receiver, intentFilter);
- return expected;
- }
-
- private ExpectedBroadcast expectConnectivityAction(int type, NetworkInfo.DetailedState state) {
- return registerConnectivityBroadcastThat(1, intent ->
- type == intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) && state.equals(
- ((NetworkInfo) intent.getParcelableExtra(EXTRA_NETWORK_INFO))
- .getDetailedState()));
- }
-
- @Test
- public void testNetworkTypes() {
- // Ensure that our mocks for the networkAttributes config variable work as expected. If they
- // don't, then tests that depend on CONNECTIVITY_ACTION broadcasts for these network types
- // will fail. Failing here is much easier to debug.
- assertTrue(mCm.isNetworkSupported(TYPE_WIFI));
- assertTrue(mCm.isNetworkSupported(TYPE_MOBILE));
- assertTrue(mCm.isNetworkSupported(TYPE_MOBILE_MMS));
- assertFalse(mCm.isNetworkSupported(TYPE_MOBILE_FOTA));
-
- // Check that TYPE_ETHERNET is supported. Unlike the asserts above, which only validate our
- // mocks, this assert exercises the ConnectivityService code path that ensures that
- // TYPE_ETHERNET is supported if the ethernet service is running.
- assertTrue(mCm.isNetworkSupported(TYPE_ETHERNET));
- }
-
- @Test
- public void testNetworkFeature() throws Exception {
- // Connect the cell agent and wait for the connected broadcast.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_SUPL);
- ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
-
- // Build legacy request for SUPL.
- final NetworkCapabilities legacyCaps = new NetworkCapabilities();
- legacyCaps.addTransportType(TRANSPORT_CELLULAR);
- legacyCaps.addCapability(NET_CAPABILITY_SUPL);
- final NetworkRequest legacyRequest = new NetworkRequest(legacyCaps, TYPE_MOBILE_SUPL,
- ConnectivityManager.REQUEST_ID_UNSET, NetworkRequest.Type.REQUEST);
-
- // File request, withdraw it and make sure no broadcast is sent
- b = registerConnectivityBroadcast(1);
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.requestNetwork(legacyRequest, callback);
- callback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
- mCm.unregisterNetworkCallback(callback);
- b.expectNoBroadcast(800); // 800ms long enough to at least flake if this is sent
-
- // Disconnect the network and expect mobile disconnected broadcast.
- b = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
- mCellNetworkAgent.disconnect();
- b.expectBroadcast();
- }
-
- @Test
- public void testLingering() throws Exception {
- verifyNoNetwork();
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- assertNull(mCm.getActiveNetworkInfo());
- assertNull(mCm.getActiveNetwork());
- // Test bringing up validated cellular.
- ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- assertLength(2, mCm.getAllNetworks());
- assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) ||
- mCm.getAllNetworks()[1].equals(mCm.getActiveNetwork()));
- assertTrue(mCm.getAllNetworks()[0].equals(mWiFiNetworkAgent.getNetwork()) ||
- mCm.getAllNetworks()[1].equals(mWiFiNetworkAgent.getNetwork()));
- // Test bringing up validated WiFi.
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- assertLength(2, mCm.getAllNetworks());
- assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) ||
- mCm.getAllNetworks()[1].equals(mCm.getActiveNetwork()));
- assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) ||
- mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork()));
- // Test cellular linger timeout.
- mCellNetworkAgent.expectDisconnected();
- waitForIdle();
- assertLength(1, mCm.getAllNetworks());
- verifyActiveNetwork(TRANSPORT_WIFI);
- assertLength(1, mCm.getAllNetworks());
- assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());
- // Test WiFi disconnect.
- b = registerConnectivityBroadcast(1);
- mWiFiNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyNoNetwork();
- }
-
- @Test
- public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
- // Test bringing up unvalidated WiFi
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test bringing up unvalidated cellular
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false);
- waitForIdle();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test cellular disconnect.
- mCellNetworkAgent.disconnect();
- waitForIdle();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test bringing up validated cellular
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- b = registerConnectivityBroadcast(2);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test cellular disconnect.
- b = registerConnectivityBroadcast(2);
- mCellNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test WiFi disconnect.
- b = registerConnectivityBroadcast(1);
- mWiFiNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyNoNetwork();
- }
-
- @Test
- public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception {
- // Test bringing up unvalidated cellular.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mCellNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test bringing up unvalidated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test WiFi disconnect.
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test cellular disconnect.
- b = registerConnectivityBroadcast(1);
- mCellNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyNoNetwork();
- }
-
- @Test
- public void testUnlingeringDoesNotValidate() throws Exception {
- // Test bringing up unvalidated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- // Test bringing up validated cellular.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- b = registerConnectivityBroadcast(2);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- // Test cellular disconnect.
- b = registerConnectivityBroadcast(2);
- mCellNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Unlingering a network should not cause it to be marked as validated.
- assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- }
-
- @Test
- public void testCellularOutscoresWeakWifi() throws Exception {
- // Test bringing up validated cellular.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test bringing up validated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test WiFi getting really weak.
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.adjustScore(-11);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test WiFi restoring signal strength.
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.adjustScore(11);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- }
-
- @Test
- public void testReapingNetwork() throws Exception {
- // Test bringing up WiFi without NET_CAPABILITY_INTERNET.
- // Expect it to be torn down immediately because it satisfies no requests.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithoutInternet();
- mWiFiNetworkAgent.expectDisconnected();
- // Test bringing up cellular without NET_CAPABILITY_INTERNET.
- // Expect it to be torn down immediately because it satisfies no requests.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mCellNetworkAgent.connectWithoutInternet();
- mCellNetworkAgent.expectDisconnected();
- // Test bringing up validated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test bringing up unvalidated cellular.
- // Expect it to be torn down because it could never be the highest scoring network
- // satisfying the default request even if it validated.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false);
- mCellNetworkAgent.expectDisconnected();
- verifyActiveNetwork(TRANSPORT_WIFI);
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- }
-
- @Test
- public void testCellularFallback() throws Exception {
- // Test bringing up validated cellular.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test bringing up validated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Reevaluate WiFi (it'll instantly fail DNS).
- b = registerConnectivityBroadcast(2);
- assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- mCm.reportBadNetwork(mWiFiNetworkAgent.getNetwork());
- // Should quickly fall back to Cellular.
- b.expectBroadcast();
- assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Reevaluate cellular (it'll instantly fail DNS).
- b = registerConnectivityBroadcast(2);
- assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
- // Should quickly fall back to WiFi.
- b.expectBroadcast();
- assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- verifyActiveNetwork(TRANSPORT_WIFI);
- }
-
- @Test
- public void testWiFiFallback() throws Exception {
- // Test bringing up unvalidated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test bringing up validated cellular.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- b = registerConnectivityBroadcast(2);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Reevaluate cellular (it'll instantly fail DNS).
- b = registerConnectivityBroadcast(2);
- assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
- // Should quickly fall back to WiFi.
- b.expectBroadcast();
- assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- verifyActiveNetwork(TRANSPORT_WIFI);
- }
-
- @Test
- public void testRequiresValidation() {
- assertTrue(NetworkMonitorUtils.isValidationRequired(
- mCm.getDefaultRequest().networkCapabilities));
- }
-
- /**
- * Utility NetworkCallback for testing. The caller must explicitly test for all the callbacks
- * this class receives, by calling expectCallback() exactly once each time a callback is
- * received. assertNoCallback may be called at any time.
- */
- private class TestNetworkCallback extends TestableNetworkCallback {
- TestNetworkCallback() {
- super(TEST_CALLBACK_TIMEOUT_MS);
- }
-
- @Override
- public void assertNoCallback() {
- // TODO: better support this use case in TestableNetworkCallback
- waitForIdle();
- assertNoCallback(0 /* timeout */);
- }
-
- @Override
- public <T extends CallbackEntry> T expectCallback(final KClass<T> type, final HasNetwork n,
- final long timeoutMs) {
- final T callback = super.expectCallback(type, n, timeoutMs);
- if (callback instanceof CallbackEntry.Losing) {
- // TODO : move this to the specific test(s) needing this rather than here.
- final CallbackEntry.Losing losing = (CallbackEntry.Losing) callback;
- final int maxMsToLive = losing.getMaxMsToLive();
- String msg = String.format(
- "Invalid linger time value %d, must be between %d and %d",
- maxMsToLive, 0, mService.mLingerDelayMs);
- assertTrue(msg, 0 <= maxMsToLive && maxMsToLive <= mService.mLingerDelayMs);
- }
- return callback;
- }
- }
-
- // Can't be part of TestNetworkCallback because "cannot be declared static; static methods can
- // only be declared in a static or top level type".
- static void assertNoCallbacks(TestNetworkCallback ... callbacks) {
- for (TestNetworkCallback c : callbacks) {
- c.assertNoCallback();
- }
- }
-
- @Test
- public void testStateChangeNetworkCallbacks() throws Exception {
- final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest genericRequest = new NetworkRequest.Builder()
- .clearCapabilities().build();
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
- mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
- mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
-
- // Test unvalidated networks
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false);
- genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- cellNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- b.expectBroadcast();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- // This should not trigger spurious onAvailable() callbacks, b/21762680.
- mCellNetworkAgent.adjustScore(-1);
- waitForIdle();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- b.expectBroadcast();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- b.expectBroadcast();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- b = registerConnectivityBroadcast(1);
- mCellNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- b.expectBroadcast();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- // Test validated networks
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- genericNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- // This should not trigger spurious onAvailable() callbacks, b/21762680.
- mCellNetworkAgent.adjustScore(-1);
- waitForIdle();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- genericNetworkCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- wifiNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- mWiFiNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- mCellNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
- }
-
- private void doNetworkCallbacksSanitizationTest(boolean sanitized) throws Exception {
- final TestNetworkCallback callback = new TestNetworkCallback();
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- mCm.registerNetworkCallback(wifiRequest, callback);
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- final LinkProperties newLp = new LinkProperties();
- final Uri capportUrl = Uri.parse("https://capport.example.com/api");
- final CaptivePortalData capportData = new CaptivePortalData.Builder()
- .setCaptive(true).build();
-
- final Uri expectedCapportUrl = sanitized ? null : capportUrl;
- newLp.setCaptivePortalApiUrl(capportUrl);
- mWiFiNetworkAgent.sendLinkProperties(newLp);
- callback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
- Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()));
- defaultCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
- Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()));
-
- final CaptivePortalData expectedCapportData = sanitized ? null : capportData;
- mWiFiNetworkAgent.notifyCaptivePortalDataChanged(capportData);
- callback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
- Objects.equals(expectedCapportData, lp.getCaptivePortalData()));
- defaultCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
- Objects.equals(expectedCapportData, lp.getCaptivePortalData()));
-
- final LinkProperties lp = mCm.getLinkProperties(mWiFiNetworkAgent.getNetwork());
- assertEquals(expectedCapportUrl, lp.getCaptivePortalApiUrl());
- assertEquals(expectedCapportData, lp.getCaptivePortalData());
- }
-
- @Test
- public void networkCallbacksSanitizationTest_Sanitize() throws Exception {
- mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- PERMISSION_DENIED);
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
- PERMISSION_DENIED);
- doNetworkCallbacksSanitizationTest(true /* sanitized */);
- }
-
- @Test
- public void networkCallbacksSanitizationTest_NoSanitize_NetworkStack() throws Exception {
- mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- PERMISSION_GRANTED);
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED);
- doNetworkCallbacksSanitizationTest(false /* sanitized */);
- }
-
- @Test
- public void networkCallbacksSanitizationTest_NoSanitize_Settings() throws Exception {
- mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- PERMISSION_DENIED);
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
- doNetworkCallbacksSanitizationTest(false /* sanitized */);
- }
-
- @Test
- public void testMultipleLingering() throws Exception {
- // This test would be flaky with the default 120ms timer: that is short enough that
- // lingered networks are torn down before assertions can be run. We don't want to mock the
- // lingering timer to keep the WakeupMessage logic realistic: this has already proven useful
- // in detecting races.
- mService.mLingerDelayMs = 300;
-
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities().addCapability(NET_CAPABILITY_NOT_METERED)
- .build();
- TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
-
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
-
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mWiFiNetworkAgent.connect(true);
- // We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request.
- // We then get LOSING when wifi validates and cell is outscored.
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- // TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mEthernetNetworkAgent.connect(true);
- callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
- // TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackEntry.LOSING, mWiFiNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
- assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
- defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- for (int i = 0; i < 4; i++) {
- TestNetworkAgentWrapper oldNetwork, newNetwork;
- if (i % 2 == 0) {
- mWiFiNetworkAgent.adjustScore(-15);
- oldNetwork = mWiFiNetworkAgent;
- newNetwork = mCellNetworkAgent;
- } else {
- mWiFiNetworkAgent.adjustScore(15);
- oldNetwork = mCellNetworkAgent;
- newNetwork = mWiFiNetworkAgent;
-
- }
- callback.expectCallback(CallbackEntry.LOSING, oldNetwork);
- // TODO: should we send an AVAILABLE callback to newNetwork, to indicate that it is no
- // longer lingering?
- defaultCallback.expectAvailableCallbacksValidated(newNetwork);
- assertEquals(newNetwork.getNetwork(), mCm.getActiveNetwork());
- }
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Verify that if a network no longer satisfies a request, we send LOST and not LOSING, even
- // if the network is still up.
- mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- // We expect a notification about the capabilities change, and nothing else.
- defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
- defaultCallback.assertNoCallback();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Wifi no longer satisfies our listen, which is for an unmetered network.
- // But because its score is 55, it's still up (and the default network).
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Disconnect our test networks.
- mWiFiNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- waitForIdle();
- assertEquals(null, mCm.getActiveNetwork());
-
- mCm.unregisterNetworkCallback(callback);
- waitForIdle();
-
- // Check that a network is only lingered or torn down if it would not satisfy a request even
- // if it validated.
- request = new NetworkRequest.Builder().clearCapabilities().build();
- callback = new TestNetworkCallback();
-
- mCm.registerNetworkCallback(request, callback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false); // Score: 10
- callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring up wifi with a score of 20.
- // Cell stays up because it would satisfy the default request if it validated.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false); // Score: 20
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring up wifi with a score of 70.
- // Cell is lingered because it would not satisfy any request, even if it validated.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.adjustScore(50);
- mWiFiNetworkAgent.connect(false); // Score: 70
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Tear down wifi.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
- // it's arguably correct to linger it, since it was the default network before it validated.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- // TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- mCellNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- waitForIdle();
- assertEquals(null, mCm.getActiveNetwork());
-
- // If a network is lingering, and we add and remove a request from it, resume lingering.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- // TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- NetworkCallback noopCallback = new NetworkCallback();
- mCm.requestNetwork(cellRequest, noopCallback);
- // TODO: should this cause an AVAILABLE callback, to indicate that the network is no longer
- // lingering?
- mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
-
- // Similar to the above: lingering can start even after the lingered request is removed.
- // Disconnect wifi and switch to cell.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Cell is now the default network. Pin it with a cell-specific request.
- noopCallback = new NetworkCallback(); // Can't reuse NetworkCallbacks. http://b/20701525
- mCm.requestNetwork(cellRequest, noopCallback);
-
- // Now connect wifi, and expect it to become the default network.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- // The default request is lingering on cell, but nothing happens to cell, and we send no
- // callbacks for it, because it's kept up by cellRequest.
- callback.assertNoCallback();
- // Now unregister cellRequest and expect cell to start lingering.
- mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
-
- // Let linger run its course.
- callback.assertNoCallback();
- final int lingerTimeoutMs = mService.mLingerDelayMs + mService.mLingerDelayMs / 4;
- callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent, lingerTimeoutMs);
-
- // Register a TRACK_DEFAULT request and check that it does not affect lingering.
- TestNetworkCallback trackDefaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(trackDefaultCallback);
- trackDefaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
- mEthernetNetworkAgent.connect(true);
- callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mWiFiNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
- trackDefaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Let linger run its course.
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent, lingerTimeoutMs);
-
- // Clean up.
- mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
- trackDefaultCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
-
- mCm.unregisterNetworkCallback(callback);
- mCm.unregisterNetworkCallback(defaultCallback);
- mCm.unregisterNetworkCallback(trackDefaultCallback);
- }
-
- private void grantUsingBackgroundNetworksPermissionForUid(final int uid) throws Exception {
- final String testPackageName = mContext.getPackageName();
- when(mPackageManager.getPackageInfo(eq(testPackageName), eq(GET_PERMISSIONS)))
- .thenReturn(buildPackageInfo(true, uid));
- mService.mPermissionMonitor.onPackageAdded(testPackageName, uid);
- }
-
- @Test
- public void testNetworkGoesIntoBackgroundAfterLinger() throws Exception {
- setAlwaysOnNetworks(true);
- grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities()
- .build();
- TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-
- // Wifi comes up and cell lingers.
- mWiFiNetworkAgent.connect(true);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
-
- // File a request for cellular, then release it.
- NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- NetworkCallback noopCallback = new NetworkCallback();
- mCm.requestNetwork(cellRequest, noopCallback);
- mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
-
- // Let linger run its course.
- callback.assertNoCallback();
- final int lingerTimeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
- callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent,
- lingerTimeoutMs);
-
- // Clean up.
- mCm.unregisterNetworkCallback(defaultCallback);
- mCm.unregisterNetworkCallback(callback);
- }
-
- @Test
- public void testExplicitlySelected() throws Exception {
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
- .build();
- TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- // Bring up validated cell.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-
- // Bring up unvalidated wifi with explicitlySelected=true.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(true, false);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- // Cell Remains the default.
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Lower wifi's score to below than cell, and check that it doesn't disconnect because
- // it's explicitly selected.
- mWiFiNetworkAgent.adjustScore(-40);
- mWiFiNetworkAgent.adjustScore(40);
- callback.assertNoCallback();
-
- // If the user chooses yes on the "No Internet access, stay connected?" dialog, we switch to
- // wifi even though it's unvalidated.
- mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), true, false);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Disconnect wifi, and then reconnect, again with explicitlySelected=true.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(true, false);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- // If the user chooses no on the "No Internet access, stay connected?" dialog, we ask the
- // network to disconnect.
- mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), false, false);
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Reconnect, again with explicitlySelected=true, but this time validate.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(true, false);
- mWiFiNetworkAgent.connect(true);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // BUG: the network will no longer linger, even though it's validated and outscored.
- // TODO: fix this.
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
- mEthernetNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
- assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- callback.assertNoCallback();
-
- // Disconnect wifi, and then reconnect as if the user had selected "yes, don't ask again"
- // (i.e., with explicitlySelected=true and acceptUnvalidated=true). Expect to switch to
- // wifi immediately.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(true, true);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mEthernetNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
-
- // Disconnect and reconnect with explicitlySelected=false and acceptUnvalidated=true.
- // Check that the network is not scored specially and that the device prefers cell data.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(false, true);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Clean up.
- mWiFiNetworkAgent.disconnect();
- mCellNetworkAgent.disconnect();
-
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- }
-
- private int[] makeIntArray(final int size, final int value) {
- final int[] array = new int[size];
- Arrays.fill(array, value);
- return array;
- }
-
- private void tryNetworkFactoryRequests(int capability) throws Exception {
- // Verify NOT_RESTRICTED is set appropriately
- final NetworkCapabilities nc = new NetworkRequest.Builder().addCapability(capability)
- .build().networkCapabilities;
- if (capability == NET_CAPABILITY_CBS || capability == NET_CAPABILITY_DUN ||
- capability == NET_CAPABILITY_EIMS || capability == NET_CAPABILITY_FOTA ||
- capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS ||
- capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP) {
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- } else {
- assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- }
-
- NetworkCapabilities filter = new NetworkCapabilities();
- filter.addCapability(capability);
- final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
- handlerThread.start();
- final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactory", filter);
- testFactory.setScoreFilter(40);
- ConditionVariable cv = testFactory.getNetworkStartedCV();
- testFactory.expectAddRequestsWithScores(0);
- testFactory.register();
- testFactory.waitForNetworkRequests(1);
- int expectedRequestCount = 1;
- NetworkCallback networkCallback = null;
- // For non-INTERNET capabilities we cannot rely on the default request being present, so
- // add one.
- if (capability != NET_CAPABILITY_INTERNET) {
- assertFalse(testFactory.getMyStartRequested());
- NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build();
- networkCallback = new NetworkCallback();
- testFactory.expectAddRequestsWithScores(0); // New request
- mCm.requestNetwork(request, networkCallback);
- expectedRequestCount++;
- testFactory.waitForNetworkRequests(expectedRequestCount);
- }
- waitFor(cv);
- assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
- assertTrue(testFactory.getMyStartRequested());
-
- // Now bring in a higher scored network.
- TestNetworkAgentWrapper testAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- // Rather than create a validated network which complicates things by registering it's
- // own NetworkRequest during startup, just bump up the score to cancel out the
- // unvalidated penalty.
- testAgent.adjustScore(40);
- cv = testFactory.getNetworkStoppedCV();
-
- // When testAgent connects, ConnectivityService will re-send us all current requests with
- // the new score. There are expectedRequestCount such requests, and we must wait for all of
- // them.
- testFactory.expectAddRequestsWithScores(makeIntArray(expectedRequestCount, 50));
- testAgent.connect(false);
- testAgent.addCapability(capability);
- waitFor(cv);
- testFactory.waitForNetworkRequests(expectedRequestCount);
- assertFalse(testFactory.getMyStartRequested());
-
- // Bring in a bunch of requests.
- testFactory.expectAddRequestsWithScores(makeIntArray(10, 50));
- assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
- ConnectivityManager.NetworkCallback[] networkCallbacks =
- new ConnectivityManager.NetworkCallback[10];
- for (int i = 0; i< networkCallbacks.length; i++) {
- networkCallbacks[i] = new ConnectivityManager.NetworkCallback();
- NetworkRequest.Builder builder = new NetworkRequest.Builder();
- builder.addCapability(capability);
- mCm.requestNetwork(builder.build(), networkCallbacks[i]);
- }
- testFactory.waitForNetworkRequests(10 + expectedRequestCount);
- assertFalse(testFactory.getMyStartRequested());
-
- // Remove the requests.
- testFactory.expectRemoveRequests(10);
- for (int i = 0; i < networkCallbacks.length; i++) {
- mCm.unregisterNetworkCallback(networkCallbacks[i]);
- }
- testFactory.waitForNetworkRequests(expectedRequestCount);
- assertFalse(testFactory.getMyStartRequested());
-
- // Drop the higher scored network.
- cv = testFactory.getNetworkStartedCV();
- // With the default network disconnecting, the requests are sent with score 0 to factories.
- testFactory.expectAddRequestsWithScores(makeIntArray(expectedRequestCount, 0));
- testAgent.disconnect();
- waitFor(cv);
- testFactory.waitForNetworkRequests(expectedRequestCount);
- assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
- assertTrue(testFactory.getMyStartRequested());
-
- testFactory.terminate();
- if (networkCallback != null) mCm.unregisterNetworkCallback(networkCallback);
- handlerThread.quit();
- }
-
- @Test
- public void testNetworkFactoryRequests() throws Exception {
- tryNetworkFactoryRequests(NET_CAPABILITY_MMS);
- tryNetworkFactoryRequests(NET_CAPABILITY_SUPL);
- tryNetworkFactoryRequests(NET_CAPABILITY_DUN);
- tryNetworkFactoryRequests(NET_CAPABILITY_FOTA);
- tryNetworkFactoryRequests(NET_CAPABILITY_IMS);
- tryNetworkFactoryRequests(NET_CAPABILITY_CBS);
- tryNetworkFactoryRequests(NET_CAPABILITY_WIFI_P2P);
- tryNetworkFactoryRequests(NET_CAPABILITY_IA);
- tryNetworkFactoryRequests(NET_CAPABILITY_RCS);
- tryNetworkFactoryRequests(NET_CAPABILITY_XCAP);
- tryNetworkFactoryRequests(NET_CAPABILITY_EIMS);
- tryNetworkFactoryRequests(NET_CAPABILITY_NOT_METERED);
- tryNetworkFactoryRequests(NET_CAPABILITY_INTERNET);
- tryNetworkFactoryRequests(NET_CAPABILITY_TRUSTED);
- tryNetworkFactoryRequests(NET_CAPABILITY_NOT_VPN);
- // Skipping VALIDATED and CAPTIVE_PORTAL as they're disallowed.
- }
-
- @Test
- public void testNetworkFactoryUnregister() throws Exception {
- final NetworkCapabilities filter = new NetworkCapabilities();
- filter.clearAll();
-
- final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
- handlerThread.start();
-
- // Checks that calling setScoreFilter on a NetworkFactory immediately before closing it
- // does not crash.
- for (int i = 0; i < 100; i++) {
- final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactory", filter);
- // Register the factory and don't be surprised when the default request arrives.
- testFactory.expectAddRequestsWithScores(0);
- testFactory.register();
- testFactory.waitForNetworkRequests(1);
-
- testFactory.setScoreFilter(42);
- testFactory.terminate();
-
- if (i % 2 == 0) {
- try {
- testFactory.register();
- fail("Re-registering terminated NetworkFactory should throw");
- } catch (IllegalStateException expected) {
- }
- }
- }
- handlerThread.quit();
- }
-
- @Test
- public void testNoMutableNetworkRequests() throws Exception {
- PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("a"), 0);
- NetworkRequest request1 = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_VALIDATED)
- .build();
- NetworkRequest request2 = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL)
- .build();
-
- Class<IllegalArgumentException> expected = IllegalArgumentException.class;
- assertThrows(expected, () -> mCm.requestNetwork(request1, new NetworkCallback()));
- assertThrows(expected, () -> mCm.requestNetwork(request1, pendingIntent));
- assertThrows(expected, () -> mCm.requestNetwork(request2, new NetworkCallback()));
- assertThrows(expected, () -> mCm.requestNetwork(request2, pendingIntent));
- }
-
- @Test
- public void testMMSonWiFi() throws Exception {
- // Test bringing up cellular without MMS NetworkRequest gets reaped
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
- mCellNetworkAgent.connectWithoutInternet();
- mCellNetworkAgent.expectDisconnected();
- waitForIdle();
- assertEmpty(mCm.getAllNetworks());
- verifyNoNetwork();
-
- // Test bringing up validated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
-
- // Register MMS NetworkRequest
- NetworkRequest.Builder builder = new NetworkRequest.Builder();
- builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(builder.build(), networkCallback);
-
- // Test bringing up unvalidated cellular with MMS
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
- mCellNetworkAgent.connectWithoutInternet();
- networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- verifyActiveNetwork(TRANSPORT_WIFI);
-
- // Test releasing NetworkRequest disconnects cellular with MMS
- mCm.unregisterNetworkCallback(networkCallback);
- mCellNetworkAgent.expectDisconnected();
- verifyActiveNetwork(TRANSPORT_WIFI);
- }
-
- @Test
- public void testMMSonCell() throws Exception {
- // Test bringing up cellular without MMS
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
- mCellNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
-
- // Register MMS NetworkRequest
- NetworkRequest.Builder builder = new NetworkRequest.Builder();
- builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(builder.build(), networkCallback);
-
- // Test bringing up MMS cellular network
- TestNetworkAgentWrapper
- mmsNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
- mmsNetworkAgent.connectWithoutInternet();
- networkCallback.expectAvailableCallbacksUnvalidated(mmsNetworkAgent);
- verifyActiveNetwork(TRANSPORT_CELLULAR);
-
- // Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
- mCm.unregisterNetworkCallback(networkCallback);
- mmsNetworkAgent.expectDisconnected();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- }
-
- @Test
- public void testPartialConnectivity() throws Exception {
- // Register network callback.
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
- .build();
- TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- // Bring up validated mobile data.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-
- // Bring up wifi with partial connectivity.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithPartialConnectivity();
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
-
- // Mobile data should be the default network.
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- callback.assertNoCallback();
-
- // With HTTPS probe disabled, NetworkMonitor should pass the network validation with http
- // probe.
- mWiFiNetworkAgent.setNetworkPartialValid(false /* isStrictMode */);
- // If the user chooses yes to use this partial connectivity wifi, switch the default
- // network to wifi and check if wifi becomes valid or not.
- mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */,
- false /* always */);
- // If user accepts partial connectivity network,
- // NetworkMonitor#setAcceptPartialConnectivity() should be called too.
- waitForIdle();
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
-
- // Need a trigger point to let NetworkMonitor tell ConnectivityService that network is
- // validated.
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- NetworkCapabilities nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED,
- mWiFiNetworkAgent);
- assertTrue(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Disconnect and reconnect wifi with partial connectivity again.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithPartialConnectivity();
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
-
- // Mobile data should be the default network.
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // If the user chooses no, disconnect wifi immediately.
- mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), false/* accept */,
- false /* always */);
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // If user accepted partial connectivity before, and device reconnects to that network
- // again, but now the network has full connectivity. The network shouldn't contain
- // NET_CAPABILITY_PARTIAL_CONNECTIVITY.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- // acceptUnvalidated is also used as setting for accepting partial networks.
- mWiFiNetworkAgent.explicitlySelected(true /* explicitlySelected */,
- true /* acceptUnvalidated */);
- mWiFiNetworkAgent.connect(true);
-
- // If user accepted partial connectivity network before,
- // NetworkMonitor#setAcceptPartialConnectivity() will be called in
- // ConnectivityService#updateNetworkInfo().
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- assertFalse(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
-
- // Wifi should be the default network.
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // The user accepted partial connectivity and selected "don't ask again". Now the user
- // reconnects to the partial connectivity network. Switch to wifi as soon as partial
- // connectivity is detected.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(true /* explicitlySelected */,
- true /* acceptUnvalidated */);
- mWiFiNetworkAgent.connectWithPartialConnectivity();
- // If user accepted partial connectivity network before,
- // NetworkMonitor#setAcceptPartialConnectivity() will be called in
- // ConnectivityService#updateNetworkInfo().
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
- mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */);
-
- // Need a trigger point to let NetworkMonitor tell ConnectivityService that network is
- // validated.
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // If the user accepted partial connectivity, and the device auto-reconnects to the partial
- // connectivity network, it should contain both PARTIAL_CONNECTIVITY and VALIDATED.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(false /* explicitlySelected */,
- true /* acceptUnvalidated */);
-
- // NetworkMonitor will immediately (once the HTTPS probe fails...) report the network as
- // valid, because ConnectivityService calls setAcceptPartialConnectivity before it calls
- // notifyNetworkConnected.
- mWiFiNetworkAgent.connectWithPartialValidConnectivity(false /* isStrictMode */);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(
- NET_CAPABILITY_PARTIAL_CONNECTIVITY | NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- }
-
- @Test
- public void testCaptivePortalOnPartialConnectivity() throws Exception {
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- final TestNetworkCallback validatedCallback = new TestNetworkCallback();
- final NetworkRequest validatedRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_VALIDATED).build();
- mCm.registerNetworkCallback(validatedRequest, validatedCallback);
-
- // Bring up a network with a captive portal.
- // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- String redirectUrl = "http://android.com/path";
- mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl, false /* isStrictMode */);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), redirectUrl);
-
- // Check that startCaptivePortalApp sends the expected command to NetworkMonitor.
- mCm.startCaptivePortalApp(mWiFiNetworkAgent.getNetwork());
- verify(mWiFiNetworkAgent.mNetworkMonitor, timeout(TIMEOUT_MS).times(1))
- .launchCaptivePortalApp();
-
- // Report that the captive portal is dismissed with partial connectivity, and check that
- // callbacks are fired.
- mWiFiNetworkAgent.setNetworkPartial();
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- waitForIdle();
- captivePortalCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY,
- mWiFiNetworkAgent);
-
- // Report partial connectivity is accepted.
- mWiFiNetworkAgent.setNetworkPartialValid(false /* isStrictMode */);
- mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */,
- false /* always */);
- waitForIdle();
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- NetworkCapabilities nc =
- validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY,
- mWiFiNetworkAgent);
-
- mCm.unregisterNetworkCallback(captivePortalCallback);
- mCm.unregisterNetworkCallback(validatedCallback);
- }
-
- @Test
- public void testCaptivePortal() throws Exception {
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- final TestNetworkCallback validatedCallback = new TestNetworkCallback();
- final NetworkRequest validatedRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_VALIDATED).build();
- mCm.registerNetworkCallback(validatedRequest, validatedCallback);
-
- // Bring up a network with a captive portal.
- // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- String firstRedirectUrl = "http://example.com/firstPath";
- mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl, false /* isStrictMode */);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl);
-
- // Take down network.
- // Expect onLost callback.
- mWiFiNetworkAgent.disconnect();
- captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Bring up a network with a captive portal.
- // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- String secondRedirectUrl = "http://example.com/secondPath";
- mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl, false /* isStrictMode */);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl);
-
- // Make captive portal disappear then revalidate.
- // Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
- mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */);
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
- validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
-
- // Break network connectivity.
- // Expect NET_CAPABILITY_VALIDATED onLost callback.
- mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */);
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
- validatedCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- }
-
- @Test
- public void testCaptivePortalApp() throws Exception {
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- final TestNetworkCallback validatedCallback = new TestNetworkCallback();
- final NetworkRequest validatedRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_VALIDATED).build();
- mCm.registerNetworkCallback(validatedRequest, validatedCallback);
-
- // Bring up wifi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
-
- // Check that calling startCaptivePortalApp does nothing.
- final int fastTimeoutMs = 100;
- mCm.startCaptivePortalApp(wifiNetwork);
- waitForIdle();
- verify(mWiFiNetworkAgent.mNetworkMonitor, never()).launchCaptivePortalApp();
- mServiceContext.expectNoStartActivityIntent(fastTimeoutMs);
-
- // Turn into a captive portal.
- mWiFiNetworkAgent.setNetworkPortal("http://example.com", false /* isStrictMode */);
- mCm.reportNetworkConnectivity(wifiNetwork, false);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- validatedCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Check that startCaptivePortalApp sends the expected command to NetworkMonitor.
- mCm.startCaptivePortalApp(wifiNetwork);
- waitForIdle();
- verify(mWiFiNetworkAgent.mNetworkMonitor).launchCaptivePortalApp();
-
- // NetworkMonitor uses startCaptivePortal(Network, Bundle) (startCaptivePortalAppInternal)
- final Bundle testBundle = new Bundle();
- final String testKey = "testkey";
- final String testValue = "testvalue";
- testBundle.putString(testKey, testValue);
- mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- PERMISSION_GRANTED);
- mCm.startCaptivePortalApp(wifiNetwork, testBundle);
- final Intent signInIntent = mServiceContext.expectStartActivityIntent(TIMEOUT_MS);
- assertEquals(ACTION_CAPTIVE_PORTAL_SIGN_IN, signInIntent.getAction());
- assertEquals(testValue, signInIntent.getStringExtra(testKey));
-
- // Report that the captive portal is dismissed, and check that callbacks are fired
- mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */);
- mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- mCm.unregisterNetworkCallback(validatedCallback);
- mCm.unregisterNetworkCallback(captivePortalCallback);
- }
-
- @Test
- public void testAvoidOrIgnoreCaptivePortals() throws Exception {
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- final TestNetworkCallback validatedCallback = new TestNetworkCallback();
- final NetworkRequest validatedRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_VALIDATED).build();
- mCm.registerNetworkCallback(validatedRequest, validatedCallback);
-
- setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_AVOID);
- // Bring up a network with a captive portal.
- // Expect it to fail to connect and not result in any callbacks.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- String firstRedirectUrl = "http://example.com/firstPath";
-
- mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl, false /* isStrictMode */);
- mWiFiNetworkAgent.expectDisconnected();
- mWiFiNetworkAgent.expectPreventReconnectReceived();
-
- assertNoCallbacks(captivePortalCallback, validatedCallback);
- }
-
- @Test
- public void testCaptivePortalApi() throws Exception {
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final String redirectUrl = "http://example.com/firstPath";
-
- mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl, false /* isStrictMode */);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- final CaptivePortalData testData = new CaptivePortalData.Builder()
- .setUserPortalUrl(Uri.parse(redirectUrl))
- .setBytesRemaining(12345L)
- .build();
-
- mWiFiNetworkAgent.notifyCaptivePortalDataChanged(testData);
-
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> testData.equals(lp.getCaptivePortalData()));
-
- final LinkProperties newLps = new LinkProperties();
- newLps.setMtu(1234);
- mWiFiNetworkAgent.sendLinkProperties(newLps);
- // CaptivePortalData is not lost and unchanged when LPs are received from the NetworkAgent
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> testData.equals(lp.getCaptivePortalData()) && lp.getMtu() == 1234);
- }
-
- private NetworkRequest.Builder newWifiRequestBuilder() {
- return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI);
- }
-
- /**
- * Verify request matching behavior with network specifiers.
- *
- * Note: this test is somewhat problematic since it involves removing capabilities from
- * agents - i.e. agents rejecting requests which they previously accepted. This is flagged
- * as a WTF bug in
- * {@link ConnectivityService#mixInCapabilities(NetworkAgentInfo, NetworkCapabilities)} but
- * does work.
- */
- @Test
- public void testNetworkSpecifier() throws Exception {
- // A NetworkSpecifier subclass that matches all networks but must not be visible to apps.
- class ConfidentialMatchAllNetworkSpecifier extends NetworkSpecifier implements
- Parcelable {
- @Override
- public boolean canBeSatisfiedBy(NetworkSpecifier other) {
- return true;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {}
-
- @Override
- public NetworkSpecifier redact() {
- return null;
- }
- }
-
- // A network specifier that matches either another LocalNetworkSpecifier with the same
- // string or a ConfidentialMatchAllNetworkSpecifier, and can be passed to apps as is.
- class LocalStringNetworkSpecifier extends NetworkSpecifier implements Parcelable {
- private String mString;
-
- LocalStringNetworkSpecifier(String string) {
- mString = string;
- }
-
- @Override
- public boolean canBeSatisfiedBy(NetworkSpecifier other) {
- if (other instanceof LocalStringNetworkSpecifier) {
- return TextUtils.equals(mString,
- ((LocalStringNetworkSpecifier) other).mString);
- }
- if (other instanceof ConfidentialMatchAllNetworkSpecifier) return true;
- return false;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
- @Override
- public void writeToParcel(Parcel dest, int flags) {}
- }
-
-
- NetworkRequest rEmpty1 = newWifiRequestBuilder().build();
- NetworkRequest rEmpty2 = newWifiRequestBuilder().setNetworkSpecifier((String) null).build();
- NetworkRequest rEmpty3 = newWifiRequestBuilder().setNetworkSpecifier("").build();
- NetworkRequest rEmpty4 = newWifiRequestBuilder().setNetworkSpecifier(
- (NetworkSpecifier) null).build();
- NetworkRequest rFoo = newWifiRequestBuilder().setNetworkSpecifier(
- new LocalStringNetworkSpecifier("foo")).build();
- NetworkRequest rBar = newWifiRequestBuilder().setNetworkSpecifier(
- new LocalStringNetworkSpecifier("bar")).build();
-
- TestNetworkCallback cEmpty1 = new TestNetworkCallback();
- TestNetworkCallback cEmpty2 = new TestNetworkCallback();
- TestNetworkCallback cEmpty3 = new TestNetworkCallback();
- TestNetworkCallback cEmpty4 = new TestNetworkCallback();
- TestNetworkCallback cFoo = new TestNetworkCallback();
- TestNetworkCallback cBar = new TestNetworkCallback();
- TestNetworkCallback[] emptyCallbacks = new TestNetworkCallback[] {
- cEmpty1, cEmpty2, cEmpty3, cEmpty4 };
-
- mCm.registerNetworkCallback(rEmpty1, cEmpty1);
- mCm.registerNetworkCallback(rEmpty2, cEmpty2);
- mCm.registerNetworkCallback(rEmpty3, cEmpty3);
- mCm.registerNetworkCallback(rEmpty4, cEmpty4);
- mCm.registerNetworkCallback(rFoo, cFoo);
- mCm.registerNetworkCallback(rBar, cBar);
-
- LocalStringNetworkSpecifier nsFoo = new LocalStringNetworkSpecifier("foo");
- LocalStringNetworkSpecifier nsBar = new LocalStringNetworkSpecifier("bar");
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- cEmpty1.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- cEmpty2.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- cEmpty3.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- cEmpty4.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertNoCallbacks(cFoo, cBar);
-
- mWiFiNetworkAgent.setNetworkSpecifier(nsFoo);
- cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- for (TestNetworkCallback c: emptyCallbacks) {
- c.expectCapabilitiesThat(mWiFiNetworkAgent,
- (caps) -> caps.getNetworkSpecifier().equals(nsFoo));
- }
- cFoo.expectCapabilitiesThat(mWiFiNetworkAgent,
- (caps) -> caps.getNetworkSpecifier().equals(nsFoo));
- assertEquals(nsFoo,
- mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
- cFoo.assertNoCallback();
-
- mWiFiNetworkAgent.setNetworkSpecifier(nsBar);
- cFoo.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- cBar.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- for (TestNetworkCallback c: emptyCallbacks) {
- c.expectCapabilitiesThat(mWiFiNetworkAgent,
- (caps) -> caps.getNetworkSpecifier().equals(nsBar));
- }
- cBar.expectCapabilitiesThat(mWiFiNetworkAgent,
- (caps) -> caps.getNetworkSpecifier().equals(nsBar));
- assertEquals(nsBar,
- mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
- cBar.assertNoCallback();
-
- mWiFiNetworkAgent.setNetworkSpecifier(new ConfidentialMatchAllNetworkSpecifier());
- cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- for (TestNetworkCallback c : emptyCallbacks) {
- c.expectCapabilitiesThat(mWiFiNetworkAgent,
- (caps) -> caps.getNetworkSpecifier() == null);
- }
- cFoo.expectCapabilitiesThat(mWiFiNetworkAgent,
- (caps) -> caps.getNetworkSpecifier() == null);
- cBar.expectCapabilitiesThat(mWiFiNetworkAgent,
- (caps) -> caps.getNetworkSpecifier() == null);
- assertNull(
- mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
- cFoo.assertNoCallback();
- cBar.assertNoCallback();
-
- mWiFiNetworkAgent.setNetworkSpecifier(null);
- cFoo.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- cBar.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- for (TestNetworkCallback c: emptyCallbacks) {
- c.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mWiFiNetworkAgent);
- }
-
- assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar);
- }
-
- @Test
- public void testInvalidNetworkSpecifier() {
- assertThrows(IllegalArgumentException.class, () -> {
- NetworkRequest.Builder builder = new NetworkRequest.Builder();
- builder.setNetworkSpecifier(new MatchAllNetworkSpecifier());
- });
-
- assertThrows(IllegalArgumentException.class, () -> {
- NetworkCapabilities networkCapabilities = new NetworkCapabilities();
- networkCapabilities.addTransportType(TRANSPORT_WIFI)
- .setNetworkSpecifier(new MatchAllNetworkSpecifier());
- mService.requestNetwork(networkCapabilities, null, 0, null,
- ConnectivityManager.TYPE_WIFI, mContext.getPackageName());
- });
-
- class NonParcelableSpecifier extends NetworkSpecifier {
- @Override
- public boolean canBeSatisfiedBy(NetworkSpecifier other) {
- return false;
- }
- };
- class ParcelableSpecifier extends NonParcelableSpecifier implements Parcelable {
- @Override public int describeContents() { return 0; }
- @Override public void writeToParcel(Parcel p, int flags) {}
- }
-
- final NetworkRequest.Builder builder =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET);
- assertThrows(ClassCastException.class, () -> {
- builder.setNetworkSpecifier(new NonParcelableSpecifier());
- Parcel parcelW = Parcel.obtain();
- builder.build().writeToParcel(parcelW, 0);
- });
-
- final NetworkRequest nr =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET)
- .setNetworkSpecifier(new ParcelableSpecifier())
- .build();
- assertNotNull(nr);
-
- assertThrows(BadParcelableException.class, () -> {
- Parcel parcelW = Parcel.obtain();
- nr.writeToParcel(parcelW, 0);
- byte[] bytes = parcelW.marshall();
- parcelW.recycle();
-
- Parcel parcelR = Parcel.obtain();
- parcelR.unmarshall(bytes, 0, bytes.length);
- parcelR.setDataPosition(0);
- NetworkRequest rereadNr = NetworkRequest.CREATOR.createFromParcel(parcelR);
- });
- }
-
- @Test
- public void testNetworkRequestUidSpoofSecurityException() throws Exception {
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- NetworkRequest networkRequest = newWifiRequestBuilder().build();
- TestNetworkCallback networkCallback = new TestNetworkCallback();
- doThrow(new SecurityException()).when(mAppOpsManager).checkPackage(anyInt(), anyString());
- assertThrows(SecurityException.class, () -> {
- mCm.requestNetwork(networkRequest, networkCallback);
- });
- }
-
- @Test
- public void testInvalidSignalStrength() {
- NetworkRequest r = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addTransportType(TRANSPORT_WIFI)
- .setSignalStrength(-75)
- .build();
- // Registering a NetworkCallback with signal strength but w/o NETWORK_SIGNAL_STRENGTH_WAKEUP
- // permission should get SecurityException.
- assertThrows(SecurityException.class, () ->
- mCm.registerNetworkCallback(r, new NetworkCallback()));
-
- assertThrows(SecurityException.class, () ->
- mCm.registerNetworkCallback(r, PendingIntent.getService(
- mServiceContext, 0, new Intent(), 0)));
-
- // Requesting a Network with signal strength should get IllegalArgumentException.
- assertThrows(IllegalArgumentException.class, () ->
- mCm.requestNetwork(r, new NetworkCallback()));
-
- assertThrows(IllegalArgumentException.class, () ->
- mCm.requestNetwork(r, PendingIntent.getService(
- mServiceContext, 0, new Intent(), 0)));
- }
-
- @Test
- public void testRegisterDefaultNetworkCallback() throws Exception {
- final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
- defaultNetworkCallback.assertNoCallback();
-
- // Create a TRANSPORT_CELLULAR request to keep the mobile interface up
- // whenever Wi-Fi is up. Without this, the mobile network agent is
- // reaped before any other activity can take place.
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.requestNetwork(cellRequest, cellNetworkCallback);
- cellNetworkCallback.assertNoCallback();
-
- // Bring up cell and expect CALLBACK_AVAILABLE.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring up wifi and expect CALLBACK_AVAILABLE.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- cellNetworkCallback.assertNoCallback();
- defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring down cell. Expect no default network callback, since it wasn't the default.
- mCellNetworkAgent.disconnect();
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultNetworkCallback.assertNoCallback();
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring up cell. Expect no default network callback, since it won't be the default.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultNetworkCallback.assertNoCallback();
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring down wifi. Expect the default network callback to notified of LOST wifi
- // followed by AVAILABLE cell.
- mWiFiNetworkAgent.disconnect();
- cellNetworkCallback.assertNoCallback();
- defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- mCellNetworkAgent.disconnect();
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- waitForIdle();
- assertEquals(null, mCm.getActiveNetwork());
-
- mMockVpn.establishForMyUid();
- defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mMockVpn.disconnect();
- defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- waitForIdle();
- assertEquals(null, mCm.getActiveNetwork());
- }
-
- @Test
- public void testAdditionalStateCallbacks() throws Exception {
- // File a network request for mobile.
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.requestNetwork(cellRequest, cellNetworkCallback);
-
- // Bring up the mobile network.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- // We should get onAvailable(), onCapabilitiesChanged(), and
- // onLinkPropertiesChanged() in rapid succession. Additionally, we
- // should get onCapabilitiesChanged() when the mobile network validates.
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
-
- // Update LinkProperties.
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("foonet_data0");
- mCellNetworkAgent.sendLinkProperties(lp);
- // We should get onLinkPropertiesChanged().
- cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
-
- // Suspend the network.
- mCellNetworkAgent.suspend();
- cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_SUSPENDED,
- mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.SUSPENDED, mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertEquals(NetworkInfo.State.SUSPENDED, mCm.getActiveNetworkInfo().getState());
-
- // Register a garden variety default network request.
- TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
- // We should get onAvailable(), onCapabilitiesChanged(), onLinkPropertiesChanged(),
- // as well as onNetworkSuspended() in rapid succession.
- dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent, true);
- dfltNetworkCallback.assertNoCallback();
- mCm.unregisterNetworkCallback(dfltNetworkCallback);
-
- mCellNetworkAgent.resume();
- cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_SUSPENDED,
- mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.RESUMED, mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertEquals(NetworkInfo.State.CONNECTED, mCm.getActiveNetworkInfo().getState());
-
- dfltNetworkCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
- // This time onNetworkSuspended should not be called.
- dfltNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- dfltNetworkCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(dfltNetworkCallback);
- mCm.unregisterNetworkCallback(cellNetworkCallback);
- }
-
- private void setCaptivePortalMode(int mode) {
- ContentResolver cr = mServiceContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, mode);
- }
-
- private void setAlwaysOnNetworks(boolean enable) {
- ContentResolver cr = mServiceContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0);
- mService.updateAlwaysOnNetworks();
- waitForIdle();
- }
-
- private void setPrivateDnsSettings(String mode, String specifier) {
- final ContentResolver cr = mServiceContext.getContentResolver();
- Settings.Global.putString(cr, Settings.Global.PRIVATE_DNS_MODE, mode);
- Settings.Global.putString(cr, Settings.Global.PRIVATE_DNS_SPECIFIER, specifier);
- mService.updatePrivateDnsSettings();
- waitForIdle();
- }
-
- private boolean isForegroundNetwork(TestNetworkAgentWrapper network) {
- NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
- assertNotNull(nc);
- return nc.hasCapability(NET_CAPABILITY_FOREGROUND);
- }
-
- @Test
- public void testBackgroundNetworks() throws Exception {
- // Create a background request. We can't do this ourselves because ConnectivityService
- // doesn't have an API for it. So just turn on mobile data always on.
- setAlwaysOnNetworks(true);
- grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
- final NetworkRequest request = new NetworkRequest.Builder().build();
- final NetworkRequest fgRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_FOREGROUND).build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- final TestNetworkCallback fgCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
- mCm.registerNetworkCallback(fgRequest, fgCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- fgCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertTrue(isForegroundNetwork(mCellNetworkAgent));
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
-
- // When wifi connects, cell lingers.
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- fgCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- assertTrue(isForegroundNetwork(mCellNetworkAgent));
- assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
-
- // When lingering is complete, cell is still there but is now in the background.
- waitForIdle();
- int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
- fgCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent, timeoutMs);
- // Expect a network capabilities update sans FOREGROUND.
- callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
- assertFalse(isForegroundNetwork(mCellNetworkAgent));
- assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
-
- // File a cell request and check that cell comes into the foreground.
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- final TestNetworkCallback cellCallback = new TestNetworkCallback();
- mCm.requestNetwork(cellRequest, cellCallback);
- cellCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- // Expect a network capabilities update with FOREGROUND, because the most recent
- // request causes its state to change.
- cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
- assertTrue(isForegroundNetwork(mCellNetworkAgent));
- assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
-
- // Release the request. The network immediately goes into the background, since it was not
- // lingering.
- mCm.unregisterNetworkCallback(cellCallback);
- fgCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- // Expect a network capabilities update sans FOREGROUND.
- callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
- assertFalse(isForegroundNetwork(mCellNetworkAgent));
- assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
-
- // Disconnect wifi and check that cell is foreground again.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertTrue(isForegroundNetwork(mCellNetworkAgent));
-
- mCm.unregisterNetworkCallback(callback);
- mCm.unregisterNetworkCallback(fgCallback);
- }
-
- @Ignore // This test has instrinsic chances of spurious failures: ignore for continuous testing.
- public void benchmarkRequestRegistrationAndCallbackDispatch() throws Exception {
- // TODO: turn this unit test into a real benchmarking test.
- // Benchmarks connecting and switching performance in the presence of a large number of
- // NetworkRequests.
- // 1. File NUM_REQUESTS requests.
- // 2. Have a network connect. Wait for NUM_REQUESTS onAvailable callbacks to fire.
- // 3. Have a new network connect and outscore the previous. Wait for NUM_REQUESTS onLosing
- // and NUM_REQUESTS onAvailable callbacks to fire.
- // See how long it took.
- final int NUM_REQUESTS = 90;
- final int REGISTER_TIME_LIMIT_MS = 200;
- final int CONNECT_TIME_LIMIT_MS = 60;
- final int SWITCH_TIME_LIMIT_MS = 60;
- final int UNREGISTER_TIME_LIMIT_MS = 20;
-
- final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
- final NetworkCallback[] callbacks = new NetworkCallback[NUM_REQUESTS];
- final CountDownLatch availableLatch = new CountDownLatch(NUM_REQUESTS);
- final CountDownLatch losingLatch = new CountDownLatch(NUM_REQUESTS);
-
- for (int i = 0; i < NUM_REQUESTS; i++) {
- callbacks[i] = new NetworkCallback() {
- @Override public void onAvailable(Network n) { availableLatch.countDown(); }
- @Override public void onLosing(Network n, int t) { losingLatch.countDown(); }
- };
- }
-
- assertRunsInAtMost("Registering callbacks", REGISTER_TIME_LIMIT_MS, () -> {
- for (NetworkCallback cb : callbacks) {
- mCm.registerNetworkCallback(request, cb);
- }
- });
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- // Don't request that the network validate, because otherwise connect() will block until
- // the network gets NET_CAPABILITY_VALIDATED, after all the callbacks below have fired,
- // and we won't actually measure anything.
- mCellNetworkAgent.connect(false);
-
- long onAvailableDispatchingDuration = durationOf(() -> {
- await(availableLatch, 10 * CONNECT_TIME_LIMIT_MS);
- });
- Log.d(TAG, String.format("Dispatched %d of %d onAvailable callbacks in %dms",
- NUM_REQUESTS - availableLatch.getCount(), NUM_REQUESTS,
- onAvailableDispatchingDuration));
- assertTrue(String.format("Dispatching %d onAvailable callbacks in %dms, expected %dms",
- NUM_REQUESTS, onAvailableDispatchingDuration, CONNECT_TIME_LIMIT_MS),
- onAvailableDispatchingDuration <= CONNECT_TIME_LIMIT_MS);
-
- // Give wifi a high enough score that we'll linger cell when wifi comes up.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.adjustScore(40);
- mWiFiNetworkAgent.connect(false);
-
- long onLostDispatchingDuration = durationOf(() -> {
- await(losingLatch, 10 * SWITCH_TIME_LIMIT_MS);
- });
- Log.d(TAG, String.format("Dispatched %d of %d onLosing callbacks in %dms",
- NUM_REQUESTS - losingLatch.getCount(), NUM_REQUESTS, onLostDispatchingDuration));
- assertTrue(String.format("Dispatching %d onLosing callbacks in %dms, expected %dms",
- NUM_REQUESTS, onLostDispatchingDuration, SWITCH_TIME_LIMIT_MS),
- onLostDispatchingDuration <= SWITCH_TIME_LIMIT_MS);
-
- assertRunsInAtMost("Unregistering callbacks", UNREGISTER_TIME_LIMIT_MS, () -> {
- for (NetworkCallback cb : callbacks) {
- mCm.unregisterNetworkCallback(cb);
- }
- });
- }
-
- @Test
- public void testMobileDataAlwaysOn() throws Exception {
- grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
-
- final HandlerThread handlerThread = new HandlerThread("MobileDataAlwaysOnFactory");
- handlerThread.start();
- NetworkCapabilities filter = new NetworkCapabilities()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET);
- final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactory", filter);
- testFactory.setScoreFilter(40);
-
- // Register the factory and expect it to start looking for a network.
- testFactory.expectAddRequestsWithScores(0); // Score 0 as the request is not served yet.
- testFactory.register();
- testFactory.waitForNetworkRequests(1);
- assertTrue(testFactory.getMyStartRequested());
-
- // Bring up wifi. The factory stops looking for a network.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- // Score 60 - 40 penalty for not validated yet, then 60 when it validates
- testFactory.expectAddRequestsWithScores(20, 60);
- mWiFiNetworkAgent.connect(true);
- testFactory.waitForRequests();
- assertFalse(testFactory.getMyStartRequested());
-
- ContentResolver cr = mServiceContext.getContentResolver();
-
- // Turn on mobile data always on. The factory starts looking again.
- testFactory.expectAddRequestsWithScores(0); // Always on requests comes up with score 0
- setAlwaysOnNetworks(true);
- testFactory.waitForNetworkRequests(2);
- assertTrue(testFactory.getMyStartRequested());
-
- // Bring up cell data and check that the factory stops looking.
- assertLength(1, mCm.getAllNetworks());
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- testFactory.expectAddRequestsWithScores(10, 50); // Unvalidated, then validated
- mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- testFactory.waitForNetworkRequests(2);
- assertFalse(testFactory.getMyStartRequested()); // Because the cell network outscores us.
-
- // Check that cell data stays up.
- waitForIdle();
- verifyActiveNetwork(TRANSPORT_WIFI);
- assertLength(2, mCm.getAllNetworks());
-
- // Turn off mobile data always on and expect the request to disappear...
- testFactory.expectRemoveRequests(1);
- setAlwaysOnNetworks(false);
- testFactory.waitForNetworkRequests(1);
-
- // ... and cell data to be torn down.
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- assertLength(1, mCm.getAllNetworks());
-
- testFactory.terminate();
- mCm.unregisterNetworkCallback(cellNetworkCallback);
- handlerThread.quit();
- }
-
- @Test
- public void testAvoidBadWifiSetting() throws Exception {
- final ContentResolver cr = mServiceContext.getContentResolver();
- final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
-
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
- String[] values = new String[] {null, "0", "1"};
- for (int i = 0; i < values.length; i++) {
- Settings.Global.putInt(cr, settingName, 1);
- mPolicyTracker.reevaluate();
- waitForIdle();
- String msg = String.format("config=false, setting=%s", values[i]);
- assertTrue(mService.avoidBadWifi());
- assertFalse(msg, mPolicyTracker.shouldNotifyWifiUnvalidated());
- }
-
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
-
- Settings.Global.putInt(cr, settingName, 0);
- mPolicyTracker.reevaluate();
- waitForIdle();
- assertFalse(mService.avoidBadWifi());
- assertFalse(mPolicyTracker.shouldNotifyWifiUnvalidated());
-
- Settings.Global.putInt(cr, settingName, 1);
- mPolicyTracker.reevaluate();
- waitForIdle();
- assertTrue(mService.avoidBadWifi());
- assertFalse(mPolicyTracker.shouldNotifyWifiUnvalidated());
-
- Settings.Global.putString(cr, settingName, null);
- mPolicyTracker.reevaluate();
- waitForIdle();
- assertFalse(mService.avoidBadWifi());
- assertTrue(mPolicyTracker.shouldNotifyWifiUnvalidated());
- }
-
- @Test
- public void testAvoidBadWifi() throws Exception {
- final ContentResolver cr = mServiceContext.getContentResolver();
-
- // Pretend we're on a carrier that restricts switching away from bad wifi.
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
-
- // File a request for cell to ensure it doesn't go down.
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.requestNetwork(cellRequest, cellNetworkCallback);
-
- TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- NetworkRequest validatedWifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI)
- .addCapability(NET_CAPABILITY_VALIDATED)
- .build();
- TestNetworkCallback validatedWifiCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);
-
- Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 0);
- mPolicyTracker.reevaluate();
-
- // Bring up validated cell.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- Network cellNetwork = mCellNetworkAgent.getNetwork();
-
- // Bring up validated wifi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
-
- // Fail validation on wifi.
- mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */);
- mCm.reportNetworkConnectivity(wifiNetwork, false);
- defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Because avoid bad wifi is off, we don't switch to cellular.
- defaultCallback.assertNoCallback();
- assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertEquals(mCm.getActiveNetwork(), wifiNetwork);
-
- // Simulate switching to a carrier that does not restrict avoiding bad wifi, and expect
- // that we switch back to cell.
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
- mPolicyTracker.reevaluate();
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertEquals(mCm.getActiveNetwork(), cellNetwork);
-
- // Switch back to a restrictive carrier.
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
- mPolicyTracker.reevaluate();
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mCm.getActiveNetwork(), wifiNetwork);
-
- // Simulate the user selecting "switch" on the dialog, and check that we switch to cell.
- mCm.setAvoidUnvalidated(wifiNetwork);
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertEquals(mCm.getActiveNetwork(), cellNetwork);
-
- // Disconnect and reconnect wifi to clear the one-time switch above.
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- wifiNetwork = mWiFiNetworkAgent.getNetwork();
-
- // Fail validation on wifi and expect the dialog to appear.
- mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */);
- mCm.reportNetworkConnectivity(wifiNetwork, false);
- defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Simulate the user selecting "switch" and checking the don't ask again checkbox.
- Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
- mPolicyTracker.reevaluate();
-
- // We now switch to cell.
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertEquals(mCm.getActiveNetwork(), cellNetwork);
-
- // Simulate the user turning the cellular fallback setting off and then on.
- // We switch to wifi and then to cell.
- Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
- mPolicyTracker.reevaluate();
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mCm.getActiveNetwork(), wifiNetwork);
- Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
- mPolicyTracker.reevaluate();
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertEquals(mCm.getActiveNetwork(), cellNetwork);
-
- // If cell goes down, we switch to wifi.
- mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- validatedWifiCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(cellNetworkCallback);
- mCm.unregisterNetworkCallback(validatedWifiCallback);
- mCm.unregisterNetworkCallback(defaultCallback);
- }
-
- @Test
- public void testMeteredMultipathPreferenceSetting() throws Exception {
- final ContentResolver cr = mServiceContext.getContentResolver();
- final String settingName = Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
-
- for (int config : Arrays.asList(0, 3, 2)) {
- for (String setting: Arrays.asList(null, "0", "2", "1")) {
- mPolicyTracker.mConfigMeteredMultipathPreference = config;
- Settings.Global.putString(cr, settingName, setting);
- mPolicyTracker.reevaluate();
- waitForIdle();
-
- final int expected = (setting != null) ? Integer.parseInt(setting) : config;
- String msg = String.format("config=%d, setting=%s", config, setting);
- assertEquals(msg, expected, mCm.getMultipathPreference(null));
- }
- }
- }
-
- /**
- * Validate that a satisfied network request does not trigger onUnavailable() once the
- * time-out period expires.
- */
- @Test
- public void testSatisfiedNetworkRequestDoesNotTriggerOnUnavailable() throws Exception {
- NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
- NetworkCapabilities.TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false,
- TEST_CALLBACK_TIMEOUT_MS);
-
- // pass timeout and validate that UNAVAILABLE is not called
- networkCallback.assertNoCallback();
- }
-
- /**
- * Validate that a satisfied network request followed by a disconnected (lost) network does
- * not trigger onUnavailable() once the time-out period expires.
- */
- @Test
- public void testSatisfiedThenLostNetworkRequestDoesNotTriggerOnUnavailable() throws Exception {
- NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
- NetworkCapabilities.TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false,
- TEST_CALLBACK_TIMEOUT_MS);
- mWiFiNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Validate that UNAVAILABLE is not called
- networkCallback.assertNoCallback();
- }
-
- /**
- * Validate that when a time-out is specified for a network request the onUnavailable()
- * callback is called when time-out expires. Then validate that if network request is
- * (somehow) satisfied - the callback isn't called later.
- */
- @Test
- public void testTimedoutNetworkRequest() throws Exception {
- NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
- NetworkCapabilities.TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- final int timeoutMs = 10;
- mCm.requestNetwork(nr, networkCallback, timeoutMs);
-
- // pass timeout and validate that UNAVAILABLE is called
- networkCallback.expectCallback(CallbackEntry.UNAVAILABLE, (Network) null);
-
- // create a network satisfying request - validate that request not triggered
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- networkCallback.assertNoCallback();
- }
-
- /**
- * Validate that when a network request is unregistered (cancelled), no posterior event can
- * trigger the callback.
- */
- @Test
- public void testNoCallbackAfterUnregisteredNetworkRequest() throws Exception {
- NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
- NetworkCapabilities.TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- final int timeoutMs = 10;
-
- mCm.requestNetwork(nr, networkCallback, timeoutMs);
- mCm.unregisterNetworkCallback(networkCallback);
- // Regardless of the timeout, unregistering the callback in ConnectivityManager ensures
- // that this callback will not be called.
- networkCallback.assertNoCallback();
-
- // create a network satisfying request - validate that request not triggered
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- networkCallback.assertNoCallback();
- }
-
- @Test
- public void testUnfulfillableNetworkRequest() throws Exception {
- runUnfulfillableNetworkRequest(false);
- }
-
- @Test
- public void testUnfulfillableNetworkRequestAfterUnregister() throws Exception {
- runUnfulfillableNetworkRequest(true);
- }
-
- /**
- * Validate the callback flow for a factory releasing a request as unfulfillable.
- */
- private void runUnfulfillableNetworkRequest(boolean preUnregister) throws Exception {
- NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
- NetworkCapabilities.TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
-
- final HandlerThread handlerThread = new HandlerThread("testUnfulfillableNetworkRequest");
- handlerThread.start();
- NetworkCapabilities filter = new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .addCapability(NET_CAPABILITY_INTERNET);
- final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactory", filter);
- testFactory.setScoreFilter(40);
-
- // Register the factory and expect it to receive the default request.
- testFactory.expectAddRequestsWithScores(0);
- testFactory.register();
- SparseArray<NetworkRequest> requests = testFactory.waitForNetworkRequests(1);
-
- assertEquals(1, requests.size()); // have 1 request at this point
- int origRequestId = requests.valueAt(0).requestId;
-
- // Now file the test request and expect it.
- testFactory.expectAddRequestsWithScores(0);
- mCm.requestNetwork(nr, networkCallback);
- requests = testFactory.waitForNetworkRequests(2); // have 2 requests at this point
-
- int newRequestId = 0;
- for (int i = 0; i < requests.size(); ++i) {
- if (requests.valueAt(i).requestId != origRequestId) {
- newRequestId = requests.valueAt(i).requestId;
- break;
- }
- }
-
- testFactory.expectRemoveRequests(1);
- if (preUnregister) {
- mCm.unregisterNetworkCallback(networkCallback);
-
- // Simulate the factory releasing the request as unfulfillable: no-op since
- // the callback has already been unregistered (but a test that no exceptions are
- // thrown).
- testFactory.triggerUnfulfillable(requests.get(newRequestId));
- } else {
- // Simulate the factory releasing the request as unfulfillable and expect onUnavailable!
- testFactory.triggerUnfulfillable(requests.get(newRequestId));
-
- networkCallback.expectCallback(CallbackEntry.UNAVAILABLE, (Network) null);
- testFactory.waitForRequests();
-
- // unregister network callback - a no-op (since already freed by the
- // on-unavailable), but should not fail or throw exceptions.
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- testFactory.terminate();
- handlerThread.quit();
- }
-
- private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
-
- public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR }
-
- private class CallbackValue {
- public CallbackType callbackType;
- public int error;
-
- public CallbackValue(CallbackType type) {
- this.callbackType = type;
- this.error = PacketKeepalive.SUCCESS;
- assertTrue("onError callback must have error", type != CallbackType.ON_ERROR);
- }
-
- public CallbackValue(CallbackType type, int error) {
- this.callbackType = type;
- this.error = error;
- assertEquals("error can only be set for onError", type, CallbackType.ON_ERROR);
- }
-
- @Override
- public boolean equals(Object o) {
- return o instanceof CallbackValue &&
- this.callbackType == ((CallbackValue) o).callbackType &&
- this.error == ((CallbackValue) o).error;
- }
-
- @Override
- public String toString() {
- return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType, error);
- }
- }
-
- private final LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
-
- @Override
- public void onStarted() {
- mCallbacks.add(new CallbackValue(CallbackType.ON_STARTED));
- }
-
- @Override
- public void onStopped() {
- mCallbacks.add(new CallbackValue(CallbackType.ON_STOPPED));
- }
-
- @Override
- public void onError(int error) {
- mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, error));
- }
-
- private void expectCallback(CallbackValue callbackValue) throws InterruptedException {
- assertEquals(callbackValue, mCallbacks.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- }
-
- public void expectStarted() throws Exception {
- expectCallback(new CallbackValue(CallbackType.ON_STARTED));
- }
-
- public void expectStopped() throws Exception {
- expectCallback(new CallbackValue(CallbackType.ON_STOPPED));
- }
-
- public void expectError(int error) throws Exception {
- expectCallback(new CallbackValue(CallbackType.ON_ERROR, error));
- }
- }
-
- private static class TestSocketKeepaliveCallback extends SocketKeepalive.Callback {
-
- public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
-
- private class CallbackValue {
- public CallbackType callbackType;
- public int error;
-
- CallbackValue(CallbackType type) {
- this.callbackType = type;
- this.error = SocketKeepalive.SUCCESS;
- assertTrue("onError callback must have error", type != CallbackType.ON_ERROR);
- }
-
- CallbackValue(CallbackType type, int error) {
- this.callbackType = type;
- this.error = error;
- assertEquals("error can only be set for onError", type, CallbackType.ON_ERROR);
- }
-
- @Override
- public boolean equals(Object o) {
- return o instanceof CallbackValue
- && this.callbackType == ((CallbackValue) o).callbackType
- && this.error == ((CallbackValue) o).error;
- }
-
- @Override
- public String toString() {
- return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType,
- error);
- }
- }
-
- private LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
- private final Executor mExecutor;
-
- TestSocketKeepaliveCallback(@NonNull Executor executor) {
- mExecutor = executor;
- }
-
- @Override
- public void onStarted() {
- mCallbacks.add(new CallbackValue(CallbackType.ON_STARTED));
- }
-
- @Override
- public void onStopped() {
- mCallbacks.add(new CallbackValue(CallbackType.ON_STOPPED));
- }
-
- @Override
- public void onError(int error) {
- mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, error));
- }
-
- private void expectCallback(CallbackValue callbackValue) throws InterruptedException {
- assertEquals(callbackValue, mCallbacks.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
- }
-
- public void expectStarted() throws InterruptedException {
- expectCallback(new CallbackValue(CallbackType.ON_STARTED));
- }
-
- public void expectStopped() throws InterruptedException {
- expectCallback(new CallbackValue(CallbackType.ON_STOPPED));
- }
-
- public void expectError(int error) throws InterruptedException {
- expectCallback(new CallbackValue(CallbackType.ON_ERROR, error));
- }
-
- public void assertNoCallback() {
- waitForIdleSerialExecutor(mExecutor, TIMEOUT_MS);
- CallbackValue cv = mCallbacks.peek();
- assertNull("Unexpected callback: " + cv, cv);
- }
- }
-
- private Network connectKeepaliveNetwork(LinkProperties lp) throws Exception {
- // Ensure the network is disconnected before we do anything.
- if (mWiFiNetworkAgent != null) {
- assertNull(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()));
- }
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- waitForIdle();
- return mWiFiNetworkAgent.getNetwork();
- }
-
- @Test
- @FlakyTest(bugId = 140305589)
- public void testPacketKeepalives() throws Exception {
- InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
- InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
- InetAddress myIPv6 = InetAddress.getByName("2001:db8::1");
- InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
- InetAddress dstIPv6 = InetAddress.getByName("2001:4860:4860::8888");
-
- final int validKaInterval = 15;
- final int invalidKaInterval = 9;
-
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("wlan12");
- lp.addLinkAddress(new LinkAddress(myIPv6, 64));
- lp.addLinkAddress(new LinkAddress(myIPv4, 25));
- lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
- lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
-
- Network notMyNet = new Network(61234);
- Network myNet = connectKeepaliveNetwork(lp);
-
- TestKeepaliveCallback callback = new TestKeepaliveCallback();
- PacketKeepalive ka;
-
- // Attempt to start keepalives with invalid parameters and check for errors.
- ka = mCm.startNattKeepalive(notMyNet, validKaInterval, callback, myIPv4, 1234, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
-
- ka = mCm.startNattKeepalive(myNet, invalidKaInterval, callback, myIPv4, 1234, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_INVALID_INTERVAL);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 1234, dstIPv6);
- callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv6, 1234, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
-
- // NAT-T is only supported for IPv4.
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv6, 1234, dstIPv6);
- callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 123456, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_INVALID_PORT);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 123456, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_INVALID_PORT);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
-
- // Check that a started keepalive can be stopped.
- mWiFiNetworkAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS);
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectStarted();
- mWiFiNetworkAgent.setStopKeepaliveEvent(PacketKeepalive.SUCCESS);
- ka.stop();
- callback.expectStopped();
-
- // Check that deleting the IP address stops the keepalive.
- LinkProperties bogusLp = new LinkProperties(lp);
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectStarted();
- bogusLp.removeLinkAddress(new LinkAddress(myIPv4, 25));
- bogusLp.addLinkAddress(new LinkAddress(notMyIPv4, 25));
- mWiFiNetworkAgent.sendLinkProperties(bogusLp);
- callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
- mWiFiNetworkAgent.sendLinkProperties(lp);
-
- // Check that a started keepalive is stopped correctly when the network disconnects.
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectStarted();
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
-
- // ... and that stopping it after that has no adverse effects.
- waitForIdle();
- final Network myNetAlias = myNet;
- assertNull(mCm.getNetworkCapabilities(myNetAlias));
- ka.stop();
-
- // Reconnect.
- myNet = connectKeepaliveNetwork(lp);
- mWiFiNetworkAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS);
-
- // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
- mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectStarted();
-
- // The second one gets slot 2.
- mWiFiNetworkAgent.setExpectedKeepaliveSlot(2);
- TestKeepaliveCallback callback2 = new TestKeepaliveCallback();
- PacketKeepalive ka2 = mCm.startNattKeepalive(
- myNet, validKaInterval, callback2, myIPv4, 6789, dstIPv4);
- callback2.expectStarted();
-
- // Now stop the first one and create a third. This also gets slot 1.
- ka.stop();
- callback.expectStopped();
-
- mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
- TestKeepaliveCallback callback3 = new TestKeepaliveCallback();
- PacketKeepalive ka3 = mCm.startNattKeepalive(
- myNet, validKaInterval, callback3, myIPv4, 9876, dstIPv4);
- callback3.expectStarted();
-
- ka2.stop();
- callback2.expectStopped();
-
- ka3.stop();
- callback3.expectStopped();
- }
-
- // Helper method to prepare the executor and run test
- private void runTestWithSerialExecutors(ExceptionUtils.ThrowingConsumer<Executor> functor)
- throws Exception {
- final ExecutorService executorSingleThread = Executors.newSingleThreadExecutor();
- final Executor executorInline = (Runnable r) -> r.run();
- functor.accept(executorSingleThread);
- executorSingleThread.shutdown();
- functor.accept(executorInline);
- }
-
- @Test
- public void testNattSocketKeepalives() throws Exception {
- runTestWithSerialExecutors(executor -> doTestNattSocketKeepalivesWithExecutor(executor));
- runTestWithSerialExecutors(executor -> doTestNattSocketKeepalivesFdWithExecutor(executor));
- }
-
- private void doTestNattSocketKeepalivesWithExecutor(Executor executor) throws Exception {
- // TODO: 1. Move this outside of ConnectivityServiceTest.
- // 2. Make test to verify that Nat-T keepalive socket is created by IpSecService.
- // 3. Mock ipsec service.
- final InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
- final InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
- final InetAddress myIPv6 = InetAddress.getByName("2001:db8::1");
- final InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
- final InetAddress dstIPv6 = InetAddress.getByName("2001:4860:4860::8888");
-
- final int validKaInterval = 15;
- final int invalidKaInterval = 9;
-
- final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
- final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket();
- final int srcPort = testSocket.getPort();
-
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("wlan12");
- lp.addLinkAddress(new LinkAddress(myIPv6, 64));
- lp.addLinkAddress(new LinkAddress(myIPv4, 25));
- lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
- lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
-
- Network notMyNet = new Network(61234);
- Network myNet = connectKeepaliveNetwork(lp);
-
- TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor);
-
- // Attempt to start keepalives with invalid parameters and check for errors.
- // Invalid network.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- notMyNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK);
- }
-
- // Invalid interval.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(invalidKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_INTERVAL);
- }
-
- // Invalid destination.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv6, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
- }
-
- // Invalid source;
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv6, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
- }
-
- // NAT-T is only supported for IPv4.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv6, dstIPv6, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
- }
-
- // Sanity check before testing started keepalive.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_UNSUPPORTED);
- }
-
- // Check that a started keepalive can be stopped.
- mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
- mWiFiNetworkAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS);
- ka.stop();
- callback.expectStopped();
-
- // Check that keepalive could be restarted.
- ka.start(validKaInterval);
- callback.expectStarted();
- ka.stop();
- callback.expectStopped();
-
- // Check that keepalive can be restarted without waiting for callback.
- ka.start(validKaInterval);
- callback.expectStarted();
- ka.stop();
- ka.start(validKaInterval);
- callback.expectStopped();
- callback.expectStarted();
- ka.stop();
- callback.expectStopped();
- }
-
- // Check that deleting the IP address stops the keepalive.
- LinkProperties bogusLp = new LinkProperties(lp);
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
- bogusLp.removeLinkAddress(new LinkAddress(myIPv4, 25));
- bogusLp.addLinkAddress(new LinkAddress(notMyIPv4, 25));
- mWiFiNetworkAgent.sendLinkProperties(bogusLp);
- callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- }
-
- // Check that a started keepalive is stopped correctly when the network disconnects.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK);
-
- // ... and that stopping it after that has no adverse effects.
- waitForIdle();
- final Network myNetAlias = myNet;
- assertNull(mCm.getNetworkCapabilities(myNetAlias));
- ka.stop();
- callback.assertNoCallback();
- }
-
- // Reconnect.
- myNet = connectKeepaliveNetwork(lp);
- mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
-
- // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
- mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
- int srcPort2 = 0;
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
-
- // The second one gets slot 2.
- mWiFiNetworkAgent.setExpectedKeepaliveSlot(2);
- final UdpEncapsulationSocket testSocket2 = mIpSec.openUdpEncapsulationSocket();
- srcPort2 = testSocket2.getPort();
- TestSocketKeepaliveCallback callback2 = new TestSocketKeepaliveCallback(executor);
- try (SocketKeepalive ka2 = mCm.createSocketKeepalive(
- myNet, testSocket2, myIPv4, dstIPv4, executor, callback2)) {
- ka2.start(validKaInterval);
- callback2.expectStarted();
-
- ka.stop();
- callback.expectStopped();
-
- ka2.stop();
- callback2.expectStopped();
-
- testSocket.close();
- testSocket2.close();
- }
- }
-
- // Check that there is no port leaked after all keepalives and sockets are closed.
- // TODO: enable this check after ensuring a valid free port. See b/129512753#comment7.
- // assertFalse(isUdpPortInUse(srcPort));
- // assertFalse(isUdpPortInUse(srcPort2));
-
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- mWiFiNetworkAgent = null;
- }
-
- @Test
- public void testTcpSocketKeepalives() throws Exception {
- runTestWithSerialExecutors(executor -> doTestTcpSocketKeepalivesWithExecutor(executor));
- }
-
- private void doTestTcpSocketKeepalivesWithExecutor(Executor executor) throws Exception {
- final int srcPortV4 = 12345;
- final int srcPortV6 = 23456;
- final InetAddress myIPv4 = InetAddress.getByName("127.0.0.1");
- final InetAddress myIPv6 = InetAddress.getByName("::1");
-
- final int validKaInterval = 15;
-
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("wlan12");
- lp.addLinkAddress(new LinkAddress(myIPv6, 64));
- lp.addLinkAddress(new LinkAddress(myIPv4, 25));
- lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
- lp.addRoute(new RouteInfo(InetAddress.getByName("127.0.0.254")));
-
- final Network notMyNet = new Network(61234);
- final Network myNet = connectKeepaliveNetwork(lp);
-
- final Socket testSocketV4 = new Socket();
- final Socket testSocketV6 = new Socket();
-
- TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor);
-
- // Attempt to start Tcp keepalives with invalid parameters and check for errors.
- // Invalid network.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- notMyNet, testSocketV4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK);
- }
-
- // Invalid Socket (socket is not bound with IPv4 address).
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocketV4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
- }
-
- // Invalid Socket (socket is not bound with IPv6 address).
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocketV6, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
- }
-
- // Bind the socket address
- testSocketV4.bind(new InetSocketAddress(myIPv4, srcPortV4));
- testSocketV6.bind(new InetSocketAddress(myIPv6, srcPortV6));
-
- // Invalid Socket (socket is bound with IPv4 address).
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocketV4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
- }
-
- // Invalid Socket (socket is bound with IPv6 address).
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocketV6, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
- }
-
- testSocketV4.close();
- testSocketV6.close();
-
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- mWiFiNetworkAgent = null;
- }
-
- private void doTestNattSocketKeepalivesFdWithExecutor(Executor executor) throws Exception {
- final InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
- final InetAddress anyIPv4 = InetAddress.getByName("0.0.0.0");
- final InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
- final int validKaInterval = 15;
-
- // Prepare the target network.
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("wlan12");
- lp.addLinkAddress(new LinkAddress(myIPv4, 25));
- lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
- Network myNet = connectKeepaliveNetwork(lp);
- mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
- mWiFiNetworkAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS);
-
- TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor);
-
- // Prepare the target file descriptor, keep only one instance.
- final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
- final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket();
- final int srcPort = testSocket.getPort();
- final ParcelFileDescriptor testPfd =
- ParcelFileDescriptor.dup(testSocket.getFileDescriptor());
- testSocket.close();
- assertTrue(isUdpPortInUse(srcPort));
-
- // Start keepalive and explicit make the variable goes out of scope with try-with-resources
- // block.
- try (SocketKeepalive ka = mCm.createNattKeepalive(
- myNet, testPfd, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
- ka.stop();
- callback.expectStopped();
- }
-
- // Check that the ParcelFileDescriptor is still valid after keepalive stopped,
- // ErrnoException with EBADF will be thrown if the socket is closed when checking local
- // address.
- assertTrue(isUdpPortInUse(srcPort));
- final InetSocketAddress sa =
- (InetSocketAddress) Os.getsockname(testPfd.getFileDescriptor());
- assertEquals(anyIPv4, sa.getAddress());
-
- testPfd.close();
- // TODO: enable this check after ensuring a valid free port. See b/129512753#comment7.
- // assertFalse(isUdpPortInUse(srcPort));
-
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- mWiFiNetworkAgent = null;
- }
-
- private static boolean isUdpPortInUse(int port) {
- try (DatagramSocket ignored = new DatagramSocket(port)) {
- return false;
- } catch (IOException alreadyInUse) {
- return true;
- }
- }
-
- @Test
- public void testGetCaptivePortalServerUrl() throws Exception {
- String url = mCm.getCaptivePortalServerUrl();
- assertEquals("http://connectivitycheck.gstatic.com/generate_204", url);
- }
-
- private static class TestNetworkPinner extends NetworkPinner {
- public static boolean awaitPin(int timeoutMs) throws InterruptedException {
- synchronized(sLock) {
- if (sNetwork == null) {
- sLock.wait(timeoutMs);
- }
- return sNetwork != null;
- }
- }
-
- public static boolean awaitUnpin(int timeoutMs) throws InterruptedException {
- synchronized(sLock) {
- if (sNetwork != null) {
- sLock.wait(timeoutMs);
- }
- return sNetwork == null;
- }
- }
- }
-
- private void assertPinnedToWifiWithCellDefault() {
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- }
-
- private void assertPinnedToWifiWithWifiDefault() {
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- }
-
- private void assertNotPinnedToWifi() {
- assertNull(mCm.getBoundNetworkForProcess());
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- }
-
- @Test
- public void testNetworkPinner() throws Exception {
- NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI)
- .build();
- assertNull(mCm.getBoundNetworkForProcess());
-
- TestNetworkPinner.pin(mServiceContext, wifiRequest);
- assertNull(mCm.getBoundNetworkForProcess());
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
-
- // When wi-fi connects, expect to be pinned.
- assertTrue(TestNetworkPinner.awaitPin(100));
- assertPinnedToWifiWithCellDefault();
-
- // Disconnect and expect the pin to drop.
- mWiFiNetworkAgent.disconnect();
- assertTrue(TestNetworkPinner.awaitUnpin(100));
- assertNotPinnedToWifi();
-
- // Reconnecting does not cause the pin to come back.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- assertFalse(TestNetworkPinner.awaitPin(100));
- assertNotPinnedToWifi();
-
- // Pinning while connected causes the pin to take effect immediately.
- TestNetworkPinner.pin(mServiceContext, wifiRequest);
- assertTrue(TestNetworkPinner.awaitPin(100));
- assertPinnedToWifiWithCellDefault();
-
- // Explicitly unpin and expect to use the default network again.
- TestNetworkPinner.unpin();
- assertNotPinnedToWifi();
-
- // Disconnect cell and wifi.
- ExpectedBroadcast b = registerConnectivityBroadcast(3); // cell down, wifi up, wifi down.
- mCellNetworkAgent.disconnect();
- mWiFiNetworkAgent.disconnect();
- b.expectBroadcast();
-
- // Pinning takes effect even if the pinned network is the default when the pin is set...
- TestNetworkPinner.pin(mServiceContext, wifiRequest);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- assertTrue(TestNetworkPinner.awaitPin(100));
- assertPinnedToWifiWithWifiDefault();
-
- // ... and is maintained even when that network is no longer the default.
- b = registerConnectivityBroadcast(1);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- assertPinnedToWifiWithCellDefault();
- }
-
- @Test
- public void testNetworkCallbackMaximum() {
- // We can only have 99 callbacks, because MultipathPolicyTracker is
- // already one of them.
- final int MAX_REQUESTS = 99;
- final int CALLBACKS = 89;
- final int INTENTS = 10;
- assertEquals(MAX_REQUESTS, CALLBACKS + INTENTS);
-
- NetworkRequest networkRequest = new NetworkRequest.Builder().build();
- ArrayList<Object> registered = new ArrayList<>();
-
- int j = 0;
- while (j++ < CALLBACKS / 2) {
- NetworkCallback cb = new NetworkCallback();
- mCm.requestNetwork(networkRequest, cb);
- registered.add(cb);
- }
- while (j++ < CALLBACKS) {
- NetworkCallback cb = new NetworkCallback();
- mCm.registerNetworkCallback(networkRequest, cb);
- registered.add(cb);
- }
- j = 0;
- while (j++ < INTENTS / 2) {
- PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, new Intent("a" + j), 0);
- mCm.requestNetwork(networkRequest, pi);
- registered.add(pi);
- }
- while (j++ < INTENTS) {
- PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, new Intent("b" + j), 0);
- mCm.registerNetworkCallback(networkRequest, pi);
- registered.add(pi);
- }
-
- // Test that the limit is enforced when MAX_REQUESTS simultaneous requests are added.
- assertThrows(TooManyRequestsException.class, () ->
- mCm.requestNetwork(networkRequest, new NetworkCallback())
- );
- assertThrows(TooManyRequestsException.class, () ->
- mCm.registerNetworkCallback(networkRequest, new NetworkCallback())
- );
- assertThrows(TooManyRequestsException.class, () ->
- mCm.requestNetwork(networkRequest,
- PendingIntent.getBroadcast(mContext, 0, new Intent("c"), 0))
- );
- assertThrows(TooManyRequestsException.class, () ->
- mCm.registerNetworkCallback(networkRequest,
- PendingIntent.getBroadcast(mContext, 0, new Intent("d"), 0))
- );
-
- for (Object o : registered) {
- if (o instanceof NetworkCallback) {
- mCm.unregisterNetworkCallback((NetworkCallback)o);
- }
- if (o instanceof PendingIntent) {
- mCm.unregisterNetworkCallback((PendingIntent)o);
- }
- }
- waitForIdle();
-
- // Test that the limit is not hit when MAX_REQUESTS requests are added and removed.
- for (int i = 0; i < MAX_REQUESTS; i++) {
- NetworkCallback networkCallback = new NetworkCallback();
- mCm.requestNetwork(networkRequest, networkCallback);
- mCm.unregisterNetworkCallback(networkCallback);
- }
- waitForIdle();
-
- for (int i = 0; i < MAX_REQUESTS; i++) {
- NetworkCallback networkCallback = new NetworkCallback();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
- mCm.unregisterNetworkCallback(networkCallback);
- }
- waitForIdle();
-
- for (int i = 0; i < MAX_REQUESTS; i++) {
- PendingIntent pendingIntent =
- PendingIntent.getBroadcast(mContext, 0, new Intent("e" + i), 0);
- mCm.requestNetwork(networkRequest, pendingIntent);
- mCm.unregisterNetworkCallback(pendingIntent);
- }
- waitForIdle();
-
- for (int i = 0; i < MAX_REQUESTS; i++) {
- PendingIntent pendingIntent =
- PendingIntent.getBroadcast(mContext, 0, new Intent("f" + i), 0);
- mCm.registerNetworkCallback(networkRequest, pendingIntent);
- mCm.unregisterNetworkCallback(pendingIntent);
- }
- }
-
- @Test
- public void testNetworkInfoOfTypeNone() throws Exception {
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
-
- verifyNoNetwork();
- TestNetworkAgentWrapper wifiAware = new TestNetworkAgentWrapper(TRANSPORT_WIFI_AWARE);
- assertNull(mCm.getActiveNetworkInfo());
-
- Network[] allNetworks = mCm.getAllNetworks();
- assertLength(1, allNetworks);
- Network network = allNetworks[0];
- NetworkCapabilities capabilities = mCm.getNetworkCapabilities(network);
- assertTrue(capabilities.hasTransport(TRANSPORT_WIFI_AWARE));
-
- final NetworkRequest request =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI_AWARE).build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- // Bring up wifi aware network.
- wifiAware.connect(false, false, false /* isStrictMode */);
- callback.expectAvailableCallbacksUnvalidated(wifiAware);
-
- assertNull(mCm.getActiveNetworkInfo());
- assertNull(mCm.getActiveNetwork());
- // TODO: getAllNetworkInfo is dirty and returns a non-empty array right from the start
- // of this test. Fix it and uncomment the assert below.
- //assertEmpty(mCm.getAllNetworkInfo());
-
- // Disconnect wifi aware network.
- wifiAware.disconnect();
- callback.expectCallbackThat(TIMEOUT_MS, (info) -> info instanceof CallbackEntry.Lost);
- mCm.unregisterNetworkCallback(callback);
-
- verifyNoNetwork();
- b.expectNoBroadcast(10);
- }
-
- @Test
- public void testDeprecatedAndUnsupportedOperations() throws Exception {
- final int TYPE_NONE = ConnectivityManager.TYPE_NONE;
- assertNull(mCm.getNetworkInfo(TYPE_NONE));
- assertNull(mCm.getNetworkForType(TYPE_NONE));
- assertNull(mCm.getLinkProperties(TYPE_NONE));
- assertFalse(mCm.isNetworkSupported(TYPE_NONE));
-
- assertThrows(IllegalArgumentException.class,
- () -> mCm.networkCapabilitiesForType(TYPE_NONE));
-
- Class<UnsupportedOperationException> unsupported = UnsupportedOperationException.class;
- assertThrows(unsupported, () -> mCm.startUsingNetworkFeature(TYPE_WIFI, ""));
- assertThrows(unsupported, () -> mCm.stopUsingNetworkFeature(TYPE_WIFI, ""));
- // TODO: let test context have configuration application target sdk version
- // and test that pre-M requesting for TYPE_NONE sends back APN_REQUEST_FAILED
- assertThrows(unsupported, () -> mCm.startUsingNetworkFeature(TYPE_NONE, ""));
- assertThrows(unsupported, () -> mCm.stopUsingNetworkFeature(TYPE_NONE, ""));
- assertThrows(unsupported, () -> mCm.requestRouteToHostAddress(TYPE_NONE, null));
- }
-
- @Test
- public void testLinkPropertiesEnsuresDirectlyConnectedRoutes() throws Exception {
- final NetworkRequest networkRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
-
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(WIFI_IFNAME);
- LinkAddress myIpv4Address = new LinkAddress("192.168.12.3/24");
- RouteInfo myIpv4DefaultRoute = new RouteInfo((IpPrefix) null,
- NetworkUtils.numericToInetAddress("192.168.12.1"), lp.getInterfaceName());
- lp.addLinkAddress(myIpv4Address);
- lp.addRoute(myIpv4DefaultRoute);
-
- // Verify direct routes are added when network agent is first registered in
- // ConnectivityService.
- TestNetworkAgentWrapper networkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp);
- networkAgent.connect(true);
- networkCallback.expectCallback(CallbackEntry.AVAILABLE, networkAgent);
- networkCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, networkAgent);
- CallbackEntry.LinkPropertiesChanged cbi =
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- networkAgent);
- networkCallback.expectCallback(CallbackEntry.BLOCKED_STATUS, networkAgent);
- networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, networkAgent);
- networkCallback.assertNoCallback();
- checkDirectlyConnectedRoutes(cbi.getLp(), Arrays.asList(myIpv4Address),
- Arrays.asList(myIpv4DefaultRoute));
- checkDirectlyConnectedRoutes(mCm.getLinkProperties(networkAgent.getNetwork()),
- Arrays.asList(myIpv4Address), Arrays.asList(myIpv4DefaultRoute));
-
- // Verify direct routes are added during subsequent link properties updates.
- LinkProperties newLp = new LinkProperties(lp);
- LinkAddress myIpv6Address1 = new LinkAddress("fe80::cafe/64");
- LinkAddress myIpv6Address2 = new LinkAddress("2001:db8::2/64");
- newLp.addLinkAddress(myIpv6Address1);
- newLp.addLinkAddress(myIpv6Address2);
- networkAgent.sendLinkProperties(newLp);
- cbi = networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, networkAgent);
- networkCallback.assertNoCallback();
- checkDirectlyConnectedRoutes(cbi.getLp(),
- Arrays.asList(myIpv4Address, myIpv6Address1, myIpv6Address2),
- Arrays.asList(myIpv4DefaultRoute));
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- private <T> void assertSameElementsNoDuplicates(T[] expected, T[] actual) {
- // Easier to implement than a proper "assertSameElements" method that also correctly deals
- // with duplicates.
- final String msg = Arrays.toString(expected) + " != " + Arrays.toString(actual);
- assertEquals(msg, expected.length, actual.length);
- Set expectedSet = new ArraySet<>(Arrays.asList(expected));
- assertEquals("expected contains duplicates", expectedSet.size(), expected.length);
- // actual cannot have duplicates because it's the same length and has the same elements.
- Set actualSet = new ArraySet<>(Arrays.asList(actual));
- assertEquals(expectedSet, actualSet);
- }
-
- private void expectForceUpdateIfaces(Network[] networks, String defaultIface,
- Integer vpnUid, String vpnIfname, String[] underlyingIfaces) throws Exception {
- ArgumentCaptor<Network[]> networksCaptor = ArgumentCaptor.forClass(Network[].class);
- ArgumentCaptor<VpnInfo[]> vpnInfosCaptor = ArgumentCaptor.forClass(VpnInfo[].class);
-
- verify(mStatsService, atLeastOnce()).forceUpdateIfaces(networksCaptor.capture(),
- any(NetworkState[].class), eq(defaultIface), vpnInfosCaptor.capture());
-
- assertSameElementsNoDuplicates(networksCaptor.getValue(), networks);
-
- VpnInfo[] infos = vpnInfosCaptor.getValue();
- if (vpnUid != null) {
- assertEquals("Should have exactly one VPN:", 1, infos.length);
- VpnInfo info = infos[0];
- assertEquals("Unexpected VPN owner:", (int) vpnUid, info.ownerUid);
- assertEquals("Unexpected VPN interface:", vpnIfname, info.vpnIface);
- assertSameElementsNoDuplicates(underlyingIfaces, info.underlyingIfaces);
- } else {
- assertEquals(0, infos.length);
- return;
- }
- }
-
- private void expectForceUpdateIfaces(Network[] networks, String defaultIface) throws Exception {
- expectForceUpdateIfaces(networks, defaultIface, null, null, new String[0]);
- }
-
- @Test
- public void testStatsIfacesChanged() throws Exception {
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-
- final Network[] onlyCell = new Network[] {mCellNetworkAgent.getNetwork()};
- final Network[] onlyWifi = new Network[] {mWiFiNetworkAgent.getNetwork()};
-
- LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- LinkProperties wifiLp = new LinkProperties();
- wifiLp.setInterfaceName(WIFI_IFNAME);
-
- // Simple connection should have updated ifaces
- mCellNetworkAgent.connect(false);
- mCellNetworkAgent.sendLinkProperties(cellLp);
- waitForIdle();
- expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
- reset(mStatsService);
-
- // Default network switch should update ifaces.
- mWiFiNetworkAgent.connect(false);
- mWiFiNetworkAgent.sendLinkProperties(wifiLp);
- waitForIdle();
- assertEquals(wifiLp, mService.getActiveLinkProperties());
- expectForceUpdateIfaces(onlyWifi, WIFI_IFNAME);
- reset(mStatsService);
-
- // Disconnect should update ifaces.
- mWiFiNetworkAgent.disconnect();
- waitForIdle();
- expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
- reset(mStatsService);
-
- // Metered change should update ifaces
- mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- waitForIdle();
- expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
- reset(mStatsService);
-
- mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- waitForIdle();
- expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
- reset(mStatsService);
-
- // Captive portal change shouldn't update ifaces
- mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
- waitForIdle();
- verify(mStatsService, never())
- .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
- eq(new VpnInfo[0]));
- reset(mStatsService);
-
- // Roaming change should update ifaces
- mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
- waitForIdle();
- expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
- reset(mStatsService);
-
- // Test VPNs.
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(VPN_IFNAME);
-
- mMockVpn.establishForMyUid(lp);
-
- final Network[] cellAndVpn = new Network[] {
- mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork()};
-
- // A VPN with default (null) underlying networks sets the underlying network's interfaces...
- expectForceUpdateIfaces(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{MOBILE_IFNAME});
-
- // ...and updates them as the default network switches.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- mWiFiNetworkAgent.sendLinkProperties(wifiLp);
- final Network[] onlyNull = new Network[]{null};
- final Network[] wifiAndVpn = new Network[] {
- mWiFiNetworkAgent.getNetwork(), mMockVpn.getNetwork()};
- final Network[] cellAndWifi = new Network[] {
- mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork()};
- final Network[] cellNullAndWifi = new Network[] {
- mCellNetworkAgent.getNetwork(), null, mWiFiNetworkAgent.getNetwork()};
-
- waitForIdle();
- assertEquals(wifiLp, mService.getActiveLinkProperties());
- expectForceUpdateIfaces(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{WIFI_IFNAME});
- reset(mStatsService);
-
- // A VPN that sets its underlying networks passes the underlying interfaces, and influences
- // the default interface sent to NetworkStatsService by virtue of applying to the system
- // server UID (or, in this test, to the test's UID). This is the reason for sending
- // MOBILE_IFNAME even though the default network is wifi.
- // TODO: fix this to pass in the actual default network interface. Whether or not the VPN
- // applies to the system server UID should not have any bearing on network stats.
- mService.setUnderlyingNetworksForVpn(onlyCell);
- waitForIdle();
- expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{MOBILE_IFNAME});
- reset(mStatsService);
-
- mService.setUnderlyingNetworksForVpn(cellAndWifi);
- waitForIdle();
- expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{MOBILE_IFNAME, WIFI_IFNAME});
- reset(mStatsService);
-
- // Null underlying networks are ignored.
- mService.setUnderlyingNetworksForVpn(cellNullAndWifi);
- waitForIdle();
- expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{MOBILE_IFNAME, WIFI_IFNAME});
- reset(mStatsService);
-
- // If an underlying network disconnects, that interface should no longer be underlying.
- // This doesn't actually work because disconnectAndDestroyNetwork only notifies
- // NetworkStatsService before the underlying network is actually removed. So the underlying
- // network will only be removed if notifyIfacesChangedForNetworkStats is called again. This
- // could result in incorrect data usage measurements if the interface used by the
- // disconnected network is reused by a system component that does not register an agent for
- // it (e.g., tethering).
- mCellNetworkAgent.disconnect();
- waitForIdle();
- assertNull(mService.getLinkProperties(mCellNetworkAgent.getNetwork()));
- expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{MOBILE_IFNAME, WIFI_IFNAME});
-
- // Confirm that we never tell NetworkStatsService that cell is no longer the underlying
- // network for the VPN...
- verify(mStatsService, never()).forceUpdateIfaces(any(Network[].class),
- any(NetworkState[].class), any() /* anyString() doesn't match null */,
- argThat(infos -> infos[0].underlyingIfaces.length == 1
- && WIFI_IFNAME.equals(infos[0].underlyingIfaces[0])));
- verifyNoMoreInteractions(mStatsService);
- reset(mStatsService);
-
- // ... but if something else happens that causes notifyIfacesChangedForNetworkStats to be
- // called again, it does. For example, connect Ethernet, but with a low score, such that it
- // does not become the default network.
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
- mEthernetNetworkAgent.adjustScore(-40);
- mEthernetNetworkAgent.connect(false);
- waitForIdle();
- verify(mStatsService).forceUpdateIfaces(any(Network[].class),
- any(NetworkState[].class), any() /* anyString() doesn't match null */,
- argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.length == 1
- && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces[0])));
- mEthernetNetworkAgent.disconnect();
- waitForIdle();
- reset(mStatsService);
-
- // When a VPN declares no underlying networks (i.e., no connectivity), getAllVpnInfo
- // does not return the VPN, so CS does not pass it to NetworkStatsService. This causes
- // NetworkStatsFactory#adjustForTunAnd464Xlat not to attempt any VPN data migration, which
- // is probably a performance improvement (though it's very unlikely that a VPN would declare
- // no underlying networks).
- // Also, for the same reason as above, the active interface passed in is null.
- mService.setUnderlyingNetworksForVpn(new Network[0]);
- waitForIdle();
- expectForceUpdateIfaces(wifiAndVpn, null);
- reset(mStatsService);
-
- // Specifying only a null underlying network is the same as no networks.
- mService.setUnderlyingNetworksForVpn(onlyNull);
- waitForIdle();
- expectForceUpdateIfaces(wifiAndVpn, null);
- reset(mStatsService);
-
- // Specifying networks that are all disconnected is the same as specifying no networks.
- mService.setUnderlyingNetworksForVpn(onlyCell);
- waitForIdle();
- expectForceUpdateIfaces(wifiAndVpn, null);
- reset(mStatsService);
- }
-
- @Test
- public void testBasicDnsConfigurationPushed() throws Exception {
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
-
- // Clear any interactions that occur as a result of CS starting up.
- reset(mMockDnsResolver);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- waitForIdle();
- verify(mMockDnsResolver, never()).setResolverConfiguration(any());
- verifyNoMoreInteractions(mMockDnsResolver);
-
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- // Add IPv4 and IPv6 default routes, because DNS-over-TLS code does
- // "is-reachable" testing in order to not program netd with unreachable
- // nameservers that it might try repeated to validate.
- cellLp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
- cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
- MOBILE_IFNAME));
- cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
- cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
- MOBILE_IFNAME));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- mCellNetworkAgent.connect(false);
- waitForIdle();
-
- verify(mMockDnsResolver, times(1)).createNetworkCache(
- eq(mCellNetworkAgent.getNetwork().netId));
- // CS tells dnsresolver about the empty DNS config for this network.
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
- reset(mMockDnsResolver);
-
- cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- waitForIdle();
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(1, resolvrParams.servers.length);
- assertTrue(ArrayUtils.contains(resolvrParams.servers, "2001:db8::1"));
- // Opportunistic mode.
- assertTrue(ArrayUtils.contains(resolvrParams.tlsServers, "2001:db8::1"));
- reset(mMockDnsResolver);
-
- cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- waitForIdle();
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(2, resolvrParams.servers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
- // Opportunistic mode.
- assertEquals(2, resolvrParams.tlsServers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
- reset(mMockDnsResolver);
-
- final String TLS_SPECIFIER = "tls.example.com";
- final String TLS_SERVER6 = "2001:db8:53::53";
- final InetAddress[] TLS_IPS = new InetAddress[]{ InetAddress.getByName(TLS_SERVER6) };
- final String[] TLS_SERVERS = new String[]{ TLS_SERVER6 };
- mCellNetworkAgent.mNmCallbacks.notifyPrivateDnsConfigResolved(
- new PrivateDnsConfig(TLS_SPECIFIER, TLS_IPS).toParcel());
-
- waitForIdle();
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(2, resolvrParams.servers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
- reset(mMockDnsResolver);
- }
-
- @Test
- public void testDnsConfigurationTransTypesPushed() throws Exception {
- // Clear any interactions that occur as a result of CS starting up.
- reset(mMockDnsResolver);
-
- final NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
- .build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- verify(mMockDnsResolver, times(1)).createNetworkCache(
- eq(mWiFiNetworkAgent.getNetwork().netId));
- verify(mMockDnsResolver, times(2)).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- final ResolverParamsParcel resolverParams = mResolverParamsParcelCaptor.getValue();
- assertContainsExactly(resolverParams.transportTypes, TRANSPORT_WIFI);
- reset(mMockDnsResolver);
- }
-
- @Test
- public void testPrivateDnsNotification() throws Exception {
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
- .build();
- TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
- // Bring up wifi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- // Private DNS resolution failed, checking if the notification will be shown or not.
- mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */);
- mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- waitForIdle();
- // If network validation failed, NetworkMonitor will re-evaluate the network.
- // ConnectivityService should filter the redundant notification. This part is trying to
- // simulate that situation and check if ConnectivityService could filter that case.
- mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- waitForIdle();
- verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).notifyAsUser(anyString(),
- eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any(), eq(UserHandle.ALL));
- // If private DNS resolution successful, the PRIVATE_DNS_BROKEN notification shouldn't be
- // shown.
- mWiFiNetworkAgent.setNetworkValid(true /* isStrictMode */);
- mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- waitForIdle();
- verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).cancelAsUser(anyString(),
- eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), eq(UserHandle.ALL));
- // If private DNS resolution failed again, the PRIVATE_DNS_BROKEN notification should be
- // shown again.
- mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */);
- mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- waitForIdle();
- verify(mNotificationManager, timeout(TIMEOUT_MS).times(2)).notifyAsUser(anyString(),
- eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any(), eq(UserHandle.ALL));
- }
-
- @Test
- public void testPrivateDnsSettingsChange() throws Exception {
- // Clear any interactions that occur as a result of CS starting up.
- reset(mMockDnsResolver);
-
- // The default on Android is opportunistic mode ("Automatic").
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
-
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.requestNetwork(cellRequest, cellNetworkCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- waitForIdle();
- // CS tells netd about the empty DNS config for this network.
- verify(mMockDnsResolver, never()).setResolverConfiguration(any());
- verifyNoMoreInteractions(mMockDnsResolver);
-
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- // Add IPv4 and IPv6 default routes, because DNS-over-TLS code does
- // "is-reachable" testing in order to not program netd with unreachable
- // nameservers that it might try repeated to validate.
- cellLp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
- cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
- MOBILE_IFNAME));
- cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
- cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
- MOBILE_IFNAME));
- cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
- cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
-
- mCellNetworkAgent.sendLinkProperties(cellLp);
- mCellNetworkAgent.connect(false);
- waitForIdle();
- verify(mMockDnsResolver, times(1)).createNetworkCache(
- eq(mCellNetworkAgent.getNetwork().netId));
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(2, resolvrParams.tlsServers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
- // Opportunistic mode.
- assertEquals(2, resolvrParams.tlsServers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
- reset(mMockDnsResolver);
- cellNetworkCallback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED,
- mCellNetworkAgent);
- CallbackEntry.LinkPropertiesChanged cbi = cellNetworkCallback.expectCallback(
- CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.BLOCKED_STATUS, mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertFalse(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
-
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
- verify(mMockDnsResolver, times(1)).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(2, resolvrParams.servers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
- reset(mMockDnsResolver);
- cellNetworkCallback.assertNoCallback();
-
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(2, resolvrParams.servers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
- assertEquals(2, resolvrParams.tlsServers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
- reset(mMockDnsResolver);
- cellNetworkCallback.assertNoCallback();
-
- setPrivateDnsSettings(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, "strict.example.com");
- // Can't test dns configuration for strict mode without properly mocking
- // out the DNS lookups, but can test that LinkProperties is updated.
- cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertTrue(cbi.getLp().isPrivateDnsActive());
- assertEquals("strict.example.com", cbi.getLp().getPrivateDnsServerName());
- }
-
- @Test
- public void testLinkPropertiesWithPrivateDnsValidationEvents() throws Exception {
- // The default on Android is opportunistic mode ("Automatic").
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
-
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.requestNetwork(cellRequest, cellNetworkCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- waitForIdle();
- LinkProperties lp = new LinkProperties();
- mCellNetworkAgent.sendLinkProperties(lp);
- mCellNetworkAgent.connect(false);
- waitForIdle();
- cellNetworkCallback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED,
- mCellNetworkAgent);
- CallbackEntry.LinkPropertiesChanged cbi = cellNetworkCallback.expectCallback(
- CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.BLOCKED_STATUS, mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertFalse(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
- Set<InetAddress> dnsServers = new HashSet<>();
- checkDnsServers(cbi.getLp(), dnsServers);
-
- // Send a validation event for a server that is not part of the current
- // resolver config. The validation event should be ignored.
- mService.mNetdEventCallback.onPrivateDnsValidationEvent(
- mCellNetworkAgent.getNetwork().netId, "", "145.100.185.18", true);
- cellNetworkCallback.assertNoCallback();
-
- // Add a dns server to the LinkProperties.
- LinkProperties lp2 = new LinkProperties(lp);
- lp2.addDnsServer(InetAddress.getByName("145.100.185.16"));
- mCellNetworkAgent.sendLinkProperties(lp2);
- cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertFalse(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
- dnsServers.add(InetAddress.getByName("145.100.185.16"));
- checkDnsServers(cbi.getLp(), dnsServers);
-
- // Send a validation event containing a hostname that is not part of
- // the current resolver config. The validation event should be ignored.
- mService.mNetdEventCallback.onPrivateDnsValidationEvent(
- mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "hostname", true);
- cellNetworkCallback.assertNoCallback();
-
- // Send a validation event where validation failed.
- mService.mNetdEventCallback.onPrivateDnsValidationEvent(
- mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", false);
- cellNetworkCallback.assertNoCallback();
-
- // Send a validation event where validation succeeded for a server in
- // the current resolver config. A LinkProperties callback with updated
- // private dns fields should be sent.
- mService.mNetdEventCallback.onPrivateDnsValidationEvent(
- mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", true);
- cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertTrue(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
- checkDnsServers(cbi.getLp(), dnsServers);
-
- // The private dns fields in LinkProperties should be preserved when
- // the network agent sends unrelated changes.
- LinkProperties lp3 = new LinkProperties(lp2);
- lp3.setMtu(1300);
- mCellNetworkAgent.sendLinkProperties(lp3);
- cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertTrue(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
- checkDnsServers(cbi.getLp(), dnsServers);
- assertEquals(1300, cbi.getLp().getMtu());
-
- // Removing the only validated server should affect the private dns
- // fields in LinkProperties.
- LinkProperties lp4 = new LinkProperties(lp3);
- lp4.removeDnsServer(InetAddress.getByName("145.100.185.16"));
- mCellNetworkAgent.sendLinkProperties(lp4);
- cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertFalse(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
- dnsServers.remove(InetAddress.getByName("145.100.185.16"));
- checkDnsServers(cbi.getLp(), dnsServers);
- assertEquals(1300, cbi.getLp().getMtu());
- }
-
- private void checkDirectlyConnectedRoutes(Object callbackObj,
- Collection<LinkAddress> linkAddresses, Collection<RouteInfo> otherRoutes) {
- assertTrue(callbackObj instanceof LinkProperties);
- LinkProperties lp = (LinkProperties) callbackObj;
-
- Set<RouteInfo> expectedRoutes = new ArraySet<>();
- expectedRoutes.addAll(otherRoutes);
- for (LinkAddress address : linkAddresses) {
- RouteInfo localRoute = new RouteInfo(address, null, lp.getInterfaceName());
- // Duplicates in linkAddresses are considered failures
- assertTrue(expectedRoutes.add(localRoute));
- }
- List<RouteInfo> observedRoutes = lp.getRoutes();
- assertEquals(expectedRoutes.size(), observedRoutes.size());
- assertTrue(observedRoutes.containsAll(expectedRoutes));
- }
-
- private static void checkDnsServers(Object callbackObj, Set<InetAddress> dnsServers) {
- assertTrue(callbackObj instanceof LinkProperties);
- LinkProperties lp = (LinkProperties) callbackObj;
- assertEquals(dnsServers.size(), lp.getDnsServers().size());
- assertTrue(lp.getDnsServers().containsAll(dnsServers));
- }
-
- @Test
- public void testVpnConnectDisconnectUnderlyingNetwork() throws Exception {
- final TestNetworkCallback callback = new TestNetworkCallback();
- final NetworkRequest request = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN).build();
-
- mCm.registerNetworkCallback(request, callback);
-
- // Bring up a VPN that specifies an underlying network that does not exist yet.
- // Note: it's sort of meaningless for a VPN app to declare a network that doesn't exist yet,
- // (and doing so is difficult without using reflection) but it's good to test that the code
- // behaves approximately correctly.
- mMockVpn.establishForMyUid(false, true, false);
- final Network wifiNetwork = new Network(mNetIdManager.peekNextNetId());
- mService.setUnderlyingNetworksForVpn(new Network[]{wifiNetwork});
- callback.expectAvailableCallbacksUnvalidated(mMockVpn);
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasTransport(TRANSPORT_VPN));
- assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasTransport(TRANSPORT_WIFI));
-
- // Make that underlying network connect, and expect to see its capabilities immediately
- // reflected in the VPN's capabilities.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- assertEquals(wifiNetwork, mWiFiNetworkAgent.getNetwork());
- mWiFiNetworkAgent.connect(false);
- // TODO: the callback for the VPN happens before any callbacks are called for the wifi
- // network that has just connected. There appear to be two issues here:
- // 1. The VPN code will accept an underlying network as soon as getNetworkCapabilities() for
- // it returns non-null (which happens very early, during handleRegisterNetworkAgent).
- // This is not correct because that that point the network is not connected and cannot
- // pass any traffic.
- // 2. When a network connects, updateNetworkInfo propagates underlying network capabilities
- // before rematching networks.
- // Given that this scenario can't really happen, this is probably fine for now.
- callback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasTransport(TRANSPORT_VPN));
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasTransport(TRANSPORT_WIFI));
-
- // Disconnect the network, and expect to see the VPN capabilities change accordingly.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- callback.expectCapabilitiesThat(mMockVpn, (nc) ->
- nc.getTransportTypes().length == 1 && nc.hasTransport(TRANSPORT_VPN));
-
- mMockVpn.disconnect();
- mCm.unregisterNetworkCallback(callback);
- }
-
- private void assertGetNetworkInfoOfGetActiveNetworkIsConnected(boolean expectedConnectivity) {
- // What Chromium used to do before https://chromium-review.googlesource.com/2605304
- assertEquals("Unexpected result for getActiveNetworkInfo(getActiveNetwork())",
- expectedConnectivity, mCm.getNetworkInfo(mCm.getActiveNetwork()).isConnected());
- }
-
- @Test
- public void testVpnUnderlyingNetworkSuspended() throws Exception {
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(callback);
-
- // Connect a VPN.
- mMockVpn.establishForMyUid(false, true, false);
- callback.expectAvailableCallbacksUnvalidated(mMockVpn);
-
- // Connect cellular data.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false /* validated */);
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- callback.assertNoCallback();
-
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
-
- // Suspend the cellular network and expect the VPN to be suspended.
- mCellNetworkAgent.suspend();
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- callback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
- callback.assertNoCallback();
-
- assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
- // VPN's main underlying network is suspended, so no connectivity.
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
-
- // Switch to another network. The VPN should no longer be suspended.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false /* validated */);
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_WIFI));
- callback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
- callback.assertNoCallback();
-
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
-
- // Unsuspend cellular and then switch back to it. The VPN remains not suspended.
- mCellNetworkAgent.resume();
- mWiFiNetworkAgent.disconnect();
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- // Spurious double callback?
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- callback.assertNoCallback();
-
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
-
- // Suspend cellular and expect no connectivity.
- mCellNetworkAgent.suspend();
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- callback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
- callback.assertNoCallback();
-
- assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
-
- // Resume cellular and expect that connectivity comes back.
- mCellNetworkAgent.resume();
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- callback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
- callback.assertNoCallback();
-
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
- }
-
- @Test
- public void testVpnNetworkActive() throws Exception {
- final int uid = Process.myUid();
-
- final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback genericNotVpnNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- final NetworkRequest genericNotVpnRequest = new NetworkRequest.Builder().build();
- final NetworkRequest genericRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN).build();
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .addTransportType(TRANSPORT_VPN).build();
- mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
- mCm.registerNetworkCallback(genericNotVpnRequest, genericNotVpnNetworkCallback);
- mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
- mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
- mCm.registerDefaultNetworkCallback(defaultCallback);
- defaultCallback.assertNoCallback();
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
-
- genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- genericNotVpnNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- vpnNetworkCallback.assertNoCallback();
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- final Set<UidRange> ranges = uidRangesForUid(uid);
- mMockVpn.registerAgent(ranges);
- mService.setUnderlyingNetworksForVpn(new Network[0]);
-
- // VPN networks do not satisfy the default request and are automatically validated
- // by NetworkMonitor
- assertFalse(NetworkMonitorUtils.isValidationRequired(
- mMockVpn.getAgent().getNetworkCapabilities()));
- mMockVpn.getAgent().setNetworkValid(false /* isStrictMode */);
-
- mMockVpn.connect(false);
-
- genericNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- genericNotVpnNetworkCallback.assertNoCallback();
- wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- ranges.clear();
- mMockVpn.setUids(ranges);
-
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- genericNotVpnNetworkCallback.assertNoCallback();
- wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
-
- // TODO : The default network callback should actually get a LOST call here (also see the
- // comment below for AVAILABLE). This is because ConnectivityService does not look at UID
- // ranges at all when determining whether a network should be rematched. In practice, VPNs
- // can't currently update their UIDs without disconnecting, so this does not matter too
- // much, but that is the reason the test here has to check for an update to the
- // capabilities instead of the expected LOST then AVAILABLE.
- defaultCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
-
- ranges.add(new UidRange(uid, uid));
- mMockVpn.setUids(ranges);
-
- genericNetworkCallback.expectAvailableCallbacksValidated(mMockVpn);
- genericNotVpnNetworkCallback.assertNoCallback();
- wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectAvailableCallbacksValidated(mMockVpn);
- // TODO : Here like above, AVAILABLE would be correct, but because this can't actually
- // happen outside of the test, ConnectivityService does not rematch callbacks.
- defaultCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
-
- mWiFiNetworkAgent.disconnect();
-
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- genericNotVpnNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- vpnNetworkCallback.assertNoCallback();
- defaultCallback.assertNoCallback();
-
- mMockVpn.disconnect();
-
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- genericNotVpnNetworkCallback.assertNoCallback();
- wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- assertEquals(null, mCm.getActiveNetwork());
-
- mCm.unregisterNetworkCallback(genericNetworkCallback);
- mCm.unregisterNetworkCallback(wifiNetworkCallback);
- mCm.unregisterNetworkCallback(vpnNetworkCallback);
- mCm.unregisterNetworkCallback(defaultCallback);
- }
-
- @Test
- public void testVpnWithoutInternet() throws Exception {
- final int uid = Process.myUid();
-
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
-
- defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */,
- false /* isStrictMode */);
-
- defaultCallback.assertNoCallback();
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mMockVpn.disconnect();
- defaultCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(defaultCallback);
- }
-
- @Test
- public void testVpnWithInternet() throws Exception {
- final int uid = Process.myUid();
-
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
-
- defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mMockVpn.establishForMyUid(true /* validated */, true /* hasInternet */,
- false /* isStrictMode */);
-
- defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mMockVpn.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
-
- mCm.unregisterNetworkCallback(defaultCallback);
- }
-
- @Test
- public void testVpnUnvalidated() throws Exception {
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(callback);
-
- // Bring up Ethernet.
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
- mEthernetNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
- callback.assertNoCallback();
-
- // Bring up a VPN that has the INTERNET capability, initially unvalidated.
- mMockVpn.establishForMyUid(false /* validated */, true /* hasInternet */,
- false /* isStrictMode */);
-
- // Even though the VPN is unvalidated, it becomes the default network for our app.
- callback.expectAvailableCallbacksUnvalidated(mMockVpn);
- callback.assertNoCallback();
-
- assertTrue(mMockVpn.getAgent().getScore() > mEthernetNetworkAgent.getScore());
- assertEquals(ConnectivityConstants.VPN_DEFAULT_SCORE, mMockVpn.getAgent().getScore());
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
-
- NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED));
- assertTrue(nc.hasCapability(NET_CAPABILITY_INTERNET));
-
- assertFalse(NetworkMonitorUtils.isValidationRequired(
- mMockVpn.getAgent().getNetworkCapabilities()));
- assertTrue(NetworkMonitorUtils.isPrivateDnsValidationRequired(
- mMockVpn.getAgent().getNetworkCapabilities()));
-
- // Pretend that the VPN network validates.
- mMockVpn.getAgent().setNetworkValid(false /* isStrictMode */);
- mMockVpn.getAgent().mNetworkMonitor.forceReevaluation(Process.myUid());
- // Expect to see the validated capability, but no other changes, because the VPN is already
- // the default network for the app.
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mMockVpn);
- callback.assertNoCallback();
-
- mMockVpn.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mMockVpn);
- callback.expectAvailableCallbacksValidated(mEthernetNetworkAgent);
- }
-
- @Test
- public void testVpnStartsWithUnderlyingCaps() throws Exception {
- final int uid = Process.myUid();
-
- final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
- final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .addTransportType(TRANSPORT_VPN)
- .build();
- mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
- vpnNetworkCallback.assertNoCallback();
-
- // Connect cell. It will become the default network, and in the absence of setting
- // underlying networks explicitly it will become the sole underlying network for the vpn.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- mCellNetworkAgent.connect(true);
-
- mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */,
- false /* isStrictMode */);
-
- vpnNetworkCallback.expectAvailableCallbacks(mMockVpn.getNetwork(),
- false /* suspended */, false /* validated */, false /* blocked */, TIMEOUT_MS);
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn.getNetwork(), TIMEOUT_MS,
- nc -> nc.hasCapability(NET_CAPABILITY_VALIDATED));
-
- final NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- assertTrue(nc.hasTransport(TRANSPORT_VPN));
- assertTrue(nc.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(nc.hasTransport(TRANSPORT_WIFI));
- assertTrue(nc.hasCapability(NET_CAPABILITY_VALIDATED));
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- }
-
- private void assertDefaultNetworkCapabilities(int userId, NetworkAgentWrapper... networks) {
- final NetworkCapabilities[] defaultCaps = mService.getDefaultNetworkCapabilitiesForUser(
- userId, "com.android.calling.package");
- final String defaultCapsString = Arrays.toString(defaultCaps);
- assertEquals(defaultCapsString, defaultCaps.length, networks.length);
- final Set<NetworkCapabilities> defaultCapsSet = new ArraySet<>(defaultCaps);
- for (NetworkAgentWrapper network : networks) {
- final NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
- final String msg = "Did not find " + nc + " in " + Arrays.toString(defaultCaps);
- assertTrue(msg, defaultCapsSet.contains(nc));
- }
- }
-
- @Test
- public void testVpnSetUnderlyingNetworks() throws Exception {
- final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
- final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .addTransportType(TRANSPORT_VPN)
- .build();
- NetworkCapabilities nc;
- mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
- vpnNetworkCallback.assertNoCallback();
-
- mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */,
- false /* isStrictMode */);
-
- vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- assertTrue(nc.hasTransport(TRANSPORT_VPN));
- assertFalse(nc.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(nc.hasTransport(TRANSPORT_WIFI));
- // For safety reasons a VPN without underlying networks is considered metered.
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
- // A VPN without underlying networks is not suspended.
- assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- final int userId = UserHandle.getUserId(Process.myUid());
- assertDefaultNetworkCapabilities(userId /* no networks */);
-
- // Connect cell and use it as an underlying network.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- mCellNetworkAgent.connect(true);
-
- mService.setUnderlyingNetworksForVpn(
- new Network[] { mCellNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- mWiFiNetworkAgent.connect(true);
-
- mService.setUnderlyingNetworksForVpn(
- new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
-
- // Don't disconnect, but note the VPN is not using wifi any more.
- mService.setUnderlyingNetworksForVpn(
- new Network[] { mCellNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- // The return value of getDefaultNetworkCapabilitiesForUser always includes the default
- // network (wifi) as well as the underlying networks (cell).
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
-
- // Remove NOT_SUSPENDED from the only network and observe VPN is now suspended.
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && !caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- vpnNetworkCallback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
-
- // Add NOT_SUSPENDED again and observe VPN is no longer suspended.
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- vpnNetworkCallback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
-
- // Use Wifi but not cell. Note the VPN is now unmetered and not suspended.
- mService.setUnderlyingNetworksForVpn(
- new Network[] { mWiFiNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertDefaultNetworkCapabilities(userId, mWiFiNetworkAgent);
-
- // Use both again.
- mService.setUnderlyingNetworksForVpn(
- new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
-
- // Cell is suspended again. As WiFi is not, this should not cause a callback.
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
- vpnNetworkCallback.assertNoCallback();
-
- // Stop using WiFi. The VPN is suspended again.
- mService.setUnderlyingNetworksForVpn(
- new Network[] { mCellNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && !caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- vpnNetworkCallback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
-
- // Use both again.
- mService.setUnderlyingNetworksForVpn(
- new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- vpnNetworkCallback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
-
- // Disconnect cell. Receive update without even removing the dead network from the
- // underlying networks – it's dead anyway. Not metered any more.
- mCellNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertDefaultNetworkCapabilities(userId, mWiFiNetworkAgent);
-
- // Disconnect wifi too. No underlying networks means this is now metered.
- mWiFiNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- // When a network disconnects, the callbacks are fired before all state is updated, so for a
- // short time, synchronous calls will behave as if the network is still connected. Wait for
- // things to settle.
- waitForIdle();
- assertDefaultNetworkCapabilities(userId /* no networks */);
-
- mMockVpn.disconnect();
- }
-
- @Test
- public void testNullUnderlyingNetworks() throws Exception {
- final int uid = Process.myUid();
-
- final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
- final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .addTransportType(TRANSPORT_VPN)
- .build();
- NetworkCapabilities nc;
- mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
- vpnNetworkCallback.assertNoCallback();
-
- mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */,
- false /* isStrictMode */);
-
- vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- assertTrue(nc.hasTransport(TRANSPORT_VPN));
- assertFalse(nc.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(nc.hasTransport(TRANSPORT_WIFI));
- // By default, VPN is set to track default network (i.e. its underlying networks is null).
- // In case of no default network, VPN is considered metered.
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
-
- // Connect to Cell; Cell is the default network.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
-
- // Connect to WiFi; WiFi is the new default.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED));
-
- // Disconnect Cell. The default network did not change, so there shouldn't be any changes in
- // the capabilities.
- mCellNetworkAgent.disconnect();
-
- // Disconnect wifi too. Now we have no default network.
- mWiFiNetworkAgent.disconnect();
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
-
- mMockVpn.disconnect();
- }
-
- @Test
- public void testIsActiveNetworkMeteredOverWifi() throws Exception {
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
-
- assertFalse(mCm.isActiveNetworkMetered());
- }
-
- @Test
- public void testIsActiveNetworkMeteredOverCell() throws Exception {
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- mCellNetworkAgent.connect(true);
- waitForIdle();
-
- assertTrue(mCm.isActiveNetworkMetered());
- }
-
- @Test
- public void testIsActiveNetworkMeteredOverVpnTrackingPlatformDefault() throws Exception {
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- mCellNetworkAgent.connect(true);
- waitForIdle();
- assertTrue(mCm.isActiveNetworkMetered());
-
- // Connect VPN network. By default it is using current default network (Cell).
- mMockVpn.establishForMyUid();
-
- // Ensure VPN is now the active network.
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
-
- // Expect VPN to be metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // Connect WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- // VPN should still be the active network.
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
-
- // Expect VPN to be unmetered as it should now be using WiFi (new default).
- assertFalse(mCm.isActiveNetworkMetered());
-
- // Disconnecting Cell should not affect VPN's meteredness.
- mCellNetworkAgent.disconnect();
- waitForIdle();
-
- assertFalse(mCm.isActiveNetworkMetered());
-
- // Disconnect WiFi; Now there is no platform default network.
- mWiFiNetworkAgent.disconnect();
- waitForIdle();
-
- // VPN without any underlying networks is treated as metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- mMockVpn.disconnect();
- }
-
- @Test
- public void testIsActiveNetworkMeteredOverVpnSpecifyingUnderlyingNetworks() throws Exception {
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- mCellNetworkAgent.connect(true);
- waitForIdle();
- assertTrue(mCm.isActiveNetworkMetered());
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- assertFalse(mCm.isActiveNetworkMetered());
-
- // Connect VPN network.
- mMockVpn.establishForMyUid();
-
- // Ensure VPN is now the active network.
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
- // VPN is using Cell
- mService.setUnderlyingNetworksForVpn(
- new Network[] { mCellNetworkAgent.getNetwork() });
- waitForIdle();
-
- // Expect VPN to be metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // VPN is now using WiFi
- mService.setUnderlyingNetworksForVpn(
- new Network[] { mWiFiNetworkAgent.getNetwork() });
- waitForIdle();
-
- // Expect VPN to be unmetered
- assertFalse(mCm.isActiveNetworkMetered());
-
- // VPN is using Cell | WiFi.
- mService.setUnderlyingNetworksForVpn(
- new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
- waitForIdle();
-
- // Expect VPN to be metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // VPN is using WiFi | Cell.
- mService.setUnderlyingNetworksForVpn(
- new Network[] { mWiFiNetworkAgent.getNetwork(), mCellNetworkAgent.getNetwork() });
- waitForIdle();
-
- // Order should not matter and VPN should still be metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // VPN is not using any underlying networks.
- mService.setUnderlyingNetworksForVpn(new Network[0]);
- waitForIdle();
-
- // VPN without underlying networks is treated as metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- mMockVpn.disconnect();
- }
-
- @Test
- public void testIsActiveNetworkMeteredOverAlwaysMeteredVpn() throws Exception {
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- assertFalse(mCm.isActiveNetworkMetered());
-
- // Connect VPN network.
- mMockVpn.registerAgent(true /* isAlwaysMetered */, uidRangesForUid(Process.myUid()),
- new LinkProperties());
- mMockVpn.connect(true);
- waitForIdle();
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
-
- // VPN is tracking current platform default (WiFi).
- mService.setUnderlyingNetworksForVpn(null);
- waitForIdle();
-
- // Despite VPN using WiFi (which is unmetered), VPN itself is marked as always metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // VPN explicitly declares WiFi as its underlying network.
- mService.setUnderlyingNetworksForVpn(
- new Network[] { mWiFiNetworkAgent.getNetwork() });
- waitForIdle();
-
- // Doesn't really matter whether VPN declares its underlying networks explicitly.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // With WiFi lost, VPN is basically without any underlying networks. And in that case it is
- // anyways suppose to be metered.
- mWiFiNetworkAgent.disconnect();
- waitForIdle();
-
- assertTrue(mCm.isActiveNetworkMetered());
-
- mMockVpn.disconnect();
- }
-
- @Test
- public void testNetworkBlockedStatus() throws Exception {
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .build();
- mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-
- setUidRulesChanged(RULE_REJECT_ALL);
- cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
-
- // ConnectivityService should cache it not to invoke the callback again.
- setUidRulesChanged(RULE_REJECT_METERED);
- cellNetworkCallback.assertNoCallback();
-
- setUidRulesChanged(RULE_NONE);
- cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
-
- setUidRulesChanged(RULE_REJECT_METERED);
- cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
-
- // Restrict the network based on UID rule and NOT_METERED capability change.
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
- cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
- mCellNetworkAgent);
- cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
- setUidRulesChanged(RULE_ALLOW_METERED);
- cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
-
- setUidRulesChanged(RULE_NONE);
- cellNetworkCallback.assertNoCallback();
-
- // Restrict the network based on BackgroundRestricted.
- setRestrictBackgroundChanged(true);
- cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
- setRestrictBackgroundChanged(true);
- cellNetworkCallback.assertNoCallback();
- setRestrictBackgroundChanged(false);
- cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(cellNetworkCallback);
- }
-
- @Test
- public void testNetworkBlockedStatusBeforeAndAfterConnect() throws Exception {
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- // No Networkcallbacks invoked before any network is active.
- setUidRulesChanged(RULE_REJECT_ALL);
- setUidRulesChanged(RULE_NONE);
- setUidRulesChanged(RULE_REJECT_METERED);
- defaultCallback.assertNoCallback();
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
- defaultCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mCellNetworkAgent);
-
- // Allow to use the network after switching to NOT_METERED network.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
-
- // Switch to METERED network. Restrict the use of the network.
- mWiFiNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksValidatedAndBlocked(mCellNetworkAgent);
-
- // Network becomes NOT_METERED.
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- defaultCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
- defaultCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
-
- // Verify there's no Networkcallbacks invoked after data saver on/off.
- setRestrictBackgroundChanged(true);
- setRestrictBackgroundChanged(false);
- defaultCallback.assertNoCallback();
-
- mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(defaultCallback);
- }
-
- private void checkNetworkInfo(NetworkInfo ni, int type, DetailedState state) {
- assertNotNull(ni);
- assertEquals(type, ni.getType());
- assertEquals(ConnectivityManager.getNetworkTypeName(type), state, ni.getDetailedState());
- }
-
- private void assertActiveNetworkInfo(int type, DetailedState state) {
- checkNetworkInfo(mCm.getActiveNetworkInfo(), type, state);
- }
- private void assertNetworkInfo(int type, DetailedState state) {
- checkNetworkInfo(mCm.getNetworkInfo(type), type, state);
- }
-
- @Test
- public final void testLoseTrusted() throws Exception {
- final NetworkRequest trustedRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_TRUSTED)
- .build();
- final TestNetworkCallback trustedCallback = new TestNetworkCallback();
- mCm.requestNetwork(trustedRequest, trustedCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- trustedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- verify(mNetworkManagementService).setDefaultNetId(eq(mCellNetworkAgent.getNetwork().netId));
- reset(mNetworkManagementService);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- trustedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- verify(mNetworkManagementService).setDefaultNetId(eq(mWiFiNetworkAgent.getNetwork().netId));
- reset(mNetworkManagementService);
-
- mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
- trustedCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- verify(mNetworkManagementService).setDefaultNetId(eq(mCellNetworkAgent.getNetwork().netId));
- reset(mNetworkManagementService);
-
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
- trustedCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- verify(mNetworkManagementService).clearDefaultNetId();
-
- mCm.unregisterNetworkCallback(trustedCallback);
- }
-
- @Ignore // 40%+ flakiness : figure out why and re-enable.
- @Test
- public final void testBatteryStatsNetworkType() throws Exception {
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName("cell0");
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
- mCellNetworkAgent.connect(true);
- waitForIdle();
- verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
- TYPE_MOBILE);
- reset(mBatteryStatsService);
-
- final LinkProperties wifiLp = new LinkProperties();
- wifiLp.setInterfaceName("wifi0");
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- verify(mBatteryStatsService).noteNetworkInterfaceType(wifiLp.getInterfaceName(),
- TYPE_WIFI);
- reset(mBatteryStatsService);
-
- mCellNetworkAgent.disconnect();
-
- cellLp.setInterfaceName("wifi0");
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
- mCellNetworkAgent.connect(true);
- waitForIdle();
- verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
- TYPE_MOBILE);
- }
-
- /**
- * Make simulated InterfaceConfig for Nat464Xlat to query clat lower layer info.
- */
- private InterfaceConfiguration getClatInterfaceConfig(LinkAddress la) {
- InterfaceConfiguration cfg = new InterfaceConfiguration();
- cfg.setHardwareAddress("11:22:33:44:55:66");
- cfg.setLinkAddress(la);
- return cfg;
- }
-
- /**
- * Make expected stack link properties, copied from Nat464Xlat.
- */
- private LinkProperties makeClatLinkProperties(LinkAddress la) {
- LinkAddress clatAddress = la;
- LinkProperties stacked = new LinkProperties();
- stacked.setInterfaceName(CLAT_PREFIX + MOBILE_IFNAME);
- RouteInfo ipv4Default = new RouteInfo(
- new LinkAddress(Inet4Address.ANY, 0),
- clatAddress.getAddress(), CLAT_PREFIX + MOBILE_IFNAME);
- stacked.addRoute(ipv4Default);
- stacked.addLinkAddress(clatAddress);
- return stacked;
- }
-
- @Test
- public void testStackedLinkProperties() throws Exception {
- final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24");
- final LinkAddress myIpv6 = new LinkAddress("2001:db8:1::1/64");
- final String kNat64PrefixString = "2001:db8:64:64:64:64::";
- final IpPrefix kNat64Prefix = new IpPrefix(InetAddress.getByName(kNat64PrefixString), 96);
- final String kOtherNat64PrefixString = "64:ff9b::";
- final IpPrefix kOtherNat64Prefix = new IpPrefix(
- InetAddress.getByName(kOtherNat64PrefixString), 96);
- final RouteInfo defaultRoute = new RouteInfo((IpPrefix) null, myIpv6.getAddress(),
- MOBILE_IFNAME);
- final RouteInfo ipv6Subnet = new RouteInfo(myIpv6, null, MOBILE_IFNAME);
- final RouteInfo ipv4Subnet = new RouteInfo(myIpv4, null, MOBILE_IFNAME);
- final RouteInfo stackedDefault = new RouteInfo((IpPrefix) null, myIpv4.getAddress(),
- CLAT_PREFIX + MOBILE_IFNAME);
-
- final NetworkRequest networkRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
-
- // Prepare ipv6 only link properties.
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- cellLp.addLinkAddress(myIpv6);
- cellLp.addRoute(defaultRoute);
- cellLp.addRoute(ipv6Subnet);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
- reset(mNetworkManagementService);
- reset(mMockDnsResolver);
- reset(mMockNetd);
- reset(mBatteryStatsService);
-
- // Connect with ipv6 link properties. Expect prefix discovery to be started.
- mCellNetworkAgent.connect(true);
- final int cellNetId = mCellNetworkAgent.getNetwork().netId;
- waitForIdle();
-
- verify(mMockNetd, times(1)).networkCreatePhysical(eq(cellNetId), anyInt());
- assertRoutesAdded(cellNetId, ipv6Subnet, defaultRoute);
- verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
- verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
- TYPE_MOBILE);
-
- networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
-
- // Switching default network updates TCP buffer sizes.
- verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
-
- // Add an IPv4 address. Expect prefix discovery to be stopped. Netd doesn't tell us that
- // the NAT64 prefix was removed because one was never discovered.
- cellLp.addLinkAddress(myIpv4);
- mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- assertRoutesAdded(cellNetId, ipv4Subnet);
- verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
-
- // Make sure BatteryStats was not told about any v4- interfaces, as none should have
- // come online yet.
- waitForIdle();
- verify(mBatteryStatsService, never()).noteNetworkInterfaceType(startsWith("v4-"), anyInt());
-
- verifyNoMoreInteractions(mMockNetd);
- verifyNoMoreInteractions(mMockDnsResolver);
- reset(mNetworkManagementService);
- reset(mMockNetd);
- reset(mMockDnsResolver);
- when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
- .thenReturn(getClatInterfaceConfig(myIpv4));
-
- // Remove IPv4 address. Expect prefix discovery to be started again.
- cellLp.removeLinkAddress(myIpv4);
- mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
- assertRoutesRemoved(cellNetId, ipv4Subnet);
-
- // When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
- Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent);
- assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix());
- mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
- kNat64PrefixString, 96);
- LinkProperties lpBeforeClat = networkCallback.expectCallback(
- CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent).getLp();
- assertEquals(0, lpBeforeClat.getStackedLinks().size());
- assertEquals(kNat64Prefix, lpBeforeClat.getNat64Prefix());
- verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
-
- // Clat iface comes up. Expect stacked link to be added.
- clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork())
- .getStackedLinks();
- assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0));
- assertRoutesAdded(cellNetId, stackedDefault);
-
- // Change trivial linkproperties and see if stacked link is preserved.
- cellLp.addDnsServer(InetAddress.getByName("8.8.8.8"));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
-
- List<LinkProperties> stackedLpsAfterChange =
- mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getStackedLinks();
- assertNotEquals(stackedLpsAfterChange, Collections.EMPTY_LIST);
- assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0));
-
- verify(mMockDnsResolver, times(1)).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(1, resolvrParams.servers.length);
- assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8"));
-
- for (final LinkProperties stackedLp : stackedLpsAfterChange) {
- verify(mBatteryStatsService).noteNetworkInterfaceType(stackedLp.getInterfaceName(),
- TYPE_MOBILE);
- }
- reset(mMockNetd);
-
- // Change the NAT64 prefix without first removing it.
- // Expect clatd to be stopped and started with the new prefix.
- mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
- kOtherNat64PrefixString, 96);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getStackedLinks().size() == 0);
- verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
- assertRoutesRemoved(cellNetId, stackedDefault);
-
- verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kOtherNat64Prefix.toString());
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getNat64Prefix().equals(kOtherNat64Prefix));
- clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getStackedLinks().size() == 1);
- assertRoutesAdded(cellNetId, stackedDefault);
- reset(mMockNetd);
-
- // Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
- // linkproperties are cleaned up.
- cellLp.addLinkAddress(myIpv4);
- cellLp.addRoute(ipv4Subnet);
- mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- assertRoutesAdded(cellNetId, ipv4Subnet);
- verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
- verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
-
- // As soon as stop is called, the linkproperties lose the stacked interface.
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork());
- LinkProperties expected = new LinkProperties(cellLp);
- expected.setNat64Prefix(kOtherNat64Prefix);
- assertEquals(expected, actualLpAfterIpv4);
- assertEquals(0, actualLpAfterIpv4.getStackedLinks().size());
- assertRoutesRemoved(cellNetId, stackedDefault);
-
- // The interface removed callback happens but has no effect after stop is called.
- clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
- networkCallback.assertNoCallback();
-
- verifyNoMoreInteractions(mMockNetd);
- verifyNoMoreInteractions(mMockDnsResolver);
- reset(mNetworkManagementService);
- reset(mMockNetd);
- reset(mMockDnsResolver);
- when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
- .thenReturn(getClatInterfaceConfig(myIpv4));
-
- // Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
- mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
- kOtherNat64PrefixString, 96);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getNat64Prefix() == null);
-
- // Remove IPv4 address and expect prefix discovery and clatd to be started again.
- cellLp.removeLinkAddress(myIpv4);
- cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
- cellLp.removeDnsServer(InetAddress.getByName("8.8.8.8"));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- assertRoutesRemoved(cellNetId, ipv4Subnet); // Directly-connected routes auto-added.
- verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
- mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
- kNat64PrefixString, 96);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
-
- // Clat iface comes up. Expect stacked link to be added.
- clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getStackedLinks().size() == 1 && lp.getNat64Prefix() != null);
- assertRoutesAdded(cellNetId, stackedDefault);
-
- // NAT64 prefix is removed. Expect that clat is stopped.
- mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
- kNat64PrefixString, 96);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null);
- assertRoutesRemoved(cellNetId, ipv4Subnet, stackedDefault);
-
- // Stop has no effect because clat is already stopped.
- verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getStackedLinks().size() == 0);
- verifyNoMoreInteractions(mMockNetd);
-
- // Clean up.
- mCellNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- networkCallback.assertNoCallback();
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- private void expectNat64PrefixChange(TestableNetworkCallback callback,
- TestNetworkAgentWrapper agent, IpPrefix prefix) {
- callback.expectLinkPropertiesThat(agent, x -> Objects.equals(x.getNat64Prefix(), prefix));
- }
-
- @Test
- public void testNat64PrefixMultipleSources() throws Exception {
- final String iface = "wlan0";
- final String pref64FromRaStr = "64:ff9b::";
- final String pref64FromDnsStr = "2001:db8:64::";
- final IpPrefix pref64FromRa = new IpPrefix(InetAddress.getByName(pref64FromRaStr), 96);
- final IpPrefix pref64FromDns = new IpPrefix(InetAddress.getByName(pref64FromDnsStr), 96);
- final IpPrefix newPref64FromRa = new IpPrefix("2001:db8:64:64:64:64::/96");
-
- final NetworkRequest request = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- final LinkProperties baseLp = new LinkProperties();
- baseLp.setInterfaceName(iface);
- baseLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
- baseLp.addDnsServer(InetAddress.getByName("2001:4860:4860::6464"));
-
- reset(mMockNetd, mMockDnsResolver);
- InOrder inOrder = inOrder(mMockNetd, mMockDnsResolver);
-
- // If a network already has a NAT64 prefix on connect, clatd is started immediately and
- // prefix discovery is never started.
- LinkProperties lp = new LinkProperties(baseLp);
- lp.setNat64Prefix(pref64FromRa);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp);
- mWiFiNetworkAgent.connect(false);
- final Network network = mWiFiNetworkAgent.getNetwork();
- int netId = network.getNetId();
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString());
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString());
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
- callback.assertNoCallback();
- assertEquals(pref64FromRa, mCm.getLinkProperties(network).getNat64Prefix());
-
- // If the RA prefix is withdrawn, clatd is stopped and prefix discovery is started.
- lp.setNat64Prefix(null);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, null);
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
- inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
-
- // If the RA prefix appears while DNS discovery is in progress, discovery is stopped and
- // clatd is started with the prefix from the RA.
- lp.setNat64Prefix(pref64FromRa);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromRa);
- inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString());
- inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString());
-
- // Withdraw the RA prefix so we can test the case where an RA prefix appears after DNS
- // discovery has succeeded.
- lp.setNat64Prefix(null);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, null);
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
- inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
-
- mService.mNetdEventCallback.onNat64PrefixEvent(netId, true /* added */,
- pref64FromDnsStr, 96);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns);
- inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString());
-
- // If an RA advertises the same prefix that was discovered by DNS, nothing happens: prefix
- // discovery is not stopped, and there are no callbacks.
- lp.setNat64Prefix(pref64FromDns);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- callback.assertNoCallback();
- inOrder.verify(mMockNetd, never()).clatdStop(iface);
- inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
- inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString());
-
- // If the RA is later withdrawn, nothing happens again.
- lp.setNat64Prefix(null);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- callback.assertNoCallback();
- inOrder.verify(mMockNetd, never()).clatdStop(iface);
- inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
- inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString());
-
- // If the RA prefix changes, clatd is restarted and prefix discovery is stopped.
- lp.setNat64Prefix(pref64FromRa);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromRa);
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
-
- // Stopping prefix discovery results in a prefix removed notification.
- mService.mNetdEventCallback.onNat64PrefixEvent(netId, false /* added */,
- pref64FromDnsStr, 96);
-
- inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString());
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString());
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
-
- // If the RA prefix changes, clatd is restarted and prefix discovery is not started.
- lp.setNat64Prefix(newPref64FromRa);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, newPref64FromRa);
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
- inOrder.verify(mMockNetd).clatdStart(iface, newPref64FromRa.toString());
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, newPref64FromRa.toString());
- inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
-
- // If the RA prefix changes to the same value, nothing happens.
- lp.setNat64Prefix(newPref64FromRa);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- callback.assertNoCallback();
- assertEquals(newPref64FromRa, mCm.getLinkProperties(network).getNat64Prefix());
- inOrder.verify(mMockNetd, never()).clatdStop(iface);
- inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
- inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString());
-
- // The transition between no prefix and DNS prefix is tested in testStackedLinkProperties.
-
- // If the same prefix is learned first by DNS and then by RA, and clat is later stopped,
- // (e.g., because the network disconnects) setPrefix64(netid, "") is never called.
- lp.setNat64Prefix(null);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, null);
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
- inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
- mService.mNetdEventCallback.onNat64PrefixEvent(netId, true /* added */,
- pref64FromDnsStr, 96);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns);
- inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString());
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), any());
-
- lp.setNat64Prefix(pref64FromDns);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- callback.assertNoCallback();
- inOrder.verify(mMockNetd, never()).clatdStop(iface);
- inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
- inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString());
-
- // When tearing down a network, clat state is only updated after CALLBACK_LOST is fired, but
- // before CONNECTIVITY_ACTION is sent. Wait for CONNECTIVITY_ACTION before verifying that
- // clat has been stopped, or the test will be flaky.
- ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- b.expectBroadcast();
-
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString());
-
- mCm.unregisterNetworkCallback(callback);
- }
-
- @Test
- public void testDataActivityTracking() throws Exception {
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- final NetworkRequest networkRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- mCellNetworkAgent.sendLinkProperties(cellLp);
- reset(mNetworkManagementService);
- mCellNetworkAgent.connect(true);
- networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(),
- eq(ConnectivityManager.TYPE_MOBILE));
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final LinkProperties wifiLp = new LinkProperties();
- wifiLp.setInterfaceName(WIFI_IFNAME);
- mWiFiNetworkAgent.sendLinkProperties(wifiLp);
-
- // Network switch
- reset(mNetworkManagementService);
- mWiFiNetworkAgent.connect(true);
- networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- networkCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- verify(mNetworkManagementService, times(1)).addIdleTimer(eq(WIFI_IFNAME), anyInt(),
- eq(ConnectivityManager.TYPE_WIFI));
- verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(MOBILE_IFNAME));
-
- // Disconnect wifi and switch back to cell
- reset(mNetworkManagementService);
- mWiFiNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- assertNoCallbacks(networkCallback);
- verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME));
- verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(),
- eq(ConnectivityManager.TYPE_MOBILE));
-
- // reconnect wifi
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- wifiLp.setInterfaceName(WIFI_IFNAME);
- mWiFiNetworkAgent.sendLinkProperties(wifiLp);
- mWiFiNetworkAgent.connect(true);
- networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- networkCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
-
- // Disconnect cell
- reset(mNetworkManagementService);
- reset(mMockNetd);
- mCellNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- // LOST callback is triggered earlier than removing idle timer. Broadcast should also be
- // sent as network being switched. Ensure rule removal for cell will not be triggered
- // unexpectedly before network being removed.
- waitForIdle();
- verify(mNetworkManagementService, times(0)).removeIdleTimer(eq(MOBILE_IFNAME));
- verify(mMockNetd, times(1)).networkDestroy(eq(mCellNetworkAgent.getNetwork().netId));
- verify(mMockDnsResolver, times(1))
- .destroyNetworkCache(eq(mCellNetworkAgent.getNetwork().netId));
-
- // Disconnect wifi
- ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
- reset(mNetworkManagementService);
- mWiFiNetworkAgent.disconnect();
- b.expectBroadcast();
- verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME));
-
- // Clean up
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- private void verifyTcpBufferSizeChange(String tcpBufferSizes) throws Exception {
- String[] values = tcpBufferSizes.split(",");
- String rmemValues = String.join(" ", values[0], values[1], values[2]);
- String wmemValues = String.join(" ", values[3], values[4], values[5]);
- verify(mMockNetd, atLeastOnce()).setTcpRWmemorySize(rmemValues, wmemValues);
- reset(mMockNetd);
- }
-
- @Test
- public void testTcpBufferReset() throws Exception {
- final String testTcpBufferSizes = "1,2,3,4,5,6";
- final NetworkRequest networkRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- reset(mMockNetd);
- // Switching default network updates TCP buffer sizes.
- mCellNetworkAgent.connect(false);
- networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
-
- // Change link Properties should have updated tcp buffer size.
- LinkProperties lp = new LinkProperties();
- lp.setTcpBufferSizes(testTcpBufferSizes);
- mCellNetworkAgent.sendLinkProperties(lp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- verifyTcpBufferSizeChange(testTcpBufferSizes);
-
- // Clean up.
- mCellNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- networkCallback.assertNoCallback();
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- @Test
- public void testGetGlobalProxyForNetwork() throws Exception {
- final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
- when(mService.mProxyTracker.getGlobalProxy()).thenReturn(testProxyInfo);
- assertEquals(testProxyInfo, mService.getProxyForNetwork(wifiNetwork));
- }
-
- @Test
- public void testGetProxyForActiveNetwork() throws Exception {
- final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- assertNull(mService.getProxyForNetwork(null));
-
- final LinkProperties testLinkProperties = new LinkProperties();
- testLinkProperties.setHttpProxy(testProxyInfo);
-
- mWiFiNetworkAgent.sendLinkProperties(testLinkProperties);
- waitForIdle();
-
- assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
- }
-
- @Test
- public void testGetProxyForVPN() throws Exception {
- final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
-
- // Set up a WiFi network with no proxy
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- assertNull(mService.getProxyForNetwork(null));
-
- // Connect a VPN network with a proxy.
- LinkProperties testLinkProperties = new LinkProperties();
- testLinkProperties.setHttpProxy(testProxyInfo);
- mMockVpn.establishForMyUid(testLinkProperties);
-
- // Test that the VPN network returns a proxy, and the WiFi does not.
- assertEquals(testProxyInfo, mService.getProxyForNetwork(mMockVpn.getNetwork()));
- assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
- assertNull(mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork()));
-
- // Test that the VPN network returns no proxy when it is set to null.
- testLinkProperties.setHttpProxy(null);
- mMockVpn.sendLinkProperties(testLinkProperties);
- waitForIdle();
- assertNull(mService.getProxyForNetwork(mMockVpn.getNetwork()));
- assertNull(mService.getProxyForNetwork(null));
-
- // Set WiFi proxy and check that the vpn proxy is still null.
- testLinkProperties.setHttpProxy(testProxyInfo);
- mWiFiNetworkAgent.sendLinkProperties(testLinkProperties);
- waitForIdle();
- assertNull(mService.getProxyForNetwork(null));
-
- // Disconnect from VPN and check that the active network, which is now the WiFi, has the
- // correct proxy setting.
- mMockVpn.disconnect();
- waitForIdle();
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(testProxyInfo, mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork()));
- assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
- }
-
- @Test
- public void testFullyRoutedVpnResultsInInterfaceFilteringRules() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
- // The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
- mMockVpn.establish(lp, VPN_UID, vpnRange);
-
- // Connected VPN should have interface rules set up. There are two expected invocations,
- // one during VPN uid update, one during VPN LinkProperties update
- ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
- verify(mMockNetd, times(2)).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
- assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID);
- assertContainsExactly(uidCaptor.getAllValues().get(1), APP1_UID, APP2_UID);
- assertTrue(mService.mPermissionMonitor.getVpnUidRanges("tun0").equals(vpnRange));
-
- mMockVpn.disconnect();
- waitForIdle();
-
- // Disconnected VPN should have interface rules removed
- verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
- assertNull(mService.mPermissionMonitor.getVpnUidRanges("tun0"));
- }
-
- @Test
- public void testLegacyVpnDoesNotResultInInterfaceFilteringRule() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
- // The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
- mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
-
- // Legacy VPN should not have interface rules set up
- verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any());
- }
-
- @Test
- public void testLocalIpv4OnlyVpnDoesNotResultInInterfaceFilteringRule()
- throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0"));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
- // The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
- mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
-
- // IPv6 unreachable route should not be misinterpreted as a default route
- verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any());
- }
-
- @Test
- public void testVpnHandoverChangesInterfaceFilteringRule() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- // The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
- mMockVpn.establish(lp, VPN_UID, vpnRange);
-
- // Connected VPN should have interface rules set up. There are two expected invocations,
- // one during VPN uid update, one during VPN LinkProperties update
- ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
- verify(mMockNetd, times(2)).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
- assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID);
- assertContainsExactly(uidCaptor.getAllValues().get(1), APP1_UID, APP2_UID);
-
- reset(mMockNetd);
- InOrder inOrder = inOrder(mMockNetd);
- lp.setInterfaceName("tun1");
- mMockVpn.sendLinkProperties(lp);
- waitForIdle();
- // VPN handover (switch to a new interface) should result in rules being updated (old rules
- // removed first, then new rules added)
- inOrder.verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
- inOrder.verify(mMockNetd).firewallAddUidInterfaceRules(eq("tun1"), uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
-
- reset(mMockNetd);
- lp = new LinkProperties();
- lp.setInterfaceName("tun1");
- lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun1"));
- mMockVpn.sendLinkProperties(lp);
- waitForIdle();
- // VPN not routing everything should no longer have interface filtering rules
- verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
-
- reset(mMockNetd);
- lp = new LinkProperties();
- lp.setInterfaceName("tun1");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- mMockVpn.sendLinkProperties(lp);
- waitForIdle();
- // Back to routing all IPv6 traffic should have filtering rules
- verify(mMockNetd).firewallAddUidInterfaceRules(eq("tun1"), uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
- }
-
- @Test
- public void testStartVpnProfileFromDiffPackage() throws Exception {
- final String notMyVpnPkg = "com.not.my.vpn";
- assertThrows(SecurityException.class, () -> mService.startVpnProfile(notMyVpnPkg));
- }
-
- @Test
- public void testStopVpnProfileFromDiffPackage() throws Exception {
- final String notMyVpnPkg = "com.not.my.vpn";
- assertThrows(SecurityException.class, () -> mService.stopVpnProfile(notMyVpnPkg));
- }
-
- @Test
- public void testUidUpdateChangesInterfaceFilteringRule() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- // The uid range needs to cover the test app so the network is visible to it.
- final UidRange vpnRange = UidRange.createForUser(VPN_USER);
- mMockVpn.establish(lp, VPN_UID, Collections.singleton(vpnRange));
-
- reset(mMockNetd);
- InOrder inOrder = inOrder(mMockNetd);
-
- // Update to new range which is old range minus APP1, i.e. only APP2
- final Set<UidRange> newRanges = new HashSet<>(Arrays.asList(
- new UidRange(vpnRange.start, APP1_UID - 1),
- new UidRange(APP1_UID + 1, vpnRange.stop)));
- mMockVpn.setUids(newRanges);
- waitForIdle();
-
- ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
- // Verify old rules are removed before new rules are added
- inOrder.verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
- inOrder.verify(mMockNetd).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP2_UID);
- }
-
- @Test
- public void testLinkPropertiesWithWakeOnLanForActiveNetwork() throws Exception {
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-
- LinkProperties wifiLp = new LinkProperties();
- wifiLp.setInterfaceName(WIFI_WOL_IFNAME);
- wifiLp.setWakeOnLanSupported(false);
-
- // Default network switch should update ifaces.
- mWiFiNetworkAgent.connect(false);
- mWiFiNetworkAgent.sendLinkProperties(wifiLp);
- waitForIdle();
-
- // ConnectivityService should have changed the WakeOnLanSupported to true
- wifiLp.setWakeOnLanSupported(true);
- assertEquals(wifiLp, mService.getActiveLinkProperties());
- }
-
- @Test
- public void testLegacyExtraInfoSentToNetworkMonitor() throws Exception {
- class TestNetworkAgent extends NetworkAgent {
- TestNetworkAgent(Context context, Looper looper, NetworkAgentConfig config) {
- super(context, looper, "MockAgent", new NetworkCapabilities(),
- new LinkProperties(), 40 , config, null /* provider */);
- }
- }
- final NetworkAgent naNoExtraInfo = new TestNetworkAgent(
- mServiceContext, mCsHandlerThread.getLooper(), new NetworkAgentConfig());
- naNoExtraInfo.register();
- verify(mNetworkStack).makeNetworkMonitor(any(), isNull(String.class), any());
- naNoExtraInfo.unregister();
-
- reset(mNetworkStack);
- final NetworkAgentConfig config =
- new NetworkAgentConfig.Builder().setLegacyExtraInfo("legacyinfo").build();
- final NetworkAgent naExtraInfo = new TestNetworkAgent(
- mServiceContext, mCsHandlerThread.getLooper(), config);
- naExtraInfo.register();
- verify(mNetworkStack).makeNetworkMonitor(any(), eq("legacyinfo"), any());
- naExtraInfo.unregister();
- }
-
- private void setupLocationPermissions(
- int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
- final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.targetSdkVersion = targetSdk;
- when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
- .thenReturn(applicationInfo);
-
- when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
-
- if (op != null) {
- when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName())))
- .thenReturn(AppOpsManager.MODE_ALLOWED);
- }
-
- if (perm != null) {
- mServiceContext.setPermission(perm, PERMISSION_GRANTED);
- }
- }
-
- private int getOwnerUidNetCapsForCallerPermission(int ownerUid, int callerUid) {
- final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
-
- return mService
- .maybeSanitizeLocationInfoForCaller(netCap, callerUid, mContext.getPackageName())
- .getOwnerUid();
- }
-
- @Test
- public void testMaybeSanitizeLocationInfoForCallerWithFineLocationAfterQ() throws Exception {
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- final int myUid = Process.myUid();
- assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
- }
-
- @Test
- public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationPreQ() throws Exception {
- setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION);
-
- final int myUid = Process.myUid();
- assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
- }
-
- @Test
- public void testMaybeSanitizeLocationInfoForCallerLocationOff() throws Exception {
- // Test that even with fine location permission, and UIDs matching, the UID is sanitized.
- setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
- }
-
- @Test
- public void testMaybeSanitizeLocationInfoForCallerWrongUid() throws Exception {
- // Test that even with fine location permission, not being the owner leads to sanitization.
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid + 1, myUid));
- }
-
- @Test
- public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationAfterQ() throws Exception {
- // Test that not having fine location permission leads to sanitization.
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION);
-
- // Test that without the location permission, the owner field is sanitized.
- final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
- }
-
- @Test
- public void testMaybeSanitizeLocationInfoForCallerWithoutLocationPermission() throws Exception {
- setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
-
- // Test that without the location permission, the owner field is sanitized.
- final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
- }
-
- private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
- throws Exception {
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
- mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange);
- mMockVpn.setVpnType(vpnType);
-
- final VpnInfo vpnInfo = new VpnInfo();
- vpnInfo.ownerUid = vpnOwnerUid;
- mMockVpn.setVpnInfo(vpnInfo);
- }
-
- private void setupConnectionOwnerUidAsVpnApp(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
- throws Exception {
- setupConnectionOwnerUid(vpnOwnerUid, vpnType);
-
- // Test as VPN app
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
- mServiceContext.setPermission(
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, PERMISSION_DENIED);
- }
-
- private ConnectionInfo getTestConnectionInfo() throws Exception {
- return new ConnectionInfo(
- IPPROTO_TCP,
- new InetSocketAddress(InetAddresses.parseNumericAddress("1.2.3.4"), 1234),
- new InetSocketAddress(InetAddresses.parseNumericAddress("2.3.4.5"), 2345));
- }
-
- @Test
- public void testGetConnectionOwnerUidPlatformVpn() throws Exception {
- final int myUid = Process.myUid();
- setupConnectionOwnerUidAsVpnApp(myUid, VpnManager.TYPE_VPN_PLATFORM);
-
- try {
- mService.getConnectionOwnerUid(getTestConnectionInfo());
- fail("Expected SecurityException for non-VpnService app");
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void testGetConnectionOwnerUidVpnServiceWrongUser() throws Exception {
- final int myUid = Process.myUid();
- setupConnectionOwnerUidAsVpnApp(myUid + 1, VpnManager.TYPE_VPN_SERVICE);
-
- try {
- mService.getConnectionOwnerUid(getTestConnectionInfo());
- fail("Expected SecurityException for non-VpnService app");
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void testGetConnectionOwnerUidVpnServiceDoesNotThrow() throws Exception {
- final int myUid = Process.myUid();
- setupConnectionOwnerUidAsVpnApp(myUid, VpnManager.TYPE_VPN_SERVICE);
-
- // TODO: Test the returned UID
- mService.getConnectionOwnerUid(getTestConnectionInfo());
- }
-
- @Test
- public void testGetConnectionOwnerUidVpnServiceNetworkStackDoesNotThrow() throws Exception {
- final int myUid = Process.myUid();
- setupConnectionOwnerUid(myUid, VpnManager.TYPE_VPN_SERVICE);
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
-
- // TODO: Test the returned UID
- mService.getConnectionOwnerUid(getTestConnectionInfo());
- }
-
- @Test
- public void testGetConnectionOwnerUidVpnServiceMainlineNetworkStackDoesNotThrow()
- throws Exception {
- final int myUid = Process.myUid();
- setupConnectionOwnerUid(myUid, VpnManager.TYPE_VPN_SERVICE);
- mServiceContext.setPermission(
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, PERMISSION_GRANTED);
-
- // TODO: Test the returned UID
- mService.getConnectionOwnerUid(getTestConnectionInfo());
- }
-
- private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid) {
- final PackageInfo packageInfo = new PackageInfo();
- if (hasSystemPermission) {
- packageInfo.requestedPermissions = new String[] {
- CHANGE_NETWORK_STATE, CONNECTIVITY_USE_RESTRICTED_NETWORKS };
- packageInfo.requestedPermissionsFlags = new int[] {
- REQUESTED_PERMISSION_GRANTED, REQUESTED_PERMISSION_GRANTED };
- } else {
- packageInfo.requestedPermissions = new String[0];
- }
- packageInfo.applicationInfo = new ApplicationInfo();
- packageInfo.applicationInfo.privateFlags = 0;
- packageInfo.applicationInfo.uid = UserHandle.getUid(UserHandle.USER_SYSTEM,
- UserHandle.getAppId(uid));
- return packageInfo;
- }
-
- @Test
- public void testRegisterConnectivityDiagnosticsCallbackInvalidRequest() throws Exception {
- final NetworkRequest request =
- new NetworkRequest(
- new NetworkCapabilities(), TYPE_ETHERNET, 0, NetworkRequest.Type.NONE);
- try {
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
- fail("registerConnectivityDiagnosticsCallback should throw on invalid NetworkRequest");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- private void assertRouteInfoParcelMatches(RouteInfo route, RouteInfoParcel parcel) {
- assertEquals(route.getDestination().toString(), parcel.destination);
- assertEquals(route.getInterface(), parcel.ifName);
- assertEquals(route.getMtu(), parcel.mtu);
-
- switch (route.getType()) {
- case RouteInfo.RTN_UNICAST:
- if (route.hasGateway()) {
- assertEquals(route.getGateway().getHostAddress(), parcel.nextHop);
- } else {
- assertEquals(INetd.NEXTHOP_NONE, parcel.nextHop);
- }
- break;
- case RouteInfo.RTN_UNREACHABLE:
- assertEquals(INetd.NEXTHOP_UNREACHABLE, parcel.nextHop);
- break;
- case RouteInfo.RTN_THROW:
- assertEquals(INetd.NEXTHOP_THROW, parcel.nextHop);
- break;
- default:
- assertEquals(INetd.NEXTHOP_NONE, parcel.nextHop);
- break;
- }
- }
-
- private void assertRoutesAdded(int netId, RouteInfo... routes) throws Exception {
- ArgumentCaptor<RouteInfoParcel> captor = ArgumentCaptor.forClass(RouteInfoParcel.class);
- verify(mMockNetd, times(routes.length)).networkAddRouteParcel(eq(netId), captor.capture());
- for (int i = 0; i < routes.length; i++) {
- assertRouteInfoParcelMatches(routes[i], captor.getAllValues().get(i));
- }
- }
-
- private void assertRoutesRemoved(int netId, RouteInfo... routes) throws Exception {
- ArgumentCaptor<RouteInfoParcel> captor = ArgumentCaptor.forClass(RouteInfoParcel.class);
- verify(mMockNetd, times(routes.length)).networkRemoveRouteParcel(eq(netId),
- captor.capture());
- for (int i = 0; i < routes.length; i++) {
- assertRouteInfoParcelMatches(routes[i], captor.getAllValues().get(i));
- }
- }
-
- @Test
- public void testRegisterUnregisterConnectivityDiagnosticsCallback() throws Exception {
- final NetworkRequest wifiRequest =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build();
- when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
-
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName());
-
- // Block until all other events are done processing.
- HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- verify(mIBinder).linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
- verify(mConnectivityDiagnosticsCallback).asBinder();
- assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
-
- mService.unregisterConnectivityDiagnosticsCallback(mConnectivityDiagnosticsCallback);
- verify(mIBinder, timeout(TIMEOUT_MS))
- .unlinkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
- assertFalse(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
- verify(mConnectivityDiagnosticsCallback, atLeastOnce()).asBinder();
- }
-
- @Test
- public void testRegisterDuplicateConnectivityDiagnosticsCallback() throws Exception {
- final NetworkRequest wifiRequest =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build();
- when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
-
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName());
-
- // Block until all other events are done processing.
- HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- verify(mIBinder).linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
- verify(mConnectivityDiagnosticsCallback).asBinder();
- assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
-
- // Register the same callback again
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName());
-
- // Block until all other events are done processing.
- HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception {
- final NetworkAgentInfo naiWithoutUid =
- new NetworkAgentInfo(
- null, null, null, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
-
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
- assertTrue(
- "NetworkStack permission not applied",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid(), Process.myUid(), naiWithoutUid,
- mContext.getOpPackageName()));
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsWrongUidPackageName() throws Exception {
- final NetworkAgentInfo naiWithoutUid =
- new NetworkAgentInfo(
- null, null, null, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
-
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
-
- assertFalse(
- "Mismatched uid/package name should not pass the location permission check",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid() + 1, Process.myUid() + 1, naiWithoutUid,
- mContext.getOpPackageName()));
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsNoLocationPermission() throws Exception {
- final NetworkAgentInfo naiWithoutUid =
- new NetworkAgentInfo(
- null, null, null, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
-
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
-
- assertFalse(
- "ACCESS_FINE_LOCATION permission necessary for Connectivity Diagnostics",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid(), Process.myUid(), naiWithoutUid,
- mContext.getOpPackageName()));
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsActiveVpn() throws Exception {
- final Network network = new Network(NET_ID);
- final NetworkAgentInfo naiWithoutUid =
- new NetworkAgentInfo(
- null, null, network, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
-
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- // setUp() calls mockVpn() which adds a VPN with the Test Runner's uid. Configure it to be
- // active
- final VpnInfo info = new VpnInfo();
- info.ownerUid = Process.myUid();
- info.vpnIface = VPN_IFNAME;
- mMockVpn.setVpnInfo(info);
-
- mMockVpn.establishForMyUid();
- waitForIdle();
-
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
-
-
- assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {network}));
- assertTrue(
- "Active VPN permission not applied",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid(), Process.myUid(), naiWithoutUid,
- mContext.getOpPackageName()));
-
- assertTrue(mService.setUnderlyingNetworksForVpn(null));
- assertFalse(
- "VPN shouldn't receive callback on non-underlying network",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid(), Process.myUid(), naiWithoutUid,
- mContext.getOpPackageName()));
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsNetworkAdministrator() throws Exception {
- final NetworkCapabilities nc = new NetworkCapabilities();
- nc.setAdministratorUids(new int[] {Process.myUid()});
- final NetworkAgentInfo naiWithUid =
- new NetworkAgentInfo(
- null, null, null, null, null, nc, 0, mServiceContext, null, null,
- mService, null, null, null, 0, INVALID_UID);
-
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
-
- assertTrue(
- "NetworkCapabilities administrator uid permission not applied",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid(), Process.myUid(), naiWithUid, mContext.getOpPackageName()));
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsFails() throws Exception {
- final NetworkCapabilities nc = new NetworkCapabilities();
- nc.setOwnerUid(Process.myUid());
- nc.setAdministratorUids(new int[] {Process.myUid()});
- final NetworkAgentInfo naiWithUid =
- new NetworkAgentInfo(
- null, null, null, null, null, nc, 0, mServiceContext, null, null,
- mService, null, null, null, 0, INVALID_UID);
-
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
-
- // Use wrong pid and uid
- assertFalse(
- "Permissions allowed when they shouldn't be granted",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid() + 1, Process.myUid() + 1, naiWithUid,
- mContext.getOpPackageName()));
- }
-
- @Test
- public void testRegisterConnectivityDiagnosticsCallbackCallsOnConnectivityReport()
- throws Exception {
- // Set up the Network, which leads to a ConnectivityReport being cached for the network.
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(callback);
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setInterfaceName(INTERFACE_NAME);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, linkProperties);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- callback.assertNoCallback();
-
- final NetworkRequest request = new NetworkRequest.Builder().build();
- when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
-
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
-
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
-
- // Block until all other events are done processing.
- HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- verify(mConnectivityDiagnosticsCallback)
- .onConnectivityReportAvailable(argThat(report -> {
- return INTERFACE_NAME.equals(report.getLinkProperties().getInterfaceName())
- && report.getNetworkCapabilities().hasTransport(TRANSPORT_CELLULAR);
- }));
- }
-
- private void setUpConnectivityDiagnosticsCallback() throws Exception {
- final NetworkRequest request = new NetworkRequest.Builder().build();
- when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
-
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
-
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
-
- // Block until all other events are done processing.
- HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- // Connect the cell agent verify that it notifies TestNetworkCallback that it is available
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(callback);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- callback.assertNoCallback();
- }
-
- @Test
- public void testConnectivityDiagnosticsCallbackOnConnectivityReportAvailable()
- throws Exception {
- setUpConnectivityDiagnosticsCallback();
-
- // Block until all other events are done processing.
- HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- // Verify onConnectivityReport fired
- verify(mConnectivityDiagnosticsCallback).onConnectivityReportAvailable(
- argThat(report -> {
- final NetworkCapabilities nc = report.getNetworkCapabilities();
- return nc.getUids() == null
- && nc.getAdministratorUids().length == 0
- && nc.getOwnerUid() == Process.INVALID_UID;
- }));
- }
-
- @Test
- public void testConnectivityDiagnosticsCallbackOnDataStallSuspected() throws Exception {
- setUpConnectivityDiagnosticsCallback();
-
- // Trigger notifyDataStallSuspected() on the INetworkMonitorCallbacks instance in the
- // cellular network agent
- mCellNetworkAgent.notifyDataStallSuspected();
-
- // Block until all other events are done processing.
- HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- // Verify onDataStallSuspected fired
- verify(mConnectivityDiagnosticsCallback).onDataStallSuspected(
- argThat(report -> {
- final NetworkCapabilities nc = report.getNetworkCapabilities();
- return nc.getUids() == null
- && nc.getAdministratorUids().length == 0
- && nc.getOwnerUid() == Process.INVALID_UID;
- }));
- }
-
- @Test
- public void testConnectivityDiagnosticsCallbackOnConnectivityReported() throws Exception {
- setUpConnectivityDiagnosticsCallback();
-
- final Network n = mCellNetworkAgent.getNetwork();
- final boolean hasConnectivity = true;
- mService.reportNetworkConnectivity(n, hasConnectivity);
-
- // Block until all other events are done processing.
- HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- // Verify onNetworkConnectivityReported fired
- verify(mConnectivityDiagnosticsCallback)
- .onNetworkConnectivityReported(eq(n), eq(hasConnectivity));
-
- final boolean noConnectivity = false;
- mService.reportNetworkConnectivity(n, noConnectivity);
-
- // Block until all other events are done processing.
- HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- // Wait for onNetworkConnectivityReported to fire
- verify(mConnectivityDiagnosticsCallback)
- .onNetworkConnectivityReported(eq(n), eq(noConnectivity));
- }
-
- @Test
- public void testRouteAddDeleteUpdate() throws Exception {
- final NetworkRequest request = new NetworkRequest.Builder().build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, networkCallback);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- reset(mMockNetd);
- mCellNetworkAgent.connect(false);
- networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- final int netId = mCellNetworkAgent.getNetwork().netId;
-
- final String iface = "rmnet_data0";
- final InetAddress gateway = InetAddress.getByName("fe80::5678");
- RouteInfo direct = RouteInfo.makeHostRoute(gateway, iface);
- RouteInfo rio1 = new RouteInfo(new IpPrefix("2001:db8:1::/48"), gateway, iface);
- RouteInfo rio2 = new RouteInfo(new IpPrefix("2001:db8:2::/48"), gateway, iface);
- RouteInfo defaultRoute = new RouteInfo((IpPrefix) null, gateway, iface);
- RouteInfo defaultWithMtu = new RouteInfo(null, gateway, iface, RouteInfo.RTN_UNICAST,
- 1280 /* mtu */);
-
- // Send LinkProperties and check that we ask netd to add routes.
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(iface);
- lp.addRoute(direct);
- lp.addRoute(rio1);
- lp.addRoute(defaultRoute);
- mCellNetworkAgent.sendLinkProperties(lp);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, x -> x.getRoutes().size() == 3);
-
- assertRoutesAdded(netId, direct, rio1, defaultRoute);
- reset(mMockNetd);
-
- // Send updated LinkProperties and check that we ask netd to add, remove, update routes.
- assertTrue(lp.getRoutes().contains(defaultRoute));
- lp.removeRoute(rio1);
- lp.addRoute(rio2);
- lp.addRoute(defaultWithMtu);
- // Ensure adding the same route with a different MTU replaces the previous route.
- assertFalse(lp.getRoutes().contains(defaultRoute));
- assertTrue(lp.getRoutes().contains(defaultWithMtu));
-
- mCellNetworkAgent.sendLinkProperties(lp);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- x -> x.getRoutes().contains(rio2));
-
- assertRoutesRemoved(netId, rio1);
- assertRoutesAdded(netId, rio2);
-
- ArgumentCaptor<RouteInfoParcel> captor = ArgumentCaptor.forClass(RouteInfoParcel.class);
- verify(mMockNetd).networkUpdateRouteParcel(eq(netId), captor.capture());
- assertRouteInfoParcelMatches(defaultWithMtu, captor.getValue());
-
-
- mCm.unregisterNetworkCallback(networkCallback);
- }
-}
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
deleted file mode 100644
index 529d03c520ba..000000000000
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ /dev/null
@@ -1,838 +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 android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.AppOpsManager;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.net.INetd;
-import android.net.IpSecAlgorithm;
-import android.net.IpSecConfig;
-import android.net.IpSecManager;
-import android.net.IpSecSpiResponse;
-import android.net.IpSecTransform;
-import android.net.IpSecTransformResponse;
-import android.net.IpSecTunnelInterfaceResponse;
-import android.net.IpSecUdpEncapResponse;
-import android.net.LinkAddress;
-import android.net.Network;
-import android.net.NetworkUtils;
-import android.os.Binder;
-import android.os.INetworkManagementService;
-import android.os.ParcelFileDescriptor;
-import android.system.Os;
-import android.test.mock.MockContext;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.net.Inet4Address;
-import java.net.Socket;
-import java.util.Arrays;
-import java.util.Collection;
-
-/** Unit tests for {@link IpSecService}. */
-@SmallTest
-@RunWith(Parameterized.class)
-public class IpSecServiceParameterizedTest {
-
- private static final int TEST_SPI = 0xD1201D;
-
- private final String mSourceAddr;
- private final String mDestinationAddr;
- private final LinkAddress mLocalInnerAddress;
- private final int mFamily;
-
- private static final int[] ADDRESS_FAMILIES =
- new int[] {AF_INET, AF_INET6};
-
- @Parameterized.Parameters
- public static Collection ipSecConfigs() {
- return Arrays.asList(
- new Object[][] {
- {"1.2.3.4", "8.8.4.4", "10.0.1.1/24", AF_INET},
- {"2601::2", "2601::10", "2001:db8::1/64", AF_INET6}
- });
- }
-
- private static final byte[] AEAD_KEY = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
- 0x73, 0x61, 0x6C, 0x74
- };
- private static final byte[] CRYPT_KEY = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
- };
- private static final byte[] AUTH_KEY = {
- 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
- 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
- };
-
- AppOpsManager mMockAppOps = mock(AppOpsManager.class);
-
- MockContext mMockContext = new MockContext() {
- @Override
- public Object getSystemService(String name) {
- switch(name) {
- case Context.APP_OPS_SERVICE:
- return mMockAppOps;
- default:
- return null;
- }
- }
-
- @Override
- public PackageManager getPackageManager() {
- return mMockPkgMgr;
- }
-
- @Override
- public void enforceCallingOrSelfPermission(String permission, String message) {
- if (permission == android.Manifest.permission.MANAGE_IPSEC_TUNNELS) {
- return;
- }
- throw new SecurityException("Unavailable permission requested");
- }
- };
-
- INetd mMockNetd;
- INetworkManagementService mNetworkManager;
- PackageManager mMockPkgMgr;
- IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
- IpSecService mIpSecService;
- Network fakeNetwork = new Network(0xAB);
- int mUid = Os.getuid();
-
- private static final IpSecAlgorithm AUTH_ALGO =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
- private static final IpSecAlgorithm CRYPT_ALGO =
- new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- private static final IpSecAlgorithm AEAD_ALGO =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
- private static final int REMOTE_ENCAP_PORT = 4500;
-
- public IpSecServiceParameterizedTest(
- String sourceAddr, String destAddr, String localInnerAddr, int family) {
- mSourceAddr = sourceAddr;
- mDestinationAddr = destAddr;
- mLocalInnerAddress = new LinkAddress(localInnerAddr);
- mFamily = family;
- }
-
- @Before
- public void setUp() throws Exception {
- mMockNetd = mock(INetd.class);
- mNetworkManager = mock(INetworkManagementService.class);
- mMockPkgMgr = mock(PackageManager.class);
- mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
- mIpSecService = new IpSecService(mMockContext, mNetworkManager, mMockIpSecSrvConfig);
-
- // Injecting mock netd
- when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
-
- // PackageManager should always return true (feature flag tests in IpSecServiceTest)
- when(mMockPkgMgr.hasSystemFeature(anyString())).thenReturn(true);
-
- // A package granted the AppOp for MANAGE_IPSEC_TUNNELS will be MODE_ALLOWED.
- when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("blessedPackage")))
- .thenReturn(AppOpsManager.MODE_ALLOWED);
- // A system package will not be granted the app op, so this should fall back to
- // a permissions check, which should pass.
- when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("systemPackage")))
- .thenReturn(AppOpsManager.MODE_DEFAULT);
- // A mismatch between the package name and the UID will return MODE_IGNORED.
- when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("badPackage")))
- .thenReturn(AppOpsManager.MODE_IGNORED);
- }
-
- //TODO: Add a test to verify SPI.
-
- @Test
- public void testIpSecServiceReserveSpi() throws Exception {
- when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
- .thenReturn(TEST_SPI);
-
- IpSecSpiResponse spiResp =
- mIpSecService.allocateSecurityParameterIndex(
- mDestinationAddr, TEST_SPI, new Binder());
- assertEquals(IpSecManager.Status.OK, spiResp.status);
- assertEquals(TEST_SPI, spiResp.spi);
- }
-
- @Test
- public void testReleaseSecurityParameterIndex() throws Exception {
- when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
- .thenReturn(TEST_SPI);
-
- IpSecSpiResponse spiResp =
- mIpSecService.allocateSecurityParameterIndex(
- mDestinationAddr, TEST_SPI, new Binder());
-
- mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
-
- verify(mMockNetd)
- .ipSecDeleteSecurityAssociation(
- eq(mUid),
- anyString(),
- anyString(),
- eq(TEST_SPI),
- anyInt(),
- anyInt(),
- anyInt());
-
- // Verify quota and RefcountedResource objects cleaned up
- IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
- try {
- userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
- fail("Expected IllegalArgumentException on attempt to access deleted resource");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testSecurityParameterIndexBinderDeath() throws Exception {
- when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
- .thenReturn(TEST_SPI);
-
- IpSecSpiResponse spiResp =
- mIpSecService.allocateSecurityParameterIndex(
- mDestinationAddr, TEST_SPI, new Binder());
-
- IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- IpSecService.RefcountedResource refcountedRecord =
- userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
-
- refcountedRecord.binderDied();
-
- verify(mMockNetd)
- .ipSecDeleteSecurityAssociation(
- eq(mUid),
- anyString(),
- anyString(),
- eq(TEST_SPI),
- anyInt(),
- anyInt(),
- anyInt());
-
- // Verify quota and RefcountedResource objects cleaned up
- assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
- try {
- userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
- fail("Expected IllegalArgumentException on attempt to access deleted resource");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- private int getNewSpiResourceId(String remoteAddress, int returnSpi) throws Exception {
- when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), anyString(), anyInt()))
- .thenReturn(returnSpi);
-
- IpSecSpiResponse spi =
- mIpSecService.allocateSecurityParameterIndex(
- NetworkUtils.numericToInetAddress(remoteAddress).getHostAddress(),
- IpSecManager.INVALID_SECURITY_PARAMETER_INDEX,
- new Binder());
- return spi.resourceId;
- }
-
- private void addDefaultSpisAndRemoteAddrToIpSecConfig(IpSecConfig config) throws Exception {
- config.setSpiResourceId(getNewSpiResourceId(mDestinationAddr, TEST_SPI));
- config.setSourceAddress(mSourceAddr);
- config.setDestinationAddress(mDestinationAddr);
- }
-
- private void addAuthAndCryptToIpSecConfig(IpSecConfig config) throws Exception {
- config.setEncryption(CRYPT_ALGO);
- config.setAuthentication(AUTH_ALGO);
- }
-
- private void addEncapSocketToIpSecConfig(int resourceId, IpSecConfig config) throws Exception {
- config.setEncapType(IpSecTransform.ENCAP_ESPINUDP);
- config.setEncapSocketResourceId(resourceId);
- config.setEncapRemotePort(REMOTE_ENCAP_PORT);
- }
-
- private void verifyTransformNetdCalledForCreatingSA(
- IpSecConfig config, IpSecTransformResponse resp) throws Exception {
- verifyTransformNetdCalledForCreatingSA(config, resp, 0);
- }
-
- private void verifyTransformNetdCalledForCreatingSA(
- IpSecConfig config, IpSecTransformResponse resp, int encapSocketPort) throws Exception {
- IpSecAlgorithm auth = config.getAuthentication();
- IpSecAlgorithm crypt = config.getEncryption();
- IpSecAlgorithm authCrypt = config.getAuthenticatedEncryption();
-
- verify(mMockNetd, times(1))
- .ipSecAddSecurityAssociation(
- eq(mUid),
- eq(config.getMode()),
- eq(config.getSourceAddress()),
- eq(config.getDestinationAddress()),
- eq((config.getNetwork() != null) ? config.getNetwork().netId : 0),
- eq(TEST_SPI),
- eq(0),
- eq(0),
- eq((auth != null) ? auth.getName() : ""),
- eq((auth != null) ? auth.getKey() : new byte[] {}),
- eq((auth != null) ? auth.getTruncationLengthBits() : 0),
- eq((crypt != null) ? crypt.getName() : ""),
- eq((crypt != null) ? crypt.getKey() : new byte[] {}),
- eq((crypt != null) ? crypt.getTruncationLengthBits() : 0),
- eq((authCrypt != null) ? authCrypt.getName() : ""),
- eq((authCrypt != null) ? authCrypt.getKey() : new byte[] {}),
- eq((authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0),
- eq(config.getEncapType()),
- eq(encapSocketPort),
- eq(config.getEncapRemotePort()),
- eq(config.getXfrmInterfaceId()));
- }
-
- @Test
- public void testCreateTransform() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
- assertEquals(IpSecManager.Status.OK, createTransformResp.status);
-
- verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
- }
-
- @Test
- public void testCreateTransformAead() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
-
- ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
- assertEquals(IpSecManager.Status.OK, createTransformResp.status);
-
- verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
- }
-
- @Test
- public void testCreateTransportModeTransformWithEncap() throws Exception {
- IpSecUdpEncapResponse udpSock = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
-
- IpSecConfig ipSecConfig = new IpSecConfig();
- ipSecConfig.setMode(IpSecTransform.MODE_TRANSPORT);
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
- addEncapSocketToIpSecConfig(udpSock.resourceId, ipSecConfig);
-
- if (mFamily == AF_INET) {
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
- assertEquals(IpSecManager.Status.OK, createTransformResp.status);
-
- verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
- } else {
- try {
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
- fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
- } catch (IllegalArgumentException expected) {
- }
- }
- }
-
- @Test
- public void testCreateTunnelModeTransformWithEncap() throws Exception {
- IpSecUdpEncapResponse udpSock = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
-
- IpSecConfig ipSecConfig = new IpSecConfig();
- ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
- addEncapSocketToIpSecConfig(udpSock.resourceId, ipSecConfig);
-
- if (mFamily == AF_INET) {
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
- assertEquals(IpSecManager.Status.OK, createTransformResp.status);
-
- verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
- } else {
- try {
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
- fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
- } catch (IllegalArgumentException expected) {
- }
- }
- }
-
- @Test
- public void testCreateTwoTransformsWithSameSpis() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
- assertEquals(IpSecManager.Status.OK, createTransformResp.status);
-
- // Attempting to create transform a second time with the same SPIs should throw an error...
- try {
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
- fail("IpSecService should have thrown an error for reuse of SPI");
- } catch (IllegalStateException expected) {
- }
-
- // ... even if the transform is deleted
- mIpSecService.deleteTransform(createTransformResp.resourceId);
- try {
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
- fail("IpSecService should have thrown an error for reuse of SPI");
- } catch (IllegalStateException expected) {
- }
- }
-
- @Test
- public void testReleaseOwnedSpi() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
- IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
- mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
- verify(mMockNetd, times(0))
- .ipSecDeleteSecurityAssociation(
- eq(mUid),
- anyString(),
- anyString(),
- eq(TEST_SPI),
- anyInt(),
- anyInt(),
- anyInt());
- // quota is not released until the SPI is released by the Transform
- assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
- }
-
- @Test
- public void testDeleteTransform() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
- mIpSecService.deleteTransform(createTransformResp.resourceId);
-
- verify(mMockNetd, times(1))
- .ipSecDeleteSecurityAssociation(
- eq(mUid),
- anyString(),
- anyString(),
- eq(TEST_SPI),
- anyInt(),
- anyInt(),
- anyInt());
-
- // Verify quota and RefcountedResource objects cleaned up
- IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
- assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
-
- mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
- // Verify that ipSecDeleteSa was not called when the SPI was released because the
- // ownedByTransform property should prevent it; (note, the called count is cumulative).
- verify(mMockNetd, times(1))
- .ipSecDeleteSecurityAssociation(
- anyInt(),
- anyString(),
- anyString(),
- anyInt(),
- anyInt(),
- anyInt(),
- anyInt());
- assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
-
- try {
- userRecord.mTransformRecords.getRefcountedResourceOrThrow(
- createTransformResp.resourceId);
- fail("Expected IllegalArgumentException on attempt to access deleted resource");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testTransportModeTransformBinderDeath() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
-
- IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- IpSecService.RefcountedResource refcountedRecord =
- userRecord.mTransformRecords.getRefcountedResourceOrThrow(
- createTransformResp.resourceId);
-
- refcountedRecord.binderDied();
-
- verify(mMockNetd)
- .ipSecDeleteSecurityAssociation(
- eq(mUid),
- anyString(),
- anyString(),
- eq(TEST_SPI),
- anyInt(),
- anyInt(),
- anyInt());
-
- // Verify quota and RefcountedResource objects cleaned up
- assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
- try {
- userRecord.mTransformRecords.getRefcountedResourceOrThrow(
- createTransformResp.resourceId);
- fail("Expected IllegalArgumentException on attempt to access deleted resource");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testApplyTransportModeTransform() throws Exception {
- verifyApplyTransportModeTransformCommon(false);
- }
-
- @Test
- public void testApplyTransportModeTransformReleasedSpi() throws Exception {
- verifyApplyTransportModeTransformCommon(true);
- }
-
- public void verifyApplyTransportModeTransformCommon(
- boolean closeSpiBeforeApply) throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
-
- if (closeSpiBeforeApply) {
- mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
- }
-
- Socket socket = new Socket();
- socket.bind(null);
- ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
-
- int resourceId = createTransformResp.resourceId;
- mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
-
- verify(mMockNetd)
- .ipSecApplyTransportModeTransform(
- eq(pfd),
- eq(mUid),
- eq(IpSecManager.DIRECTION_OUT),
- anyString(),
- anyString(),
- eq(TEST_SPI));
- }
-
- @Test
- public void testApplyTransportModeTransformWithClosedSpi() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
-
- // Close SPI record
- mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
-
- Socket socket = new Socket();
- socket.bind(null);
- ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
-
- int resourceId = createTransformResp.resourceId;
- mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
-
- verify(mMockNetd)
- .ipSecApplyTransportModeTransform(
- eq(pfd),
- eq(mUid),
- eq(IpSecManager.DIRECTION_OUT),
- anyString(),
- anyString(),
- eq(TEST_SPI));
- }
-
- @Test
- public void testRemoveTransportModeTransform() throws Exception {
- Socket socket = new Socket();
- socket.bind(null);
- ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
- mIpSecService.removeTransportModeTransforms(pfd);
-
- verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd);
- }
-
- private IpSecTunnelInterfaceResponse createAndValidateTunnel(
- String localAddr, String remoteAddr, String pkgName) {
- IpSecTunnelInterfaceResponse createTunnelResp =
- mIpSecService.createTunnelInterface(
- mSourceAddr, mDestinationAddr, fakeNetwork, new Binder(), pkgName);
-
- assertNotNull(createTunnelResp);
- assertEquals(IpSecManager.Status.OK, createTunnelResp.status);
- return createTunnelResp;
- }
-
- @Test
- public void testCreateTunnelInterface() throws Exception {
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
-
- // Check that we have stored the tracking object, and retrieve it
- IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- IpSecService.RefcountedResource refcountedRecord =
- userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
- createTunnelResp.resourceId);
-
- assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
- verify(mMockNetd)
- .ipSecAddTunnelInterface(
- eq(createTunnelResp.interfaceName),
- eq(mSourceAddr),
- eq(mDestinationAddr),
- anyInt(),
- anyInt(),
- anyInt());
- verify(mNetworkManager).setInterfaceUp(createTunnelResp.interfaceName);
- }
-
- @Test
- public void testDeleteTunnelInterface() throws Exception {
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
-
- IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
-
- mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, "blessedPackage");
-
- // Verify quota and RefcountedResource objects cleaned up
- assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
- verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
- try {
- userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
- createTunnelResp.resourceId);
- fail("Expected IllegalArgumentException on attempt to access deleted resource");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testTunnelInterfaceBinderDeath() throws Exception {
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
-
- IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- IpSecService.RefcountedResource refcountedRecord =
- userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
- createTunnelResp.resourceId);
-
- refcountedRecord.binderDied();
-
- // Verify quota and RefcountedResource objects cleaned up
- assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
- verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
- try {
- userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
- createTunnelResp.resourceId);
- fail("Expected IllegalArgumentException on attempt to access deleted resource");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testApplyTunnelModeTransform() throws Exception {
- verifyApplyTunnelModeTransformCommon(false);
- }
-
- @Test
- public void testApplyTunnelModeTransformReleasedSpi() throws Exception {
- verifyApplyTunnelModeTransformCommon(true);
- }
-
- public void verifyApplyTunnelModeTransformCommon(boolean closeSpiBeforeApply) throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
-
- if (closeSpiBeforeApply) {
- mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
- }
-
- int transformResourceId = createTransformResp.resourceId;
- int tunnelResourceId = createTunnelResp.resourceId;
- mIpSecService.applyTunnelModeTransform(tunnelResourceId, IpSecManager.DIRECTION_OUT,
- transformResourceId, "blessedPackage");
-
- for (int selAddrFamily : ADDRESS_FAMILIES) {
- verify(mMockNetd)
- .ipSecUpdateSecurityPolicy(
- eq(mUid),
- eq(selAddrFamily),
- eq(IpSecManager.DIRECTION_OUT),
- anyString(),
- anyString(),
- eq(TEST_SPI),
- anyInt(), // iKey/oKey
- anyInt(), // mask
- eq(tunnelResourceId));
- }
-
- ipSecConfig.setXfrmInterfaceId(tunnelResourceId);
- verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
- }
-
-
- @Test
- public void testApplyTunnelModeTransformWithClosedSpi() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
-
- // Close SPI record
- mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
-
- int transformResourceId = createTransformResp.resourceId;
- int tunnelResourceId = createTunnelResp.resourceId;
- mIpSecService.applyTunnelModeTransform(tunnelResourceId, IpSecManager.DIRECTION_OUT,
- transformResourceId, "blessedPackage");
-
- for (int selAddrFamily : ADDRESS_FAMILIES) {
- verify(mMockNetd)
- .ipSecUpdateSecurityPolicy(
- eq(mUid),
- eq(selAddrFamily),
- eq(IpSecManager.DIRECTION_OUT),
- anyString(),
- anyString(),
- eq(TEST_SPI),
- anyInt(), // iKey/oKey
- anyInt(), // mask
- eq(tunnelResourceId));
- }
-
- ipSecConfig.setXfrmInterfaceId(tunnelResourceId);
- verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
- }
-
- @Test
- public void testAddRemoveAddressFromTunnelInterface() throws Exception {
- for (String pkgName : new String[]{"blessedPackage", "systemPackage"}) {
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, pkgName);
- mIpSecService.addAddressToTunnelInterface(
- createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
- verify(mMockNetd, times(1))
- .interfaceAddAddress(
- eq(createTunnelResp.interfaceName),
- eq(mLocalInnerAddress.getAddress().getHostAddress()),
- eq(mLocalInnerAddress.getPrefixLength()));
- mIpSecService.removeAddressFromTunnelInterface(
- createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
- verify(mMockNetd, times(1))
- .interfaceDelAddress(
- eq(createTunnelResp.interfaceName),
- eq(mLocalInnerAddress.getAddress().getHostAddress()),
- eq(mLocalInnerAddress.getPrefixLength()));
- mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, pkgName);
- }
- }
-
- @Ignore
- @Test
- public void testAddTunnelFailsForBadPackageName() throws Exception {
- try {
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, "badPackage");
- fail("Expected a SecurityException for badPackage.");
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void testFeatureFlagVerification() throws Exception {
- when(mMockPkgMgr.hasSystemFeature(eq(PackageManager.FEATURE_IPSEC_TUNNELS)))
- .thenReturn(false);
-
- try {
- String addr = Inet4Address.getLoopbackAddress().getHostAddress();
- mIpSecService.createTunnelInterface(
- addr, addr, new Network(0), new Binder(), "blessedPackage");
- fail("Expected UnsupportedOperationException for disabled feature");
- } catch (UnsupportedOperationException expected) {
- }
- }
-}
diff --git a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
deleted file mode 100644
index 788e4efe097e..000000000000
--- a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
+++ /dev/null
@@ -1,360 +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 org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.INetworkManagementService;
-import android.os.RemoteException;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.IpSecService.IResource;
-import com.android.server.IpSecService.RefcountedResource;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ThreadLocalRandom;
-
-/** Unit tests for {@link IpSecService.RefcountedResource}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class IpSecServiceRefcountedResourceTest {
- Context mMockContext;
- IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
- IpSecService mIpSecService;
-
- @Before
- public void setUp() throws Exception {
- mMockContext = mock(Context.class);
- mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
- mIpSecService = new IpSecService(
- mMockContext, mock(INetworkManagementService.class), mMockIpSecSrvConfig);
- }
-
- private void assertResourceState(
- RefcountedResource<IResource> resource,
- int refCount,
- int userReleaseCallCount,
- int releaseReferenceCallCount,
- int invalidateCallCount,
- int freeUnderlyingResourcesCallCount)
- throws RemoteException {
- // Check refcount on RefcountedResource
- assertEquals(refCount, resource.mRefCount);
-
- // Check call count of RefcountedResource
- verify(resource, times(userReleaseCallCount)).userRelease();
- verify(resource, times(releaseReferenceCallCount)).releaseReference();
-
- // Check call count of IResource
- verify(resource.getResource(), times(invalidateCallCount)).invalidate();
- verify(resource.getResource(), times(freeUnderlyingResourcesCallCount))
- .freeUnderlyingResources();
- }
-
- /** Adds mockito instrumentation */
- private RefcountedResource<IResource> getTestRefcountedResource(
- RefcountedResource... children) {
- return getTestRefcountedResource(new Binder(), children);
- }
-
- /** Adds mockito instrumentation with provided binder */
- private RefcountedResource<IResource> getTestRefcountedResource(
- IBinder binder, RefcountedResource... children) {
- return spy(
- mIpSecService
- .new RefcountedResource<IResource>(mock(IResource.class), binder, children));
- }
-
- @Test
- public void testConstructor() throws RemoteException {
- IBinder binderMock = mock(IBinder.class);
- RefcountedResource<IResource> resource = getTestRefcountedResource(binderMock);
-
- // Verify resource's refcount starts at 1 (for user-reference)
- assertResourceState(resource, 1, 0, 0, 0, 0);
-
- // Verify linking to binder death
- verify(binderMock).linkToDeath(anyObject(), anyInt());
- }
-
- @Test
- public void testConstructorWithChildren() throws RemoteException {
- IBinder binderMockChild = mock(IBinder.class);
- IBinder binderMockParent = mock(IBinder.class);
- RefcountedResource<IResource> childResource = getTestRefcountedResource(binderMockChild);
- RefcountedResource<IResource> parentResource =
- getTestRefcountedResource(binderMockParent, childResource);
-
- // Verify parent's refcount starts at 1 (for user-reference)
- assertResourceState(parentResource, 1, 0, 0, 0, 0);
-
- // Verify child's refcounts were incremented
- assertResourceState(childResource, 2, 0, 0, 0, 0);
-
- // Verify linking to binder death
- verify(binderMockChild).linkToDeath(anyObject(), anyInt());
- verify(binderMockParent).linkToDeath(anyObject(), anyInt());
- }
-
- @Test
- public void testFailLinkToDeath() throws RemoteException {
- IBinder binderMock = mock(IBinder.class);
- doThrow(new RemoteException()).when(binderMock).linkToDeath(anyObject(), anyInt());
-
- try {
- getTestRefcountedResource(binderMock);
- fail("Expected exception to propogate when binder fails to link to death");
- } catch (RuntimeException expected) {
- }
- }
-
- @Test
- public void testCleanupAndRelease() throws RemoteException {
- IBinder binderMock = mock(IBinder.class);
- RefcountedResource<IResource> refcountedResource = getTestRefcountedResource(binderMock);
-
- // Verify user-initiated cleanup path decrements refcount and calls full cleanup flow
- refcountedResource.userRelease();
- assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
-
- // Verify user-initated cleanup path unlinks from binder
- verify(binderMock).unlinkToDeath(eq(refcountedResource), eq(0));
- assertNull(refcountedResource.mBinder);
- }
-
- @Test
- public void testMultipleCallsToCleanupAndRelease() throws RemoteException {
- RefcountedResource<IResource> refcountedResource = getTestRefcountedResource();
-
- // Verify calling userRelease multiple times does not trigger any other cleanup
- // methods
- refcountedResource.userRelease();
- assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
-
- refcountedResource.userRelease();
- refcountedResource.userRelease();
- assertResourceState(refcountedResource, -1, 3, 1, 1, 1);
- }
-
- @Test
- public void testBinderDeathAfterCleanupAndReleaseDoesNothing() throws RemoteException {
- RefcountedResource<IResource> refcountedResource = getTestRefcountedResource();
-
- refcountedResource.userRelease();
- assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
-
- // Verify binder death call does not trigger any other cleanup methods if called after
- // userRelease()
- refcountedResource.binderDied();
- assertResourceState(refcountedResource, -1, 2, 1, 1, 1);
- }
-
- @Test
- public void testBinderDeath() throws RemoteException {
- RefcountedResource<IResource> refcountedResource = getTestRefcountedResource();
-
- // Verify binder death caused cleanup
- refcountedResource.binderDied();
- verify(refcountedResource, times(1)).binderDied();
- assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
- assertNull(refcountedResource.mBinder);
- }
-
- @Test
- public void testCleanupParentDecrementsChildRefcount() throws RemoteException {
- RefcountedResource<IResource> childResource = getTestRefcountedResource();
- RefcountedResource<IResource> parentResource = getTestRefcountedResource(childResource);
-
- parentResource.userRelease();
-
- // Verify parent gets cleaned up properly, and triggers releaseReference on
- // child
- assertResourceState(childResource, 1, 0, 1, 0, 0);
- assertResourceState(parentResource, -1, 1, 1, 1, 1);
- }
-
- @Test
- public void testCleanupReferencedChildDoesNotTriggerRelease() throws RemoteException {
- RefcountedResource<IResource> childResource = getTestRefcountedResource();
- RefcountedResource<IResource> parentResource = getTestRefcountedResource(childResource);
-
- childResource.userRelease();
-
- // Verify that child does not clean up kernel resources and quota.
- assertResourceState(childResource, 1, 1, 1, 1, 0);
- assertResourceState(parentResource, 1, 0, 0, 0, 0);
- }
-
- @Test
- public void testTwoParents() throws RemoteException {
- RefcountedResource<IResource> childResource = getTestRefcountedResource();
- RefcountedResource<IResource> parentResource1 = getTestRefcountedResource(childResource);
- RefcountedResource<IResource> parentResource2 = getTestRefcountedResource(childResource);
-
- // Verify that child does not cleanup kernel resources and quota until all references
- // have been released. Assumption: parents release correctly based on
- // testCleanupParentDecrementsChildRefcount()
- childResource.userRelease();
- assertResourceState(childResource, 2, 1, 1, 1, 0);
-
- parentResource1.userRelease();
- assertResourceState(childResource, 1, 1, 2, 1, 0);
-
- parentResource2.userRelease();
- assertResourceState(childResource, -1, 1, 3, 1, 1);
- }
-
- @Test
- public void testTwoChildren() throws RemoteException {
- RefcountedResource<IResource> childResource1 = getTestRefcountedResource();
- RefcountedResource<IResource> childResource2 = getTestRefcountedResource();
- RefcountedResource<IResource> parentResource =
- getTestRefcountedResource(childResource1, childResource2);
-
- childResource1.userRelease();
- assertResourceState(childResource1, 1, 1, 1, 1, 0);
- assertResourceState(childResource2, 2, 0, 0, 0, 0);
-
- parentResource.userRelease();
- assertResourceState(childResource1, -1, 1, 2, 1, 1);
- assertResourceState(childResource2, 1, 0, 1, 0, 0);
-
- childResource2.userRelease();
- assertResourceState(childResource1, -1, 1, 2, 1, 1);
- assertResourceState(childResource2, -1, 1, 2, 1, 1);
- }
-
- @Test
- public void testSampleUdpEncapTranform() throws RemoteException {
- RefcountedResource<IResource> spi1 = getTestRefcountedResource();
- RefcountedResource<IResource> spi2 = getTestRefcountedResource();
- RefcountedResource<IResource> udpEncapSocket = getTestRefcountedResource();
- RefcountedResource<IResource> transform =
- getTestRefcountedResource(spi1, spi2, udpEncapSocket);
-
- // Pretend one SPI goes out of reference (releaseManagedResource -> userRelease)
- spi1.userRelease();
-
- // User called releaseManagedResource on udpEncap socket
- udpEncapSocket.userRelease();
-
- // User dies, and binder kills the rest
- spi2.binderDied();
- transform.binderDied();
-
- // Check resource states
- assertResourceState(spi1, -1, 1, 2, 1, 1);
- assertResourceState(spi2, -1, 1, 2, 1, 1);
- assertResourceState(udpEncapSocket, -1, 1, 2, 1, 1);
- assertResourceState(transform, -1, 1, 1, 1, 1);
- }
-
- @Test
- public void testSampleDualTransformEncapSocket() throws RemoteException {
- RefcountedResource<IResource> spi1 = getTestRefcountedResource();
- RefcountedResource<IResource> spi2 = getTestRefcountedResource();
- RefcountedResource<IResource> spi3 = getTestRefcountedResource();
- RefcountedResource<IResource> spi4 = getTestRefcountedResource();
- RefcountedResource<IResource> udpEncapSocket = getTestRefcountedResource();
- RefcountedResource<IResource> transform1 =
- getTestRefcountedResource(spi1, spi2, udpEncapSocket);
- RefcountedResource<IResource> transform2 =
- getTestRefcountedResource(spi3, spi4, udpEncapSocket);
-
- // Pretend one SPIs goes out of reference (releaseManagedResource -> userRelease)
- spi1.userRelease();
-
- // User called releaseManagedResource on udpEncap socket and spi4
- udpEncapSocket.userRelease();
- spi4.userRelease();
-
- // User dies, and binder kills the rest
- spi2.binderDied();
- spi3.binderDied();
- transform2.binderDied();
- transform1.binderDied();
-
- // Check resource states
- assertResourceState(spi1, -1, 1, 2, 1, 1);
- assertResourceState(spi2, -1, 1, 2, 1, 1);
- assertResourceState(spi3, -1, 1, 2, 1, 1);
- assertResourceState(spi4, -1, 1, 2, 1, 1);
- assertResourceState(udpEncapSocket, -1, 1, 3, 1, 1);
- assertResourceState(transform1, -1, 1, 1, 1, 1);
- assertResourceState(transform2, -1, 1, 1, 1, 1);
- }
-
- @Test
- public void fuzzTest() throws RemoteException {
- List<RefcountedResource<IResource>> resources = new ArrayList<>();
-
- // Build a tree of resources
- for (int i = 0; i < 100; i++) {
- // Choose a random number of children from the existing list
- int numChildren = ThreadLocalRandom.current().nextInt(0, resources.size() + 1);
-
- // Build a (random) list of children
- Set<RefcountedResource<IResource>> children = new HashSet<>();
- for (int j = 0; j < numChildren; j++) {
- int childIndex = ThreadLocalRandom.current().nextInt(0, resources.size());
- children.add(resources.get(childIndex));
- }
-
- RefcountedResource<IResource> newRefcountedResource =
- getTestRefcountedResource(
- children.toArray(new RefcountedResource[children.size()]));
- resources.add(newRefcountedResource);
- }
-
- // Cleanup all resources in a random order
- List<RefcountedResource<IResource>> clonedResources =
- new ArrayList<>(resources); // shallow copy
- while (!clonedResources.isEmpty()) {
- int index = ThreadLocalRandom.current().nextInt(0, clonedResources.size());
- RefcountedResource<IResource> refcountedResource = clonedResources.get(index);
- refcountedResource.userRelease();
- clonedResources.remove(index);
- }
-
- // Verify all resources were cleaned up properly
- for (RefcountedResource<IResource> refcountedResource : resources) {
- assertEquals(-1, refcountedResource.mRefCount);
- }
- }
-}
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
deleted file mode 100644
index 536e98327e1f..000000000000
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ /dev/null
@@ -1,671 +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 android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.EADDRINUSE;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_DGRAM;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.INetd;
-import android.net.IpSecAlgorithm;
-import android.net.IpSecConfig;
-import android.net.IpSecManager;
-import android.net.IpSecSpiResponse;
-import android.net.IpSecUdpEncapResponse;
-import android.os.Binder;
-import android.os.INetworkManagementService;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.StructStat;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import dalvik.system.SocketTagger;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
-
-import java.io.FileDescriptor;
-import java.net.InetAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.List;
-
-/** Unit tests for {@link IpSecService}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class IpSecServiceTest {
-
- private static final int DROID_SPI = 0xD1201D;
- private static final int MAX_NUM_ENCAP_SOCKETS = 100;
- private static final int MAX_NUM_SPIS = 100;
- private static final int TEST_UDP_ENCAP_INVALID_PORT = 100;
- private static final int TEST_UDP_ENCAP_PORT_OUT_RANGE = 100000;
-
- private static final InetAddress INADDR_ANY;
-
- private static final byte[] AEAD_KEY = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
- 0x73, 0x61, 0x6C, 0x74
- };
- private static final byte[] CRYPT_KEY = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
- };
- private static final byte[] AUTH_KEY = {
- 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
- 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
- };
-
- private static final IpSecAlgorithm AUTH_ALGO =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
- private static final IpSecAlgorithm CRYPT_ALGO =
- new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- private static final IpSecAlgorithm AEAD_ALGO =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
-
- static {
- try {
- INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0});
- } catch (UnknownHostException e) {
- throw new RuntimeException(e);
- }
- }
-
- Context mMockContext;
- INetworkManagementService mMockNetworkManager;
- INetd mMockNetd;
- IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
- IpSecService mIpSecService;
-
- @Before
- public void setUp() throws Exception {
- mMockContext = mock(Context.class);
- mMockNetworkManager = mock(INetworkManagementService.class);
- mMockNetd = mock(INetd.class);
- mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
- mIpSecService = new IpSecService(mMockContext, mMockNetworkManager, mMockIpSecSrvConfig);
-
- // Injecting mock netd
- when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
- }
-
- @Test
- public void testIpSecServiceCreate() throws InterruptedException {
- IpSecService ipSecSrv = IpSecService.create(mMockContext, mMockNetworkManager);
- assertNotNull(ipSecSrv);
- }
-
- @Test
- public void testReleaseInvalidSecurityParameterIndex() throws Exception {
- try {
- mIpSecService.releaseSecurityParameterIndex(1);
- fail("IllegalArgumentException not thrown");
- } catch (IllegalArgumentException e) {
- }
- }
-
- /** This function finds an available port */
- int findUnusedPort() throws Exception {
- // Get an available port.
- ServerSocket s = new ServerSocket(0);
- int port = s.getLocalPort();
- s.close();
- return port;
- }
-
- @Test
- public void testOpenAndCloseUdpEncapsulationSocket() throws Exception {
- int localport = -1;
- IpSecUdpEncapResponse udpEncapResp = null;
-
- for (int i = 0; i < IpSecService.MAX_PORT_BIND_ATTEMPTS; i++) {
- localport = findUnusedPort();
-
- udpEncapResp = mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
- assertNotNull(udpEncapResp);
- if (udpEncapResp.status == IpSecManager.Status.OK) {
- break;
- }
-
- // Else retry to reduce possibility for port-bind failures.
- }
-
- assertNotNull(udpEncapResp);
- assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- assertEquals(localport, udpEncapResp.port);
-
- mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
- udpEncapResp.fileDescriptor.close();
-
- // Verify quota and RefcountedResource objects cleaned up
- IpSecService.UserRecord userRecord =
- mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
- assertEquals(0, userRecord.mSocketQuotaTracker.mCurrent);
- try {
- userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(udpEncapResp.resourceId);
- fail("Expected IllegalArgumentException on attempt to access deleted resource");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testUdpEncapsulationSocketBinderDeath() throws Exception {
- IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(0, new Binder());
-
- IpSecService.UserRecord userRecord =
- mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
- IpSecService.RefcountedResource refcountedRecord =
- userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(
- udpEncapResp.resourceId);
-
- refcountedRecord.binderDied();
-
- // Verify quota and RefcountedResource objects cleaned up
- assertEquals(0, userRecord.mSocketQuotaTracker.mCurrent);
- try {
- userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(udpEncapResp.resourceId);
- fail("Expected IllegalArgumentException on attempt to access deleted resource");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testOpenUdpEncapsulationSocketAfterClose() throws Exception {
- IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(0, new Binder());
- assertNotNull(udpEncapResp);
- assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- int localport = udpEncapResp.port;
-
- mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
- udpEncapResp.fileDescriptor.close();
-
- /** Check if localport is available. */
- FileDescriptor newSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- Os.bind(newSocket, INADDR_ANY, localport);
- Os.close(newSocket);
- }
-
- /**
- * This function checks if the IpSecService holds the reserved port. If
- * closeUdpEncapsulationSocket is not called, the socket cleanup should not be complete.
- */
- @Test
- public void testUdpEncapPortNotReleased() throws Exception {
- IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(0, new Binder());
- assertNotNull(udpEncapResp);
- assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- int localport = udpEncapResp.port;
-
- udpEncapResp.fileDescriptor.close();
-
- FileDescriptor newSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- try {
- Os.bind(newSocket, INADDR_ANY, localport);
- fail("ErrnoException not thrown");
- } catch (ErrnoException e) {
- assertEquals(EADDRINUSE, e.errno);
- }
- mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
- }
-
- @Test
- public void testOpenUdpEncapsulationSocketOnRandomPort() throws Exception {
- IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(0, new Binder());
- assertNotNull(udpEncapResp);
- assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- assertNotEquals(0, udpEncapResp.port);
- mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
- udpEncapResp.fileDescriptor.close();
- }
-
- @Test
- public void testOpenUdpEncapsulationSocketPortRange() throws Exception {
- try {
- mIpSecService.openUdpEncapsulationSocket(TEST_UDP_ENCAP_INVALID_PORT, new Binder());
- fail("IllegalArgumentException not thrown");
- } catch (IllegalArgumentException e) {
- }
-
- try {
- mIpSecService.openUdpEncapsulationSocket(TEST_UDP_ENCAP_PORT_OUT_RANGE, new Binder());
- fail("IllegalArgumentException not thrown");
- } catch (IllegalArgumentException e) {
- }
- }
-
- @Test
- public void testOpenUdpEncapsulationSocketTwice() throws Exception {
- IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(0, new Binder());
- assertNotNull(udpEncapResp);
- assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- int localport = udpEncapResp.port;
-
- IpSecUdpEncapResponse testUdpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
- assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, testUdpEncapResp.status);
-
- mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
- udpEncapResp.fileDescriptor.close();
- }
-
- @Test
- public void testCloseInvalidUdpEncapsulationSocket() throws Exception {
- try {
- mIpSecService.closeUdpEncapsulationSocket(1);
- fail("IllegalArgumentException not thrown");
- } catch (IllegalArgumentException e) {
- }
- }
-
- @Test
- public void testValidateAlgorithmsAuth() {
- // Validate that correct algorithm type succeeds
- IpSecConfig config = new IpSecConfig();
- config.setAuthentication(AUTH_ALGO);
- mIpSecService.validateAlgorithms(config);
-
- // Validate that incorrect algorithm types fails
- for (IpSecAlgorithm algo : new IpSecAlgorithm[] {CRYPT_ALGO, AEAD_ALGO}) {
- try {
- config = new IpSecConfig();
- config.setAuthentication(algo);
- mIpSecService.validateAlgorithms(config);
- fail("Did not throw exception on invalid algorithm type");
- } catch (IllegalArgumentException expected) {
- }
- }
- }
-
- @Test
- public void testValidateAlgorithmsCrypt() {
- // Validate that correct algorithm type succeeds
- IpSecConfig config = new IpSecConfig();
- config.setEncryption(CRYPT_ALGO);
- mIpSecService.validateAlgorithms(config);
-
- // Validate that incorrect algorithm types fails
- for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, AEAD_ALGO}) {
- try {
- config = new IpSecConfig();
- config.setEncryption(algo);
- mIpSecService.validateAlgorithms(config);
- fail("Did not throw exception on invalid algorithm type");
- } catch (IllegalArgumentException expected) {
- }
- }
- }
-
- @Test
- public void testValidateAlgorithmsAead() {
- // Validate that correct algorithm type succeeds
- IpSecConfig config = new IpSecConfig();
- config.setAuthenticatedEncryption(AEAD_ALGO);
- mIpSecService.validateAlgorithms(config);
-
- // Validate that incorrect algorithm types fails
- for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, CRYPT_ALGO}) {
- try {
- config = new IpSecConfig();
- config.setAuthenticatedEncryption(algo);
- mIpSecService.validateAlgorithms(config);
- fail("Did not throw exception on invalid algorithm type");
- } catch (IllegalArgumentException expected) {
- }
- }
- }
-
- @Test
- public void testValidateAlgorithmsAuthCrypt() {
- // Validate that correct algorithm type succeeds
- IpSecConfig config = new IpSecConfig();
- config.setAuthentication(AUTH_ALGO);
- config.setEncryption(CRYPT_ALGO);
- mIpSecService.validateAlgorithms(config);
- }
-
- @Test
- public void testValidateAlgorithmsNoAlgorithms() {
- IpSecConfig config = new IpSecConfig();
- try {
- mIpSecService.validateAlgorithms(config);
- fail("Expected exception; no algorithms specified");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testValidateAlgorithmsAeadWithAuth() {
- IpSecConfig config = new IpSecConfig();
- config.setAuthenticatedEncryption(AEAD_ALGO);
- config.setAuthentication(AUTH_ALGO);
- try {
- mIpSecService.validateAlgorithms(config);
- fail("Expected exception; both AEAD and auth algorithm specified");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testValidateAlgorithmsAeadWithCrypt() {
- IpSecConfig config = new IpSecConfig();
- config.setAuthenticatedEncryption(AEAD_ALGO);
- config.setEncryption(CRYPT_ALGO);
- try {
- mIpSecService.validateAlgorithms(config);
- fail("Expected exception; both AEAD and crypt algorithm specified");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testValidateAlgorithmsAeadWithAuthAndCrypt() {
- IpSecConfig config = new IpSecConfig();
- config.setAuthenticatedEncryption(AEAD_ALGO);
- config.setAuthentication(AUTH_ALGO);
- config.setEncryption(CRYPT_ALGO);
- try {
- mIpSecService.validateAlgorithms(config);
- fail("Expected exception; AEAD, auth and crypt algorithm specified");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testDeleteInvalidTransform() throws Exception {
- try {
- mIpSecService.deleteTransform(1);
- fail("IllegalArgumentException not thrown");
- } catch (IllegalArgumentException e) {
- }
- }
-
- @Test
- public void testRemoveTransportModeTransform() throws Exception {
- Socket socket = new Socket();
- socket.bind(null);
- ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
- mIpSecService.removeTransportModeTransforms(pfd);
-
- verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd);
- }
-
- @Test
- public void testValidateIpAddresses() throws Exception {
- String[] invalidAddresses =
- new String[] {"www.google.com", "::", "2001::/64", "0.0.0.0", ""};
- for (String address : invalidAddresses) {
- try {
- IpSecSpiResponse spiResp =
- mIpSecService.allocateSecurityParameterIndex(
- address, DROID_SPI, new Binder());
- fail("Invalid address was passed through IpSecService validation: " + address);
- } catch (IllegalArgumentException e) {
- } catch (Exception e) {
- fail(
- "Invalid InetAddress was not caught in validation: "
- + address
- + ", Exception: "
- + e);
- }
- }
- }
-
- /**
- * This function checks if the number of encap UDP socket that one UID can reserve has a
- * reasonable limit.
- */
- @Test
- public void testSocketResourceTrackerLimitation() throws Exception {
- List<IpSecUdpEncapResponse> openUdpEncapSockets = new ArrayList<IpSecUdpEncapResponse>();
- // Reserve sockets until it fails.
- for (int i = 0; i < MAX_NUM_ENCAP_SOCKETS; i++) {
- IpSecUdpEncapResponse newUdpEncapSocket =
- mIpSecService.openUdpEncapsulationSocket(0, new Binder());
- assertNotNull(newUdpEncapSocket);
- if (IpSecManager.Status.OK != newUdpEncapSocket.status) {
- break;
- }
- openUdpEncapSockets.add(newUdpEncapSocket);
- }
- // Assert that the total sockets quota has a reasonable limit.
- assertTrue("No UDP encap socket was open", !openUdpEncapSockets.isEmpty());
- assertTrue(
- "Number of open UDP encap sockets is out of bound",
- openUdpEncapSockets.size() < MAX_NUM_ENCAP_SOCKETS);
-
- // Try to reserve one more UDP encapsulation socket, and should fail.
- IpSecUdpEncapResponse extraUdpEncapSocket =
- mIpSecService.openUdpEncapsulationSocket(0, new Binder());
- assertNotNull(extraUdpEncapSocket);
- assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraUdpEncapSocket.status);
-
- // Close one of the open UDP encapsulation sockets.
- mIpSecService.closeUdpEncapsulationSocket(openUdpEncapSockets.get(0).resourceId);
- openUdpEncapSockets.get(0).fileDescriptor.close();
- openUdpEncapSockets.remove(0);
-
- // Try to reserve one more UDP encapsulation socket, and should be successful.
- extraUdpEncapSocket = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
- assertNotNull(extraUdpEncapSocket);
- assertEquals(IpSecManager.Status.OK, extraUdpEncapSocket.status);
- openUdpEncapSockets.add(extraUdpEncapSocket);
-
- // Close open UDP sockets.
- for (IpSecUdpEncapResponse openSocket : openUdpEncapSockets) {
- mIpSecService.closeUdpEncapsulationSocket(openSocket.resourceId);
- openSocket.fileDescriptor.close();
- }
- }
-
- /**
- * This function checks if the number of SPI that one UID can reserve has a reasonable limit.
- * This test does not test for both address families or duplicate SPIs because resource tracking
- * code does not depend on them.
- */
- @Test
- public void testSpiResourceTrackerLimitation() throws Exception {
- List<IpSecSpiResponse> reservedSpis = new ArrayList<IpSecSpiResponse>();
- // Return the same SPI for all SPI allocation since IpSecService only
- // tracks the resource ID.
- when(mMockNetd.ipSecAllocateSpi(
- anyInt(),
- anyString(),
- eq(InetAddress.getLoopbackAddress().getHostAddress()),
- anyInt()))
- .thenReturn(DROID_SPI);
- // Reserve spis until it fails.
- for (int i = 0; i < MAX_NUM_SPIS; i++) {
- IpSecSpiResponse newSpi =
- mIpSecService.allocateSecurityParameterIndex(
- InetAddress.getLoopbackAddress().getHostAddress(),
- DROID_SPI + i,
- new Binder());
- assertNotNull(newSpi);
- if (IpSecManager.Status.OK != newSpi.status) {
- break;
- }
- reservedSpis.add(newSpi);
- }
- // Assert that the SPI quota has a reasonable limit.
- assertTrue(reservedSpis.size() > 0 && reservedSpis.size() < MAX_NUM_SPIS);
-
- // Try to reserve one more SPI, and should fail.
- IpSecSpiResponse extraSpi =
- mIpSecService.allocateSecurityParameterIndex(
- InetAddress.getLoopbackAddress().getHostAddress(),
- DROID_SPI + MAX_NUM_SPIS,
- new Binder());
- assertNotNull(extraSpi);
- assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraSpi.status);
-
- // Release one reserved spi.
- mIpSecService.releaseSecurityParameterIndex(reservedSpis.get(0).resourceId);
- reservedSpis.remove(0);
-
- // Should successfully reserve one more spi.
- extraSpi =
- mIpSecService.allocateSecurityParameterIndex(
- InetAddress.getLoopbackAddress().getHostAddress(),
- DROID_SPI + MAX_NUM_SPIS,
- new Binder());
- assertNotNull(extraSpi);
- assertEquals(IpSecManager.Status.OK, extraSpi.status);
-
- // Release reserved SPIs.
- for (IpSecSpiResponse spiResp : reservedSpis) {
- mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
- }
- }
-
- @Test
- public void testUidFdtagger() throws Exception {
- SocketTagger actualSocketTagger = SocketTagger.get();
-
- try {
- FileDescriptor sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-
- // Has to be done after socket creation because BlockGuardOS calls tag on new sockets
- SocketTagger mockSocketTagger = mock(SocketTagger.class);
- SocketTagger.set(mockSocketTagger);
-
- mIpSecService.mUidFdTagger.tag(sockFd, Process.LAST_APPLICATION_UID);
- verify(mockSocketTagger).tag(eq(sockFd));
- } finally {
- SocketTagger.set(actualSocketTagger);
- }
- }
-
- /**
- * Checks if two file descriptors point to the same file.
- *
- * <p>According to stat.h documentation, the correct way to check for equivalent or duplicated
- * file descriptors is to check their inode and device. These two entries uniquely identify any
- * file.
- */
- private boolean fileDescriptorsEqual(FileDescriptor fd1, FileDescriptor fd2) {
- try {
- StructStat fd1Stat = Os.fstat(fd1);
- StructStat fd2Stat = Os.fstat(fd2);
-
- return fd1Stat.st_ino == fd2Stat.st_ino && fd1Stat.st_dev == fd2Stat.st_dev;
- } catch (ErrnoException e) {
- return false;
- }
- }
-
- @Test
- public void testOpenUdpEncapSocketTagsSocket() throws Exception {
- IpSecService.UidFdTagger mockTagger = mock(IpSecService.UidFdTagger.class);
- IpSecService testIpSecService = new IpSecService(
- mMockContext, mMockNetworkManager, mMockIpSecSrvConfig, mockTagger);
-
- IpSecUdpEncapResponse udpEncapResp =
- testIpSecService.openUdpEncapsulationSocket(0, new Binder());
- assertNotNull(udpEncapResp);
- assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
-
- FileDescriptor sockFd = udpEncapResp.fileDescriptor.getFileDescriptor();
- ArgumentMatcher<FileDescriptor> fdMatcher =
- (argFd) -> {
- return fileDescriptorsEqual(sockFd, argFd);
- };
- verify(mockTagger).tag(argThat(fdMatcher), eq(Os.getuid()));
-
- testIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
- udpEncapResp.fileDescriptor.close();
- }
-
- @Test
- public void testOpenUdpEncapsulationSocketCallsSetEncapSocketOwner() throws Exception {
- IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(0, new Binder());
-
- FileDescriptor sockFd = udpEncapResp.fileDescriptor.getFileDescriptor();
- ArgumentMatcher<ParcelFileDescriptor> fdMatcher = (arg) -> {
- try {
- StructStat sockStat = Os.fstat(sockFd);
- StructStat argStat = Os.fstat(arg.getFileDescriptor());
-
- return sockStat.st_ino == argStat.st_ino
- && sockStat.st_dev == argStat.st_dev;
- } catch (ErrnoException e) {
- return false;
- }
- };
-
- verify(mMockNetd).ipSecSetEncapSocketOwner(argThat(fdMatcher), eq(Os.getuid()));
- mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
- }
-
- @Test
- public void testReserveNetId() {
- int start = mIpSecService.TUN_INTF_NETID_START;
- for (int i = 0; i < mIpSecService.TUN_INTF_NETID_RANGE; i++) {
- assertEquals(start + i, mIpSecService.reserveNetId());
- }
-
- // Check that resource exhaustion triggers an exception
- try {
- mIpSecService.reserveNetId();
- fail("Did not throw error for all netIds reserved");
- } catch (IllegalStateException expected) {
- }
-
- // Now release one and try again
- int releasedNetId =
- mIpSecService.TUN_INTF_NETID_START + mIpSecService.TUN_INTF_NETID_RANGE / 2;
- mIpSecService.releaseNetId(releasedNetId);
- assertEquals(releasedNetId, mIpSecService.reserveNetId());
- }
-}
diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
deleted file mode 100644
index 42d4cf3c382b..000000000000
--- a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server
-
-import android.net.ConnectivityManager.TYPE_ETHERNET
-import android.net.ConnectivityManager.TYPE_MOBILE
-import android.net.ConnectivityManager.TYPE_MOBILE_SUPL
-import android.net.ConnectivityManager.TYPE_WIFI
-import android.net.ConnectivityManager.TYPE_WIMAX
-import android.net.NetworkInfo.DetailedState.CONNECTED
-import android.net.NetworkInfo.DetailedState.DISCONNECTED
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.server.ConnectivityService.LegacyTypeTracker
-import com.android.server.connectivity.NetworkAgentInfo
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertNull
-import org.junit.Assert.assertSame
-import org.junit.Assert.assertTrue
-import org.junit.Assert.fail
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.reset
-import org.mockito.Mockito.verify
-
-const val UNSUPPORTED_TYPE = TYPE_WIMAX
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class LegacyTypeTrackerTest {
- private val supportedTypes = arrayOf(TYPE_MOBILE, TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_SUPL)
-
- private val mMockService = mock(ConnectivityService::class.java).apply {
- doReturn(false).`when`(this).isDefaultNetwork(any())
- }
- private val mTracker = LegacyTypeTracker(mMockService).apply {
- supportedTypes.forEach {
- addSupportedType(it)
- }
- }
-
- @Test
- fun testSupportedTypes() {
- try {
- mTracker.addSupportedType(supportedTypes[0])
- fail("Expected IllegalStateException")
- } catch (expected: IllegalStateException) {}
- supportedTypes.forEach {
- assertTrue(mTracker.isTypeSupported(it))
- }
- assertFalse(mTracker.isTypeSupported(UNSUPPORTED_TYPE))
- }
-
- @Test
- fun testSupl() {
- val mobileNai = mock(NetworkAgentInfo::class.java)
- mTracker.add(TYPE_MOBILE, mobileNai)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE)
- reset(mMockService)
- mTracker.add(TYPE_MOBILE_SUPL, mobileNai)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
- reset(mMockService)
- mTracker.remove(TYPE_MOBILE_SUPL, mobileNai, false /* wasDefault */)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
- reset(mMockService)
- mTracker.add(TYPE_MOBILE_SUPL, mobileNai)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
- reset(mMockService)
- mTracker.remove(mobileNai, false)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE)
- }
-
- @Test
- fun testAddNetwork() {
- val mobileNai = mock(NetworkAgentInfo::class.java)
- val wifiNai = mock(NetworkAgentInfo::class.java)
- mTracker.add(TYPE_MOBILE, mobileNai)
- mTracker.add(TYPE_WIFI, wifiNai)
- assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
- assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
- // Make sure adding a second NAI does not change the results.
- val secondMobileNai = mock(NetworkAgentInfo::class.java)
- mTracker.add(TYPE_MOBILE, secondMobileNai)
- assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
- assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
- // Make sure removing a network that wasn't added for this type is a no-op.
- mTracker.remove(TYPE_MOBILE, wifiNai, false /* wasDefault */)
- assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
- assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
- // Remove the top network for mobile and make sure the second one becomes the network
- // of record for this type.
- mTracker.remove(TYPE_MOBILE, mobileNai, false /* wasDefault */)
- assertSame(mTracker.getNetworkForType(TYPE_MOBILE), secondMobileNai)
- assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
- // Make sure adding a network for an unsupported type does not register it.
- mTracker.add(UNSUPPORTED_TYPE, mobileNai)
- assertNull(mTracker.getNetworkForType(UNSUPPORTED_TYPE))
- }
-
- @Test
- fun testBroadcastOnDisconnect() {
- val mobileNai1 = mock(NetworkAgentInfo::class.java)
- val mobileNai2 = mock(NetworkAgentInfo::class.java)
- doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai1)
- mTracker.add(TYPE_MOBILE, mobileNai1)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, CONNECTED, TYPE_MOBILE)
- reset(mMockService)
- doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai2)
- mTracker.add(TYPE_MOBILE, mobileNai2)
- verify(mMockService, never()).sendLegacyNetworkBroadcast(any(), any(), anyInt())
- mTracker.remove(TYPE_MOBILE, mobileNai1, false /* wasDefault */)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, DISCONNECTED, TYPE_MOBILE)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai2, CONNECTED, TYPE_MOBILE)
- }
-}
diff --git a/tests/net/java/com/android/server/NetIdManagerTest.kt b/tests/net/java/com/android/server/NetIdManagerTest.kt
deleted file mode 100644
index 045f89f85e3b..000000000000
--- a/tests/net/java/com/android/server/NetIdManagerTest.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.server.NetIdManager.MIN_NET_ID
-import com.android.testutils.ExceptionUtils.ThrowingRunnable
-import com.android.testutils.assertThrows
-import org.junit.Test
-import org.junit.runner.RunWith
-import kotlin.test.assertEquals
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class NetIdManagerTest {
- @Test
- fun testReserveReleaseNetId() {
- val manager = NetIdManager(MIN_NET_ID + 4)
- assertEquals(MIN_NET_ID, manager.reserveNetId())
- assertEquals(MIN_NET_ID + 1, manager.reserveNetId())
- assertEquals(MIN_NET_ID + 2, manager.reserveNetId())
- assertEquals(MIN_NET_ID + 3, manager.reserveNetId())
-
- manager.releaseNetId(MIN_NET_ID + 1)
- manager.releaseNetId(MIN_NET_ID + 3)
- // IDs only loop once there is no higher ID available
- assertEquals(MIN_NET_ID + 4, manager.reserveNetId())
- assertEquals(MIN_NET_ID + 1, manager.reserveNetId())
- assertEquals(MIN_NET_ID + 3, manager.reserveNetId())
- assertThrows(IllegalStateException::class.java, ThrowingRunnable { manager.reserveNetId() })
- manager.releaseNetId(MIN_NET_ID + 5)
- // Still no ID available: MIN_NET_ID + 5 was not reserved
- assertThrows(IllegalStateException::class.java, ThrowingRunnable { manager.reserveNetId() })
- manager.releaseNetId(MIN_NET_ID + 2)
- // Throwing an exception still leaves the manager in a working state
- assertEquals(MIN_NET_ID + 2, manager.reserveNetId())
- }
-} \ No newline at end of file
diff --git a/tests/net/java/com/android/server/NetworkManagementServiceTest.java b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
deleted file mode 100644
index 968b3071bf1d..000000000000
--- a/tests/net/java/com/android/server/NetworkManagementServiceTest.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.net.INetd;
-import android.net.INetdUnsolicitedEventListener;
-import android.net.LinkAddress;
-import android.os.BatteryStats;
-import android.os.Binder;
-import android.os.IBinder;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.app.IBatteryStats;
-import com.android.server.NetworkManagementService.SystemServices;
-import com.android.server.net.BaseNetworkObserver;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests for {@link NetworkManagementService}.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkManagementServiceTest {
-
- private NetworkManagementService mNMService;
-
- @Mock private Context mContext;
- @Mock private IBatteryStats.Stub mBatteryStatsService;
- @Mock private INetd.Stub mNetdService;
-
- @NonNull
- @Captor
- private ArgumentCaptor<INetdUnsolicitedEventListener> mUnsolListenerCaptor;
-
- private final SystemServices mServices = new SystemServices() {
- @Override
- public IBinder getService(String name) {
- switch (name) {
- case BatteryStats.SERVICE_NAME:
- return mBatteryStatsService;
- default:
- throw new UnsupportedOperationException("Unknown service " + name);
- }
- }
- @Override
- public void registerLocalService(NetworkManagementInternal nmi) {
- }
- @Override
- public INetd getNetd() {
- return mNetdService;
- }
- };
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- doNothing().when(mNetdService)
- .registerUnsolicitedEventListener(mUnsolListenerCaptor.capture());
- // Start the service and wait until it connects to our socket.
- mNMService = NetworkManagementService.create(mContext, mServices);
- }
-
- @After
- public void tearDown() throws Exception {
- mNMService.shutdown();
- }
-
- private static <T> T expectSoon(T mock) {
- return verify(mock, timeout(200));
- }
-
- /**
- * Tests that network observers work properly.
- */
- @Test
- public void testNetworkObservers() throws Exception {
- BaseNetworkObserver observer = mock(BaseNetworkObserver.class);
- doReturn(new Binder()).when(observer).asBinder(); // Used by registerObserver.
- mNMService.registerObserver(observer);
-
- // Forget everything that happened to the mock so far, so we can explicitly verify
- // everything that happens and does not happen to it from now on.
-
- INetdUnsolicitedEventListener unsolListener = mUnsolListenerCaptor.getValue();
- reset(observer);
- // Now call unsolListener methods and ensure that the observer methods are
- // called. After every method we expect a callback soon after; to ensure that
- // invalid messages don't cause any callbacks, we call verifyNoMoreInteractions at the end.
-
- /**
- * Interface changes.
- */
- unsolListener.onInterfaceAdded("rmnet12");
- expectSoon(observer).interfaceAdded("rmnet12");
-
- unsolListener.onInterfaceRemoved("eth1");
- expectSoon(observer).interfaceRemoved("eth1");
-
- unsolListener.onInterfaceChanged("clat4", true);
- expectSoon(observer).interfaceStatusChanged("clat4", true);
-
- unsolListener.onInterfaceLinkStateChanged("rmnet0", false);
- expectSoon(observer).interfaceLinkStateChanged("rmnet0", false);
-
- /**
- * Bandwidth control events.
- */
- unsolListener.onQuotaLimitReached("data", "rmnet_usb0");
- expectSoon(observer).limitReached("data", "rmnet_usb0");
-
- /**
- * Interface class activity.
- */
- unsolListener.onInterfaceClassActivityChanged(true, 1, 1234, 0);
- expectSoon(observer).interfaceClassDataActivityChanged("1", true, 1234);
-
- unsolListener.onInterfaceClassActivityChanged(false, 9, 5678, 0);
- expectSoon(observer).interfaceClassDataActivityChanged("9", false, 5678);
-
- unsolListener.onInterfaceClassActivityChanged(false, 9, 4321, 0);
- expectSoon(observer).interfaceClassDataActivityChanged("9", false, 4321);
-
- /**
- * IP address changes.
- */
- unsolListener.onInterfaceAddressUpdated("fe80::1/64", "wlan0", 128, 253);
- expectSoon(observer).addressUpdated("wlan0", new LinkAddress("fe80::1/64", 128, 253));
-
- unsolListener.onInterfaceAddressRemoved("fe80::1/64", "wlan0", 128, 253);
- expectSoon(observer).addressRemoved("wlan0", new LinkAddress("fe80::1/64", 128, 253));
-
- unsolListener.onInterfaceAddressRemoved("2001:db8::1/64", "wlan0", 1, 0);
- expectSoon(observer).addressRemoved("wlan0", new LinkAddress("2001:db8::1/64", 1, 0));
-
- /**
- * DNS information broadcasts.
- */
- unsolListener.onInterfaceDnsServerInfo("rmnet_usb0", 3600, new String[]{"2001:db8::1"});
- expectSoon(observer).interfaceDnsServerInfo("rmnet_usb0", 3600,
- new String[]{"2001:db8::1"});
-
- unsolListener.onInterfaceDnsServerInfo("wlan0", 14400,
- new String[]{"2001:db8::1", "2001:db8::2"});
- expectSoon(observer).interfaceDnsServerInfo("wlan0", 14400,
- new String[]{"2001:db8::1", "2001:db8::2"});
-
- // We don't check for negative lifetimes, only for parse errors.
- unsolListener.onInterfaceDnsServerInfo("wlan0", -3600, new String[]{"::1"});
- expectSoon(observer).interfaceDnsServerInfo("wlan0", -3600,
- new String[]{"::1"});
-
- // No syntax checking on the addresses.
- unsolListener.onInterfaceDnsServerInfo("wlan0", 600,
- new String[]{"", "::", "", "foo", "::1"});
- expectSoon(observer).interfaceDnsServerInfo("wlan0", 600,
- new String[]{"", "::", "", "foo", "::1"});
-
- // Make sure nothing else was called.
- verifyNoMoreInteractions(observer);
- }
-}
diff --git a/tests/net/java/com/android/server/NsdServiceTest.java b/tests/net/java/com/android/server/NsdServiceTest.java
deleted file mode 100644
index a90fa6882c25..000000000000
--- a/tests/net/java/com/android/server/NsdServiceTest.java
+++ /dev/null
@@ -1,194 +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 org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.net.nsd.NsdManager;
-import android.net.nsd.NsdServiceInfo;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.NsdService.DaemonConnection;
-import com.android.server.NsdService.DaemonConnectionSupplier;
-import com.android.server.NsdService.NativeCallbackReceiver;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-// TODOs:
-// - test client can send requests and receive replies
-// - test NSD_ON ENABLE/DISABLED listening
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NsdServiceTest {
-
- static final int PROTOCOL = NsdManager.PROTOCOL_DNS_SD;
-
- long mTimeoutMs = 100; // non-final so that tests can adjust the value.
-
- @Mock Context mContext;
- @Mock ContentResolver mResolver;
- @Mock NsdService.NsdSettings mSettings;
- @Mock DaemonConnection mDaemon;
- NativeCallbackReceiver mDaemonCallback;
- HandlerThread mThread;
- TestHandler mHandler;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- mThread = new HandlerThread("mock-service-handler");
- mThread.start();
- mHandler = new TestHandler(mThread.getLooper());
- when(mContext.getContentResolver()).thenReturn(mResolver);
- }
-
- @After
- public void tearDown() throws Exception {
- if (mThread != null) {
- mThread.quit();
- mThread = null;
- }
- }
-
- @Test
- public void testClientsCanConnectAndDisconnect() {
- when(mSettings.isEnabled()).thenReturn(true);
-
- NsdService service = makeService();
-
- NsdManager client1 = connectClient(service);
- verify(mDaemon, timeout(100).times(1)).start();
-
- NsdManager client2 = connectClient(service);
-
- client1.disconnect();
- client2.disconnect();
-
- verify(mDaemon, timeout(mTimeoutMs).times(1)).stop();
-
- client1.disconnect();
- client2.disconnect();
- }
-
- @Test
- public void testClientRequestsAreGCedAtDisconnection() {
- when(mSettings.isEnabled()).thenReturn(true);
- when(mDaemon.execute(any())).thenReturn(true);
-
- NsdService service = makeService();
- NsdManager client = connectClient(service);
-
- verify(mDaemon, timeout(100).times(1)).start();
-
- NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
- request.setPort(2201);
-
- // Client registration request
- NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
- client.registerService(request, PROTOCOL, listener1);
- verifyDaemonCommand("register 2 a_name a_type 2201");
-
- // Client discovery request
- NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
- client.discoverServices("a_type", PROTOCOL, listener2);
- verifyDaemonCommand("discover 3 a_type");
-
- // Client resolve request
- NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
- client.resolveService(request, listener3);
- verifyDaemonCommand("resolve 4 a_name a_type local.");
-
- // Client disconnects
- client.disconnect();
- verify(mDaemon, timeout(mTimeoutMs).times(1)).stop();
-
- // checks that request are cleaned
- verifyDaemonCommands("stop-register 2", "stop-discover 3", "stop-resolve 4");
-
- client.disconnect();
- }
-
- NsdService makeService() {
- DaemonConnectionSupplier supplier = (callback) -> {
- mDaemonCallback = callback;
- return mDaemon;
- };
- NsdService service = new NsdService(mContext, mSettings, mHandler, supplier);
- verify(mDaemon, never()).execute(any(String.class));
- return service;
- }
-
- NsdManager connectClient(NsdService service) {
- return new NsdManager(mContext, service);
- }
-
- void verifyDaemonCommands(String... wants) {
- verifyDaemonCommand(String.join(" ", wants), wants.length);
- }
-
- void verifyDaemonCommand(String want) {
- verifyDaemonCommand(want, 1);
- }
-
- void verifyDaemonCommand(String want, int n) {
- ArgumentCaptor<Object> argumentsCaptor = ArgumentCaptor.forClass(Object.class);
- verify(mDaemon, timeout(mTimeoutMs).times(n)).execute(argumentsCaptor.capture());
- String got = "";
- for (Object o : argumentsCaptor.getAllValues()) {
- got += o + " ";
- }
- assertEquals(want, got.trim());
- // rearm deamon for next command verification
- reset(mDaemon);
- when(mDaemon.execute(any())).thenReturn(true);
- }
-
- public static class TestHandler extends Handler {
- public Message lastMessage;
-
- TestHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- lastMessage = obtainMessage();
- lastMessage.copyFrom(msg);
- }
- }
-}
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
deleted file mode 100644
index 508b5cd9cb19..000000000000
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * Copyright (C) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
-import static android.net.NetworkCapabilities.MAX_TRANSPORT;
-import static android.net.NetworkCapabilities.MIN_TRANSPORT;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
-import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
-import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
-
-import static com.android.testutils.MiscAssertsKt.assertContainsExactly;
-import static com.android.testutils.MiscAssertsKt.assertContainsStringsExactly;
-import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.net.IDnsResolver;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.ResolverOptionsParcel;
-import android.net.ResolverParamsParcel;
-import android.net.RouteInfo;
-import android.net.shared.PrivateDnsConfig;
-import android.provider.Settings;
-import android.test.mock.MockContentResolver;
-import android.util.SparseArray;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.MessageUtils;
-import com.android.internal.util.test.FakeSettingsProvider;
-
-import libcore.net.InetAddressUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.net.InetAddress;
-import java.util.Arrays;
-
-/**
- * Tests for {@link DnsManager}.
- *
- * Build, install and run with:
- * runtest frameworks-net -c com.android.server.connectivity.DnsManagerTest
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DnsManagerTest {
- static final String TEST_IFACENAME = "test_wlan0";
- static final int TEST_NETID = 100;
- static final int TEST_NETID_ALTERNATE = 101;
- static final int TEST_NETID_UNTRACKED = 102;
- static final int TEST_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800;
- static final int TEST_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25;
- static final int TEST_DEFAULT_MIN_SAMPLES = 8;
- static final int TEST_DEFAULT_MAX_SAMPLES = 64;
- static final int[] TEST_TRANSPORT_TYPES = {TRANSPORT_WIFI, TRANSPORT_VPN};
-
- DnsManager mDnsManager;
- MockContentResolver mContentResolver;
-
- @Mock Context mCtx;
- @Mock IDnsResolver mMockDnsResolver;
- @Mock MockableSystemProperties mSystemProperties;
-
- private void assertResolverOptionsEquals(
- @NonNull ResolverOptionsParcel actual,
- @NonNull ResolverOptionsParcel expected) {
- assertEquals(actual.hosts, expected.hosts);
- assertEquals(actual.tcMode, expected.tcMode);
- assertEquals(actual.enforceDnsUid, expected.enforceDnsUid);
- assertFieldCountEquals(3, ResolverOptionsParcel.class);
- }
-
- private void assertResolverParamsEquals(@NonNull ResolverParamsParcel actual,
- @NonNull ResolverParamsParcel expected) {
- assertEquals(actual.netId, expected.netId);
- assertEquals(actual.sampleValiditySeconds, expected.sampleValiditySeconds);
- assertEquals(actual.successThreshold, expected.successThreshold);
- assertEquals(actual.minSamples, expected.minSamples);
- assertEquals(actual.maxSamples, expected.maxSamples);
- assertEquals(actual.baseTimeoutMsec, expected.baseTimeoutMsec);
- assertEquals(actual.retryCount, expected.retryCount);
- assertContainsStringsExactly(actual.servers, expected.servers);
- assertContainsStringsExactly(actual.domains, expected.domains);
- assertEquals(actual.tlsName, expected.tlsName);
- assertContainsStringsExactly(actual.tlsServers, expected.tlsServers);
- assertContainsStringsExactly(actual.tlsFingerprints, expected.tlsFingerprints);
- assertEquals(actual.caCertificate, expected.caCertificate);
- assertEquals(actual.tlsConnectTimeoutMs, expected.tlsConnectTimeoutMs);
- assertResolverOptionsEquals(actual.resolverOptions, expected.resolverOptions);
- assertContainsExactly(actual.transportTypes, expected.transportTypes);
- assertFieldCountEquals(16, ResolverParamsParcel.class);
- }
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- mContentResolver = new MockContentResolver();
- mContentResolver.addProvider(Settings.AUTHORITY,
- new FakeSettingsProvider());
- when(mCtx.getContentResolver()).thenReturn(mContentResolver);
- mDnsManager = new DnsManager(mCtx, mMockDnsResolver, mSystemProperties);
-
- // Clear the private DNS settings
- Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "");
- Settings.Global.putString(mContentResolver, PRIVATE_DNS_MODE, "");
- Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "");
- }
-
- @Test
- public void testTrackedValidationUpdates() throws Exception {
- mDnsManager.updatePrivateDns(new Network(TEST_NETID),
- mDnsManager.getPrivateDnsConfig());
- mDnsManager.updatePrivateDns(new Network(TEST_NETID_ALTERNATE),
- mDnsManager.getPrivateDnsConfig());
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(TEST_IFACENAME);
- lp.addDnsServer(InetAddress.getByName("3.3.3.3"));
- lp.addDnsServer(InetAddress.getByName("4.4.4.4"));
-
- // Send a validation event that is tracked on the alternate netId
- mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
- mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
- mDnsManager.flushVmDnsCache();
- mDnsManager.updateTransportsForNetwork(TEST_NETID_ALTERNATE, TEST_TRANSPORT_TYPES);
- mDnsManager.noteDnsServersForNetwork(TEST_NETID_ALTERNATE, lp);
- mDnsManager.flushVmDnsCache();
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_ALTERNATE,
- InetAddress.parseNumericAddress("4.4.4.4"), "", true));
- LinkProperties fixedLp = new LinkProperties(lp);
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
- assertFalse(fixedLp.isPrivateDnsActive());
- assertNull(fixedLp.getPrivateDnsServerName());
- fixedLp = new LinkProperties(lp);
- mDnsManager.updatePrivateDnsStatus(TEST_NETID_ALTERNATE, fixedLp);
- assertTrue(fixedLp.isPrivateDnsActive());
- assertNull(fixedLp.getPrivateDnsServerName());
- assertEquals(Arrays.asList(InetAddress.getByName("4.4.4.4")),
- fixedLp.getValidatedPrivateDnsServers());
-
- // Set up addresses for strict mode and switch to it.
- lp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
- lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
- TEST_IFACENAME));
- lp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
- lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
- TEST_IFACENAME));
-
- Settings.Global.putString(mContentResolver,
- PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
- Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com");
- mDnsManager.updatePrivateDns(new Network(TEST_NETID),
- new PrivateDnsConfig("strictmode.com", new InetAddress[] {
- InetAddress.parseNumericAddress("6.6.6.6"),
- InetAddress.parseNumericAddress("2001:db8:66:66::1")
- }));
- mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
- mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
- mDnsManager.flushVmDnsCache();
- fixedLp = new LinkProperties(lp);
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
- assertTrue(fixedLp.isPrivateDnsActive());
- assertEquals("strictmode.com", fixedLp.getPrivateDnsServerName());
- // No validation events yet.
- assertEquals(Arrays.asList(new InetAddress[0]), fixedLp.getValidatedPrivateDnsServers());
- // Validate one.
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
- InetAddress.parseNumericAddress("6.6.6.6"), "strictmode.com", true));
- fixedLp = new LinkProperties(lp);
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
- assertEquals(Arrays.asList(InetAddress.parseNumericAddress("6.6.6.6")),
- fixedLp.getValidatedPrivateDnsServers());
- // Validate the 2nd one.
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
- InetAddress.parseNumericAddress("2001:db8:66:66::1"), "strictmode.com", true));
- fixedLp = new LinkProperties(lp);
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
- assertEquals(Arrays.asList(
- InetAddress.parseNumericAddress("2001:db8:66:66::1"),
- InetAddress.parseNumericAddress("6.6.6.6")),
- fixedLp.getValidatedPrivateDnsServers());
- }
-
- @Test
- public void testIgnoreUntrackedValidationUpdates() throws Exception {
- // The PrivateDnsConfig map is empty, so no validation events will
- // be tracked.
- LinkProperties lp = new LinkProperties();
- lp.addDnsServer(InetAddress.getByName("3.3.3.3"));
- mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
- mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
- mDnsManager.flushVmDnsCache();
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
- InetAddress.parseNumericAddress("3.3.3.3"), "", true));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- assertFalse(lp.isPrivateDnsActive());
- assertNull(lp.getPrivateDnsServerName());
-
- // Validation event has untracked netId
- mDnsManager.updatePrivateDns(new Network(TEST_NETID),
- mDnsManager.getPrivateDnsConfig());
- mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
- mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
- mDnsManager.flushVmDnsCache();
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_UNTRACKED,
- InetAddress.parseNumericAddress("3.3.3.3"), "", true));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- assertFalse(lp.isPrivateDnsActive());
- assertNull(lp.getPrivateDnsServerName());
-
- // Validation event has untracked ipAddress
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
- InetAddress.parseNumericAddress("4.4.4.4"), "", true));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- assertFalse(lp.isPrivateDnsActive());
- assertNull(lp.getPrivateDnsServerName());
-
- // Validation event has untracked hostname
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
- InetAddress.parseNumericAddress("3.3.3.3"), "hostname",
- true));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- assertFalse(lp.isPrivateDnsActive());
- assertNull(lp.getPrivateDnsServerName());
-
- // Validation event failed
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
- InetAddress.parseNumericAddress("3.3.3.3"), "", false));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- assertFalse(lp.isPrivateDnsActive());
- assertNull(lp.getPrivateDnsServerName());
-
- // Network removed
- mDnsManager.removeNetwork(new Network(TEST_NETID));
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
- InetAddress.parseNumericAddress("3.3.3.3"), "", true));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- assertFalse(lp.isPrivateDnsActive());
- assertNull(lp.getPrivateDnsServerName());
-
- // Turn private DNS mode off
- Settings.Global.putString(mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OFF);
- mDnsManager.updatePrivateDns(new Network(TEST_NETID),
- mDnsManager.getPrivateDnsConfig());
- mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
- mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
- mDnsManager.flushVmDnsCache();
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
- InetAddress.parseNumericAddress("3.3.3.3"), "", true));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- assertFalse(lp.isPrivateDnsActive());
- assertNull(lp.getPrivateDnsServerName());
- }
-
- @Test
- public void testOverrideDefaultMode() throws Exception {
- // Hard-coded default is opportunistic mode.
- final PrivateDnsConfig cfgAuto = DnsManager.getPrivateDnsConfig(mContentResolver);
- assertTrue(cfgAuto.useTls);
- assertEquals("", cfgAuto.hostname);
- assertEquals(new InetAddress[0], cfgAuto.ips);
-
- // Pretend a gservices push sets the default to "off".
- Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "off");
- final PrivateDnsConfig cfgOff = DnsManager.getPrivateDnsConfig(mContentResolver);
- assertFalse(cfgOff.useTls);
- assertEquals("", cfgOff.hostname);
- assertEquals(new InetAddress[0], cfgOff.ips);
-
- // Strict mode still works.
- Settings.Global.putString(
- mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
- Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com");
- final PrivateDnsConfig cfgStrict = DnsManager.getPrivateDnsConfig(mContentResolver);
- assertTrue(cfgStrict.useTls);
- assertEquals("strictmode.com", cfgStrict.hostname);
- assertEquals(new InetAddress[0], cfgStrict.ips);
- }
-
- @Test
- public void testSendDnsConfiguration() throws Exception {
- reset(mMockDnsResolver);
- mDnsManager.updatePrivateDns(new Network(TEST_NETID),
- mDnsManager.getPrivateDnsConfig());
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(TEST_IFACENAME);
- lp.addDnsServer(InetAddress.getByName("3.3.3.3"));
- lp.addDnsServer(InetAddress.getByName("4.4.4.4"));
- mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
- mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
- mDnsManager.flushVmDnsCache();
-
- final ArgumentCaptor<ResolverParamsParcel> resolverParamsParcelCaptor =
- ArgumentCaptor.forClass(ResolverParamsParcel.class);
- verify(mMockDnsResolver, times(1)).setResolverConfiguration(
- resolverParamsParcelCaptor.capture());
- final ResolverParamsParcel actualParams = resolverParamsParcelCaptor.getValue();
- final ResolverParamsParcel expectedParams = new ResolverParamsParcel();
- expectedParams.netId = TEST_NETID;
- expectedParams.sampleValiditySeconds = TEST_DEFAULT_SAMPLE_VALIDITY_SECONDS;
- expectedParams.successThreshold = TEST_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
- expectedParams.minSamples = TEST_DEFAULT_MIN_SAMPLES;
- expectedParams.maxSamples = TEST_DEFAULT_MAX_SAMPLES;
- expectedParams.servers = new String[]{"3.3.3.3", "4.4.4.4"};
- expectedParams.domains = new String[]{};
- expectedParams.tlsName = "";
- expectedParams.tlsServers = new String[]{"3.3.3.3", "4.4.4.4"};
- expectedParams.transportTypes = TEST_TRANSPORT_TYPES;
- expectedParams.resolverOptions = new ResolverOptionsParcel();
- assertResolverParamsEquals(actualParams, expectedParams);
- }
-
- @Test
- public void testTransportTypesEqual() throws Exception {
- SparseArray<String> ncTransTypes = MessageUtils.findMessageNames(
- new Class[] { NetworkCapabilities.class }, new String[]{ "TRANSPORT_" });
- SparseArray<String> dnsTransTypes = MessageUtils.findMessageNames(
- new Class[] { IDnsResolver.class }, new String[]{ "TRANSPORT_" });
- assertEquals(0, MIN_TRANSPORT);
- assertEquals(MAX_TRANSPORT + 1, ncTransTypes.size());
- // TRANSPORT_UNKNOWN in IDnsResolver is defined to -1 and only for resolver.
- assertEquals("TRANSPORT_UNKNOWN", dnsTransTypes.get(-1));
- assertEquals(ncTransTypes.size(), dnsTransTypes.size() - 1);
- for (int i = MIN_TRANSPORT; i < MAX_TRANSPORT; i++) {
- String name = ncTransTypes.get(i, null);
- assertNotNull("Could not find NetworkCapabilies.TRANSPORT_* constant equal to "
- + i, name);
- assertEquals(name, dnsTransTypes.get(i));
- }
- }
-
- @Test
- public void testGetPrivateDnsConfigForNetwork() throws Exception {
- final Network network = new Network(TEST_NETID);
- final InetAddress dnsAddr = InetAddressUtils.parseNumericAddress("3.3.3.3");
- final InetAddress[] tlsAddrs = new InetAddress[]{
- InetAddressUtils.parseNumericAddress("6.6.6.6"),
- InetAddressUtils.parseNumericAddress("2001:db8:66:66::1")
- };
- final String tlsName = "strictmode.com";
- LinkProperties lp = new LinkProperties();
- lp.addDnsServer(dnsAddr);
-
- // The PrivateDnsConfig map is empty, so the default PRIVATE_DNS_OFF is returned.
- PrivateDnsConfig privateDnsCfg = mDnsManager.getPrivateDnsConfig(network);
- assertFalse(privateDnsCfg.useTls);
- assertEquals("", privateDnsCfg.hostname);
- assertEquals(new InetAddress[0], privateDnsCfg.ips);
-
- // An entry with default PrivateDnsConfig is added to the PrivateDnsConfig map.
- mDnsManager.updatePrivateDns(network, mDnsManager.getPrivateDnsConfig());
- mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, dnsAddr, "", true));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- privateDnsCfg = mDnsManager.getPrivateDnsConfig(network);
- assertTrue(privateDnsCfg.useTls);
- assertEquals("", privateDnsCfg.hostname);
- assertEquals(new InetAddress[0], privateDnsCfg.ips);
-
- // The original entry is overwritten by a new PrivateDnsConfig.
- mDnsManager.updatePrivateDns(network, new PrivateDnsConfig(tlsName, tlsAddrs));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- privateDnsCfg = mDnsManager.getPrivateDnsConfig(network);
- assertTrue(privateDnsCfg.useTls);
- assertEquals(tlsName, privateDnsCfg.hostname);
- assertEquals(tlsAddrs, privateDnsCfg.ips);
-
- // The network is removed, so the PrivateDnsConfig map becomes empty again.
- mDnsManager.removeNetwork(network);
- privateDnsCfg = mDnsManager.getPrivateDnsConfig(network);
- assertFalse(privateDnsCfg.useTls);
- assertEquals("", privateDnsCfg.hostname);
- assertEquals(new InetAddress[0], privateDnsCfg.ips);
- }
-}
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
deleted file mode 100644
index 70495cced536..000000000000
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
+++ /dev/null
@@ -1,561 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static com.android.server.connectivity.MetricsTestUtil.aLong;
-import static com.android.server.connectivity.MetricsTestUtil.aString;
-import static com.android.server.connectivity.MetricsTestUtil.aType;
-import static com.android.server.connectivity.MetricsTestUtil.anInt;
-import static com.android.server.connectivity.MetricsTestUtil.describeIpEvent;
-import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.BLUETOOTH;
-import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.CELLULAR;
-import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
-import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.MULTIPLE;
-import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.WIFI;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.net.ConnectivityMetricsEvent;
-import android.net.metrics.ApfProgramEvent;
-import android.net.metrics.ApfStats;
-import android.net.metrics.DefaultNetworkEvent;
-import android.net.metrics.DhcpClientEvent;
-import android.net.metrics.DhcpErrorEvent;
-import android.net.metrics.IpManagerEvent;
-import android.net.metrics.IpReachabilityEvent;
-import android.net.metrics.NetworkEvent;
-import android.net.metrics.RaEvent;
-import android.net.metrics.ValidationProbeEvent;
-import android.net.metrics.WakeupStats;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-import java.util.List;
-
-// TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpConnectivityEventBuilderTest {
-
- @Test
- public void testLinkLayerInferrence() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(IpReachabilityEvent.class),
- anInt(IpReachabilityEvent.NUD_FAILED));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "version: 2\n");
- verifySerialization(want, ev);
-
- ev.netId = 123;
- ev.transports = 3; // transports have priority for inferrence of link layer
- ev.ifname = "wlan0";
- want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- String.format(" link_layer: %d", MULTIPLE),
- " network_id: 123",
- " time_ms: 1",
- " transports: 3",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "version: 2\n");
- verifySerialization(want, ev);
-
- ev.transports = 1;
- ev.ifname = null;
- want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- String.format(" link_layer: %d", CELLULAR),
- " network_id: 123",
- " time_ms: 1",
- " transports: 1",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "version: 2\n");
- verifySerialization(want, ev);
-
- ev.transports = 0;
- ev.ifname = "not_inferred";
- want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"not_inferred\"",
- " link_layer: 0",
- " network_id: 123",
- " time_ms: 1",
- " transports: 0",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "version: 2\n");
- verifySerialization(want, ev);
-
- ev.ifname = "bt-pan";
- want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- String.format(" link_layer: %d", BLUETOOTH),
- " network_id: 123",
- " time_ms: 1",
- " transports: 0",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "version: 2\n");
- verifySerialization(want, ev);
-
- ev.ifname = "rmnet_ipa0";
- want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- String.format(" link_layer: %d", CELLULAR),
- " network_id: 123",
- " time_ms: 1",
- " transports: 0",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "version: 2\n");
- verifySerialization(want, ev);
-
- ev.ifname = "wlan0";
- want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- String.format(" link_layer: %d", WIFI),
- " network_id: 123",
- " time_ms: 1",
- " transports: 0",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "version: 2\n");
- verifySerialization(want, ev);
- }
-
- @Test
- public void testDefaultNetworkEventSerialization() {
- DefaultNetworkEvent ev = new DefaultNetworkEvent(1001);
- ev.netId = 102;
- ev.transports = 2;
- ev.previousTransports = 4;
- ev.ipv4 = true;
- ev.initialScore = 20;
- ev.finalScore = 60;
- ev.durationMs = 54;
- ev.validatedMs = 27;
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 102",
- " time_ms: 0",
- " transports: 2",
- " default_network_event <",
- " default_network_duration_ms: 54",
- " final_score: 60",
- " initial_score: 20",
- " ip_support: 1",
- " no_default_network_duration_ms: 0",
- " previous_default_network_link_layer: 1",
- " previous_network_ip_support: 0",
- " validation_duration_ms: 27",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, IpConnectivityEventBuilder.toProto(ev));
- }
-
- @Test
- public void testDhcpClientEventSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(DhcpClientEvent.class),
- aString("SomeState"),
- anInt(192));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " dhcp_event <",
- " duration_ms: 192",
- " if_name: \"\"",
- " state_transition: \"SomeState\"",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testDhcpErrorEventSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(DhcpErrorEvent.class),
- anInt(DhcpErrorEvent.L4_NOT_UDP));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " dhcp_event <",
- " duration_ms: 0",
- " if_name: \"\"",
- " error_code: 50397184",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testIpManagerEventSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(IpManagerEvent.class),
- anInt(IpManagerEvent.PROVISIONING_OK),
- aLong(5678));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " ip_provisioning_event <",
- " event_type: 1",
- " if_name: \"\"",
- " latency_ms: 5678",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testIpReachabilityEventSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(IpReachabilityEvent.class),
- anInt(IpReachabilityEvent.NUD_FAILED));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testNetworkEventSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(NetworkEvent.class),
- anInt(5),
- aLong(20410));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " network_event <",
- " event_type: 5",
- " latency_ms: 20410",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testValidationProbeEventSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(ValidationProbeEvent.class),
- aLong(40730),
- anInt(ValidationProbeEvent.PROBE_HTTP),
- anInt(204));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " validation_probe_event <",
- " latency_ms: 40730",
- " probe_result: 204",
- " probe_type: 1",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testApfProgramEventSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(ApfProgramEvent.class),
- aLong(200),
- aLong(18),
- anInt(7),
- anInt(9),
- anInt(2048),
- anInt(3));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " apf_program_event <",
- " current_ras: 9",
- " drop_multicast: true",
- " effective_lifetime: 18",
- " filtered_ras: 7",
- " has_ipv4_addr: true",
- " lifetime: 200",
- " program_length: 2048",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testApfStatsSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(ApfStats.class),
- aLong(45000),
- anInt(10),
- anInt(2),
- anInt(2),
- anInt(1),
- anInt(2),
- anInt(4),
- anInt(7),
- anInt(3),
- anInt(2048));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " apf_statistics <",
- " dropped_ras: 2",
- " duration_ms: 45000",
- " matching_ras: 2",
- " max_program_size: 2048",
- " parse_errors: 2",
- " program_updates: 4",
- " program_updates_all: 7",
- " program_updates_allowing_multicast: 3",
- " received_ras: 10",
- " total_packet_dropped: 0",
- " total_packet_processed: 0",
- " zero_lifetime_ras: 1",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testRaEventSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(RaEvent.class),
- aLong(2000),
- aLong(400),
- aLong(300),
- aLong(-1),
- aLong(1000),
- aLong(-1));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " ra_event <",
- " dnssl_lifetime: -1",
- " prefix_preferred_lifetime: 300",
- " prefix_valid_lifetime: 400",
- " rdnss_lifetime: 1000",
- " route_info_lifetime: -1",
- " router_lifetime: 2000",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testWakeupStatsSerialization() {
- WakeupStats stats = new WakeupStats("wlan0");
- stats.totalWakeups = 14;
- stats.applicationWakeups = 5;
- stats.nonApplicationWakeups = 1;
- stats.rootWakeups = 2;
- stats.systemWakeups = 3;
- stats.noUidWakeups = 3;
- stats.l2UnicastCount = 5;
- stats.l2MulticastCount = 1;
- stats.l2BroadcastCount = 2;
- stats.ethertypes.put(0x800, 3);
- stats.ethertypes.put(0x86dd, 3);
- stats.ipNextHeaders.put(6, 5);
-
-
- IpConnectivityEvent got = IpConnectivityEventBuilder.toProto(stats);
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 0",
- " transports: 0",
- " wakeup_stats <",
- " application_wakeups: 5",
- " duration_sec: 0",
- " ethertype_counts <",
- " key: 2048",
- " value: 3",
- " >",
- " ethertype_counts <",
- " key: 34525",
- " value: 3",
- " >",
- " ip_next_header_counts <",
- " key: 6",
- " value: 5",
- " >",
- " l2_broadcast_count: 2",
- " l2_multicast_count: 1",
- " l2_unicast_count: 5",
- " no_uid_wakeups: 3",
- " non_application_wakeups: 1",
- " root_wakeups: 2",
- " system_wakeups: 3",
- " total_wakeups: 14",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, got);
- }
-
- static void verifySerialization(String want, ConnectivityMetricsEvent... input) {
- List<IpConnectivityEvent> protoInput =
- IpConnectivityEventBuilder.toProto(Arrays.asList(input));
- verifySerialization(want, protoInput.toArray(new IpConnectivityEvent[0]));
- }
-
- static void verifySerialization(String want, IpConnectivityEvent... input) {
- try {
- byte[] got = IpConnectivityEventBuilder.serialize(0, Arrays.asList(input));
- IpConnectivityLog log = IpConnectivityLog.parseFrom(got);
- assertEquals(want, log.toString());
- } catch (Exception e) {
- fail(e.toString());
- }
- }
-}
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
deleted file mode 100644
index 3a071667a542..000000000000
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * Copyright (C) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO;
-import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityMetricsEvent;
-import android.net.IIpConnectivityMetrics;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.RouteInfo;
-import android.net.metrics.ApfProgramEvent;
-import android.net.metrics.ApfStats;
-import android.net.metrics.DhcpClientEvent;
-import android.net.metrics.IpConnectivityLog;
-import android.net.metrics.IpManagerEvent;
-import android.net.metrics.IpReachabilityEvent;
-import android.net.metrics.RaEvent;
-import android.net.metrics.ValidationProbeEvent;
-import android.os.Parcelable;
-import android.system.OsConstants;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Base64;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.BitUtils;
-import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpConnectivityMetricsTest {
- static final IpReachabilityEvent FAKE_EV =
- new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED);
-
- private static final String EXAMPLE_IPV4 = "192.0.2.1";
- private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1";
-
- private static final byte[] MAC_ADDR =
- {(byte)0x84, (byte)0xc9, (byte)0xb2, (byte)0x6a, (byte)0xed, (byte)0x4b};
-
- @Mock Context mCtx;
- @Mock IIpConnectivityMetrics mMockService;
- @Mock ConnectivityManager mCm;
-
- IpConnectivityMetrics mService;
- NetdEventListenerService mNetdListener;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mService = new IpConnectivityMetrics(mCtx, (ctx) -> 2000);
- mNetdListener = new NetdEventListenerService(mCm);
- mService.mNetdListener = mNetdListener;
- }
-
- @Test
- public void testBufferFlushing() {
- String output1 = getdump("flush");
- assertEquals("", output1);
-
- new IpConnectivityLog(mService.impl).log(1, FAKE_EV);
- String output2 = getdump("flush");
- assertFalse("".equals(output2));
-
- String output3 = getdump("flush");
- assertEquals("", output3);
- }
-
- @Test
- public void testRateLimiting() {
- final IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
- final ApfProgramEvent ev = new ApfProgramEvent.Builder().build();
- final long fakeTimestamp = 1;
-
- int attempt = 100; // More than burst quota, but less than buffer size.
- for (int i = 0; i < attempt; i++) {
- logger.log(ev);
- }
-
- String output1 = getdump("flush");
- assertFalse("".equals(output1));
-
- for (int i = 0; i < attempt; i++) {
- assertFalse("expected event to be dropped", logger.log(fakeTimestamp, ev));
- }
-
- String output2 = getdump("flush");
- assertEquals("", output2);
- }
-
- @Test
- public void testDefaultNetworkEvents() throws Exception {
- final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
- final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
-
- NetworkAgentInfo[][] defaultNetworks = {
- // nothing -> cell
- {null, makeNai(100, 10, false, true, cell)},
- // cell -> wifi
- {makeNai(100, 50, true, true, cell), makeNai(101, 20, true, false, wifi)},
- // wifi -> nothing
- {makeNai(101, 60, true, false, wifi), null},
- // nothing -> cell
- {null, makeNai(102, 10, true, true, cell)},
- // cell -> wifi
- {makeNai(102, 50, true, true, cell), makeNai(103, 20, true, false, wifi)},
- };
-
- long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
- long durationMs = 1001;
- for (NetworkAgentInfo[] pair : defaultNetworks) {
- timeMs += durationMs;
- durationMs += durationMs;
- mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs, pair[1], pair[0]);
- }
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 5",
- " network_id: 0",
- " time_ms: 0",
- " transports: 0",
- " default_network_event <",
- " default_network_duration_ms: 1001",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " no_default_network_duration_ms: 0",
- " previous_default_network_link_layer: 0",
- " previous_network_ip_support: 0",
- " validation_duration_ms: 0",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 2",
- " network_id: 100",
- " time_ms: 0",
- " transports: 1",
- " default_network_event <",
- " default_network_duration_ms: 2002",
- " final_score: 50",
- " initial_score: 10",
- " ip_support: 3",
- " no_default_network_duration_ms: 0",
- " previous_default_network_link_layer: 0",
- " previous_network_ip_support: 0",
- " validation_duration_ms: 2002",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 101",
- " time_ms: 0",
- " transports: 2",
- " default_network_event <",
- " default_network_duration_ms: 4004",
- " final_score: 60",
- " initial_score: 20",
- " ip_support: 1",
- " no_default_network_duration_ms: 0",
- " previous_default_network_link_layer: 2",
- " previous_network_ip_support: 0",
- " validation_duration_ms: 4004",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 5",
- " network_id: 0",
- " time_ms: 0",
- " transports: 0",
- " default_network_event <",
- " default_network_duration_ms: 8008",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " no_default_network_duration_ms: 0",
- " previous_default_network_link_layer: 4",
- " previous_network_ip_support: 0",
- " validation_duration_ms: 0",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 2",
- " network_id: 102",
- " time_ms: 0",
- " transports: 1",
- " default_network_event <",
- " default_network_duration_ms: 16016",
- " final_score: 50",
- " initial_score: 10",
- " ip_support: 3",
- " no_default_network_duration_ms: 0",
- " previous_default_network_link_layer: 4",
- " previous_network_ip_support: 0",
- " validation_duration_ms: 16016",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, getdump("flush"));
- }
-
- @Test
- public void testEndToEndLogging() throws Exception {
- // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
- IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
-
- NetworkCapabilities ncWifi = new NetworkCapabilities();
- NetworkCapabilities ncCell = new NetworkCapabilities();
- ncWifi.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- ncCell.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-
- when(mCm.getNetworkCapabilities(new Network(100))).thenReturn(ncWifi);
- when(mCm.getNetworkCapabilities(new Network(101))).thenReturn(ncCell);
-
- ApfStats apfStats = new ApfStats.Builder()
- .setDurationMs(45000)
- .setReceivedRas(10)
- .setMatchingRas(2)
- .setDroppedRas(2)
- .setParseErrors(2)
- .setZeroLifetimeRas(1)
- .setProgramUpdates(4)
- .setProgramUpdatesAll(7)
- .setProgramUpdatesAllowingMulticast(3)
- .setMaxProgramSize(2048)
- .build();
-
- final ValidationProbeEvent validationEv = new ValidationProbeEvent.Builder()
- .setDurationMs(40730)
- .setProbeType(ValidationProbeEvent.PROBE_HTTP, true)
- .setReturnCode(204)
- .build();
-
- final DhcpClientEvent event = new DhcpClientEvent.Builder()
- .setMsg("SomeState")
- .setDurationMs(192)
- .build();
- Parcelable[] events = {
- new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED), event,
- new IpManagerEvent(IpManagerEvent.PROVISIONING_OK, 5678),
- validationEv,
- apfStats,
- new RaEvent(2000, 400, 300, -1, 1000, -1)
- };
-
- for (int i = 0; i < events.length; i++) {
- ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
- ev.timestamp = 100 * (i + 1);
- ev.ifname = "wlan0";
- ev.data = events[i];
- logger.log(ev);
- }
-
- // netId, errno, latency, destination
- connectEvent(100, OsConstants.EALREADY, 0, EXAMPLE_IPV4);
- connectEvent(100, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6);
- connectEvent(100, 0, 110, EXAMPLE_IPV4);
- connectEvent(101, 0, 23, EXAMPLE_IPV4);
- connectEvent(101, 0, 45, EXAMPLE_IPV6);
- connectEvent(100, OsConstants.EAGAIN, 0, EXAMPLE_IPV4);
-
- // netId, type, return code, latency
- dnsEvent(100, EVENT_GETADDRINFO, 0, 3456);
- dnsEvent(100, EVENT_GETADDRINFO, 3, 45);
- dnsEvent(100, EVENT_GETHOSTBYNAME, 0, 638);
- dnsEvent(101, EVENT_GETADDRINFO, 0, 56);
- dnsEvent(101, EVENT_GETHOSTBYNAME, 0, 34);
-
- // iface, uid
- final byte[] mac = {0x48, 0x7c, 0x2b, 0x6a, 0x3e, 0x4b};
- final String srcIp = "192.168.2.1";
- final String dstIp = "192.168.2.23";
- final int sport = 2356;
- final int dport = 13489;
- final long now = 1001L;
- final int v4 = 0x800;
- final int tcp = 6;
- final int udp = 17;
- wakeupEvent("wlan0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
- wakeupEvent("wlan0", 10123, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
- wakeupEvent("wlan0", 1000, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
- wakeupEvent("wlan0", 10008, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
- wakeupEvent("wlan0", -1, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
- wakeupEvent("wlan0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
-
- long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
- final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
- final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
- NetworkAgentInfo cellNai = makeNai(100, 50, false, true, cell);
- NetworkAgentInfo wifiNai = makeNai(101, 60, true, false, wifi);
- mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs + 200, cellNai, null);
- mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs + 300, wifiNai, cellNai);
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 100",
- " transports: 0",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 200",
- " transports: 0",
- " dhcp_event <",
- " duration_ms: 192",
- " if_name: \"\"",
- " state_transition: \"SomeState\"",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 300",
- " transports: 0",
- " ip_provisioning_event <",
- " event_type: 1",
- " if_name: \"\"",
- " latency_ms: 5678",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 400",
- " transports: 0",
- " validation_probe_event <",
- " latency_ms: 40730",
- " probe_result: 204",
- " probe_type: 257",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 500",
- " transports: 0",
- " apf_statistics <",
- " dropped_ras: 2",
- " duration_ms: 45000",
- " matching_ras: 2",
- " max_program_size: 2048",
- " parse_errors: 2",
- " program_updates: 4",
- " program_updates_all: 7",
- " program_updates_allowing_multicast: 3",
- " received_ras: 10",
- " total_packet_dropped: 0",
- " total_packet_processed: 0",
- " zero_lifetime_ras: 1",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 600",
- " transports: 0",
- " ra_event <",
- " dnssl_lifetime: -1",
- " prefix_preferred_lifetime: 300",
- " prefix_valid_lifetime: 400",
- " rdnss_lifetime: 1000",
- " route_info_lifetime: -1",
- " router_lifetime: 2000",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 5",
- " network_id: 0",
- " time_ms: 0",
- " transports: 0",
- " default_network_event <",
- " default_network_duration_ms: 200",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " no_default_network_duration_ms: 0",
- " previous_default_network_link_layer: 0",
- " previous_network_ip_support: 0",
- " validation_duration_ms: 0",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 2",
- " network_id: 100",
- " time_ms: 0",
- " transports: 1",
- " default_network_event <",
- " default_network_duration_ms: 100",
- " final_score: 50",
- " initial_score: 50",
- " ip_support: 2",
- " no_default_network_duration_ms: 0",
- " previous_default_network_link_layer: 0",
- " previous_network_ip_support: 0",
- " validation_duration_ms: 100",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 100",
- " time_ms: 0",
- " transports: 2",
- " connect_statistics <",
- " connect_blocking_count: 1",
- " connect_count: 3",
- " errnos_counters <",
- " key: 11",
- " value: 1",
- " >",
- " ipv6_addr_count: 1",
- " latencies_ms: 110",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 2",
- " network_id: 101",
- " time_ms: 0",
- " transports: 1",
- " connect_statistics <",
- " connect_blocking_count: 2",
- " connect_count: 2",
- " ipv6_addr_count: 1",
- " latencies_ms: 23",
- " latencies_ms: 45",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 100",
- " time_ms: 0",
- " transports: 2",
- " dns_lookup_batch <",
- " event_types: 1",
- " event_types: 1",
- " event_types: 2",
- " getaddrinfo_error_count: 0",
- " getaddrinfo_query_count: 0",
- " gethostbyname_error_count: 0",
- " gethostbyname_query_count: 0",
- " latencies_ms: 3456",
- " latencies_ms: 45",
- " latencies_ms: 638",
- " return_codes: 0",
- " return_codes: 3",
- " return_codes: 0",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 2",
- " network_id: 101",
- " time_ms: 0",
- " transports: 1",
- " dns_lookup_batch <",
- " event_types: 1",
- " event_types: 2",
- " getaddrinfo_error_count: 0",
- " getaddrinfo_query_count: 0",
- " gethostbyname_error_count: 0",
- " gethostbyname_query_count: 0",
- " latencies_ms: 56",
- " latencies_ms: 34",
- " return_codes: 0",
- " return_codes: 0",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 0",
- " transports: 0",
- " wakeup_stats <",
- " application_wakeups: 3",
- " duration_sec: 0",
- " ethertype_counts <",
- " key: 2048",
- " value: 6",
- " >",
- " ip_next_header_counts <",
- " key: 6",
- " value: 3",
- " >",
- " ip_next_header_counts <",
- " key: 17",
- " value: 3",
- " >",
- " l2_broadcast_count: 0",
- " l2_multicast_count: 0",
- " l2_unicast_count: 6",
- " no_uid_wakeups: 1",
- " non_application_wakeups: 0",
- " root_wakeups: 0",
- " system_wakeups: 2",
- " total_wakeups: 6",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, getdump("flush"));
- }
-
- String getdump(String ... command) {
- StringWriter buffer = new StringWriter();
- PrintWriter writer = new PrintWriter(buffer);
- mService.impl.dump(null, writer, command);
- return buffer.toString();
- }
-
- void connectEvent(int netid, int error, int latencyMs, String ipAddr) throws Exception {
- mNetdListener.onConnectEvent(netid, error, latencyMs, ipAddr, 80, 1);
- }
-
- void dnsEvent(int netId, int type, int result, int latency) throws Exception {
- mNetdListener.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
- }
-
- void wakeupEvent(String iface, int uid, int ether, int ip, byte[] mac, String srcIp,
- String dstIp, int sport, int dport, long now) throws Exception {
- String prefix = NetdEventListenerService.WAKEUP_EVENT_IFACE_PREFIX + iface;
- mNetdListener.onWakeupEvent(prefix, uid, ether, ip, mac, srcIp, dstIp, sport, dport, now);
- }
-
- NetworkAgentInfo makeNai(int netId, int score, boolean ipv4, boolean ipv6, long transports) {
- NetworkAgentInfo nai = mock(NetworkAgentInfo.class);
- when(nai.network()).thenReturn(new Network(netId));
- when(nai.getCurrentScore()).thenReturn(score);
- nai.linkProperties = new LinkProperties();
- nai.networkCapabilities = new NetworkCapabilities();
- nai.lastValidated = true;
- for (int t : BitUtils.unpackBits(transports)) {
- nai.networkCapabilities.addTransportType(t);
- }
- if (ipv4) {
- nai.linkProperties.addLinkAddress(new LinkAddress("192.0.2.12/24"));
- nai.linkProperties.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0")));
- }
- if (ipv6) {
- nai.linkProperties.addLinkAddress(new LinkAddress("2001:db8:dead:beef:f00::a0/64"));
- nai.linkProperties.addRoute(new RouteInfo(new IpPrefix("::/0")));
- }
- return nai;
- }
-
-
-
- static void verifySerialization(String want, String output) {
- try {
- byte[] got = Base64.decode(output, Base64.DEFAULT);
- IpConnectivityLogClass.IpConnectivityLog log =
- IpConnectivityLogClass.IpConnectivityLog.parseFrom(got);
- assertEquals(want, log.toString());
- } catch (Exception e) {
- fail(e.toString());
- }
- }
-}
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
deleted file mode 100644
index aafa18a532fa..000000000000
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Copyright (C) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.IDnsResolver;
-import android.net.INetd;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkProvider;
-import android.os.Binder;
-import android.os.INetworkManagementService;
-import android.text.format.DateUtils;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.R;
-import com.android.server.ConnectivityService;
-import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class LingerMonitorTest {
- static final String CELLULAR = "CELLULAR";
- static final String WIFI = "WIFI";
-
- static final long LOW_RATE_LIMIT = DateUtils.MINUTE_IN_MILLIS;
- static final long HIGH_RATE_LIMIT = 0;
-
- static final int LOW_DAILY_LIMIT = 2;
- static final int HIGH_DAILY_LIMIT = 1000;
-
- LingerMonitor mMonitor;
-
- @Mock ConnectivityService mConnService;
- @Mock IDnsResolver mDnsResolver;
- @Mock INetd mNetd;
- @Mock INetworkManagementService mNMS;
- @Mock Context mCtx;
- @Mock NetworkNotificationManager mNotifier;
- @Mock Resources mResources;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mCtx.getResources()).thenReturn(mResources);
- when(mCtx.getPackageName()).thenReturn("com.android.server.connectivity");
-
- mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, HIGH_RATE_LIMIT);
- }
-
- @Test
- public void testTransitions() {
- setNotificationSwitch(transition(WIFI, CELLULAR));
- NetworkAgentInfo nai1 = wifiNai(100);
- NetworkAgentInfo nai2 = cellNai(101);
-
- assertTrue(mMonitor.isNotificationEnabled(nai1, nai2));
- assertFalse(mMonitor.isNotificationEnabled(nai2, nai1));
- }
-
- @Test
- public void testNotificationOnLinger() {
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNotification(from, to);
- }
-
- @Test
- public void testToastOnLinger() {
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyToast(from, to);
- }
-
- @Test
- public void testNotificationClearedAfterDisconnect() {
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNotification(from, to);
-
- mMonitor.noteDisconnect(to);
- verify(mNotifier, times(1)).clearNotification(100);
- }
-
- @Test
- public void testNotificationClearedAfterSwitchingBack() {
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNotification(from, to);
-
- mMonitor.noteLingerDefaultNetwork(to, from);
- verify(mNotifier, times(1)).clearNotification(100);
- }
-
- @Test
- public void testUniqueToast() {
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyToast(from, to);
-
- mMonitor.noteLingerDefaultNetwork(to, from);
- verify(mNotifier, times(1)).clearNotification(100);
-
- reset(mNotifier);
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNoNotifications();
- }
-
- @Test
- public void testMultipleNotifications() {
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
- NetworkAgentInfo wifi1 = wifiNai(100);
- NetworkAgentInfo wifi2 = wifiNai(101);
- NetworkAgentInfo cell = cellNai(102);
-
- mMonitor.noteLingerDefaultNetwork(wifi1, cell);
- verifyNotification(wifi1, cell);
-
- mMonitor.noteLingerDefaultNetwork(cell, wifi2);
- verify(mNotifier, times(1)).clearNotification(100);
-
- reset(mNotifier);
- mMonitor.noteLingerDefaultNetwork(wifi2, cell);
- verifyNotification(wifi2, cell);
- }
-
- @Test
- public void testRateLimiting() throws InterruptedException {
- mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, LOW_RATE_LIMIT);
-
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
- NetworkAgentInfo wifi1 = wifiNai(100);
- NetworkAgentInfo wifi2 = wifiNai(101);
- NetworkAgentInfo wifi3 = wifiNai(102);
- NetworkAgentInfo cell = cellNai(103);
-
- mMonitor.noteLingerDefaultNetwork(wifi1, cell);
- verifyNotification(wifi1, cell);
- reset(mNotifier);
-
- Thread.sleep(50);
- mMonitor.noteLingerDefaultNetwork(cell, wifi2);
- mMonitor.noteLingerDefaultNetwork(wifi2, cell);
- verifyNoNotifications();
-
- Thread.sleep(50);
- mMonitor.noteLingerDefaultNetwork(cell, wifi3);
- mMonitor.noteLingerDefaultNetwork(wifi3, cell);
- verifyNoNotifications();
- }
-
- @Test
- public void testDailyLimiting() throws InterruptedException {
- mMonitor = new TestableLingerMonitor(mCtx, mNotifier, LOW_DAILY_LIMIT, HIGH_RATE_LIMIT);
-
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
- NetworkAgentInfo wifi1 = wifiNai(100);
- NetworkAgentInfo wifi2 = wifiNai(101);
- NetworkAgentInfo wifi3 = wifiNai(102);
- NetworkAgentInfo cell = cellNai(103);
-
- mMonitor.noteLingerDefaultNetwork(wifi1, cell);
- verifyNotification(wifi1, cell);
- reset(mNotifier);
-
- Thread.sleep(50);
- mMonitor.noteLingerDefaultNetwork(cell, wifi2);
- mMonitor.noteLingerDefaultNetwork(wifi2, cell);
- verifyNotification(wifi2, cell);
- reset(mNotifier);
-
- Thread.sleep(50);
- mMonitor.noteLingerDefaultNetwork(cell, wifi3);
- mMonitor.noteLingerDefaultNetwork(wifi3, cell);
- verifyNoNotifications();
- }
-
- @Test
- public void testUniqueNotification() {
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNotification(from, to);
-
- mMonitor.noteLingerDefaultNetwork(to, from);
- verify(mNotifier, times(1)).clearNotification(100);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNotification(from, to);
- }
-
- @Test
- public void testIgnoreNeverValidatedNetworks() {
- setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
- setNotificationSwitch(transition(WIFI, CELLULAR));
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
- from.everValidated = false;
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNoNotifications();
- }
-
- @Test
- public void testIgnoreCurrentlyValidatedNetworks() {
- setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
- setNotificationSwitch(transition(WIFI, CELLULAR));
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
- from.lastValidated = true;
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNoNotifications();
- }
-
- @Test
- public void testNoNotificationType() {
- setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
- setNotificationSwitch();
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNoNotifications();
- }
-
- @Test
- public void testNoTransitionToNotify() {
- setNotificationType(LingerMonitor.NOTIFY_TYPE_NONE);
- setNotificationSwitch(transition(WIFI, CELLULAR));
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNoNotifications();
- }
-
- @Test
- public void testDifferentTransitionToNotify() {
- setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
- setNotificationSwitch(transition(CELLULAR, WIFI));
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNoNotifications();
- }
-
- void setNotificationSwitch(String... transitions) {
- when(mResources.getStringArray(R.array.config_networkNotifySwitches))
- .thenReturn(transitions);
- }
-
- String transition(String from, String to) {
- return from + "-" + to;
- }
-
- void setNotificationType(int type) {
- when(mResources.getInteger(R.integer.config_networkNotifySwitchType)).thenReturn(type);
- }
-
- void verifyNoToast() {
- verify(mNotifier, never()).showToast(any(), any());
- }
-
- void verifyNoNotification() {
- verify(mNotifier, never())
- .showNotification(anyInt(), any(), any(), any(), any(), anyBoolean());
- }
-
- void verifyNoNotifications() {
- verifyNoToast();
- verifyNoNotification();
- }
-
- void verifyToast(NetworkAgentInfo from, NetworkAgentInfo to) {
- verifyNoNotification();
- verify(mNotifier, times(1)).showToast(from, to);
- }
-
- void verifyNotification(NetworkAgentInfo from, NetworkAgentInfo to) {
- verifyNoToast();
- verify(mNotifier, times(1)).showNotification(eq(from.network.netId),
- eq(NotificationType.NETWORK_SWITCH), eq(from), eq(to), any(), eq(true));
- }
-
- NetworkAgentInfo nai(int netId, int transport, int networkType, String networkTypeName) {
- NetworkInfo info = new NetworkInfo(networkType, 0, networkTypeName, "");
- NetworkCapabilities caps = new NetworkCapabilities();
- caps.addCapability(0);
- caps.addTransportType(transport);
- NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
- caps, 50, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
- NetworkProvider.ID_NONE, Binder.getCallingUid());
- nai.everValidated = true;
- return nai;
- }
-
- NetworkAgentInfo wifiNai(int netId) {
- return nai(netId, NetworkCapabilities.TRANSPORT_WIFI,
- ConnectivityManager.TYPE_WIFI, WIFI);
- }
-
- NetworkAgentInfo cellNai(int netId) {
- return nai(netId, NetworkCapabilities.TRANSPORT_CELLULAR,
- ConnectivityManager.TYPE_MOBILE, CELLULAR);
- }
-
- public static class TestableLingerMonitor extends LingerMonitor {
- public TestableLingerMonitor(Context c, NetworkNotificationManager n, int l, long r) {
- super(c, n, l, r);
- }
- @Override protected PendingIntent createNotificationIntent() {
- return null;
- }
- }
-}
diff --git a/tests/net/java/com/android/server/connectivity/MetricsTestUtil.java b/tests/net/java/com/android/server/connectivity/MetricsTestUtil.java
deleted file mode 100644
index 5064b9bd91b9..000000000000
--- a/tests/net/java/com/android/server/connectivity/MetricsTestUtil.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import android.net.ConnectivityMetricsEvent;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.function.Consumer;
-
-abstract public class MetricsTestUtil {
- private MetricsTestUtil() {
- }
-
- static ConnectivityMetricsEvent ev(Parcelable p) {
- ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
- ev.timestamp = 1L;
- ev.data = p;
- return ev;
- }
-
- static ConnectivityMetricsEvent describeIpEvent(Consumer<Parcel>... fs) {
- Parcel p = Parcel.obtain();
- for (Consumer<Parcel> f : fs) {
- f.accept(p);
- }
- p.setDataPosition(0);
- return ev(p.readParcelable(ClassLoader.getSystemClassLoader()));
- }
-
- static Consumer<Parcel> aType(Class<?> c) {
- return aString(c.getName());
- }
-
- static Consumer<Parcel> aBool(boolean b) {
- return aByte((byte) (b ? 1 : 0));
- }
-
- static Consumer<Parcel> aByte(byte b) {
- return (p) -> p.writeByte(b);
- }
-
- static Consumer<Parcel> anInt(int i) {
- return (p) -> p.writeInt(i);
- }
-
- static Consumer<Parcel> aLong(long l) {
- return (p) -> p.writeLong(l);
- }
-
- static Consumer<Parcel> aString(String s) {
- return (p) -> p.writeString(s);
- }
-
- static Consumer<Parcel> aByteArray(byte... ary) {
- return (p) -> p.writeByteArray(ary);
- }
-
- static Consumer<Parcel> anIntArray(int... ary) {
- return (p) -> p.writeIntArray(ary);
- }
-
- static byte b(int i) {
- return (byte) i;
- }
-}
diff --git a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
deleted file mode 100644
index de1028cd2303..000000000000
--- a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.content.Intent.ACTION_CONFIGURATION_CHANGED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkPolicy.LIMIT_DISABLED;
-import static android.net.NetworkPolicy.SNOOZE_NEVER;
-import static android.net.NetworkPolicy.WARNING_DISABLED;
-import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES;
-
-import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_MULTIPATH;
-import static com.android.server.net.NetworkPolicyManagerService.OPPORTUNISTIC_QUOTA_UNKNOWN;
-
-import static junit.framework.TestCase.assertNotNull;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.usage.NetworkStatsManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkPolicy;
-import android.net.NetworkPolicyManager;
-import android.net.NetworkTemplate;
-import android.net.StringNetworkSpecifier;
-import android.net.TelephonyNetworkSpecifier;
-import android.os.Handler;
-import android.provider.Settings;
-import android.telephony.TelephonyManager;
-import android.test.mock.MockContentResolver;
-import android.util.DataUnit;
-import android.util.RecurrenceRule;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.R;
-import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.LocalServices;
-import com.android.server.net.NetworkPolicyManagerInternal;
-import com.android.server.net.NetworkStatsManagerInternal;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.time.Clock;
-import java.time.Instant;
-import java.time.Period;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.time.temporal.ChronoUnit;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class MultipathPolicyTrackerTest {
- private static final Network TEST_NETWORK = new Network(123);
- private static final int POLICY_SNOOZED = -100;
-
- @Mock private Context mContext;
- @Mock private Resources mResources;
- @Mock private Handler mHandler;
- @Mock private MultipathPolicyTracker.Dependencies mDeps;
- @Mock private Clock mClock;
- @Mock private ConnectivityManager mCM;
- @Mock private NetworkPolicyManager mNPM;
- @Mock private NetworkStatsManager mStatsManager;
- @Mock private NetworkPolicyManagerInternal mNPMI;
- @Mock private NetworkStatsManagerInternal mNetworkStatsManagerInternal;
- @Mock private TelephonyManager mTelephonyManager;
- private MockContentResolver mContentResolver;
-
- private ArgumentCaptor<BroadcastReceiver> mConfigChangeReceiverCaptor;
-
- private MultipathPolicyTracker mTracker;
-
- private Clock mPreviousRecurrenceRuleClock;
- private boolean mRecurrenceRuleClockMocked;
-
- private <T> void mockService(String serviceName, Class<T> serviceClass, T service) {
- when(mContext.getSystemServiceName(serviceClass)).thenReturn(serviceName);
- when(mContext.getSystemService(serviceName)).thenReturn(service);
- }
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- mPreviousRecurrenceRuleClock = RecurrenceRule.sClock;
- RecurrenceRule.sClock = mClock;
- mRecurrenceRuleClockMocked = true;
-
- mConfigChangeReceiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class);
-
- when(mContext.getResources()).thenReturn(mResources);
- when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
- when(mContext.registerReceiverAsUser(mConfigChangeReceiverCaptor.capture(),
- any(), argThat(f -> f.hasAction(ACTION_CONFIGURATION_CHANGED)), any(), any()))
- .thenReturn(null);
-
- when(mDeps.getClock()).thenReturn(mClock);
-
- when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
-
- mContentResolver = Mockito.spy(new MockContentResolver(mContext));
- mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
- Settings.Global.clearProviderForTest();
- when(mContext.getContentResolver()).thenReturn(mContentResolver);
-
- mockService(Context.CONNECTIVITY_SERVICE, ConnectivityManager.class, mCM);
- mockService(Context.NETWORK_POLICY_SERVICE, NetworkPolicyManager.class, mNPM);
- mockService(Context.NETWORK_STATS_SERVICE, NetworkStatsManager.class, mStatsManager);
- mockService(Context.TELEPHONY_SERVICE, TelephonyManager.class, mTelephonyManager);
-
- LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
- LocalServices.addService(NetworkPolicyManagerInternal.class, mNPMI);
-
- LocalServices.removeServiceForTest(NetworkStatsManagerInternal.class);
- LocalServices.addService(NetworkStatsManagerInternal.class, mNetworkStatsManagerInternal);
-
- mTracker = new MultipathPolicyTracker(mContext, mHandler, mDeps);
- }
-
- @After
- public void tearDown() {
- // Avoid setting static clock to null (which should normally not be the case)
- // if MockitoAnnotations.initMocks threw an exception
- if (mRecurrenceRuleClockMocked) {
- RecurrenceRule.sClock = mPreviousRecurrenceRuleClock;
- }
- mRecurrenceRuleClockMocked = false;
- }
-
- private void setDefaultQuotaGlobalSetting(long setting) {
- Settings.Global.putInt(mContentResolver, NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES,
- (int) setting);
- }
-
- private void testGetMultipathPreference(
- long usedBytesToday, long subscriptionQuota, long policyWarning, long policyLimit,
- long defaultGlobalSetting, long defaultResSetting, boolean roaming) {
-
- // TODO: tests should not use ZoneId.systemDefault() once code handles TZ correctly.
- final ZonedDateTime now = ZonedDateTime.ofInstant(
- Instant.parse("2017-04-02T10:11:12Z"), ZoneId.systemDefault());
- final ZonedDateTime startOfDay = now.truncatedTo(ChronoUnit.DAYS);
- when(mClock.millis()).thenReturn(now.toInstant().toEpochMilli());
- when(mClock.instant()).thenReturn(now.toInstant());
- when(mClock.getZone()).thenReturn(ZoneId.systemDefault());
-
- // Setup plan quota
- when(mNPMI.getSubscriptionOpportunisticQuota(TEST_NETWORK, QUOTA_TYPE_MULTIPATH))
- .thenReturn(subscriptionQuota);
-
- // Setup user policy warning / limit
- if (policyWarning != WARNING_DISABLED || policyLimit != LIMIT_DISABLED) {
- final Instant recurrenceStart = Instant.parse("2017-04-01T00:00:00Z");
- final RecurrenceRule recurrenceRule = new RecurrenceRule(
- ZonedDateTime.ofInstant(
- recurrenceStart,
- ZoneId.systemDefault()),
- null /* end */,
- Period.ofMonths(1));
- final boolean snoozeWarning = policyWarning == POLICY_SNOOZED;
- final boolean snoozeLimit = policyLimit == POLICY_SNOOZED;
- when(mNPM.getNetworkPolicies()).thenReturn(new NetworkPolicy[] {
- new NetworkPolicy(
- NetworkTemplate.buildTemplateMobileWildcard(),
- recurrenceRule,
- snoozeWarning ? 0 : policyWarning,
- snoozeLimit ? 0 : policyLimit,
- snoozeWarning ? recurrenceStart.toEpochMilli() + 1 : SNOOZE_NEVER,
- snoozeLimit ? recurrenceStart.toEpochMilli() + 1 : SNOOZE_NEVER,
- SNOOZE_NEVER,
- true /* metered */,
- false /* inferred */)
- });
- } else {
- when(mNPM.getNetworkPolicies()).thenReturn(new NetworkPolicy[0]);
- }
-
- // Setup default quota in settings and resources
- if (defaultGlobalSetting > 0) {
- setDefaultQuotaGlobalSetting(defaultGlobalSetting);
- }
- when(mResources.getInteger(R.integer.config_networkDefaultDailyMultipathQuotaBytes))
- .thenReturn((int) defaultResSetting);
-
- when(mNetworkStatsManagerInternal.getNetworkTotalBytes(
- any(),
- eq(startOfDay.toInstant().toEpochMilli()),
- eq(now.toInstant().toEpochMilli()))).thenReturn(usedBytesToday);
-
- ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallback =
- ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
- mTracker.start();
- verify(mCM).registerNetworkCallback(any(), networkCallback.capture(), any());
-
- // Simulate callback after capability changes
- NetworkCapabilities capabilities = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addTransportType(TRANSPORT_CELLULAR)
- .setNetworkSpecifier(new StringNetworkSpecifier("234"));
- if (!roaming) {
- capabilities.addCapability(NET_CAPABILITY_NOT_ROAMING);
- }
- networkCallback.getValue().onCapabilitiesChanged(
- TEST_NETWORK,
- capabilities);
-
- // make sure it also works with the new introduced TelephonyNetworkSpecifier
- capabilities = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addTransportType(TRANSPORT_CELLULAR)
- .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
- .setSubscriptionId(234).build());
- if (!roaming) {
- capabilities.addCapability(NET_CAPABILITY_NOT_ROAMING);
- }
- networkCallback.getValue().onCapabilitiesChanged(
- TEST_NETWORK,
- capabilities);
- }
-
- @Test
- public void testGetMultipathPreference_SubscriptionQuota() {
- testGetMultipathPreference(
- DataUnit.MEGABYTES.toBytes(2) /* usedBytesToday */,
- DataUnit.MEGABYTES.toBytes(14) /* subscriptionQuota */,
- DataUnit.MEGABYTES.toBytes(100) /* policyWarning */,
- LIMIT_DISABLED,
- DataUnit.MEGABYTES.toBytes(12) /* defaultGlobalSetting */,
- 2_500_000 /* defaultResSetting */,
- false /* roaming */);
-
- verify(mStatsManager, times(1)).registerUsageCallback(
- any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(12)), any(), any());
- }
-
- @Test
- public void testGetMultipathPreference_UserWarningQuota() {
- testGetMultipathPreference(
- DataUnit.MEGABYTES.toBytes(7) /* usedBytesToday */,
- OPPORTUNISTIC_QUOTA_UNKNOWN,
- // 29 days from Apr. 2nd to May 1st
- DataUnit.MEGABYTES.toBytes(15 * 29 * 20) /* policyWarning */,
- LIMIT_DISABLED,
- DataUnit.MEGABYTES.toBytes(12) /* defaultGlobalSetting */,
- 2_500_000 /* defaultResSetting */,
- false /* roaming */);
-
- // Daily budget should be 15MB (5% of daily quota), 7MB used today: callback set for 8MB
- verify(mStatsManager, times(1)).registerUsageCallback(
- any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(8)), any(), any());
- }
-
- @Test
- public void testGetMultipathPreference_SnoozedWarningQuota() {
- testGetMultipathPreference(
- DataUnit.MEGABYTES.toBytes(7) /* usedBytesToday */,
- OPPORTUNISTIC_QUOTA_UNKNOWN,
- // 29 days from Apr. 2nd to May 1st
- POLICY_SNOOZED /* policyWarning */,
- DataUnit.MEGABYTES.toBytes(15 * 29 * 20) /* policyLimit */,
- DataUnit.MEGABYTES.toBytes(12) /* defaultGlobalSetting */,
- 2_500_000 /* defaultResSetting */,
- false /* roaming */);
-
- // Daily budget should be 15MB (5% of daily quota), 7MB used today: callback set for 8MB
- verify(mStatsManager, times(1)).registerUsageCallback(
- any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(8)), any(), any());
- }
-
- @Test
- public void testGetMultipathPreference_SnoozedBothQuota() {
- testGetMultipathPreference(
- DataUnit.MEGABYTES.toBytes(7) /* usedBytesToday */,
- OPPORTUNISTIC_QUOTA_UNKNOWN,
- // 29 days from Apr. 2nd to May 1st
- POLICY_SNOOZED /* policyWarning */,
- POLICY_SNOOZED /* policyLimit */,
- DataUnit.MEGABYTES.toBytes(12) /* defaultGlobalSetting */,
- 2_500_000 /* defaultResSetting */,
- false /* roaming */);
-
- // Default global setting should be used: 12 - 7 = 5
- verify(mStatsManager, times(1)).registerUsageCallback(
- any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(5)), any(), any());
- }
-
- @Test
- public void testGetMultipathPreference_SettingChanged() {
- testGetMultipathPreference(
- DataUnit.MEGABYTES.toBytes(2) /* usedBytesToday */,
- OPPORTUNISTIC_QUOTA_UNKNOWN,
- WARNING_DISABLED,
- LIMIT_DISABLED,
- -1 /* defaultGlobalSetting */,
- DataUnit.MEGABYTES.toBytes(10) /* defaultResSetting */,
- false /* roaming */);
-
- verify(mStatsManager, times(1)).registerUsageCallback(
- any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(8)), any(), any());
-
- // Update setting
- setDefaultQuotaGlobalSetting(DataUnit.MEGABYTES.toBytes(14));
- mTracker.mSettingsObserver.onChange(
- false, Settings.Global.getUriFor(NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES));
-
- // Callback must have been re-registered with new setting
- verify(mStatsManager, times(1)).unregisterUsageCallback(any());
- verify(mStatsManager, times(1)).registerUsageCallback(
- any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(12)), any(), any());
- }
-
- @Test
- public void testGetMultipathPreference_ResourceChanged() {
- testGetMultipathPreference(
- DataUnit.MEGABYTES.toBytes(2) /* usedBytesToday */,
- OPPORTUNISTIC_QUOTA_UNKNOWN,
- WARNING_DISABLED,
- LIMIT_DISABLED,
- -1 /* defaultGlobalSetting */,
- DataUnit.MEGABYTES.toBytes(14) /* defaultResSetting */,
- false /* roaming */);
-
- verify(mStatsManager, times(1)).registerUsageCallback(
- any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(12)), any(), any());
-
- when(mResources.getInteger(R.integer.config_networkDefaultDailyMultipathQuotaBytes))
- .thenReturn((int) DataUnit.MEGABYTES.toBytes(16));
-
- final BroadcastReceiver configChangeReceiver = mConfigChangeReceiverCaptor.getValue();
- assertNotNull(configChangeReceiver);
- configChangeReceiver.onReceive(mContext, new Intent());
-
- // Uses the new setting (16 - 2 = 14MB)
- verify(mStatsManager, times(1)).registerUsageCallback(
- any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(14)), any(), any());
- }
-}
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
deleted file mode 100644
index 5046b6586fb0..000000000000
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ /dev/null
@@ -1,506 +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.connectivity;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.net.ConnectivityManager;
-import android.net.IDnsResolver;
-import android.net.INetd;
-import android.net.InterfaceConfiguration;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.NetworkAgentConfig;
-import android.net.NetworkInfo;
-import android.os.Handler;
-import android.os.INetworkManagementService;
-import android.os.test.TestLooper;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.ConnectivityService;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class Nat464XlatTest {
-
- static final String BASE_IFACE = "test0";
- static final String STACKED_IFACE = "v4-test0";
- static final LinkAddress V6ADDR = new LinkAddress("2001:db8:1::f00/64");
- static final LinkAddress ADDR = new LinkAddress("192.0.2.5/29");
- static final String NAT64_PREFIX = "64:ff9b::/96";
- static final String OTHER_NAT64_PREFIX = "2001:db8:0:64::/96";
- static final int NETID = 42;
-
- @Mock ConnectivityService mConnectivity;
- @Mock IDnsResolver mDnsResolver;
- @Mock INetd mNetd;
- @Mock INetworkManagementService mNms;
- @Mock InterfaceConfiguration mConfig;
- @Mock NetworkAgentInfo mNai;
-
- TestLooper mLooper;
- Handler mHandler;
- NetworkAgentConfig mAgentConfig = new NetworkAgentConfig();
-
- Nat464Xlat makeNat464Xlat() {
- return new Nat464Xlat(mNai, mNetd, mDnsResolver, mNms) {
- @Override protected int getNetId() {
- return NETID;
- }
- };
- }
-
- private void markNetworkConnected() {
- mNai.networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
- }
-
- private void markNetworkDisconnected() {
- mNai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, "", "");
- }
-
- @Before
- public void setUp() throws Exception {
- mLooper = new TestLooper();
- mHandler = new Handler(mLooper.getLooper());
-
- MockitoAnnotations.initMocks(this);
-
- mNai.linkProperties = new LinkProperties();
- mNai.linkProperties.setInterfaceName(BASE_IFACE);
- mNai.networkInfo = new NetworkInfo(null);
- mNai.networkInfo.setType(ConnectivityManager.TYPE_WIFI);
- markNetworkConnected();
- when(mNai.connService()).thenReturn(mConnectivity);
- when(mNai.netAgentConfig()).thenReturn(mAgentConfig);
- when(mNai.handler()).thenReturn(mHandler);
-
- when(mNms.getInterfaceConfig(eq(STACKED_IFACE))).thenReturn(mConfig);
- when(mConfig.getLinkAddress()).thenReturn(ADDR);
- }
-
- private void assertRequiresClat(boolean expected, NetworkAgentInfo nai) {
- String msg = String.format("requiresClat expected %b for type=%d state=%s skip=%b "
- + "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(),
- nai.networkInfo.getDetailedState(),
- mAgentConfig.skip464xlat, nai.linkProperties.getNat64Prefix(),
- nai.linkProperties.getLinkAddresses());
- assertEquals(msg, expected, Nat464Xlat.requiresClat(nai));
- }
-
- private void assertShouldStartClat(boolean expected, NetworkAgentInfo nai) {
- String msg = String.format("shouldStartClat expected %b for type=%d state=%s skip=%b "
- + "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(),
- nai.networkInfo.getDetailedState(),
- mAgentConfig.skip464xlat, nai.linkProperties.getNat64Prefix(),
- nai.linkProperties.getLinkAddresses());
- assertEquals(msg, expected, Nat464Xlat.shouldStartClat(nai));
- }
-
- @Test
- public void testRequiresClat() throws Exception {
- final int[] supportedTypes = {
- ConnectivityManager.TYPE_MOBILE,
- ConnectivityManager.TYPE_WIFI,
- ConnectivityManager.TYPE_ETHERNET,
- };
-
- // NetworkInfo doesn't allow setting the State directly, but rather
- // requires setting DetailedState in order set State as a side-effect.
- final NetworkInfo.DetailedState[] supportedDetailedStates = {
- NetworkInfo.DetailedState.CONNECTED,
- NetworkInfo.DetailedState.SUSPENDED,
- };
-
- LinkProperties oldLp = new LinkProperties(mNai.linkProperties);
- for (int type : supportedTypes) {
- mNai.networkInfo.setType(type);
- for (NetworkInfo.DetailedState state : supportedDetailedStates) {
- mNai.networkInfo.setDetailedState(state, "reason", "extraInfo");
-
- mNai.linkProperties.setNat64Prefix(new IpPrefix(OTHER_NAT64_PREFIX));
- assertRequiresClat(false, mNai);
- assertShouldStartClat(false, mNai);
-
- mNai.linkProperties.addLinkAddress(new LinkAddress("fc00::1/64"));
- assertRequiresClat(false, mNai);
- assertShouldStartClat(false, mNai);
-
- mNai.linkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64"));
- assertRequiresClat(true, mNai);
- assertShouldStartClat(true, mNai);
-
- mAgentConfig.skip464xlat = true;
- assertRequiresClat(false, mNai);
- assertShouldStartClat(false, mNai);
-
- mAgentConfig.skip464xlat = false;
- assertRequiresClat(true, mNai);
- assertShouldStartClat(true, mNai);
-
- mNai.linkProperties.addLinkAddress(new LinkAddress("192.0.2.2/24"));
- assertRequiresClat(false, mNai);
- assertShouldStartClat(false, mNai);
-
- mNai.linkProperties.removeLinkAddress(new LinkAddress("192.0.2.2/24"));
- assertRequiresClat(true, mNai);
- assertShouldStartClat(true, mNai);
-
- mNai.linkProperties.setNat64Prefix(null);
- assertRequiresClat(true, mNai);
- assertShouldStartClat(false, mNai);
-
- mNai.linkProperties = new LinkProperties(oldLp);
- }
- }
- }
-
- private void makeClatUnnecessary(boolean dueToDisconnect) {
- if (dueToDisconnect) {
- markNetworkDisconnected();
- } else {
- mNai.linkProperties.addLinkAddress(ADDR);
- }
- }
-
- private void checkNormalStartAndStop(boolean dueToDisconnect) throws Exception {
- Nat464Xlat nat = makeNat464Xlat();
- ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
-
- mNai.linkProperties.addLinkAddress(V6ADDR);
-
- nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
-
- // Start clat.
- nat.start();
-
- verify(mNms).registerObserver(eq(nat));
- verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
-
- // Stacked interface up notification arrives.
- nat.interfaceLinkStateChanged(STACKED_IFACE, true);
- mLooper.dispatchNext();
-
- verify(mNms).getInterfaceConfig(eq(STACKED_IFACE));
- verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
- assertFalse(c.getValue().getStackedLinks().isEmpty());
- assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- assertRunning(nat);
-
- // Stop clat (Network disconnects, IPv4 addr appears, ...).
- makeClatUnnecessary(dueToDisconnect);
- nat.stop();
-
- verify(mNetd).clatdStop(eq(BASE_IFACE));
- verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
- verify(mNms).unregisterObserver(eq(nat));
- assertTrue(c.getValue().getStackedLinks().isEmpty());
- assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
- assertIdle(nat);
-
- // Stacked interface removed notification arrives and is ignored.
- nat.interfaceRemoved(STACKED_IFACE);
- mLooper.dispatchNext();
-
- verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
- }
-
- @Test
- public void testNormalStartAndStopDueToDisconnect() throws Exception {
- checkNormalStartAndStop(true);
- }
-
- @Test
- public void testNormalStartAndStopDueToIpv4Addr() throws Exception {
- checkNormalStartAndStop(false);
- }
-
- private void checkStartStopStart(boolean interfaceRemovedFirst) throws Exception {
- Nat464Xlat nat = makeNat464Xlat();
- ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
- InOrder inOrder = inOrder(mNetd, mConnectivity);
-
- mNai.linkProperties.addLinkAddress(V6ADDR);
-
- nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
-
- nat.start();
-
- inOrder.verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
-
- // Stacked interface up notification arrives.
- nat.interfaceLinkStateChanged(STACKED_IFACE, true);
- mLooper.dispatchNext();
-
- inOrder.verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
- assertFalse(c.getValue().getStackedLinks().isEmpty());
- assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- assertRunning(nat);
-
- // ConnectivityService stops clat (Network disconnects, IPv4 addr appears, ...).
- nat.stop();
-
- inOrder.verify(mNetd).clatdStop(eq(BASE_IFACE));
-
- inOrder.verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture());
- assertTrue(c.getValue().getStackedLinks().isEmpty());
- assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- assertIdle(nat);
-
- if (interfaceRemovedFirst) {
- // Stacked interface removed notification arrives and is ignored.
- nat.interfaceRemoved(STACKED_IFACE);
- mLooper.dispatchNext();
- nat.interfaceLinkStateChanged(STACKED_IFACE, false);
- mLooper.dispatchNext();
- }
-
- assertTrue(c.getValue().getStackedLinks().isEmpty());
- assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- assertIdle(nat);
- inOrder.verifyNoMoreInteractions();
-
- nat.start();
-
- inOrder.verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
-
- if (!interfaceRemovedFirst) {
- // Stacked interface removed notification arrives and is ignored.
- nat.interfaceRemoved(STACKED_IFACE);
- mLooper.dispatchNext();
- nat.interfaceLinkStateChanged(STACKED_IFACE, false);
- mLooper.dispatchNext();
- }
-
- // Stacked interface up notification arrives.
- nat.interfaceLinkStateChanged(STACKED_IFACE, true);
- mLooper.dispatchNext();
-
- inOrder.verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
- assertFalse(c.getValue().getStackedLinks().isEmpty());
- assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- assertRunning(nat);
-
- // ConnectivityService stops clat again.
- nat.stop();
-
- inOrder.verify(mNetd).clatdStop(eq(BASE_IFACE));
-
- inOrder.verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture());
- assertTrue(c.getValue().getStackedLinks().isEmpty());
- assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- assertIdle(nat);
-
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void testStartStopStart() throws Exception {
- checkStartStopStart(true);
- }
-
- @Test
- public void testStartStopStartBeforeInterfaceRemoved() throws Exception {
- checkStartStopStart(false);
- }
-
- @Test
- public void testClatdCrashWhileRunning() throws Exception {
- Nat464Xlat nat = makeNat464Xlat();
- ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
-
- nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
-
- nat.start();
-
- verify(mNms).registerObserver(eq(nat));
- verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
-
- // Stacked interface up notification arrives.
- nat.interfaceLinkStateChanged(STACKED_IFACE, true);
- mLooper.dispatchNext();
-
- verify(mNms).getInterfaceConfig(eq(STACKED_IFACE));
- verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture());
- assertFalse(c.getValue().getStackedLinks().isEmpty());
- assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- assertRunning(nat);
-
- // Stacked interface removed notification arrives (clatd crashed, ...).
- nat.interfaceRemoved(STACKED_IFACE);
- mLooper.dispatchNext();
-
- verify(mNetd).clatdStop(eq(BASE_IFACE));
- verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
- verify(mNms).unregisterObserver(eq(nat));
- verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
- assertTrue(c.getValue().getStackedLinks().isEmpty());
- assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- assertIdle(nat);
-
- // ConnectivityService stops clat: no-op.
- nat.stop();
-
- verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
- }
-
- private void checkStopBeforeClatdStarts(boolean dueToDisconnect) throws Exception {
- Nat464Xlat nat = makeNat464Xlat();
-
- mNai.linkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64"));
-
- nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
-
- nat.start();
-
- verify(mNms).registerObserver(eq(nat));
- verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
-
- // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
- makeClatUnnecessary(dueToDisconnect);
- nat.stop();
-
- verify(mNetd).clatdStop(eq(BASE_IFACE));
- verify(mNms).unregisterObserver(eq(nat));
- verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
- assertIdle(nat);
-
- // In-flight interface up notification arrives: no-op
- nat.interfaceLinkStateChanged(STACKED_IFACE, true);
- mLooper.dispatchNext();
-
- // Interface removed notification arrives after stopClatd() takes effect: no-op.
- nat.interfaceRemoved(STACKED_IFACE);
- mLooper.dispatchNext();
-
- assertIdle(nat);
-
- verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
- }
-
- @Test
- public void testStopDueToDisconnectBeforeClatdStarts() throws Exception {
- checkStopBeforeClatdStarts(true);
- }
-
- @Test
- public void testStopDueToIpv4AddrBeforeClatdStarts() throws Exception {
- checkStopBeforeClatdStarts(false);
- }
-
- private void checkStopAndClatdNeverStarts(boolean dueToDisconnect) throws Exception {
- Nat464Xlat nat = makeNat464Xlat();
-
- mNai.linkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64"));
-
- nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
-
- nat.start();
-
- verify(mNms).registerObserver(eq(nat));
- verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
-
- // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
- makeClatUnnecessary(dueToDisconnect);
- nat.stop();
-
- verify(mNetd).clatdStop(eq(BASE_IFACE));
- verify(mNms).unregisterObserver(eq(nat));
- verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
- assertIdle(nat);
-
- verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
- }
-
- @Test
- public void testStopDueToDisconnectAndClatdNeverStarts() throws Exception {
- checkStopAndClatdNeverStarts(true);
- }
-
- @Test
- public void testStopDueToIpv4AddressAndClatdNeverStarts() throws Exception {
- checkStopAndClatdNeverStarts(false);
- }
-
- @Test
- public void testNat64PrefixPreference() throws Exception {
- final IpPrefix prefixFromDns = new IpPrefix(NAT64_PREFIX);
- final IpPrefix prefixFromRa = new IpPrefix(OTHER_NAT64_PREFIX);
-
- Nat464Xlat nat = makeNat464Xlat();
-
- final LinkProperties emptyLp = new LinkProperties();
- LinkProperties fixedupLp;
-
- fixedupLp = new LinkProperties();
- nat.setNat64PrefixFromDns(prefixFromDns);
- nat.fixupLinkProperties(emptyLp, fixedupLp);
- assertEquals(prefixFromDns, fixedupLp.getNat64Prefix());
-
- fixedupLp = new LinkProperties();
- nat.setNat64PrefixFromRa(prefixFromRa);
- nat.fixupLinkProperties(emptyLp, fixedupLp);
- assertEquals(prefixFromRa, fixedupLp.getNat64Prefix());
-
- fixedupLp = new LinkProperties();
- nat.setNat64PrefixFromRa(null);
- nat.fixupLinkProperties(emptyLp, fixedupLp);
- assertEquals(prefixFromDns, fixedupLp.getNat64Prefix());
-
- fixedupLp = new LinkProperties();
- nat.setNat64PrefixFromRa(prefixFromRa);
- nat.fixupLinkProperties(emptyLp, fixedupLp);
- assertEquals(prefixFromRa, fixedupLp.getNat64Prefix());
-
- fixedupLp = new LinkProperties();
- nat.setNat64PrefixFromDns(null);
- nat.fixupLinkProperties(emptyLp, fixedupLp);
- assertEquals(prefixFromRa, fixedupLp.getNat64Prefix());
-
- fixedupLp = new LinkProperties();
- nat.setNat64PrefixFromRa(null);
- nat.fixupLinkProperties(emptyLp, fixedupLp);
- assertEquals(null, fixedupLp.getNat64Prefix());
- }
-
- static void assertIdle(Nat464Xlat nat) {
- assertTrue("Nat464Xlat was not IDLE", !nat.isStarted());
- }
-
- static void assertRunning(Nat464Xlat nat) {
- assertTrue("Nat464Xlat was not RUNNING", nat.isRunning());
- }
-}
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
deleted file mode 100644
index aef9386755d7..000000000000
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * Copyright (C) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO;
-import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME;
-
-import static com.android.testutils.MiscAssertsKt.assertStringContains;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.system.OsConstants;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Base64;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
-import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetdEventListenerServiceTest {
- private static final String EXAMPLE_IPV4 = "192.0.2.1";
- private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1";
-
- private static final byte[] MAC_ADDR =
- {(byte)0x84, (byte)0xc9, (byte)0xb2, (byte)0x6a, (byte)0xed, (byte)0x4b};
-
- NetdEventListenerService mService;
- ConnectivityManager mCm;
-
- @Before
- public void setUp() {
- NetworkCapabilities ncWifi = new NetworkCapabilities();
- NetworkCapabilities ncCell = new NetworkCapabilities();
- ncWifi.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- ncCell.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-
- mCm = mock(ConnectivityManager.class);
- when(mCm.getNetworkCapabilities(new Network(100))).thenReturn(ncWifi);
- when(mCm.getNetworkCapabilities(new Network(101))).thenReturn(ncCell);
-
- mService = new NetdEventListenerService(mCm);
- }
-
- @Test
- public void testWakeupEventLogging() throws Exception {
- final int BUFFER_LENGTH = NetdEventListenerService.WAKEUP_EVENT_BUFFER_LENGTH;
- final long now = System.currentTimeMillis();
- final String iface = "wlan0";
- final byte[] mac = MAC_ADDR;
- final String srcIp = "192.168.2.1";
- final String dstIp = "192.168.2.23";
- final String srcIp6 = "2001:db8:4:fd00:a585:13d1:6a23:4fb4";
- final String dstIp6 = "2001:db8:4006:807::200a";
- final int sport = 2356;
- final int dport = 13489;
-
- final int v4 = 0x800;
- final int v6 = 0x86dd;
- final int tcp = 6;
- final int udp = 17;
- final int icmp6 = 58;
-
- // Baseline without any event
- String[] baseline = listNetdEvent();
-
- int[] uids = {10001, 10002, 10004, 1000, 10052, 10023, 10002, 10123, 10004};
- wakeupEvent(iface, uids[0], v4, tcp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent(iface, uids[1], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent(iface, uids[2], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent(iface, uids[3], v4, icmp6, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent(iface, uids[4], v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent(iface, uids[5], v4, tcp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent(iface, uids[6], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent(iface, uids[7], v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent(iface, uids[8], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
-
- String[] events2 = remove(listNetdEvent(), baseline);
- int expectedLength2 = uids.length + 1; // +1 for the WakeupStats line
- assertEquals(expectedLength2, events2.length);
- assertStringContains(events2[0], "WakeupStats");
- assertStringContains(events2[0], "wlan0");
- assertStringContains(events2[0], "0x800");
- assertStringContains(events2[0], "0x86dd");
- for (int i = 0; i < uids.length; i++) {
- String got = events2[i+1];
- assertStringContains(got, "WakeupEvent");
- assertStringContains(got, "wlan0");
- assertStringContains(got, "uid: " + uids[i]);
- }
-
- int uid = 20000;
- for (int i = 0; i < BUFFER_LENGTH * 2; i++) {
- long ts = now + 10;
- wakeupEvent(iface, uid, 0x800, 6, mac, srcIp, dstIp, 23, 24, ts);
- }
-
- String[] events3 = remove(listNetdEvent(), baseline);
- int expectedLength3 = BUFFER_LENGTH + 1; // +1 for the WakeupStats line
- assertEquals(expectedLength3, events3.length);
- assertStringContains(events2[0], "WakeupStats");
- assertStringContains(events2[0], "wlan0");
- for (int i = 1; i < expectedLength3; i++) {
- String got = events3[i];
- assertStringContains(got, "WakeupEvent");
- assertStringContains(got, "wlan0");
- assertStringContains(got, "uid: " + uid);
- }
-
- uid = 45678;
- wakeupEvent(iface, uid, 0x800, 6, mac, srcIp, dstIp, 23, 24, now);
-
- String[] events4 = remove(listNetdEvent(), baseline);
- String lastEvent = events4[events4.length - 1];
- assertStringContains(lastEvent, "WakeupEvent");
- assertStringContains(lastEvent, "wlan0");
- assertStringContains(lastEvent, "uid: " + uid);
- }
-
- @Test
- public void testWakeupStatsLogging() throws Exception {
- final byte[] mac = MAC_ADDR;
- final String srcIp = "192.168.2.1";
- final String dstIp = "192.168.2.23";
- final String srcIp6 = "2401:fa00:4:fd00:a585:13d1:6a23:4fb4";
- final String dstIp6 = "2404:6800:4006:807::200a";
- final int sport = 2356;
- final int dport = 13489;
- final long now = 1001L;
-
- final int v4 = 0x800;
- final int v6 = 0x86dd;
- final int tcp = 6;
- final int udp = 17;
- final int icmp6 = 58;
-
- wakeupEvent("wlan0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent("rmnet0", 10123, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent("wlan0", 1000, v4, udp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent("rmnet0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent("wlan0", -1, v6, icmp6, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent("wlan0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent("rmnet0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent("wlan0", 10004, v4, udp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent("wlan0", 1000, v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent("wlan0", 0, v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent("wlan0", -1, v6, icmp6, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent("rmnet0", 10052, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent("wlan0", 0, v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent("rmnet0", 1000, v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent("wlan0", 1010, v4, udp, mac, srcIp, dstIp, sport, dport, now);
-
- String got = flushStatistics();
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 2",
- " network_id: 0",
- " time_ms: 0",
- " transports: 0",
- " wakeup_stats <",
- " application_wakeups: 3",
- " duration_sec: 0",
- " ethertype_counts <",
- " key: 2048",
- " value: 4",
- " >",
- " ethertype_counts <",
- " key: 34525",
- " value: 1",
- " >",
- " ip_next_header_counts <",
- " key: 6",
- " value: 5",
- " >",
- " l2_broadcast_count: 0",
- " l2_multicast_count: 0",
- " l2_unicast_count: 5",
- " no_uid_wakeups: 0",
- " non_application_wakeups: 0",
- " root_wakeups: 0",
- " system_wakeups: 2",
- " total_wakeups: 5",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 0",
- " transports: 0",
- " wakeup_stats <",
- " application_wakeups: 2",
- " duration_sec: 0",
- " ethertype_counts <",
- " key: 2048",
- " value: 5",
- " >",
- " ethertype_counts <",
- " key: 34525",
- " value: 5",
- " >",
- " ip_next_header_counts <",
- " key: 6",
- " value: 3",
- " >",
- " ip_next_header_counts <",
- " key: 17",
- " value: 5",
- " >",
- " ip_next_header_counts <",
- " key: 58",
- " value: 2",
- " >",
- " l2_broadcast_count: 0",
- " l2_multicast_count: 0",
- " l2_unicast_count: 10",
- " no_uid_wakeups: 2",
- " non_application_wakeups: 1",
- " root_wakeups: 2",
- " system_wakeups: 3",
- " total_wakeups: 10",
- " >",
- ">",
- "version: 2\n");
- assertEquals(want, got);
- }
-
- @Test
- public void testDnsLogging() throws Exception {
- asyncDump(100);
-
- dnsEvent(100, EVENT_GETADDRINFO, 0, 3456);
- dnsEvent(100, EVENT_GETADDRINFO, 0, 267);
- dnsEvent(100, EVENT_GETHOSTBYNAME, 22, 1230);
- dnsEvent(100, EVENT_GETADDRINFO, 3, 45);
- dnsEvent(100, EVENT_GETADDRINFO, 1, 2111);
- dnsEvent(100, EVENT_GETADDRINFO, 0, 450);
- dnsEvent(100, EVENT_GETHOSTBYNAME, 200, 638);
- dnsEvent(100, EVENT_GETHOSTBYNAME, 178, 1300);
- dnsEvent(101, EVENT_GETADDRINFO, 0, 56);
- dnsEvent(101, EVENT_GETADDRINFO, 0, 78);
- dnsEvent(101, EVENT_GETADDRINFO, 0, 14);
- dnsEvent(101, EVENT_GETHOSTBYNAME, 0, 56);
- dnsEvent(101, EVENT_GETADDRINFO, 0, 78);
- dnsEvent(101, EVENT_GETADDRINFO, 0, 14);
-
- String got = flushStatistics();
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 100",
- " time_ms: 0",
- " transports: 2",
- " dns_lookup_batch <",
- " event_types: 1",
- " event_types: 1",
- " event_types: 2",
- " event_types: 1",
- " event_types: 1",
- " event_types: 1",
- " event_types: 2",
- " event_types: 2",
- " getaddrinfo_error_count: 0",
- " getaddrinfo_query_count: 0",
- " gethostbyname_error_count: 0",
- " gethostbyname_query_count: 0",
- " latencies_ms: 3456",
- " latencies_ms: 267",
- " latencies_ms: 1230",
- " latencies_ms: 45",
- " latencies_ms: 2111",
- " latencies_ms: 450",
- " latencies_ms: 638",
- " latencies_ms: 1300",
- " return_codes: 0",
- " return_codes: 0",
- " return_codes: 22",
- " return_codes: 3",
- " return_codes: 1",
- " return_codes: 0",
- " return_codes: 200",
- " return_codes: 178",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 2",
- " network_id: 101",
- " time_ms: 0",
- " transports: 1",
- " dns_lookup_batch <",
- " event_types: 1",
- " event_types: 1",
- " event_types: 1",
- " event_types: 2",
- " event_types: 1",
- " event_types: 1",
- " getaddrinfo_error_count: 0",
- " getaddrinfo_query_count: 0",
- " gethostbyname_error_count: 0",
- " gethostbyname_query_count: 0",
- " latencies_ms: 56",
- " latencies_ms: 78",
- " latencies_ms: 14",
- " latencies_ms: 56",
- " latencies_ms: 78",
- " latencies_ms: 14",
- " return_codes: 0",
- " return_codes: 0",
- " return_codes: 0",
- " return_codes: 0",
- " return_codes: 0",
- " return_codes: 0",
- " >",
- ">",
- "version: 2\n");
- assertEquals(want, got);
- }
-
- @Test
- public void testConnectLogging() throws Exception {
- asyncDump(100);
-
- final int OK = 0;
- Thread[] logActions = {
- // ignored
- connectEventAction(100, OsConstants.EALREADY, 0, EXAMPLE_IPV4),
- connectEventAction(100, OsConstants.EALREADY, 0, EXAMPLE_IPV6),
- connectEventAction(100, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV4),
- connectEventAction(101, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6),
- connectEventAction(101, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6),
- // valid latencies
- connectEventAction(100, OK, 110, EXAMPLE_IPV4),
- connectEventAction(100, OK, 23, EXAMPLE_IPV4),
- connectEventAction(100, OK, 45, EXAMPLE_IPV4),
- connectEventAction(101, OK, 56, EXAMPLE_IPV4),
- connectEventAction(101, OK, 523, EXAMPLE_IPV6),
- connectEventAction(101, OK, 214, EXAMPLE_IPV6),
- connectEventAction(101, OK, 67, EXAMPLE_IPV6),
- // errors
- connectEventAction(100, OsConstants.EPERM, 0, EXAMPLE_IPV4),
- connectEventAction(101, OsConstants.EPERM, 0, EXAMPLE_IPV4),
- connectEventAction(100, OsConstants.EAGAIN, 0, EXAMPLE_IPV4),
- connectEventAction(100, OsConstants.EACCES, 0, EXAMPLE_IPV4),
- connectEventAction(101, OsConstants.EACCES, 0, EXAMPLE_IPV4),
- connectEventAction(101, OsConstants.EACCES, 0, EXAMPLE_IPV6),
- connectEventAction(100, OsConstants.EADDRINUSE, 0, EXAMPLE_IPV4),
- connectEventAction(101, OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV4),
- connectEventAction(100, OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV6),
- connectEventAction(100, OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV6),
- connectEventAction(101, OsConstants.ECONNREFUSED, 0, EXAMPLE_IPV4),
- };
-
- for (Thread t : logActions) {
- t.start();
- }
- for (Thread t : logActions) {
- t.join();
- }
-
- String got = flushStatistics();
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 100",
- " time_ms: 0",
- " transports: 2",
- " connect_statistics <",
- " connect_blocking_count: 3",
- " connect_count: 6",
- " errnos_counters <",
- " key: 1",
- " value: 1",
- " >",
- " errnos_counters <",
- " key: 11",
- " value: 1",
- " >",
- " errnos_counters <",
- " key: 13",
- " value: 1",
- " >",
- " errnos_counters <",
- " key: 98",
- " value: 1",
- " >",
- " errnos_counters <",
- " key: 110",
- " value: 2",
- " >",
- " ipv6_addr_count: 1",
- " latencies_ms: 23",
- " latencies_ms: 45",
- " latencies_ms: 110",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 2",
- " network_id: 101",
- " time_ms: 0",
- " transports: 1",
- " connect_statistics <",
- " connect_blocking_count: 4",
- " connect_count: 6",
- " errnos_counters <",
- " key: 1",
- " value: 1",
- " >",
- " errnos_counters <",
- " key: 13",
- " value: 2",
- " >",
- " errnos_counters <",
- " key: 110",
- " value: 1",
- " >",
- " errnos_counters <",
- " key: 111",
- " value: 1",
- " >",
- " ipv6_addr_count: 5",
- " latencies_ms: 56",
- " latencies_ms: 67",
- " latencies_ms: 214",
- " latencies_ms: 523",
- " >",
- ">",
- "version: 2\n");
- assertEquals(want, got);
- }
-
- Thread connectEventAction(int netId, int error, int latencyMs, String ipAddr) {
- return new Thread(() -> {
- try {
- mService.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
- } catch (Exception e) {
- fail(e.toString());
- }
- });
- }
-
- void dnsEvent(int netId, int type, int result, int latency) throws Exception {
- mService.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
- }
-
- void wakeupEvent(String iface, int uid, int ether, int ip, byte[] mac, String srcIp,
- String dstIp, int sport, int dport, long now) throws Exception {
- String prefix = NetdEventListenerService.WAKEUP_EVENT_IFACE_PREFIX + iface;
- mService.onWakeupEvent(prefix, uid, ether, ip, mac, srcIp, dstIp, sport, dport, now);
- }
-
- void asyncDump(long durationMs) throws Exception {
- final long stop = System.currentTimeMillis() + durationMs;
- final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
- new Thread(() -> {
- while (System.currentTimeMillis() < stop) {
- mService.list(pw);
- }
- }).start();
- }
-
- // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
- String flushStatistics() throws Exception {
- IpConnectivityMetrics metricsService =
- new IpConnectivityMetrics(mock(Context.class), (ctx) -> 2000);
- metricsService.mNetdListener = mService;
-
- StringWriter buffer = new StringWriter();
- PrintWriter writer = new PrintWriter(buffer);
- metricsService.impl.dump(null, writer, new String[]{"flush"});
- byte[] bytes = Base64.decode(buffer.toString(), Base64.DEFAULT);
- IpConnectivityLog log = IpConnectivityLog.parseFrom(bytes);
- for (IpConnectivityEvent ev : log.events) {
- if (ev.getConnectStatistics() == null) {
- continue;
- }
- // Sort repeated fields of connect() events arriving in non-deterministic order.
- Arrays.sort(ev.getConnectStatistics().latenciesMs);
- Arrays.sort(ev.getConnectStatistics().errnosCounters,
- Comparator.comparingInt((p) -> p.key));
- }
- return log.toString();
- }
-
- String[] listNetdEvent() throws Exception {
- StringWriter buffer = new StringWriter();
- PrintWriter writer = new PrintWriter(buffer);
- mService.list(writer);
- return buffer.toString().split("\\n");
- }
-
- static <T> T[] remove(T[] array, T[] filtered) {
- List<T> c = Arrays.asList(filtered);
- int next = 0;
- for (int i = 0; i < array.length; i++) {
- if (c.contains(array[i])) {
- continue;
- }
- array[next++] = array[i];
- }
- return Arrays.copyOf(array, next);
- }
-}
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
deleted file mode 100644
index 47db5d431671..000000000000
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.*;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.telephony.TelephonyManager;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.R;
-import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkNotificationManagerTest {
-
- static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
- static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
- static final NetworkCapabilities VPN_CAPABILITIES = new NetworkCapabilities();
- static {
- CELL_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
- CELL_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
-
- WIFI_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- WIFI_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
-
- // Set the underyling network to wifi.
- VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
- VPN_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
- VPN_CAPABILITIES.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
- }
-
- @Mock Context mCtx;
- @Mock Resources mResources;
- @Mock PackageManager mPm;
- @Mock TelephonyManager mTelephonyManager;
- @Mock NotificationManager mNotificationManager;
- @Mock NetworkAgentInfo mWifiNai;
- @Mock NetworkAgentInfo mCellNai;
- @Mock NetworkAgentInfo mVpnNai;
- @Mock NetworkInfo mNetworkInfo;
- ArgumentCaptor<Notification> mCaptor;
-
- NetworkNotificationManager mManager;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mCaptor = ArgumentCaptor.forClass(Notification.class);
- mWifiNai.networkCapabilities = WIFI_CAPABILITIES;
- mWifiNai.networkInfo = mNetworkInfo;
- mCellNai.networkCapabilities = CELL_CAPABILITIES;
- mCellNai.networkInfo = mNetworkInfo;
- mVpnNai.networkCapabilities = VPN_CAPABILITIES;
- mVpnNai.networkInfo = mNetworkInfo;
- doReturn(true).when(mVpnNai).isVPN();
- when(mCtx.getResources()).thenReturn(mResources);
- when(mCtx.getPackageManager()).thenReturn(mPm);
- when(mCtx.getApplicationInfo()).thenReturn(new ApplicationInfo());
- when(mNetworkInfo.getExtraInfo()).thenReturn("extra");
- when(mResources.getColor(anyInt(), any())).thenReturn(0xFF607D8B);
-
- mManager = new NetworkNotificationManager(mCtx, mTelephonyManager, mNotificationManager);
- }
-
- private void verifyTitleByNetwork(final int id, final NetworkAgentInfo nai, final int title) {
- final String tag = NetworkNotificationManager.tagFor(id);
- mManager.showNotification(id, PRIVATE_DNS_BROKEN, nai, null, null, true);
- verify(mNotificationManager, times(1))
- .notifyAsUser(eq(tag), eq(PRIVATE_DNS_BROKEN.eventId), any(), any());
- final int transportType = NetworkNotificationManager.approximateTransportType(nai);
- if (transportType == NetworkCapabilities.TRANSPORT_WIFI) {
- verify(mResources, times(1)).getString(title, eq(any()));
- } else {
- verify(mResources, times(1)).getString(title);
- }
- verify(mResources, times(1)).getString(R.string.private_dns_broken_detailed);
- }
-
- @Test
- public void testTitleOfPrivateDnsBroken() {
- // Test the title of mobile data.
- verifyTitleByNetwork(100, mCellNai, R.string.mobile_no_internet);
- reset(mResources);
-
- // Test the title of wifi.
- verifyTitleByNetwork(101, mWifiNai, R.string.wifi_no_internet);
- reset(mResources);
-
- // Test the title of other networks.
- verifyTitleByNetwork(102, mVpnNai, R.string.other_networks_no_internet);
- reset(mResources);
- }
-
- @Test
- public void testNotificationsShownAndCleared() {
- final int NETWORK_ID_BASE = 100;
- List<NotificationType> types = Arrays.asList(NotificationType.values());
- List<Integer> ids = new ArrayList<>(types.size());
- for (int i = 0; i < types.size(); i++) {
- ids.add(NETWORK_ID_BASE + i);
- }
- Collections.shuffle(ids);
- Collections.shuffle(types);
-
- for (int i = 0; i < ids.size(); i++) {
- mManager.showNotification(ids.get(i), types.get(i), mWifiNai, mCellNai, null, false);
- }
-
- List<Integer> idsToClear = new ArrayList<>(ids);
- Collections.shuffle(idsToClear);
- for (int i = 0; i < ids.size(); i++) {
- mManager.clearNotification(idsToClear.get(i));
- }
-
- for (int i = 0; i < ids.size(); i++) {
- final int id = ids.get(i);
- final int eventId = types.get(i).eventId;
- final String tag = NetworkNotificationManager.tagFor(id);
- verify(mNotificationManager, times(1)).notifyAsUser(eq(tag), eq(eventId), any(), any());
- verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(eventId), any());
- }
- }
-
- @Test
- public void testNoInternetNotificationsNotShownForCellular() {
- mManager.showNotification(100, NO_INTERNET, mCellNai, mWifiNai, null, false);
- mManager.showNotification(101, LOST_INTERNET, mCellNai, mWifiNai, null, false);
-
- verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
-
- mManager.showNotification(102, NO_INTERNET, mWifiNai, mCellNai, null, false);
-
- final int eventId = NO_INTERNET.eventId;
- final String tag = NetworkNotificationManager.tagFor(102);
- verify(mNotificationManager, times(1)).notifyAsUser(eq(tag), eq(eventId), any(), any());
- }
-
- @Test
- public void testNotificationsNotShownIfNoInternetCapability() {
- mWifiNai.networkCapabilities = new NetworkCapabilities();
- mWifiNai.networkCapabilities .addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- mManager.showNotification(102, NO_INTERNET, mWifiNai, mCellNai, null, false);
- mManager.showNotification(103, LOST_INTERNET, mWifiNai, mCellNai, null, false);
- mManager.showNotification(104, NETWORK_SWITCH, mWifiNai, mCellNai, null, false);
-
- verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
- }
-
- @Test
- public void testDuplicatedNotificationsNoInternetThenSignIn() {
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
-
- // Show first NO_INTERNET
- mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1))
- .notifyAsUser(eq(tag), eq(NO_INTERNET.eventId), any(), any());
-
- // Captive portal detection triggers SIGN_IN a bit later, clearing the previous NO_INTERNET
- mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1))
- .cancelAsUser(eq(tag), eq(NO_INTERNET.eventId), any());
- verify(mNotificationManager, times(1))
- .notifyAsUser(eq(tag), eq(SIGN_IN.eventId), any(), any());
-
- // Network disconnects
- mManager.clearNotification(id);
- verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(SIGN_IN.eventId), any());
- }
-
- @Test
- public void testDuplicatedNotificationsSignInThenNoInternet() {
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
-
- // Show first SIGN_IN
- mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1))
- .notifyAsUser(eq(tag), eq(SIGN_IN.eventId), any(), any());
- reset(mNotificationManager);
-
- // NO_INTERNET arrives after, but is ignored.
- mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, never()).cancelAsUser(any(), anyInt(), any());
- verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
-
- // Network disconnects
- mManager.clearNotification(id);
- verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(SIGN_IN.eventId), any());
- }
-
- @Test
- public void testClearNotificationByType() {
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
-
- // clearNotification(int id, NotificationType notifyType) will check if given type is equal
- // to previous type or not. If they are equal then clear the notification; if they are not
- // equal then return.
- mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1))
- .notifyAsUser(eq(tag), eq(NO_INTERNET.eventId), any(), any());
-
- // Previous notification is NO_INTERNET and given type is NO_INTERNET too. The notification
- // should be cleared.
- mManager.clearNotification(id, NO_INTERNET);
- verify(mNotificationManager, times(1))
- .cancelAsUser(eq(tag), eq(NO_INTERNET.eventId), any());
-
- // SIGN_IN is popped-up.
- mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1))
- .notifyAsUser(eq(tag), eq(SIGN_IN.eventId), any(), any());
-
- // The notification type is not matching previous one, PARTIAL_CONNECTIVITY won't be
- // cleared.
- mManager.clearNotification(id, PARTIAL_CONNECTIVITY);
- verify(mNotificationManager, never())
- .cancelAsUser(eq(tag), eq(PARTIAL_CONNECTIVITY.eventId), any());
- }
-}
diff --git a/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt b/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt
deleted file mode 100644
index 86c91165f61b..000000000000
--- a/tests/net/java/com/android/server/connectivity/NetworkRankerTest.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity
-
-import android.net.NetworkRequest
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.mock
-import kotlin.test.assertEquals
-import kotlin.test.assertNull
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class NetworkRankerTest {
- private val ranker = NetworkRanker()
-
- private fun makeNai(satisfy: Boolean, score: Int) = mock(NetworkAgentInfo::class.java).also {
- doReturn(satisfy).`when`(it).satisfies(any())
- doReturn(score).`when`(it).currentScore
- }
-
- @Test
- fun testGetBestNetwork() {
- val scores = listOf(20, 50, 90, 60, 23, 68)
- val nais = scores.map { makeNai(true, it) }
- val bestNetwork = nais[2] // The one with the top score
- val someRequest = mock(NetworkRequest::class.java)
- assertEquals(bestNetwork, ranker.getBestNetwork(someRequest, nais))
- }
-
- @Test
- fun testIgnoreNonSatisfying() {
- val nais = listOf(makeNai(true, 20), makeNai(true, 50), makeNai(false, 90),
- makeNai(false, 60), makeNai(true, 23), makeNai(false, 68))
- val bestNetwork = nais[1] // Top score that's satisfying
- val someRequest = mock(NetworkRequest::class.java)
- assertEquals(bestNetwork, ranker.getBestNetwork(someRequest, nais))
- }
-
- @Test
- fun testNoMatch() {
- val nais = listOf(makeNai(false, 20), makeNai(false, 50), makeNai(false, 90))
- val someRequest = mock(NetworkRequest::class.java)
- assertNull(ranker.getBestNetwork(someRequest, nais))
- }
-
- @Test
- fun testEmpty() {
- val someRequest = mock(NetworkRequest::class.java)
- assertNull(ranker.getBestNetwork(someRequest, emptyList()))
- }
-
- // Make sure the ranker is "stable" (as in stable sort), that is, it always returns the FIRST
- // network satisfying the request if multiple of them have the same score.
- @Test
- fun testStable() {
- val nais1 = listOf(makeNai(true, 30), makeNai(true, 30), makeNai(true, 30),
- makeNai(true, 30), makeNai(true, 30), makeNai(true, 30))
- val someRequest = mock(NetworkRequest::class.java)
- assertEquals(nais1[0], ranker.getBestNetwork(someRequest, nais1))
-
- val nais2 = listOf(makeNai(true, 30), makeNai(true, 50), makeNai(true, 20),
- makeNai(true, 50), makeNai(true, 50), makeNai(true, 40))
- assertEquals(nais2[1], ranker.getBestNetwork(someRequest, nais2))
- }
-}
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
deleted file mode 100644
index 39f849c340f7..000000000000
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ /dev/null
@@ -1,758 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.connectivity;
-
-import static android.Manifest.permission.CHANGE_NETWORK_STATE;
-import static android.Manifest.permission.CHANGE_WIFI_STATE;
-import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
-import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
-import static android.Manifest.permission.INTERNET;
-import static android.Manifest.permission.NETWORK_STACK;
-import static android.Manifest.permission.UPDATE_DEVICE_STATS;
-import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_OEM;
-import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT;
-import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
-import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
-import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_REQUIRED;
-import static android.content.pm.PackageManager.GET_PERMISSIONS;
-import static android.content.pm.PackageManager.MATCH_ANY_USER;
-import static android.os.Process.SYSTEM_UID;
-
-import static com.android.server.connectivity.PermissionMonitor.NETWORK;
-import static com.android.server.connectivity.PermissionMonitor.SYSTEM;
-
-import static junit.framework.Assert.fail;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.AdditionalMatchers.aryEq;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
-import android.content.pm.UserInfo;
-import android.net.INetd;
-import android.net.UidRange;
-import android.os.Build;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.SparseIntArray;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.LocalServices;
-import com.android.server.pm.PackageList;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
-
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class PermissionMonitorTest {
- private static final int MOCK_USER1 = 0;
- private static final int MOCK_USER2 = 1;
- private static final int MOCK_UID1 = 10001;
- private static final int MOCK_UID2 = 10086;
- private static final int SYSTEM_UID1 = 1000;
- private static final int SYSTEM_UID2 = 1008;
- private static final int VPN_UID = 10002;
- private static final String REAL_SYSTEM_PACKAGE_NAME = "android";
- private static final String MOCK_PACKAGE1 = "appName1";
- private static final String MOCK_PACKAGE2 = "appName2";
- private static final String SYSTEM_PACKAGE1 = "sysName1";
- private static final String SYSTEM_PACKAGE2 = "sysName2";
- private static final String PARTITION_SYSTEM = "system";
- private static final String PARTITION_OEM = "oem";
- private static final String PARTITION_PRODUCT = "product";
- private static final String PARTITION_VENDOR = "vendor";
- private static final int VERSION_P = Build.VERSION_CODES.P;
- private static final int VERSION_Q = Build.VERSION_CODES.Q;
-
- @Mock private Context mContext;
- @Mock private PackageManager mPackageManager;
- @Mock private INetd mNetdService;
- @Mock private PackageManagerInternal mMockPmi;
- @Mock private UserManager mUserManager;
-
- private PackageManagerInternal.PackageListObserver mObserver;
- private PermissionMonitor mPermissionMonitor;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- when(mContext.getPackageManager()).thenReturn(mPackageManager);
- when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
- when(mUserManager.getUsers(eq(true))).thenReturn(
- Arrays.asList(new UserInfo[] {
- new UserInfo(MOCK_USER1, "", 0),
- new UserInfo(MOCK_USER2, "", 0),
- }));
-
- mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService));
-
- LocalServices.removeServiceForTest(PackageManagerInternal.class);
- LocalServices.addService(PackageManagerInternal.class, mMockPmi);
- when(mMockPmi.getPackageList(any())).thenReturn(new PackageList(new ArrayList<String>(),
- /* observer */ null));
- when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
- mPermissionMonitor.startMonitoring();
-
- final ArgumentCaptor<PackageManagerInternal.PackageListObserver> observerCaptor =
- ArgumentCaptor.forClass(PackageManagerInternal.PackageListObserver.class);
- verify(mMockPmi).getPackageList(observerCaptor.capture());
- mObserver = observerCaptor.getValue();
- }
-
- private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
- String... permissions) {
- final PackageInfo packageInfo =
- packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, permissions, partition);
- packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
- packageInfo.applicationInfo.uid = uid;
- return mPermissionMonitor.hasRestrictedNetworkPermission(packageInfo);
- }
-
- private static PackageInfo systemPackageInfoWithPermissions(String... permissions) {
- return packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM);
- }
-
- private static PackageInfo vendorPackageInfoWithPermissions(String... permissions) {
- return packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_VENDOR);
- }
-
- private static PackageInfo packageInfoWithPermissions(int permissionsFlags,
- String[] permissions, String partition) {
- int[] requestedPermissionsFlags = new int[permissions.length];
- for (int i = 0; i < permissions.length; i++) {
- requestedPermissionsFlags[i] = permissionsFlags;
- }
- final PackageInfo packageInfo = new PackageInfo();
- packageInfo.requestedPermissions = permissions;
- packageInfo.applicationInfo = new ApplicationInfo();
- packageInfo.requestedPermissionsFlags = requestedPermissionsFlags;
- int privateFlags = 0;
- switch (partition) {
- case PARTITION_OEM:
- privateFlags = PRIVATE_FLAG_OEM;
- break;
- case PARTITION_PRODUCT:
- privateFlags = PRIVATE_FLAG_PRODUCT;
- break;
- case PARTITION_VENDOR:
- privateFlags = PRIVATE_FLAG_VENDOR;
- break;
- }
- packageInfo.applicationInfo.privateFlags = privateFlags;
- return packageInfo;
- }
-
- private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid, int userId) {
- final PackageInfo pkgInfo;
- if (hasSystemPermission) {
- pkgInfo = systemPackageInfoWithPermissions(
- CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
- } else {
- pkgInfo = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, new String[] {}, "");
- }
- pkgInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
- return pkgInfo;
- }
-
- @Test
- public void testHasPermission() {
- PackageInfo app = systemPackageInfoWithPermissions();
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
-
- app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE, NETWORK_STACK);
- assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
-
- app = systemPackageInfoWithPermissions(
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL);
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
- assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
-
- app = packageInfoWithPermissions(REQUESTED_PERMISSION_REQUIRED, new String[] {
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL, NETWORK_STACK },
- PARTITION_SYSTEM);
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
-
- app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
- app.requestedPermissions = null;
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
-
- app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
- app.requestedPermissionsFlags = null;
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- }
-
- @Test
- public void testIsVendorApp() {
- PackageInfo app = systemPackageInfoWithPermissions();
- assertFalse(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED,
- new String[] {}, PARTITION_OEM);
- assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED,
- new String[] {}, PARTITION_PRODUCT);
- assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = vendorPackageInfoWithPermissions();
- assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
- }
-
- @Test
- public void testHasNetworkPermission() {
- PackageInfo app = systemPackageInfoWithPermissions();
- assertFalse(mPermissionMonitor.hasNetworkPermission(app));
- app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
- assertTrue(mPermissionMonitor.hasNetworkPermission(app));
- app = systemPackageInfoWithPermissions(NETWORK_STACK);
- assertFalse(mPermissionMonitor.hasNetworkPermission(app));
- app = systemPackageInfoWithPermissions(CONNECTIVITY_USE_RESTRICTED_NETWORKS);
- assertFalse(mPermissionMonitor.hasNetworkPermission(app));
- app = systemPackageInfoWithPermissions(CONNECTIVITY_INTERNAL);
- assertFalse(mPermissionMonitor.hasNetworkPermission(app));
- }
-
- @Test
- public void testHasRestrictedNetworkPermission() {
- assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, NETWORK_STACK));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
-
- assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
- }
-
- @Test
- public void testHasRestrictedNetworkPermissionSystemUid() {
- doReturn(VERSION_P).when(mPermissionMonitor).getDeviceFirstSdkInt();
- assertTrue(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_INTERNAL));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
-
- doReturn(VERSION_Q).when(mPermissionMonitor).getDeviceFirstSdkInt();
- assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_INTERNAL));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- }
-
- @Test
- public void testHasRestrictedNetworkPermissionVendorApp() {
- assertTrue(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, NETWORK_STACK));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
-
- assertFalse(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_NETWORK_STATE));
- }
-
- private void assertBackgroundPermission(boolean hasPermission, String name, int uid,
- String... permissions) throws Exception {
- when(mPackageManager.getPackageInfo(eq(name), anyInt()))
- .thenReturn(packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM));
- mPermissionMonitor.onPackageAdded(name, uid);
- assertEquals(hasPermission, mPermissionMonitor.hasUseBackgroundNetworksPermission(uid));
- }
-
- @Test
- public void testHasUseBackgroundNetworksPermission() throws Exception {
- assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(SYSTEM_UID));
- assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID);
- assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID, CONNECTIVITY_INTERNAL);
- assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, CHANGE_NETWORK_STATE);
- assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, NETWORK_STACK);
-
- assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID1));
- assertBackgroundPermission(false, MOCK_PACKAGE1, MOCK_UID1);
- assertBackgroundPermission(true, MOCK_PACKAGE1, MOCK_UID1,
- CONNECTIVITY_USE_RESTRICTED_NETWORKS);
-
- assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID2));
- assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2);
- assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2,
- CONNECTIVITY_INTERNAL);
- assertBackgroundPermission(true, MOCK_PACKAGE2, MOCK_UID2, NETWORK_STACK);
- }
-
- private class NetdMonitor {
- private final HashMap<Integer, Boolean> mApps = new HashMap<>();
-
- NetdMonitor(INetd mockNetd) throws Exception {
- // Add hook to verify and track result of setPermission.
- doAnswer((InvocationOnMock invocation) -> {
- final Object[] args = invocation.getArguments();
- final Boolean isSystem = args[0].equals(INetd.PERMISSION_SYSTEM);
- for (final int uid : (int[]) args[1]) {
- // TODO: Currently, permission monitor will send duplicate commands for each uid
- // corresponding to each user. Need to fix that and uncomment below test.
- // if (mApps.containsKey(uid) && mApps.get(uid) == isSystem) {
- // fail("uid " + uid + " is already set to " + isSystem);
- // }
- mApps.put(uid, isSystem);
- }
- return null;
- }).when(mockNetd).networkSetPermissionForUser(anyInt(), any(int[].class));
-
- // Add hook to verify and track result of clearPermission.
- doAnswer((InvocationOnMock invocation) -> {
- final Object[] args = invocation.getArguments();
- for (final int uid : (int[]) args[0]) {
- // TODO: Currently, permission monitor will send duplicate commands for each uid
- // corresponding to each user. Need to fix that and uncomment below test.
- // if (!mApps.containsKey(uid)) {
- // fail("uid " + uid + " does not exist.");
- // }
- mApps.remove(uid);
- }
- return null;
- }).when(mockNetd).networkClearPermissionForUser(any(int[].class));
- }
-
- public void expectPermission(Boolean permission, int[] users, int[] apps) {
- for (final int user : users) {
- for (final int app : apps) {
- final int uid = UserHandle.getUid(user, app);
- if (!mApps.containsKey(uid)) {
- fail("uid " + uid + " does not exist.");
- }
- if (mApps.get(uid) != permission) {
- fail("uid " + uid + " has wrong permission: " + permission);
- }
- }
- }
- }
-
- public void expectNoPermission(int[] users, int[] apps) {
- for (final int user : users) {
- for (final int app : apps) {
- final int uid = UserHandle.getUid(user, app);
- if (mApps.containsKey(uid)) {
- fail("uid " + uid + " has listed permissions, expected none.");
- }
- }
- }
- }
- }
-
- @Test
- public void testUserAndPackageAddRemove() throws Exception {
- final NetdMonitor mNetdMonitor = new NetdMonitor(mNetdService);
-
- // MOCK_UID1: MOCK_PACKAGE1 only has network permission.
- // SYSTEM_UID: SYSTEM_PACKAGE1 has system permission.
- // SYSTEM_UID: SYSTEM_PACKAGE2 only has network permission.
- doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(eq(SYSTEM), anyString());
- doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(SYSTEM_PACKAGE1));
- doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(SYSTEM_PACKAGE2));
- doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(MOCK_PACKAGE1));
-
- // Add SYSTEM_PACKAGE2, expect only have network permission.
- mPermissionMonitor.onUserAdded(MOCK_USER1);
- addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_UID);
- mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID});
-
- // Add SYSTEM_PACKAGE1, expect permission escalate.
- addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_UID);
- mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID});
-
- mPermissionMonitor.onUserAdded(MOCK_USER2);
- mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2},
- new int[]{SYSTEM_UID});
-
- addPackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2},
- new int[]{SYSTEM_UID});
- mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
- new int[]{MOCK_UID1});
-
- // Remove MOCK_UID1, expect no permission left for all user.
- mPermissionMonitor.onPackageRemoved(MOCK_UID1);
- removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_UID1);
- mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{MOCK_UID1});
-
- // Remove SYSTEM_PACKAGE1, expect permission downgrade.
- when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{SYSTEM_PACKAGE2});
- removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, SYSTEM_UID);
- mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
- new int[]{SYSTEM_UID});
-
- mPermissionMonitor.onUserRemoved(MOCK_USER1);
- mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER2}, new int[]{SYSTEM_UID});
-
- // Remove all packages, expect no permission left.
- when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{});
- removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_UID);
- mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
- new int[]{SYSTEM_UID, MOCK_UID1});
-
- // Remove last user, expect no redundant clearPermission is invoked.
- mPermissionMonitor.onUserRemoved(MOCK_USER2);
- mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
- new int[]{SYSTEM_UID, MOCK_UID1});
- }
-
- @Test
- public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdates() throws Exception {
- when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
- Arrays.asList(new PackageInfo[] {
- buildPackageInfo(/* SYSTEM */ true, SYSTEM_UID1, MOCK_USER1),
- buildPackageInfo(/* SYSTEM */ false, MOCK_UID1, MOCK_USER1),
- buildPackageInfo(/* SYSTEM */ false, MOCK_UID2, MOCK_USER1),
- buildPackageInfo(/* SYSTEM */ false, VPN_UID, MOCK_USER1)
- }));
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
- buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
- mPermissionMonitor.startMonitoring();
- // Every app on user 0 except MOCK_UID2 are under VPN.
- final Set<UidRange> vpnRange1 = new HashSet<>(Arrays.asList(new UidRange[] {
- new UidRange(0, MOCK_UID2 - 1),
- new UidRange(MOCK_UID2 + 1, UserHandle.PER_USER_RANGE - 1)}));
- final Set<UidRange> vpnRange2 = Collections.singleton(new UidRange(MOCK_UID2, MOCK_UID2));
-
- // When VPN is connected, expect a rule to be set up for user app MOCK_UID1
- mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange1, VPN_UID);
- verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
- aryEq(new int[] {MOCK_UID1}));
-
- reset(mNetdService);
-
- // When MOCK_UID1 package is uninstalled and reinstalled, expect Netd to be updated
- mPermissionMonitor.onPackageRemoved(UserHandle.getUid(MOCK_USER1, MOCK_UID1));
- verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
- mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1));
- verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
- aryEq(new int[] {MOCK_UID1}));
-
- reset(mNetdService);
-
- // During VPN uid update (vpnRange1 -> vpnRange2), ConnectivityService first deletes the
- // old UID rules then adds the new ones. Expect netd to be updated
- mPermissionMonitor.onVpnUidRangesRemoved("tun0", vpnRange1, VPN_UID);
- verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
- mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange2, VPN_UID);
- verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
- aryEq(new int[] {MOCK_UID2}));
-
- reset(mNetdService);
-
- // When VPN is disconnected, expect rules to be torn down
- mPermissionMonitor.onVpnUidRangesRemoved("tun0", vpnRange2, VPN_UID);
- verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID2}));
- assertNull(mPermissionMonitor.getVpnUidRanges("tun0"));
- }
-
- @Test
- public void testUidFilteringDuringPackageInstallAndUninstall() throws Exception {
- when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
- Arrays.asList(new PackageInfo[] {
- buildPackageInfo(true, SYSTEM_UID1, MOCK_USER1),
- buildPackageInfo(false, VPN_UID, MOCK_USER1)
- }));
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
- buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
-
- mPermissionMonitor.startMonitoring();
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(MOCK_USER1));
- mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange, VPN_UID);
-
- // Newly-installed package should have uid rules added
- mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1));
- verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
- aryEq(new int[] {MOCK_UID1}));
-
- // Removed package should have its uid rules removed
- mPermissionMonitor.onPackageRemoved(UserHandle.getUid(MOCK_USER1, MOCK_UID1));
- verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
- }
-
-
- // Normal package add/remove operations will trigger multiple intent for uids corresponding to
- // each user. To simulate generic package operations, the onPackageAdded/Removed will need to be
- // called multiple times with the uid corresponding to each user.
- private void addPackageForUsers(int[] users, String packageName, int uid) {
- for (final int user : users) {
- mPermissionMonitor.onPackageAdded(packageName, UserHandle.getUid(user, uid));
- }
- }
-
- private void removePackageForUsers(int[] users, int uid) {
- for (final int user : users) {
- mPermissionMonitor.onPackageRemoved(UserHandle.getUid(user, uid));
- }
- }
-
- private class NetdServiceMonitor {
- private final HashMap<Integer, Integer> mPermissions = new HashMap<>();
-
- NetdServiceMonitor(INetd mockNetdService) throws Exception {
- // Add hook to verify and track result of setPermission.
- doAnswer((InvocationOnMock invocation) -> {
- final Object[] args = invocation.getArguments();
- final int permission = (int) args[0];
- for (final int uid : (int[]) args[1]) {
- mPermissions.put(uid, permission);
- }
- return null;
- }).when(mockNetdService).trafficSetNetPermForUids(anyInt(), any(int[].class));
- }
-
- public void expectPermission(int permission, int[] apps) {
- for (final int app : apps) {
- if (!mPermissions.containsKey(app)) {
- fail("uid " + app + " does not exist.");
- }
- if (mPermissions.get(app) != permission) {
- fail("uid " + app + " has wrong permission: " + mPermissions.get(app));
- }
- }
- }
- }
-
- @Test
- public void testPackagePermissionUpdate() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
- // MOCK_UID1: MOCK_PACKAGE1 only has internet permission.
- // MOCK_UID2: MOCK_PACKAGE2 does not have any permission.
- // SYSTEM_UID1: SYSTEM_PACKAGE1 has internet permission and update device stats permission.
- // SYSTEM_UID2: SYSTEM_PACKAGE2 has only update device stats permission.
-
- SparseIntArray netdPermissionsAppIds = new SparseIntArray();
- netdPermissionsAppIds.put(MOCK_UID1, INetd.PERMISSION_INTERNET);
- netdPermissionsAppIds.put(MOCK_UID2, INetd.PERMISSION_NONE);
- netdPermissionsAppIds.put(SYSTEM_UID1, INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS);
- netdPermissionsAppIds.put(SYSTEM_UID2, INetd.PERMISSION_UPDATE_DEVICE_STATS);
-
- // Send the permission information to netd, expect permission updated.
- mPermissionMonitor.sendPackagePermissionsToNetd(netdPermissionsAppIds);
-
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET,
- new int[]{MOCK_UID1});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID2});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UPDATE_DEVICE_STATS,
- new int[]{SYSTEM_UID2});
-
- // Update permission of MOCK_UID1, expect new permission show up.
- mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1,
- INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
-
- // Change permissions of SYSTEM_UID2, expect new permission show up and old permission
- // revoked.
- mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2,
- INetd.PERMISSION_INTERNET);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{SYSTEM_UID2});
-
- // Revoke permission from SYSTEM_UID1, expect no permission stored.
- mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, INetd.PERMISSION_NONE);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{SYSTEM_UID1});
- }
-
- private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions)
- throws Exception {
- PackageInfo packageInfo = packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM);
- when(mPackageManager.getPackageInfo(eq(packageName), anyInt())).thenReturn(packageInfo);
- when(mPackageManager.getPackagesForUid(eq(uid))).thenReturn(new String[]{packageName});
- return packageInfo;
- }
-
- private PackageInfo addPackage(String packageName, int uid, String[] permissions)
- throws Exception {
- PackageInfo packageInfo = setPackagePermissions(packageName, uid, permissions);
- mObserver.onPackageAdded(packageName, uid);
- return packageInfo;
- }
-
- @Test
- public void testPackageInstall() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
-
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
-
- addPackage(MOCK_PACKAGE2, MOCK_UID2, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID2});
- }
-
- @Test
- public void testPackageInstallSharedUid() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
-
- PackageInfo packageInfo1 = addPackage(MOCK_PACKAGE1, MOCK_UID1,
- new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
-
- // Install another package with the same uid and no permissions should not cause the UID to
- // lose permissions.
- PackageInfo packageInfo2 = systemPackageInfoWithPermissions();
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
- when(mPackageManager.getPackagesForUid(MOCK_UID1))
- .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
- mObserver.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
- }
-
- @Test
- public void testPackageUninstallBasic() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
-
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
-
- when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
- mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
- }
-
- @Test
- public void testPackageRemoveThenAdd() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
-
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
-
- when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
- mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
-
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
- }
-
- @Test
- public void testPackageUpdate() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
-
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID1});
-
- // When updating a package, the broadcast receiver gets two broadcasts (a remove and then an
- // add), but the observer sees only one callback (an update).
- setPackagePermissions(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
- mObserver.onPackageChanged(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
- }
-
- @Test
- public void testPackageUninstallWithMultiplePackages() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
-
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
-
- // Mock another package with the same uid but different permissions.
- PackageInfo packageInfo2 = systemPackageInfoWithPermissions(INTERNET);
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
- when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{
- MOCK_PACKAGE2});
-
- mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
- }
-
- @Test
- public void testRealSystemPermission() throws Exception {
- // Use the real context as this test must ensure the *real* system package holds the
- // necessary permission.
- final Context realContext = InstrumentationRegistry.getContext();
- final PermissionMonitor monitor = new PermissionMonitor(realContext, mNetdService);
- final PackageManager manager = realContext.getPackageManager();
- final PackageInfo systemInfo = manager.getPackageInfo(REAL_SYSTEM_PACKAGE_NAME,
- GET_PERMISSIONS | MATCH_ANY_USER);
- assertTrue(monitor.hasPermission(systemInfo, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- }
-}
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
deleted file mode 100644
index 91ffa8e9d0d8..000000000000
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ /dev/null
@@ -1,1368 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.content.pm.UserInfo.FLAG_ADMIN;
-import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
-import static android.content.pm.UserInfo.FLAG_PRIMARY;
-import static android.content.pm.UserInfo.FLAG_RESTRICTED;
-import static android.net.ConnectivityManager.NetworkCallback;
-import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.AdditionalMatchers.aryEq;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.annotation.UserIdInt;
-import android.app.AppOpsManager;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.Ikev2VpnProfile;
-import android.net.InetAddresses;
-import android.net.IpPrefix;
-import android.net.IpSecManager;
-import android.net.IpSecTunnelInterfaceResponse;
-import android.net.LinkProperties;
-import android.net.LocalSocket;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo.DetailedState;
-import android.net.RouteInfo;
-import android.net.UidRange;
-import android.net.VpnManager;
-import android.net.VpnService;
-import android.net.ipsec.ike.IkeSessionCallback;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import android.os.Build.VERSION_CODES;
-import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.INetworkManagementService;
-import android.os.Looper;
-import android.os.Process;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.security.Credentials;
-import android.security.KeyStore;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.R;
-import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnProfile;
-import com.android.server.IpSecService;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Answers;
-import org.mockito.ArgumentCaptor;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Stream;
-
-/**
- * Tests for {@link Vpn}.
- *
- * Build, install and run with:
- * runtest frameworks-net -c com.android.server.connectivity.VpnTest
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class VpnTest {
- private static final String TAG = "VpnTest";
-
- // Mock users
- static final UserInfo primaryUser = new UserInfo(27, "Primary", FLAG_ADMIN | FLAG_PRIMARY);
- static final UserInfo secondaryUser = new UserInfo(15, "Secondary", FLAG_ADMIN);
- static final UserInfo restrictedProfileA = new UserInfo(40, "RestrictedA", FLAG_RESTRICTED);
- static final UserInfo restrictedProfileB = new UserInfo(42, "RestrictedB", FLAG_RESTRICTED);
- static final UserInfo managedProfileA = new UserInfo(45, "ManagedA", FLAG_MANAGED_PROFILE);
- static {
- restrictedProfileA.restrictedProfileParentId = primaryUser.id;
- restrictedProfileB.restrictedProfileParentId = secondaryUser.id;
- managedProfileA.profileGroupId = primaryUser.id;
- }
-
- static final String EGRESS_IFACE = "wlan0";
- static final String TEST_VPN_PKG = "com.testvpn.vpn";
- private static final String TEST_VPN_SERVER = "1.2.3.4";
- private static final String TEST_VPN_IDENTITY = "identity";
- private static final byte[] TEST_VPN_PSK = "psk".getBytes();
-
- private static final Network TEST_NETWORK = new Network(Integer.MAX_VALUE);
- private static final String TEST_IFACE_NAME = "TEST_IFACE";
- private static final int TEST_TUNNEL_RESOURCE_ID = 0x2345;
- private static final long TEST_TIMEOUT_MS = 500L;
-
- /**
- * Names and UIDs for some fake packages. Important points:
- * - UID is ordered increasing.
- * - One pair of packages have consecutive UIDs.
- */
- static final String[] PKGS = {"com.example", "org.example", "net.example", "web.vpn"};
- static final int[] PKG_UIDS = {66, 77, 78, 400};
-
- // Mock packages
- static final Map<String, Integer> mPackages = new ArrayMap<>();
- static {
- for (int i = 0; i < PKGS.length; i++) {
- mPackages.put(PKGS[i], PKG_UIDS[i]);
- }
- }
-
- @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
- @Mock private UserManager mUserManager;
- @Mock private PackageManager mPackageManager;
- @Mock private INetworkManagementService mNetService;
- @Mock private AppOpsManager mAppOps;
- @Mock private NotificationManager mNotificationManager;
- @Mock private Vpn.SystemServices mSystemServices;
- @Mock private Vpn.Ikev2SessionCreator mIkev2SessionCreator;
- @Mock private ConnectivityManager mConnectivityManager;
- @Mock private IpSecService mIpSecService;
- @Mock private KeyStore mKeyStore;
- private final VpnProfile mVpnProfile;
-
- private IpSecManager mIpSecManager;
-
- public VpnTest() throws Exception {
- // Build an actual VPN profile that is capable of being converted to and from an
- // Ikev2VpnProfile
- final Ikev2VpnProfile.Builder builder =
- new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY);
- builder.setAuthPsk(TEST_VPN_PSK);
- mVpnProfile = builder.build().toVpnProfile();
- }
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- mIpSecManager = new IpSecManager(mContext, mIpSecService);
-
- when(mContext.getPackageManager()).thenReturn(mPackageManager);
- setMockedPackages(mPackages);
-
- when(mContext.getPackageName()).thenReturn(TEST_VPN_PKG);
- when(mContext.getOpPackageName()).thenReturn(TEST_VPN_PKG);
- when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
- when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
- when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
- .thenReturn(mNotificationManager);
- when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
- .thenReturn(mConnectivityManager);
- when(mContext.getSystemService(eq(Context.IPSEC_SERVICE))).thenReturn(mIpSecManager);
- when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
- .thenReturn(Resources.getSystem().getString(
- R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS))
- .thenReturn(true);
- when(mSystemServices.isCallerSystem()).thenReturn(true);
-
- // Used by {@link Notification.Builder}
- ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
- when(mContext.getApplicationInfo()).thenReturn(applicationInfo);
- when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
- .thenReturn(applicationInfo);
-
- doNothing().when(mNetService).registerObserver(any());
-
- // Deny all appops by default.
- when(mAppOps.noteOpNoThrow(anyInt(), anyInt(), anyString()))
- .thenReturn(AppOpsManager.MODE_IGNORED);
-
- // Setup IpSecService
- final IpSecTunnelInterfaceResponse tunnelResp =
- new IpSecTunnelInterfaceResponse(
- IpSecManager.Status.OK, TEST_TUNNEL_RESOURCE_ID, TEST_IFACE_NAME);
- when(mIpSecService.createTunnelInterface(any(), any(), any(), any(), any()))
- .thenReturn(tunnelResp);
- }
-
- @Test
- public void testRestrictedProfilesAreAddedToVpn() {
- setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
-
- final Vpn vpn = createVpn(primaryUser.id);
- final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
- null, null);
-
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
- UidRange.createForUser(primaryUser.id),
- UidRange.createForUser(restrictedProfileA.id)
- })), ranges);
- }
-
- @Test
- public void testManagedProfilesAreNotAddedToVpn() {
- setMockedUsers(primaryUser, managedProfileA);
-
- final Vpn vpn = createVpn(primaryUser.id);
- final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
- null, null);
-
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
- UidRange.createForUser(primaryUser.id)
- })), ranges);
- }
-
- @Test
- public void testAddUserToVpnOnlyAddsOneUser() {
- setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
-
- final Vpn vpn = createVpn(primaryUser.id);
- final Set<UidRange> ranges = new ArraySet<>();
- vpn.addUserToRanges(ranges, primaryUser.id, null, null);
-
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
- UidRange.createForUser(primaryUser.id)
- })), ranges);
- }
-
- @Test
- public void testUidWhiteAndBlacklist() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
- final UidRange user = UidRange.createForUser(primaryUser.id);
- final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
-
- // Whitelist
- final Set<UidRange> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
- Arrays.asList(packages), null);
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
- new UidRange(user.start + PKG_UIDS[0], user.start + PKG_UIDS[0]),
- new UidRange(user.start + PKG_UIDS[1], user.start + PKG_UIDS[2])
- })), allow);
-
- // Blacklist
- final Set<UidRange> disallow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
- null, Arrays.asList(packages));
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
- new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
- /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
- new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
- })), disallow);
- }
-
- @Test
- public void testGetAlwaysAndOnGetLockDown() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
-
- // Default state.
- assertFalse(vpn.getAlwaysOn());
- assertFalse(vpn.getLockdown());
-
- // Set always-on without lockdown.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList(), mKeyStore));
- assertTrue(vpn.getAlwaysOn());
- assertFalse(vpn.getLockdown());
-
- // Set always-on with lockdown.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList(), mKeyStore));
- assertTrue(vpn.getAlwaysOn());
- assertTrue(vpn.getLockdown());
-
- // Remove always-on configuration.
- assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList(), mKeyStore));
- assertFalse(vpn.getAlwaysOn());
- assertFalse(vpn.getLockdown());
- }
-
- @Test
- public void testLockdownChangingPackage() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
- final UidRange user = UidRange.createForUser(primaryUser.id);
-
- // Default state.
- assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
-
- // Set always-on without lockdown.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null, mKeyStore));
- assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
-
- // Set always-on with lockdown.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null, mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
- new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
- }));
- assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
- assertUnblocked(vpn, user.start + PKG_UIDS[1]);
-
- // Switch to another app.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
- new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
- }));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
- new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
- }));
- assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
- assertUnblocked(vpn, user.start + PKG_UIDS[3]);
- }
-
- @Test
- public void testLockdownWhitelist() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
- final UidRange user = UidRange.createForUser(primaryUser.id);
-
- // Set always-on with lockdown and whitelist app PKGS[2] from lockdown.
- assertTrue(vpn.setAlwaysOnPackage(
- PKGS[1], true, Collections.singletonList(PKGS[2]), mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
- new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
- }));
- assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
- assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
-
- // Change whitelisted app to PKGS[3].
- assertTrue(vpn.setAlwaysOnPackage(
- PKGS[1], true, Collections.singletonList(PKGS[3]), mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
- new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
- }));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1),
- new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
- }));
- assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2]);
- assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[3]);
-
- // Change the VPN app.
- assertTrue(vpn.setAlwaysOnPackage(
- PKGS[0], true, Collections.singletonList(PKGS[3]), mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
- new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1)
- }));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
- new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1)
- }));
- assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
- assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
-
- // Remove the whitelist.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null, mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
- new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1),
- new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
- }));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(user.start + PKG_UIDS[0] + 1, user.stop),
- }));
- assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2],
- user.start + PKG_UIDS[3]);
- assertUnblocked(vpn, user.start + PKG_UIDS[0]);
-
- // Add the whitelist.
- assertTrue(vpn.setAlwaysOnPackage(
- PKGS[0], true, Collections.singletonList(PKGS[1]), mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
- new UidRange(user.start + PKG_UIDS[0] + 1, user.stop)
- }));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
- new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
- }));
- assertBlocked(vpn, user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
- assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]);
-
- // Try whitelisting a package with a comma, should be rejected.
- assertFalse(vpn.setAlwaysOnPackage(
- PKGS[0], true, Collections.singletonList("a.b,c.d"), mKeyStore));
-
- // Pass a non-existent packages in the whitelist, they (and only they) should be ignored.
- // Whitelisted package should change from PGKS[1] to PKGS[2].
- assertTrue(vpn.setAlwaysOnPackage(
- PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app"), mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[]{
- new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
- new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
- }));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[]{
- new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1),
- new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
- }));
- }
-
- @Test
- public void testLockdownAddingAProfile() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
- setMockedUsers(primaryUser);
-
- // Make a copy of the restricted profile, as we're going to mark it deleted halfway through.
- final UserInfo tempProfile = new UserInfo(restrictedProfileA.id, restrictedProfileA.name,
- restrictedProfileA.flags);
- tempProfile.restrictedProfileParentId = primaryUser.id;
-
- final UidRange user = UidRange.createForUser(primaryUser.id);
- final UidRange profile = UidRange.createForUser(tempProfile.id);
-
- // Set lockdown.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
- new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
- }));
-
- // Verify restricted user isn't affected at first.
- assertUnblocked(vpn, profile.start + PKG_UIDS[0]);
-
- // Add the restricted user.
- setMockedUsers(primaryUser, tempProfile);
- vpn.onUserAdded(tempProfile.id);
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
- new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
- }));
-
- // Remove the restricted user.
- tempProfile.partial = true;
- vpn.onUserRemoved(tempProfile.id);
- verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
- new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
- new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
- }));
- }
-
- @Test
- public void testLockdownRuleRepeatability() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
-
- // Given legacy lockdown is already enabled,
- vpn.setLockdown(true);
- verify(mNetService, times(1)).setAllowOnlyVpnForUids(
- eq(true), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
-
- // Enabling legacy lockdown twice should do nothing.
- vpn.setLockdown(true);
- verify(mNetService, times(1)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
-
- // And disabling should remove the rules exactly once.
- vpn.setLockdown(false);
- verify(mNetService, times(1)).setAllowOnlyVpnForUids(
- eq(false), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
-
- // Removing the lockdown again should have no effect.
- vpn.setLockdown(false);
- verify(mNetService, times(2)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
- }
-
- @Test
- public void testLockdownRuleReversibility() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
-
- final UidRange[] entireUser = {
- UidRange.createForUser(primaryUser.id)
- };
- final UidRange[] exceptPkg0 = {
- new UidRange(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
- new UidRange(entireUser[0].start + PKG_UIDS[0] + 1, entireUser[0].stop)
- };
-
- final InOrder order = inOrder(mNetService);
-
- // Given lockdown is enabled with no package (legacy VPN),
- vpn.setLockdown(true);
- order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
-
- // When a new VPN package is set the rules should change to cover that package.
- vpn.prepare(null, PKGS[0], VpnManager.TYPE_VPN_SERVICE);
- order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(entireUser));
- order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(exceptPkg0));
-
- // When that VPN package is unset, everything should be undone again in reverse.
- vpn.prepare(null, VpnConfig.LEGACY_VPN, VpnManager.TYPE_VPN_SERVICE);
- order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(exceptPkg0));
- order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
- }
-
- @Test
- public void testIsAlwaysOnPackageSupported() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
-
- ApplicationInfo appInfo = new ApplicationInfo();
- when(mPackageManager.getApplicationInfoAsUser(eq(PKGS[0]), anyInt(), eq(primaryUser.id)))
- .thenReturn(appInfo);
-
- ServiceInfo svcInfo = new ServiceInfo();
- ResolveInfo resInfo = new ResolveInfo();
- resInfo.serviceInfo = svcInfo;
- when(mPackageManager.queryIntentServicesAsUser(any(), eq(PackageManager.GET_META_DATA),
- eq(primaryUser.id)))
- .thenReturn(Collections.singletonList(resInfo));
-
- // null package name should return false
- assertFalse(vpn.isAlwaysOnPackageSupported(null, mKeyStore));
-
- // Pre-N apps are not supported
- appInfo.targetSdkVersion = VERSION_CODES.M;
- assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0], mKeyStore));
-
- // N+ apps are supported by default
- appInfo.targetSdkVersion = VERSION_CODES.N;
- assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0], mKeyStore));
-
- // Apps that opt out explicitly are not supported
- appInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
- Bundle metaData = new Bundle();
- metaData.putBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, false);
- svcInfo.metaData = metaData;
- assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0], mKeyStore));
- }
-
- @Test
- public void testNotificationShownForAlwaysOnApp() {
- final UserHandle userHandle = UserHandle.of(primaryUser.id);
- final Vpn vpn = createVpn(primaryUser.id);
- setMockedUsers(primaryUser);
-
- final InOrder order = inOrder(mNotificationManager);
-
- // Don't show a notification for regular disconnected states.
- vpn.updateState(DetailedState.DISCONNECTED, TAG);
- order.verify(mNotificationManager, atLeastOnce())
- .cancelAsUser(anyString(), anyInt(), eq(userHandle));
-
- // Start showing a notification for disconnected once always-on.
- vpn.setAlwaysOnPackage(PKGS[0], false, null, mKeyStore);
- order.verify(mNotificationManager)
- .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
-
- // Stop showing the notification once connected.
- vpn.updateState(DetailedState.CONNECTED, TAG);
- order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
-
- // Show the notification if we disconnect again.
- vpn.updateState(DetailedState.DISCONNECTED, TAG);
- order.verify(mNotificationManager)
- .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
-
- // Notification should be cleared after unsetting always-on package.
- vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
- order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
- }
-
- @Test
- public void testCapabilities() {
- final Vpn vpn = createVpn(primaryUser.id);
- setMockedUsers(primaryUser);
-
- final Network mobile = new Network(1);
- final Network wifi = new Network(2);
-
- final Map<Network, NetworkCapabilities> networks = new HashMap<>();
- networks.put(
- mobile,
- new NetworkCapabilities()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_CONGESTED)
- .setLinkDownstreamBandwidthKbps(10));
- networks.put(
- wifi,
- new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_METERED)
- .addCapability(NET_CAPABILITY_NOT_ROAMING)
- .addCapability(NET_CAPABILITY_NOT_CONGESTED)
- .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
- .setLinkUpstreamBandwidthKbps(20));
- setMockedNetworks(networks);
-
- final NetworkCapabilities caps = new NetworkCapabilities();
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager, new Network[] {}, caps, false /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager,
- new Network[] {mobile},
- caps,
- false /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager, new Network[] {wifi}, caps, false /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
- assertTrue(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager, new Network[] {wifi}, caps, true /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
- assertTrue(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager,
- new Network[] {mobile, wifi},
- caps,
- false /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
- assertTrue(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- }
-
- /**
- * The profile name should NOT change between releases for backwards compatibility
- *
- * <p>If this is changed between releases, the {@link Vpn#getVpnProfilePrivileged()} method MUST
- * be updated to ensure backward compatibility.
- */
- @Test
- public void testGetProfileNameForPackage() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
- setMockedUsers(primaryUser);
-
- final String expected = Credentials.PLATFORM_VPN + primaryUser.id + "_" + TEST_VPN_PKG;
- assertEquals(expected, vpn.getProfileNameForPackage(TEST_VPN_PKG));
- }
-
- private Vpn createVpnAndSetupUidChecks(int... grantedOps) throws Exception {
- return createVpnAndSetupUidChecks(primaryUser, grantedOps);
- }
-
- private Vpn createVpnAndSetupUidChecks(UserInfo user, int... grantedOps) throws Exception {
- final Vpn vpn = createVpn(user.id);
- setMockedUsers(user);
-
- when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt()))
- .thenReturn(Process.myUid());
-
- for (final int op : grantedOps) {
- when(mAppOps.noteOpNoThrow(op, Process.myUid(), TEST_VPN_PKG))
- .thenReturn(AppOpsManager.MODE_ALLOWED);
- }
-
- return vpn;
- }
-
- private void checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, int... checkedOps) {
- assertEquals(expectedResult, vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile, mKeyStore));
-
- // The profile should always be stored, whether or not consent has been previously granted.
- verify(mKeyStore)
- .put(
- eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)),
- eq(mVpnProfile.encode()),
- eq(Process.SYSTEM_UID),
- eq(0));
-
- for (final int checkedOp : checkedOps) {
- verify(mAppOps).noteOpNoThrow(checkedOp, Process.myUid(), TEST_VPN_PKG);
- }
- }
-
- @Test
- public void testProvisionVpnProfileNoIpsecTunnels() throws Exception {
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS))
- .thenReturn(false);
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
-
- try {
- checkProvisionVpnProfile(
- vpn, true /* expectedResult */, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
- fail("Expected exception due to missing feature");
- } catch (UnsupportedOperationException expected) {
- }
- }
-
- @Test
- public void testProvisionVpnProfilePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
-
- checkProvisionVpnProfile(
- vpn, true /* expectedResult */, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
- }
-
- @Test
- public void testProvisionVpnProfileNotPreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
-
- // Expect that both the ACTIVATE_VPN and ACTIVATE_PLATFORM_VPN were tried, but the caller
- // had neither.
- checkProvisionVpnProfile(vpn, false /* expectedResult */,
- AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, AppOpsManager.OP_ACTIVATE_VPN);
- }
-
- @Test
- public void testProvisionVpnProfileVpnServicePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_VPN);
-
- checkProvisionVpnProfile(vpn, true /* expectedResult */, AppOpsManager.OP_ACTIVATE_VPN);
- }
-
- @Test
- public void testProvisionVpnProfileTooLarge() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
-
- final VpnProfile bigProfile = new VpnProfile("");
- bigProfile.name = new String(new byte[Vpn.MAX_VPN_PROFILE_SIZE_BYTES + 1]);
-
- try {
- vpn.provisionVpnProfile(TEST_VPN_PKG, bigProfile, mKeyStore);
- fail("Expected IAE due to profile size");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testProvisionVpnProfileRestrictedUser() throws Exception {
- final Vpn vpn =
- createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
-
- try {
- vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile, mKeyStore);
- fail("Expected SecurityException due to restricted user");
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void testDeleteVpnProfile() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
-
- vpn.deleteVpnProfile(TEST_VPN_PKG, mKeyStore);
-
- verify(mKeyStore)
- .delete(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)), eq(Process.SYSTEM_UID));
- }
-
- @Test
- public void testDeleteVpnProfileRestrictedUser() throws Exception {
- final Vpn vpn =
- createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
-
- try {
- vpn.deleteVpnProfile(TEST_VPN_PKG, mKeyStore);
- fail("Expected SecurityException due to restricted user");
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void testGetVpnProfilePrivileged() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
-
- when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
- .thenReturn(new VpnProfile("").encode());
-
- vpn.getVpnProfilePrivileged(TEST_VPN_PKG, mKeyStore);
-
- verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
- }
-
- @Test
- public void testStartVpnProfile() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
-
- when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
- .thenReturn(mVpnProfile.encode());
-
- vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
-
- verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
- verify(mAppOps)
- .noteOpNoThrow(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
- eq(Process.myUid()),
- eq(TEST_VPN_PKG));
- }
-
- @Test
- public void testStartVpnProfileVpnServicePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_VPN);
-
- when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
- .thenReturn(mVpnProfile.encode());
-
- vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
-
- // Verify that the the ACTIVATE_VPN appop was checked, but no error was thrown.
- verify(mAppOps).noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Process.myUid(), TEST_VPN_PKG);
- }
-
- @Test
- public void testStartVpnProfileNotConsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
-
- try {
- vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
- fail("Expected failure due to no user consent");
- } catch (SecurityException expected) {
- }
-
- // Verify both appops were checked.
- verify(mAppOps)
- .noteOpNoThrow(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
- eq(Process.myUid()),
- eq(TEST_VPN_PKG));
- verify(mAppOps).noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Process.myUid(), TEST_VPN_PKG);
-
- // Keystore should never have been accessed.
- verify(mKeyStore, never()).get(any());
- }
-
- @Test
- public void testStartVpnProfileMissingProfile() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
-
- when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null);
-
- try {
- vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
- fail("Expected failure due to missing profile");
- } catch (IllegalArgumentException expected) {
- }
-
- verify(mKeyStore).get(vpn.getProfileNameForPackage(TEST_VPN_PKG));
- verify(mAppOps)
- .noteOpNoThrow(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
- eq(Process.myUid()),
- eq(TEST_VPN_PKG));
- }
-
- @Test
- public void testStartVpnProfileRestrictedUser() throws Exception {
- final Vpn vpn =
- createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
-
- try {
- vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
- fail("Expected SecurityException due to restricted user");
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void testStopVpnProfileRestrictedUser() throws Exception {
- final Vpn vpn =
- createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
-
- try {
- vpn.stopVpnProfile(TEST_VPN_PKG);
- fail("Expected SecurityException due to restricted user");
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void testSetPackageAuthorizationVpnService() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
-
- assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_SERVICE));
- verify(mAppOps)
- .setMode(
- eq(AppOpsManager.OP_ACTIVATE_VPN),
- eq(Process.myUid()),
- eq(TEST_VPN_PKG),
- eq(AppOpsManager.MODE_ALLOWED));
- }
-
- @Test
- public void testSetPackageAuthorizationPlatformVpn() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
-
- assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_PLATFORM));
- verify(mAppOps)
- .setMode(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
- eq(Process.myUid()),
- eq(TEST_VPN_PKG),
- eq(AppOpsManager.MODE_ALLOWED));
- }
-
- @Test
- public void testSetPackageAuthorizationRevokeAuthorization() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
-
- assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_NONE));
- verify(mAppOps)
- .setMode(
- eq(AppOpsManager.OP_ACTIVATE_VPN),
- eq(Process.myUid()),
- eq(TEST_VPN_PKG),
- eq(AppOpsManager.MODE_IGNORED));
- verify(mAppOps)
- .setMode(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
- eq(Process.myUid()),
- eq(TEST_VPN_PKG),
- eq(AppOpsManager.MODE_IGNORED));
- }
-
- private NetworkCallback triggerOnAvailableAndGetCallback() {
- final ArgumentCaptor<NetworkCallback> networkCallbackCaptor =
- ArgumentCaptor.forClass(NetworkCallback.class);
- verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS))
- .requestNetwork(any(), networkCallbackCaptor.capture());
-
- final NetworkCallback cb = networkCallbackCaptor.getValue();
- cb.onAvailable(TEST_NETWORK);
- return cb;
- }
-
- @Test
- public void testStartPlatformVpnAuthenticationFailed() throws Exception {
- final ArgumentCaptor<IkeSessionCallback> captor =
- ArgumentCaptor.forClass(IkeSessionCallback.class);
- final IkeProtocolException exception = mock(IkeProtocolException.class);
- when(exception.getErrorType())
- .thenReturn(IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED);
-
- final Vpn vpn = startLegacyVpn(mVpnProfile);
- final NetworkCallback cb = triggerOnAvailableAndGetCallback();
-
- // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
- // state
- verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS))
- .createIkeSession(any(), any(), any(), any(), captor.capture(), any());
- final IkeSessionCallback ikeCb = captor.getValue();
- ikeCb.onClosedExceptionally(exception);
-
- verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
- assertEquals(DetailedState.FAILED, vpn.getNetworkInfo().getDetailedState());
- }
-
- @Test
- public void testStartPlatformVpnIllegalArgumentExceptionInSetup() throws Exception {
- when(mIkev2SessionCreator.createIkeSession(any(), any(), any(), any(), any(), any()))
- .thenThrow(new IllegalArgumentException());
- final Vpn vpn = startLegacyVpn(mVpnProfile);
- final NetworkCallback cb = triggerOnAvailableAndGetCallback();
-
- // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
- // state
- verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
- assertEquals(DetailedState.FAILED, vpn.getNetworkInfo().getDetailedState());
- }
-
- private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) {
- assertTrue(vpn.setAlwaysOnPackage(TEST_VPN_PKG, lockdownEnabled, null, mKeyStore));
-
- verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
- verify(mAppOps).setMode(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN), eq(uid), eq(TEST_VPN_PKG),
- eq(AppOpsManager.MODE_ALLOWED));
-
- verify(mSystemServices).settingsSecurePutStringForUser(
- eq(Settings.Secure.ALWAYS_ON_VPN_APP), eq(TEST_VPN_PKG), eq(primaryUser.id));
- verify(mSystemServices).settingsSecurePutIntForUser(
- eq(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN), eq(lockdownEnabled ? 1 : 0),
- eq(primaryUser.id));
- verify(mSystemServices).settingsSecurePutStringForUser(
- eq(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST), eq(""), eq(primaryUser.id));
- }
-
- @Test
- public void testSetAndStartAlwaysOnVpn() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
- setMockedUsers(primaryUser);
-
- // UID checks must return a different UID; otherwise it'll be treated as already prepared.
- final int uid = Process.myUid() + 1;
- when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt()))
- .thenReturn(uid);
- when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
- .thenReturn(mVpnProfile.encode());
-
- setAndVerifyAlwaysOnPackage(vpn, uid, false);
- assertTrue(vpn.startAlwaysOnVpn(mKeyStore));
-
- // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
- // a subsequent CL.
- }
-
- public Vpn startLegacyVpn(final VpnProfile vpnProfile) throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
- setMockedUsers(primaryUser);
-
- // Dummy egress interface
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(EGRESS_IFACE);
-
- final RouteInfo defaultRoute = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
- InetAddresses.parseNumericAddress("192.0.2.0"), EGRESS_IFACE);
- lp.addRoute(defaultRoute);
-
- vpn.startLegacyVpn(vpnProfile, mKeyStore, lp);
- return vpn;
- }
-
- @Test
- public void testStartPlatformVpn() throws Exception {
- startLegacyVpn(mVpnProfile);
- // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
- // a subsequent patch.
- }
-
- @Test
- public void testStartRacoonNumericAddress() throws Exception {
- startRacoon("1.2.3.4", "1.2.3.4");
- }
-
- @Test
- public void testStartRacoonHostname() throws Exception {
- startRacoon("hostname", "5.6.7.8"); // address returned by deps.resolve
- }
-
- public void startRacoon(final String serverAddr, final String expectedAddr)
- throws Exception {
- final ConditionVariable legacyRunnerReady = new ConditionVariable();
- final VpnProfile profile = new VpnProfile("testProfile" /* key */);
- profile.type = VpnProfile.TYPE_L2TP_IPSEC_PSK;
- profile.name = "testProfileName";
- profile.username = "userName";
- profile.password = "thePassword";
- profile.server = serverAddr;
- profile.ipsecIdentifier = "id";
- profile.ipsecSecret = "secret";
- profile.l2tpSecret = "l2tpsecret";
- when(mConnectivityManager.getAllNetworks())
- .thenReturn(new Network[] { new Network(101) });
- when(mConnectivityManager.registerNetworkAgent(any(), any(), any(), any(),
- anyInt(), any(), anyInt())).thenAnswer(invocation -> {
- // The runner has registered an agent and is now ready.
- legacyRunnerReady.open();
- return new Network(102);
- });
- final Vpn vpn = startLegacyVpn(profile);
- final TestDeps deps = (TestDeps) vpn.mDeps;
- try {
- // udppsk and 1701 are the values for TYPE_L2TP_IPSEC_PSK
- assertArrayEquals(
- new String[] { EGRESS_IFACE, expectedAddr, "udppsk",
- profile.ipsecIdentifier, profile.ipsecSecret, "1701" },
- deps.racoonArgs.get(10, TimeUnit.SECONDS));
- // literal values are hardcoded in Vpn.java for mtpd args
- assertArrayEquals(
- new String[] { EGRESS_IFACE, "l2tp", expectedAddr, "1701", profile.l2tpSecret,
- "name", profile.username, "password", profile.password,
- "linkname", "vpn", "refuse-eap", "nodefaultroute", "usepeerdns",
- "idle", "1800", "mtu", "1400", "mru", "1400" },
- deps.mtpdArgs.get(10, TimeUnit.SECONDS));
- // Now wait for the runner to be ready before testing for the route.
- legacyRunnerReady.block(10_000);
- // In this test the expected address is always v4 so /32
- final RouteInfo expectedRoute = new RouteInfo(new IpPrefix(expectedAddr + "/32"),
- RouteInfo.RTN_THROW);
- assertTrue("Routes lack the expected throw route (" + expectedRoute + ") : "
- + vpn.mConfig.routes,
- vpn.mConfig.routes.contains(expectedRoute));
- } finally {
- // Now interrupt the thread, unblock the runner and clean up.
- vpn.mVpnRunner.exitVpnRunner();
- deps.getStateFile().delete(); // set to delete on exit, but this deletes it earlier
- vpn.mVpnRunner.join(10_000); // wait for up to 10s for the runner to die and cleanup
- }
- }
-
- private static final class TestDeps extends Vpn.Dependencies {
- public final CompletableFuture<String[]> racoonArgs = new CompletableFuture();
- public final CompletableFuture<String[]> mtpdArgs = new CompletableFuture();
- public final File mStateFile;
-
- private final HashMap<String, Boolean> mRunningServices = new HashMap<>();
-
- TestDeps() {
- try {
- mStateFile = File.createTempFile("vpnTest", ".tmp");
- mStateFile.deleteOnExit();
- } catch (final IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void startService(final String serviceName) {
- mRunningServices.put(serviceName, true);
- }
-
- @Override
- public void stopService(final String serviceName) {
- mRunningServices.put(serviceName, false);
- }
-
- @Override
- public boolean isServiceRunning(final String serviceName) {
- return mRunningServices.getOrDefault(serviceName, false);
- }
-
- @Override
- public boolean isServiceStopped(final String serviceName) {
- return !isServiceRunning(serviceName);
- }
-
- @Override
- public File getStateFile() {
- return mStateFile;
- }
-
- @Override
- public void sendArgumentsToDaemon(
- final String daemon, final LocalSocket socket, final String[] arguments,
- final Vpn.RetryScheduler interruptChecker) throws IOException {
- if ("racoon".equals(daemon)) {
- racoonArgs.complete(arguments);
- } else if ("mtpd".equals(daemon)) {
- writeStateFile(arguments);
- mtpdArgs.complete(arguments);
- } else {
- throw new UnsupportedOperationException("Unsupported daemon : " + daemon);
- }
- }
-
- private void writeStateFile(final String[] arguments) throws IOException {
- mStateFile.delete();
- mStateFile.createNewFile();
- mStateFile.deleteOnExit();
- final BufferedWriter writer = new BufferedWriter(
- new FileWriter(mStateFile, false /* append */));
- writer.write(EGRESS_IFACE);
- writer.write("\n");
- // addresses
- writer.write("10.0.0.1/24\n");
- // routes
- writer.write("192.168.6.0/24\n");
- // dns servers
- writer.write("192.168.6.1\n");
- // search domains
- writer.write("vpn.searchdomains.com\n");
- // endpoint - intentionally empty
- writer.write("\n");
- writer.flush();
- writer.close();
- }
-
- @Override
- @NonNull
- public InetAddress resolve(final String endpoint) {
- try {
- // If a numeric IP address, return it.
- return InetAddress.parseNumericAddress(endpoint);
- } catch (IllegalArgumentException e) {
- // Otherwise, return some token IP to test for.
- return InetAddress.parseNumericAddress("5.6.7.8");
- }
- }
-
- @Override
- public boolean checkInterfacePresent(final Vpn vpn, final String iface) {
- return true;
- }
- }
-
- /**
- * Mock some methods of vpn object.
- */
- private Vpn createVpn(@UserIdInt int userId) {
- return new Vpn(Looper.myLooper(), mContext, new TestDeps(), mNetService,
- userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
- }
-
- private static void assertBlocked(Vpn vpn, int... uids) {
- for (int uid : uids) {
- final boolean blocked = vpn.getLockdown() && vpn.isBlockingUid(uid);
- assertTrue("Uid " + uid + " should be blocked", blocked);
- }
- }
-
- private static void assertUnblocked(Vpn vpn, int... uids) {
- for (int uid : uids) {
- final boolean blocked = vpn.getLockdown() && vpn.isBlockingUid(uid);
- assertFalse("Uid " + uid + " should not be blocked", blocked);
- }
- }
-
- /**
- * Populate {@link #mUserManager} with a list of fake users.
- */
- private void setMockedUsers(UserInfo... users) {
- final Map<Integer, UserInfo> userMap = new ArrayMap<>();
- for (UserInfo user : users) {
- userMap.put(user.id, user);
- }
-
- /**
- * @see UserManagerService#getUsers(boolean)
- */
- doAnswer(invocation -> {
- final boolean excludeDying = (boolean) invocation.getArguments()[0];
- final ArrayList<UserInfo> result = new ArrayList<>(users.length);
- for (UserInfo ui : users) {
- if (!excludeDying || (ui.isEnabled() && !ui.partial)) {
- result.add(ui);
- }
- }
- return result;
- }).when(mUserManager).getUsers(anyBoolean());
-
- doAnswer(invocation -> {
- final int id = (int) invocation.getArguments()[0];
- return userMap.get(id);
- }).when(mUserManager).getUserInfo(anyInt());
-
- doAnswer(invocation -> {
- final int id = (int) invocation.getArguments()[0];
- return (userMap.get(id).flags & UserInfo.FLAG_ADMIN) != 0;
- }).when(mUserManager).canHaveRestrictedProfile(anyInt());
- }
-
- /**
- * Populate {@link #mPackageManager} with a fake packageName-to-UID mapping.
- */
- private void setMockedPackages(final Map<String, Integer> packages) {
- try {
- doAnswer(invocation -> {
- final String appName = (String) invocation.getArguments()[0];
- final int userId = (int) invocation.getArguments()[1];
- Integer appId = packages.get(appName);
- if (appId == null) throw new PackageManager.NameNotFoundException(appName);
- return UserHandle.getUid(userId, appId);
- }).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt());
- } catch (Exception e) {
- }
- }
-
- private void setMockedNetworks(final Map<Network, NetworkCapabilities> networks) {
- doAnswer(invocation -> {
- final Network network = (Network) invocation.getArguments()[0];
- return networks.get(network);
- }).when(mConnectivityManager).getNetworkCapabilities(any());
- }
-
- // Need multiple copies of this, but Java's Stream objects can't be reused or
- // duplicated.
- private Stream<String> publicIpV4Routes() {
- return Stream.of(
- "0.0.0.0/5", "8.0.0.0/7", "11.0.0.0/8", "12.0.0.0/6", "16.0.0.0/4",
- "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/3", "160.0.0.0/5", "168.0.0.0/6",
- "172.0.0.0/12", "172.32.0.0/11", "172.64.0.0/10", "172.128.0.0/9",
- "173.0.0.0/8", "174.0.0.0/7", "176.0.0.0/4", "192.0.0.0/9", "192.128.0.0/11",
- "192.160.0.0/13", "192.169.0.0/16", "192.170.0.0/15", "192.172.0.0/14",
- "192.176.0.0/12", "192.192.0.0/10", "193.0.0.0/8", "194.0.0.0/7",
- "196.0.0.0/6", "200.0.0.0/5", "208.0.0.0/4");
- }
-
- private Stream<String> publicIpV6Routes() {
- return Stream.of(
- "::/1", "8000::/2", "c000::/3", "e000::/4", "f000::/5", "f800::/6",
- "fe00::/8", "2605:ef80:e:af1d::/64");
- }
-}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java b/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
deleted file mode 100644
index 858358c74f80..000000000000
--- a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.when;
-
-import android.Manifest;
-import android.Manifest.permission;
-import android.app.AppOpsManager;
-import android.app.admin.DeviceAdminInfo;
-import android.app.admin.DevicePolicyManagerInternal;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.telephony.TelephonyManager;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.LocalServices;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkStatsAccessTest {
- private static final String TEST_PKG = "com.example.test";
- private static final int TEST_UID = 12345;
-
- @Mock private Context mContext;
- @Mock private DevicePolicyManagerInternal mDpmi;
- @Mock private TelephonyManager mTm;
- @Mock private AppOpsManager mAppOps;
-
- // Hold the real service so we can restore it when tearing down the test.
- private DevicePolicyManagerInternal mSystemDpmi;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- mSystemDpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
- LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
- LocalServices.addService(DevicePolicyManagerInternal.class, mDpmi);
-
- when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTm);
- when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOps);
- }
-
- @After
- public void tearDown() throws Exception {
- LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
- LocalServices.addService(DevicePolicyManagerInternal.class, mSystemDpmi);
- }
-
- @Test
- public void testCheckAccessLevel_hasCarrierPrivileges() throws Exception {
- setHasCarrierPrivileges(true);
- setIsDeviceOwner(false);
- setIsProfileOwner(false);
- setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
- setHasReadHistoryPermission(false);
- assertEquals(NetworkStatsAccess.Level.DEVICE,
- NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
- }
-
- @Test
- public void testCheckAccessLevel_isDeviceOwner() throws Exception {
- setHasCarrierPrivileges(false);
- setIsDeviceOwner(true);
- setIsProfileOwner(false);
- setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
- setHasReadHistoryPermission(false);
- assertEquals(NetworkStatsAccess.Level.DEVICE,
- NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
- }
-
- @Test
- public void testCheckAccessLevel_isProfileOwner() throws Exception {
- setHasCarrierPrivileges(false);
- setIsDeviceOwner(false);
- setIsProfileOwner(true);
- setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
- setHasReadHistoryPermission(false);
- assertEquals(NetworkStatsAccess.Level.USER,
- NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
- }
-
- @Test
- public void testCheckAccessLevel_hasAppOpsBitAllowed() throws Exception {
- setHasCarrierPrivileges(false);
- setIsDeviceOwner(false);
- setIsProfileOwner(true);
- setHasAppOpsPermission(AppOpsManager.MODE_ALLOWED, false);
- setHasReadHistoryPermission(false);
- assertEquals(NetworkStatsAccess.Level.DEVICESUMMARY,
- NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
- }
-
- @Test
- public void testCheckAccessLevel_hasAppOpsBitDefault_grantedPermission() throws Exception {
- setHasCarrierPrivileges(false);
- setIsDeviceOwner(false);
- setIsProfileOwner(true);
- setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, true);
- setHasReadHistoryPermission(false);
- assertEquals(NetworkStatsAccess.Level.DEVICESUMMARY,
- NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
- }
-
- @Test
- public void testCheckAccessLevel_hasReadHistoryPermission() throws Exception {
- setHasCarrierPrivileges(false);
- setIsDeviceOwner(false);
- setIsProfileOwner(true);
- setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
- setHasReadHistoryPermission(true);
- assertEquals(NetworkStatsAccess.Level.DEVICESUMMARY,
- NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
- }
-
- @Test
- public void testCheckAccessLevel_deniedAppOpsBit() throws Exception {
- setHasCarrierPrivileges(false);
- setIsDeviceOwner(false);
- setIsProfileOwner(false);
- setHasAppOpsPermission(AppOpsManager.MODE_ERRORED, true);
- setHasReadHistoryPermission(false);
- assertEquals(NetworkStatsAccess.Level.DEFAULT,
- NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
- }
-
- @Test
- public void testCheckAccessLevel_deniedAppOpsBit_deniedPermission() throws Exception {
- setHasCarrierPrivileges(false);
- setIsDeviceOwner(false);
- setIsProfileOwner(false);
- setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
- setHasReadHistoryPermission(false);
- assertEquals(NetworkStatsAccess.Level.DEFAULT,
- NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
- }
-
- private void setHasCarrierPrivileges(boolean hasPrivileges) {
- when(mTm.checkCarrierPrivilegesForPackageAnyPhone(TEST_PKG)).thenReturn(
- hasPrivileges ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
- : TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
- }
-
- private void setIsDeviceOwner(boolean isOwner) {
- when(mDpmi.isActiveAdminWithPolicy(TEST_UID, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER))
- .thenReturn(isOwner);
- }
-
- private void setIsProfileOwner(boolean isOwner) {
- when(mDpmi.isActiveAdminWithPolicy(TEST_UID, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER))
- .thenReturn(isOwner);
- }
-
- private void setHasAppOpsPermission(int appOpsMode, boolean hasPermission) {
- when(mAppOps.noteOp(AppOpsManager.OP_GET_USAGE_STATS, TEST_UID, TEST_PKG))
- .thenReturn(appOpsMode);
- when(mContext.checkCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS)).thenReturn(
- hasPermission ? PackageManager.PERMISSION_GRANTED
- : PackageManager.PERMISSION_DENIED);
- }
-
- private void setHasReadHistoryPermission(boolean hasPermission) {
- when(mContext.checkCallingOrSelfPermission(permission.READ_NETWORK_USAGE_HISTORY))
- .thenReturn(hasPermission ? PackageManager.PERMISSION_GRANTED
- : PackageManager.PERMISSION_DENIED);
- }
-}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java b/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
deleted file mode 100644
index 3aafe0b075f2..000000000000
--- a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.net;
-
-import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
-import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
-import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
-import static android.net.NetworkStats.METERED_ALL;
-import static android.net.NetworkStats.METERED_NO;
-import static android.net.NetworkStats.METERED_YES;
-import static android.net.NetworkStats.ROAMING_ALL;
-import static android.net.NetworkStats.ROAMING_NO;
-import static android.net.NetworkStats.ROAMING_YES;
-import static android.net.NetworkStats.SET_ALL;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.SET_FOREGROUND;
-import static android.net.NetworkStats.TAG_NONE;
-
-import static org.junit.Assert.assertEquals;
-
-import android.net.NetworkStats;
-
-import com.android.internal.net.VpnInfo;
-
-/** Superclass with utilities for NetworkStats(Service|Factory)Test */
-abstract class NetworkStatsBaseTest {
- static final String TEST_IFACE = "test0";
- static final String TEST_IFACE2 = "test1";
- static final String TUN_IFACE = "test_nss_tun0";
- static final String TUN_IFACE2 = "test_nss_tun1";
-
- static final int UID_RED = 1001;
- static final int UID_BLUE = 1002;
- static final int UID_GREEN = 1003;
- static final int UID_VPN = 1004;
-
- void assertValues(NetworkStats stats, String iface, int uid, long rxBytes,
- long rxPackets, long txBytes, long txPackets) {
- assertValues(
- stats, iface, uid, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
- rxBytes, rxPackets, txBytes, txPackets, 0);
- }
-
- void assertValues(NetworkStats stats, String iface, int uid, int set, int tag,
- int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
- long txBytes, long txPackets, long operations) {
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- final int[] sets;
- if (set == SET_ALL) {
- sets = new int[] {SET_ALL, SET_DEFAULT, SET_FOREGROUND};
- } else {
- sets = new int[] {set};
- }
-
- final int[] roamings;
- if (roaming == ROAMING_ALL) {
- roamings = new int[] {ROAMING_ALL, ROAMING_YES, ROAMING_NO};
- } else {
- roamings = new int[] {roaming};
- }
-
- final int[] meterings;
- if (metered == METERED_ALL) {
- meterings = new int[] {METERED_ALL, METERED_YES, METERED_NO};
- } else {
- meterings = new int[] {metered};
- }
-
- final int[] defaultNetworks;
- if (defaultNetwork == DEFAULT_NETWORK_ALL) {
- defaultNetworks =
- new int[] {DEFAULT_NETWORK_ALL, DEFAULT_NETWORK_YES, DEFAULT_NETWORK_NO};
- } else {
- defaultNetworks = new int[] {defaultNetwork};
- }
-
- for (int s : sets) {
- for (int r : roamings) {
- for (int m : meterings) {
- for (int d : defaultNetworks) {
- final int i = stats.findIndex(iface, uid, s, tag, m, r, d);
- if (i != -1) {
- entry.add(stats.getValues(i, null));
- }
- }
- }
- }
- }
-
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- assertEquals("unexpected txPackets", txPackets, entry.txPackets);
- assertEquals("unexpected operations", operations, entry.operations);
- }
-
- static VpnInfo createVpnInfo(String[] underlyingIfaces) {
- return createVpnInfo(TUN_IFACE, underlyingIfaces);
- }
-
- static VpnInfo createVpnInfo(String vpnIface, String[] underlyingIfaces) {
- VpnInfo info = new VpnInfo();
- info.ownerUid = UID_VPN;
- info.vpnIface = vpnIface;
- info.underlyingIfaces = underlyingIfaces;
- return info;
- }
-}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
deleted file mode 100644
index 551498f2c0cc..000000000000
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ /dev/null
@@ -1,591 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.NetworkStats.SET_ALL;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkStatsHistory.FIELD_ALL;
-import static android.net.NetworkTemplate.buildTemplateMobileAll;
-import static android.os.Process.myUid;
-import static android.text.format.DateUtils.HOUR_IN_MILLIS;
-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-
-import static com.android.server.net.NetworkStatsCollection.multiplySafe;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.NetworkIdentity;
-import android.net.NetworkStats;
-import android.net.NetworkStatsHistory;
-import android.net.NetworkTemplate;
-import android.os.Process;
-import android.os.UserHandle;
-import android.telephony.SubscriptionPlan;
-import android.telephony.TelephonyManager;
-import android.text.format.DateUtils;
-import android.util.RecurrenceRule;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.frameworks.tests.net.R;
-
-import libcore.io.IoUtils;
-import libcore.io.Streams;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.time.Clock;
-import java.time.Instant;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tests for {@link NetworkStatsCollection}.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkStatsCollectionTest {
-
- private static final String TEST_FILE = "test.bin";
- private static final String TEST_IMSI = "310260000000000";
-
- private static final long TIME_A = 1326088800000L; // UTC: Monday 9th January 2012 06:00:00 AM
- private static final long TIME_B = 1326110400000L; // UTC: Monday 9th January 2012 12:00:00 PM
- private static final long TIME_C = 1326132000000L; // UTC: Monday 9th January 2012 06:00:00 PM
-
- private static Clock sOriginalClock;
-
- @Before
- public void setUp() throws Exception {
- sOriginalClock = RecurrenceRule.sClock;
- // ignore any device overlay while testing
- NetworkTemplate.forceAllNetworkTypes();
- }
-
- @After
- public void tearDown() throws Exception {
- RecurrenceRule.sClock = sOriginalClock;
- NetworkTemplate.resetForceAllNetworkTypes();
- }
-
- private void setClock(Instant instant) {
- RecurrenceRule.sClock = Clock.fixed(instant, ZoneId.systemDefault());
- }
-
- @Test
- public void testReadLegacyNetwork() throws Exception {
- final File testFile =
- new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
- stageFile(R.raw.netstats_v1, testFile);
-
- final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
- collection.readLegacyNetwork(testFile);
-
- // verify that history read correctly
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 636016770L, 709306L, 88038768L, 518836L, NetworkStatsAccess.Level.DEVICE);
-
- // now export into a unified format
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- collection.write(new DataOutputStream(bos));
-
- // clear structure completely
- collection.reset();
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 0L, 0L, 0L, 0L, NetworkStatsAccess.Level.DEVICE);
-
- // and read back into structure, verifying that totals are same
- collection.read(new ByteArrayInputStream(bos.toByteArray()));
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 636016770L, 709306L, 88038768L, 518836L, NetworkStatsAccess.Level.DEVICE);
- }
-
- @Test
- public void testReadLegacyUid() throws Exception {
- final File testFile =
- new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
- stageFile(R.raw.netstats_uid_v4, testFile);
-
- final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
- collection.readLegacyUid(testFile, false);
-
- // verify that history read correctly
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 637076152L, 711413L, 88343717L, 521022L, NetworkStatsAccess.Level.DEVICE);
-
- // now export into a unified format
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- collection.write(new DataOutputStream(bos));
-
- // clear structure completely
- collection.reset();
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 0L, 0L, 0L, 0L, NetworkStatsAccess.Level.DEVICE);
-
- // and read back into structure, verifying that totals are same
- collection.read(new ByteArrayInputStream(bos.toByteArray()));
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 637076152L, 711413L, 88343717L, 521022L, NetworkStatsAccess.Level.DEVICE);
- }
-
- @Test
- public void testReadLegacyUidTags() throws Exception {
- final File testFile =
- new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
- stageFile(R.raw.netstats_uid_v4, testFile);
-
- final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
- collection.readLegacyUid(testFile, true);
-
- // verify that history read correctly
- assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
- 77017831L, 100995L, 35436758L, 92344L);
-
- // now export into a unified format
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- collection.write(new DataOutputStream(bos));
-
- // clear structure completely
- collection.reset();
- assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
- 0L, 0L, 0L, 0L);
-
- // and read back into structure, verifying that totals are same
- collection.read(new ByteArrayInputStream(bos.toByteArray()));
- assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
- 77017831L, 100995L, 35436758L, 92344L);
- }
-
- @Test
- public void testStartEndAtomicBuckets() throws Exception {
- final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS);
-
- // record empty data straddling between buckets
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- entry.rxBytes = 32;
- collection.recordData(null, UID_ALL, SET_DEFAULT, TAG_NONE, 30 * MINUTE_IN_MILLIS,
- 90 * MINUTE_IN_MILLIS, entry);
-
- // assert that we report boundary in atomic buckets
- assertEquals(0, collection.getStartMillis());
- assertEquals(2 * HOUR_IN_MILLIS, collection.getEndMillis());
- }
-
- @Test
- public void testAccessLevels() throws Exception {
- final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS);
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- final NetworkIdentitySet identSet = new NetworkIdentitySet();
- identSet.add(new NetworkIdentity(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- TEST_IMSI, null, false, true, true));
-
- int myUid = Process.myUid();
- int otherUidInSameUser = Process.myUid() + 1;
- int uidInDifferentUser = Process.myUid() + UserHandle.PER_USER_RANGE;
-
- // Record one entry for the current UID.
- entry.rxBytes = 32;
- collection.recordData(identSet, myUid, SET_DEFAULT, TAG_NONE, 0, 60 * MINUTE_IN_MILLIS,
- entry);
-
- // Record one entry for another UID in this user.
- entry.rxBytes = 64;
- collection.recordData(identSet, otherUidInSameUser, SET_DEFAULT, TAG_NONE, 0,
- 60 * MINUTE_IN_MILLIS, entry);
-
- // Record one entry for the system UID.
- entry.rxBytes = 128;
- collection.recordData(identSet, Process.SYSTEM_UID, SET_DEFAULT, TAG_NONE, 0,
- 60 * MINUTE_IN_MILLIS, entry);
-
- // Record one entry for a UID in a different user.
- entry.rxBytes = 256;
- collection.recordData(identSet, uidInDifferentUser, SET_DEFAULT, TAG_NONE, 0,
- 60 * MINUTE_IN_MILLIS, entry);
-
- // Verify the set of relevant UIDs for each access level.
- assertArrayEquals(new int[] { myUid },
- collection.getRelevantUids(NetworkStatsAccess.Level.DEFAULT));
- assertArrayEquals(new int[] { Process.SYSTEM_UID, myUid, otherUidInSameUser },
- collection.getRelevantUids(NetworkStatsAccess.Level.USER));
- assertArrayEquals(
- new int[] { Process.SYSTEM_UID, myUid, otherUidInSameUser, uidInDifferentUser },
- collection.getRelevantUids(NetworkStatsAccess.Level.DEVICE));
-
- // Verify security check in getHistory.
- assertNotNull(collection.getHistory(buildTemplateMobileAll(TEST_IMSI), null, myUid, SET_DEFAULT,
- TAG_NONE, 0, 0L, 0L, NetworkStatsAccess.Level.DEFAULT, myUid));
- try {
- collection.getHistory(buildTemplateMobileAll(TEST_IMSI), null, otherUidInSameUser,
- SET_DEFAULT, TAG_NONE, 0, 0L, 0L, NetworkStatsAccess.Level.DEFAULT, myUid);
- fail("Should have thrown SecurityException for accessing different UID");
- } catch (SecurityException e) {
- // expected
- }
-
- // Verify appropriate aggregation in getSummary.
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32, 0, 0, 0,
- NetworkStatsAccess.Level.DEFAULT);
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32 + 64 + 128, 0, 0, 0,
- NetworkStatsAccess.Level.USER);
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32 + 64 + 128 + 256, 0, 0,
- 0, NetworkStatsAccess.Level.DEVICE);
- }
-
- @Test
- public void testAugmentPlan() throws Exception {
- final File testFile =
- new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
- stageFile(R.raw.netstats_v1, testFile);
-
- final NetworkStatsCollection emptyCollection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
- final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
- collection.readLegacyNetwork(testFile);
-
- // We're in the future, but not that far off
- setClock(Instant.parse("2012-06-01T00:00:00.00Z"));
-
- // Test a bunch of plans that should result in no augmentation
- final List<SubscriptionPlan> plans = new ArrayList<>();
-
- // No plan
- plans.add(null);
- // No usage anchor
- plans.add(SubscriptionPlan.Builder
- .createRecurringMonthly(ZonedDateTime.parse("2011-01-14T00:00:00.00Z")).build());
- // Usage anchor far in past
- plans.add(SubscriptionPlan.Builder
- .createRecurringMonthly(ZonedDateTime.parse("2011-01-14T00:00:00.00Z"))
- .setDataUsage(1000L, TIME_A - DateUtils.YEAR_IN_MILLIS).build());
- // Usage anchor far in future
- plans.add(SubscriptionPlan.Builder
- .createRecurringMonthly(ZonedDateTime.parse("2011-01-14T00:00:00.00Z"))
- .setDataUsage(1000L, TIME_A + DateUtils.YEAR_IN_MILLIS).build());
- // Usage anchor near but outside cycle
- plans.add(SubscriptionPlan.Builder
- .createNonrecurring(ZonedDateTime.parse("2012-01-09T09:00:00.00Z"),
- ZonedDateTime.parse("2012-01-09T15:00:00.00Z"))
- .setDataUsage(1000L, TIME_C).build());
-
- for (SubscriptionPlan plan : plans) {
- int i;
- NetworkStatsHistory history;
-
- // Empty collection should be untouched
- history = getHistory(emptyCollection, plan, TIME_A, TIME_C);
- assertEquals(0L, history.getTotalBytes());
-
- // Normal collection should be untouched
- history = getHistory(collection, plan, TIME_A, TIME_C); i = 0;
- assertEntry(100647, 197, 23649, 185, history.getValues(i++, null));
- assertEntry(100647, 196, 23648, 185, history.getValues(i++, null));
- assertEntry(18323, 76, 15032, 76, history.getValues(i++, null));
- assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
- assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
- assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
- assertEntry(10747, 50, 16839, 55, history.getValues(i++, null));
- assertEntry(10747, 49, 16837, 54, history.getValues(i++, null));
- assertEntry(89191, 151, 18021, 140, history.getValues(i++, null));
- assertEntry(89190, 150, 18020, 139, history.getValues(i++, null));
- assertEntry(3821, 23, 4525, 26, history.getValues(i++, null));
- assertEntry(3820, 21, 4524, 26, history.getValues(i++, null));
- assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
- assertEntry(8289, 36, 6864, 39, history.getValues(i++, null));
- assertEntry(8289, 34, 6862, 37, history.getValues(i++, null));
- assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
- assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
- assertEntry(11378, 49, 9261, 50, history.getValues(i++, null));
- assertEntry(11377, 48, 9261, 48, history.getValues(i++, null));
- assertEntry(201766, 328, 41808, 291, history.getValues(i++, null));
- assertEntry(201764, 328, 41807, 290, history.getValues(i++, null));
- assertEntry(106106, 219, 39918, 202, history.getValues(i++, null));
- assertEntry(106105, 216, 39916, 200, history.getValues(i++, null));
- assertEquals(history.size(), i);
-
- // Slice from middle should be untouched
- history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
- TIME_B + HOUR_IN_MILLIS); i = 0;
- assertEntry(3821, 23, 4525, 26, history.getValues(i++, null));
- assertEntry(3820, 21, 4524, 26, history.getValues(i++, null));
- assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
- assertEquals(history.size(), i);
- }
-
- // Lower anchor in the middle of plan
- {
- int i;
- NetworkStatsHistory history;
-
- final SubscriptionPlan plan = SubscriptionPlan.Builder
- .createNonrecurring(ZonedDateTime.parse("2012-01-09T09:00:00.00Z"),
- ZonedDateTime.parse("2012-01-09T15:00:00.00Z"))
- .setDataUsage(200000L, TIME_B).build();
-
- // Empty collection should be augmented
- history = getHistory(emptyCollection, plan, TIME_A, TIME_C);
- assertEquals(200000L, history.getTotalBytes());
-
- // Normal collection should be augmented
- history = getHistory(collection, plan, TIME_A, TIME_C); i = 0;
- assertEntry(100647, 197, 23649, 185, history.getValues(i++, null));
- assertEntry(100647, 196, 23648, 185, history.getValues(i++, null));
- assertEntry(18323, 76, 15032, 76, history.getValues(i++, null));
- assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
- assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
- assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
- // Cycle point; start data normalization
- assertEntry(7507, 0, 11763, 0, history.getValues(i++, null));
- assertEntry(7507, 0, 11762, 0, history.getValues(i++, null));
- assertEntry(62309, 0, 12589, 0, history.getValues(i++, null));
- assertEntry(62309, 0, 12588, 0, history.getValues(i++, null));
- assertEntry(2669, 0, 3161, 0, history.getValues(i++, null));
- assertEntry(2668, 0, 3160, 0, history.getValues(i++, null));
- // Anchor point; end data normalization
- assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
- assertEntry(8289, 36, 6864, 39, history.getValues(i++, null));
- assertEntry(8289, 34, 6862, 37, history.getValues(i++, null));
- assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
- assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
- // Cycle point
- assertEntry(11378, 49, 9261, 50, history.getValues(i++, null));
- assertEntry(11377, 48, 9261, 48, history.getValues(i++, null));
- assertEntry(201766, 328, 41808, 291, history.getValues(i++, null));
- assertEntry(201764, 328, 41807, 290, history.getValues(i++, null));
- assertEntry(106106, 219, 39918, 202, history.getValues(i++, null));
- assertEntry(106105, 216, 39916, 200, history.getValues(i++, null));
- assertEquals(history.size(), i);
-
- // Slice from middle should be augmented
- history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
- TIME_B + HOUR_IN_MILLIS); i = 0;
- assertEntry(2669, 0, 3161, 0, history.getValues(i++, null));
- assertEntry(2668, 0, 3160, 0, history.getValues(i++, null));
- assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
- assertEquals(history.size(), i);
- }
-
- // Higher anchor in the middle of plan
- {
- int i;
- NetworkStatsHistory history;
-
- final SubscriptionPlan plan = SubscriptionPlan.Builder
- .createNonrecurring(ZonedDateTime.parse("2012-01-09T09:00:00.00Z"),
- ZonedDateTime.parse("2012-01-09T15:00:00.00Z"))
- .setDataUsage(400000L, TIME_B + MINUTE_IN_MILLIS).build();
-
- // Empty collection should be augmented
- history = getHistory(emptyCollection, plan, TIME_A, TIME_C);
- assertEquals(400000L, history.getTotalBytes());
-
- // Normal collection should be augmented
- history = getHistory(collection, plan, TIME_A, TIME_C); i = 0;
- assertEntry(100647, 197, 23649, 185, history.getValues(i++, null));
- assertEntry(100647, 196, 23648, 185, history.getValues(i++, null));
- assertEntry(18323, 76, 15032, 76, history.getValues(i++, null));
- assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
- assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
- assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
- // Cycle point; start data normalization
- assertEntry(15015, 0, 23527, 0, history.getValues(i++, null));
- assertEntry(15015, 0, 23524, 0, history.getValues(i++, null));
- assertEntry(124619, 0, 25179, 0, history.getValues(i++, null));
- assertEntry(124618, 0, 25177, 0, history.getValues(i++, null));
- assertEntry(5338, 0, 6322, 0, history.getValues(i++, null));
- assertEntry(5337, 0, 6320, 0, history.getValues(i++, null));
- // Anchor point; end data normalization
- assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
- assertEntry(8289, 36, 6864, 39, history.getValues(i++, null));
- assertEntry(8289, 34, 6862, 37, history.getValues(i++, null));
- assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
- assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
- // Cycle point
- assertEntry(11378, 49, 9261, 50, history.getValues(i++, null));
- assertEntry(11377, 48, 9261, 48, history.getValues(i++, null));
- assertEntry(201766, 328, 41808, 291, history.getValues(i++, null));
- assertEntry(201764, 328, 41807, 290, history.getValues(i++, null));
- assertEntry(106106, 219, 39918, 202, history.getValues(i++, null));
- assertEntry(106105, 216, 39916, 200, history.getValues(i++, null));
-
- // Slice from middle should be augmented
- history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
- TIME_B + HOUR_IN_MILLIS); i = 0;
- assertEntry(5338, 0, 6322, 0, history.getValues(i++, null));
- assertEntry(5337, 0, 6320, 0, history.getValues(i++, null));
- assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
- assertEquals(history.size(), i);
- }
- }
-
- @Test
- public void testAugmentPlanGigantic() throws Exception {
- // We're in the future, but not that far off
- setClock(Instant.parse("2012-06-01T00:00:00.00Z"));
-
- // Create a simple history with a ton of measured usage
- final NetworkStatsCollection large = new NetworkStatsCollection(HOUR_IN_MILLIS);
- final NetworkIdentitySet ident = new NetworkIdentitySet();
- ident.add(new NetworkIdentity(ConnectivityManager.TYPE_MOBILE, -1, TEST_IMSI, null,
- false, true, true));
- large.recordData(ident, UID_ALL, SET_ALL, TAG_NONE, TIME_A, TIME_B,
- new NetworkStats.Entry(12_730_893_164L, 1, 0, 0, 0));
-
- // Verify untouched total
- assertEquals(12_730_893_164L, getHistory(large, null, TIME_A, TIME_C).getTotalBytes());
-
- // Verify anchor that might cause overflows
- final SubscriptionPlan plan = SubscriptionPlan.Builder
- .createRecurringMonthly(ZonedDateTime.parse("2012-01-09T00:00:00.00Z"))
- .setDataUsage(4_939_212_390L, TIME_B).build();
- assertEquals(4_939_212_386L, getHistory(large, plan, TIME_A, TIME_C).getTotalBytes());
- }
-
- @Test
- public void testRounding() throws Exception {
- final NetworkStatsCollection coll = new NetworkStatsCollection(HOUR_IN_MILLIS);
-
- // Special values should remain unchanged
- for (long time : new long[] {
- Long.MIN_VALUE, Long.MAX_VALUE, SubscriptionPlan.TIME_UNKNOWN
- }) {
- assertEquals(time, coll.roundUp(time));
- assertEquals(time, coll.roundDown(time));
- }
-
- assertEquals(TIME_A, coll.roundUp(TIME_A));
- assertEquals(TIME_A, coll.roundDown(TIME_A));
-
- assertEquals(TIME_A + HOUR_IN_MILLIS, coll.roundUp(TIME_A + 1));
- assertEquals(TIME_A, coll.roundDown(TIME_A + 1));
-
- assertEquals(TIME_A, coll.roundUp(TIME_A - 1));
- assertEquals(TIME_A - HOUR_IN_MILLIS, coll.roundDown(TIME_A - 1));
- }
-
- @Test
- public void testMultiplySafe() {
- assertEquals(25, multiplySafe(50, 1, 2));
- assertEquals(100, multiplySafe(50, 2, 1));
-
- assertEquals(-10, multiplySafe(30, -1, 3));
- assertEquals(0, multiplySafe(30, 0, 3));
- assertEquals(10, multiplySafe(30, 1, 3));
- assertEquals(20, multiplySafe(30, 2, 3));
- assertEquals(30, multiplySafe(30, 3, 3));
- assertEquals(40, multiplySafe(30, 4, 3));
-
- assertEquals(100_000_000_000L,
- multiplySafe(300_000_000_000L, 10_000_000_000L, 30_000_000_000L));
- assertEquals(100_000_000_010L,
- multiplySafe(300_000_000_000L, 10_000_000_001L, 30_000_000_000L));
- assertEquals(823_202_048L,
- multiplySafe(4_939_212_288L, 2_121_815_528L, 12_730_893_165L));
- }
-
- /**
- * Copy a {@link Resources#openRawResource(int)} into {@link File} for
- * testing purposes.
- */
- private void stageFile(int rawId, File file) throws Exception {
- new File(file.getParent()).mkdirs();
- InputStream in = null;
- OutputStream out = null;
- try {
- in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
- out = new FileOutputStream(file);
- Streams.copy(in, out);
- } finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(out);
- }
- }
-
- private static NetworkStatsHistory getHistory(NetworkStatsCollection collection,
- SubscriptionPlan augmentPlan, long start, long end) {
- return collection.getHistory(buildTemplateMobileAll(TEST_IMSI), augmentPlan, UID_ALL,
- SET_ALL, TAG_NONE, FIELD_ALL, start, end, NetworkStatsAccess.Level.DEVICE, myUid());
- }
-
- private static void assertSummaryTotal(NetworkStatsCollection collection,
- NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets,
- @NetworkStatsAccess.Level int accessLevel) {
- final NetworkStats.Entry actual = collection.getSummary(
- template, Long.MIN_VALUE, Long.MAX_VALUE, accessLevel, myUid())
- .getTotal(null);
- assertEntry(rxBytes, rxPackets, txBytes, txPackets, actual);
- }
-
- private static void assertSummaryTotalIncludingTags(NetworkStatsCollection collection,
- NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets) {
- final NetworkStats.Entry actual = collection.getSummary(
- template, Long.MIN_VALUE, Long.MAX_VALUE, NetworkStatsAccess.Level.DEVICE, myUid())
- .getTotalIncludingTags(null);
- assertEntry(rxBytes, rxPackets, txBytes, txPackets, actual);
- }
-
- private static void assertEntry(long rxBytes, long rxPackets, long txBytes, long txPackets,
- NetworkStats.Entry actual) {
- assertEntry(new NetworkStats.Entry(rxBytes, rxPackets, txBytes, txPackets, 0L), actual);
- }
-
- private static void assertEntry(long rxBytes, long rxPackets, long txBytes, long txPackets,
- NetworkStatsHistory.Entry actual) {
- assertEntry(new NetworkStats.Entry(rxBytes, rxPackets, txBytes, txPackets, 0L), actual);
- }
-
- private static void assertEntry(NetworkStats.Entry expected,
- NetworkStatsHistory.Entry actual) {
- assertEntry(expected, new NetworkStats.Entry(actual.rxBytes, actual.rxPackets,
- actual.txBytes, actual.txPackets, 0L));
- }
-
- private static void assertEntry(NetworkStats.Entry expected,
- NetworkStats.Entry actual) {
- assertEquals("unexpected rxBytes", expected.rxBytes, actual.rxBytes);
- assertEquals("unexpected rxPackets", expected.rxPackets, actual.rxPackets);
- assertEquals("unexpected txBytes", expected.txBytes, actual.txBytes);
- assertEquals("unexpected txPackets", expected.txPackets, actual.txPackets);
- }
-}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
deleted file mode 100644
index e4996d981fac..000000000000
--- a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
+++ /dev/null
@@ -1,569 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.net;
-
-import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
-import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
-import static android.net.NetworkStats.METERED_ALL;
-import static android.net.NetworkStats.METERED_NO;
-import static android.net.NetworkStats.ROAMING_ALL;
-import static android.net.NetworkStats.ROAMING_NO;
-import static android.net.NetworkStats.SET_ALL;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.SET_FOREGROUND;
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkStats.UID_ALL;
-
-import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.content.res.Resources;
-import android.net.NetworkStats;
-import android.net.TrafficStats;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.frameworks.tests.net.R;
-import com.android.internal.net.VpnInfo;
-
-import libcore.io.IoUtils;
-import libcore.io.Streams;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/** Tests for {@link NetworkStatsFactory}. */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
- private static final String CLAT_PREFIX = "v4-";
-
- private File mTestProc;
- private NetworkStatsFactory mFactory;
-
- @Before
- public void setUp() throws Exception {
- mTestProc = new File(InstrumentationRegistry.getContext().getFilesDir(), "proc");
- if (mTestProc.exists()) {
- IoUtils.deleteContents(mTestProc);
- }
-
- // The libandroid_servers which have the native method is not available to
- // applications. So in order to have a test support native library, the native code
- // related to networkStatsFactory is compiled to a minimal native library and loaded here.
- System.loadLibrary("networkstatsfactorytestjni");
- mFactory = new NetworkStatsFactory(mTestProc, false);
- mFactory.updateVpnInfos(new VpnInfo[0]);
- }
-
- @After
- public void tearDown() throws Exception {
- mFactory = null;
-
- if (mTestProc.exists()) {
- IoUtils.deleteContents(mTestProc);
- }
- }
-
- @Test
- public void testNetworkStatsDetail() throws Exception {
- final NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_typical);
-
- assertEquals(70, stats.size());
- assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 18621L, 2898L);
- assertStatsEntry(stats, "wlan0", 10011, SET_DEFAULT, 0x0, 35777L, 5718L);
- assertStatsEntry(stats, "wlan0", 10021, SET_DEFAULT, 0x7fffff01, 562386L, 49228L);
- assertStatsEntry(stats, "rmnet1", 10021, SET_DEFAULT, 0x30100000, 219110L, 227423L);
- assertStatsEntry(stats, "rmnet2", 10001, SET_DEFAULT, 0x0, 1125899906842624L, 984L);
- }
-
- @Test
- public void testVpnRewriteTrafficThroughItself() throws Exception {
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- //
- // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
- // over VPN.
- // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
- // over VPN.
- //
- // VPN UID rewrites packets read from TUN back to TUN, plus some of its own traffic
-
- final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_rewrite_through_self);
-
- assertValues(tunStats, TUN_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 2000L, 200L, 1000L, 100L, 0);
- assertValues(tunStats, TUN_IFACE, UID_BLUE, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 1000L, 100L, 500L, 50L, 0);
- assertValues(tunStats, TUN_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 0L, 0L, 1600L, 160L, 0);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 2000L, 200L, 1000L, 100L);
- assertValues(tunStats, TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 300L, 0L, 260L, 26L);
- }
-
- @Test
- public void testVpnWithClat() throws Exception {
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {CLAT_PREFIX + TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
- mFactory.noteStackedIface(CLAT_PREFIX + TEST_IFACE, TEST_IFACE);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
- // over VPN.
- // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
- // over VPN.
- // VPN sent 1650 bytes (150 packets), and received 3300 (300 packets) over v4-WiFi, and clat
- // added 20 bytes per packet of extra overhead
- //
- // For 1650 bytes sent over v4-WiFi, 4650 bytes were actually sent over WiFi, which is
- // expected to be split as follows:
- // UID_RED: 1000 bytes, 100 packets
- // UID_BLUE: 500 bytes, 50 packets
- // UID_VPN: 3150 bytes, 0 packets
- //
- // For 3300 bytes received over v4-WiFi, 9300 bytes were actually sent over WiFi, which is
- // expected to be split as follows:
- // UID_RED: 2000 bytes, 200 packets
- // UID_BLUE: 1000 bytes, 100 packets
- // UID_VPN: 6300 bytes, 0 packets
- final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_with_clat);
-
- assertValues(tunStats, CLAT_PREFIX + TEST_IFACE, UID_RED, 2000L, 200L, 1000, 100L);
- assertValues(tunStats, CLAT_PREFIX + TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
- assertValues(tunStats, CLAT_PREFIX + TEST_IFACE, UID_VPN, 6300L, 0L, 3150L, 0L);
- }
-
- @Test
- public void testVpnWithOneUnderlyingIface() throws Exception {
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
- // over VPN.
- // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
- // over VPN.
- // VPN sent 1650 bytes (150 packets), and received 3300 (300 packets) over WiFi.
- // Of 1650 bytes sent over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes
- // attributed to UID_BLUE, and 150 bytes attributed to UID_VPN.
- // Of 3300 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes
- // attributed to UID_BLUE, and 300 bytes attributed to UID_VPN.
- final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_one_underlying);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 2000L, 200L, 1000L, 100L);
- assertValues(tunStats, TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 300L, 0L, 150L, 0L);
- }
-
- @Test
- public void testVpnWithOneUnderlyingIfaceAndOwnTraffic() throws Exception {
- // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
- // over VPN.
- // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
- // over VPN.
- // Additionally, the VPN sends 6000 bytes (600 packets) of its own traffic into the tun
- // interface (passing that traffic to the VPN endpoint), and receives 5000 bytes (500
- // packets) from it. Including overhead that is 6600/5500 bytes.
- // VPN sent 8250 bytes (750 packets), and received 8800 (800 packets) over WiFi.
- // Of 8250 bytes sent over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes
- // attributed to UID_BLUE, and 6750 bytes attributed to UID_VPN.
- // Of 8800 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes
- // attributed to UID_BLUE, and 5800 bytes attributed to UID_VPN.
- final NetworkStats tunStats =
- parseDetailedStats(R.raw.xt_qtaguid_vpn_one_underlying_own_traffic);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 2000L, 200L, 1000L, 100L);
- assertValues(tunStats, TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 5800L, 500L, 6750L, 600L);
- }
-
- @Test
- public void testVpnWithOneUnderlyingIface_withCompression() throws Exception {
- // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
- // 3000 bytes (300 packets) were sent/received by UID_BLUE over VPN.
- // VPN sent/received 1000 bytes (100 packets) over WiFi.
- // Of 1000 bytes over WiFi, expect 250 bytes attributed UID_RED and 750 bytes to UID_BLUE,
- // with nothing attributed to UID_VPN for both rx/tx traffic.
- final NetworkStats tunStats =
- parseDetailedStats(R.raw.xt_qtaguid_vpn_one_underlying_compression);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 250L, 25L, 250L, 25L);
- assertValues(tunStats, TEST_IFACE, UID_BLUE, 750L, 75L, 750L, 75L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 0L, 0L, 0L, 0L);
- }
-
- @Test
- public void testVpnWithTwoUnderlyingIfaces_packetDuplication() throws Exception {
- // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
- // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
- // Additionally, VPN is duplicating traffic across both WiFi and Cell.
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
- mFactory.updateVpnInfos(vpnInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent/received by UID_RED and UID_BLUE over VPN.
- // VPN sent/received 4400 bytes (400 packets) over both WiFi and Cell (8800 bytes in total).
- // Of 8800 bytes over WiFi/Cell, expect:
- // - 500 bytes rx/tx each over WiFi/Cell attributed to both UID_RED and UID_BLUE.
- // - 1200 bytes rx/tx each over WiFi/Cell for VPN_UID.
- final NetworkStats tunStats =
- parseDetailedStats(R.raw.xt_qtaguid_vpn_two_underlying_duplication);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 500L, 50L, 500L, 50L);
- assertValues(tunStats, TEST_IFACE, UID_BLUE, 500L, 50L, 500L, 50L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 1200L, 100L, 1200L, 100L);
- assertValues(tunStats, TEST_IFACE2, UID_RED, 500L, 50L, 500L, 50L);
- assertValues(tunStats, TEST_IFACE2, UID_BLUE, 500L, 50L, 500L, 50L);
- assertValues(tunStats, TEST_IFACE2, UID_VPN, 1200L, 100L, 1200L, 100L);
- }
-
- @Test
- public void testConcurrentVpns() throws Exception {
- // Assume two VPNs are connected on two different network interfaces. VPN1 is using
- // TEST_IFACE and VPN2 is using TEST_IFACE2.
- final VpnInfo[] vpnInfos = new VpnInfo[] {
- createVpnInfo(TUN_IFACE, new String[] {TEST_IFACE}),
- createVpnInfo(TUN_IFACE2, new String[] {TEST_IFACE2})};
- mFactory.updateVpnInfos(vpnInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
- // over VPN1.
- // 700 bytes (70 packets) were sent, and 3000 bytes (300 packets) were received by UID_RED
- // over VPN2.
- // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
- // over VPN1.
- // 250 bytes (25 packets) were sent, and 500 bytes (50 packets) were received by UID_BLUE
- // over VPN2.
- // VPN1 sent 1650 bytes (150 packets), and received 3300 (300 packets) over TEST_IFACE.
- // Of 1650 bytes sent over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes
- // attributed to UID_BLUE, and 150 bytes attributed to UID_VPN.
- // Of 3300 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes
- // attributed to UID_BLUE, and 300 bytes attributed to UID_VPN.
- // VPN2 sent 1045 bytes (95 packets), and received 3850 (350 packets) over TEST_IFACE2.
- // Of 1045 bytes sent over Cell, expect 700 bytes attributed to UID_RED, 250 bytes
- // attributed to UID_BLUE, and 95 bytes attributed to UID_VPN.
- // Of 3850 bytes received over Cell, expect 3000 bytes attributed to UID_RED, 500 bytes
- // attributed to UID_BLUE, and 350 bytes attributed to UID_VPN.
- final NetworkStats tunStats =
- parseDetailedStats(R.raw.xt_qtaguid_vpn_one_underlying_two_vpn);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 2000L, 200L, 1000L, 100L);
- assertValues(tunStats, TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
- assertValues(tunStats, TEST_IFACE2, UID_RED, 3000L, 300L, 700L, 70L);
- assertValues(tunStats, TEST_IFACE2, UID_BLUE, 500L, 50L, 250L, 25L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 300L, 0L, 150L, 0L);
- assertValues(tunStats, TEST_IFACE2, UID_VPN, 350L, 0L, 95L, 0L);
- }
-
- @Test
- public void testVpnWithTwoUnderlyingIfaces_splitTraffic() throws Exception {
- // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
- // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
- // Additionally, VPN is arbitrarily splitting traffic across WiFi and Cell.
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
- mFactory.updateVpnInfos(vpnInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent, and 500 bytes (50 packets) received by UID_RED over
- // VPN.
- // VPN sent 660 bytes (60 packets) over WiFi and 440 bytes (40 packets) over Cell.
- // And, it received 330 bytes (30 packets) over WiFi and 220 bytes (20 packets) over Cell.
- // For UID_RED, expect 600 bytes attributed over WiFi and 400 bytes over Cell for sent (tx)
- // traffic. For received (rx) traffic, expect 300 bytes over WiFi and 200 bytes over Cell.
- //
- // For UID_VPN, expect 60 bytes attributed over WiFi and 40 bytes over Cell for tx traffic.
- // And, 30 bytes over WiFi and 20 bytes over Cell for rx traffic.
- final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_two_underlying_split);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 300L, 30L, 600L, 60L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 30L, 0L, 60L, 0L);
- assertValues(tunStats, TEST_IFACE2, UID_RED, 200L, 20L, 400L, 40L);
- assertValues(tunStats, TEST_IFACE2, UID_VPN, 20L, 0L, 40L, 0L);
- }
-
- @Test
- public void testVpnWithTwoUnderlyingIfaces_splitTrafficWithCompression() throws Exception {
- // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
- // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
- // Additionally, VPN is arbitrarily splitting compressed traffic across WiFi and Cell.
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
- mFactory.updateVpnInfos(vpnInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface:
- // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
- // VPN sent/received 600 bytes (60 packets) over WiFi and 200 bytes (20 packets) over Cell.
- // For UID_RED, expect 600 bytes attributed over WiFi and 200 bytes over Cell for both
- // rx/tx.
- // UID_VPN gets nothing attributed to it (avoiding negative stats).
- final NetworkStats tunStats =
- parseDetailedStats(R.raw.xt_qtaguid_vpn_two_underlying_split_compression);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 600L, 60L, 600L, 60L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 0L, 0L, 0L, 0L);
- assertValues(tunStats, TEST_IFACE2, UID_RED, 200L, 20L, 200L, 20L);
- assertValues(tunStats, TEST_IFACE2, UID_VPN, 0L, 0L, 0L, 0L);
- }
-
- @Test
- public void testVpnWithIncorrectUnderlyingIface() throws Exception {
- // WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2),
- // but has declared only WiFi (TEST_IFACE) in its underlying network set.
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateVpnInfos(vpnInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
- // VPN sent/received 1100 bytes (100 packets) over Cell.
- // Of 1100 bytes over Cell, expect all of it attributed to UID_VPN for both rx/tx traffic.
- final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_incorrect_iface);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 0L, 0L, 0L, 0L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 0L, 0L, 0L, 0L);
- assertValues(tunStats, TEST_IFACE2, UID_RED, 0L, 0L, 0L, 0L);
- assertValues(tunStats, TEST_IFACE2, UID_VPN, 1100L, 100L, 1100L, 100L);
- }
-
- @Test
- public void testKernelTags() throws Exception {
- assertEquals(0, kernelToTag("0x0000000000000000"));
- assertEquals(0x32, kernelToTag("0x0000003200000000"));
- assertEquals(2147483647, kernelToTag("0x7fffffff00000000"));
- assertEquals(0, kernelToTag("0x0000000000000000"));
- assertEquals(2147483136, kernelToTag("0x7FFFFE0000000000"));
-
- assertEquals(0, kernelToTag("0x0"));
- assertEquals(0, kernelToTag("0xf00d"));
- assertEquals(1, kernelToTag("0x100000000"));
- assertEquals(14438007, kernelToTag("0xdc4e7700000000"));
- assertEquals(TrafficStats.TAG_SYSTEM_DOWNLOAD, kernelToTag("0xffffff0100000000"));
- }
-
- @Test
- public void testNetworkStatsWithSet() throws Exception {
- final NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_typical);
- assertEquals(70, stats.size());
- assertStatsEntry(stats, "rmnet1", 10021, SET_DEFAULT, 0x30100000, 219110L, 578L, 227423L,
- 676L);
- assertStatsEntry(stats, "rmnet1", 10021, SET_FOREGROUND, 0x30100000, 742L, 3L, 1265L, 3L);
- }
-
- @Test
- public void testNetworkStatsSingle() throws Exception {
- stageFile(R.raw.xt_qtaguid_iface_typical, file("net/xt_qtaguid/iface_stat_all"));
-
- final NetworkStats stats = mFactory.readNetworkStatsSummaryDev();
- assertEquals(6, stats.size());
- assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 2112L, 24L, 700L, 10L);
- assertStatsEntry(stats, "test1", UID_ALL, SET_ALL, TAG_NONE, 6L, 8L, 10L, 12L);
- assertStatsEntry(stats, "test2", UID_ALL, SET_ALL, TAG_NONE, 1L, 2L, 3L, 4L);
- }
-
- @Test
- public void testNetworkStatsXt() throws Exception {
- stageFile(R.raw.xt_qtaguid_iface_fmt_typical, file("net/xt_qtaguid/iface_stat_fmt"));
-
- final NetworkStats stats = mFactory.readNetworkStatsSummaryXt();
- assertEquals(3, stats.size());
- assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 6824L, 16L, 5692L, 10L);
- assertStatsEntry(stats, "rmnet1", UID_ALL, SET_ALL, TAG_NONE, 11153922L, 8051L, 190226L,
- 2468L);
- assertStatsEntry(stats, "rmnet2", UID_ALL, SET_ALL, TAG_NONE, 4968L, 35L, 3081L, 39L);
- }
-
- @Test
- public void testDoubleClatAccountingSimple() throws Exception {
- mFactory.noteStackedIface("v4-wlan0", "wlan0");
-
- // xt_qtaguid_with_clat_simple is a synthetic file that simulates
- // - 213 received 464xlat packets of size 200 bytes
- // - 41 sent 464xlat packets of size 100 bytes
- // - no other traffic on base interface for root uid.
- NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_simple);
- assertEquals(3, stats.size());
-
- assertStatsEntry(stats, "v4-wlan0", 10060, SET_DEFAULT, 0x0, 46860L, 4920L);
- assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 0L, 0L);
- }
-
- @Test
- public void testDoubleClatAccounting() throws Exception {
- mFactory.noteStackedIface("v4-wlan0", "wlan0");
-
- NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat);
- assertEquals(42, stats.size());
-
- assertStatsEntry(stats, "v4-wlan0", 0, SET_DEFAULT, 0x0, 356L, 276L);
- assertStatsEntry(stats, "v4-wlan0", 1000, SET_DEFAULT, 0x0, 30812L, 2310L);
- assertStatsEntry(stats, "v4-wlan0", 10102, SET_DEFAULT, 0x0, 10022L, 3330L);
- assertStatsEntry(stats, "v4-wlan0", 10060, SET_DEFAULT, 0x0, 9532772L, 254112L);
- assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 0L, 0L);
- assertStatsEntry(stats, "wlan0", 1000, SET_DEFAULT, 0x0, 6126L, 2013L);
- assertStatsEntry(stats, "wlan0", 10013, SET_DEFAULT, 0x0, 0L, 144L);
- assertStatsEntry(stats, "wlan0", 10018, SET_DEFAULT, 0x0, 5980263L, 167667L);
- assertStatsEntry(stats, "wlan0", 10060, SET_DEFAULT, 0x0, 134356L, 8705L);
- assertStatsEntry(stats, "wlan0", 10079, SET_DEFAULT, 0x0, 10926L, 1507L);
- assertStatsEntry(stats, "wlan0", 10102, SET_DEFAULT, 0x0, 25038L, 8245L);
- assertStatsEntry(stats, "wlan0", 10103, SET_DEFAULT, 0x0, 0L, 192L);
- assertStatsEntry(stats, "dummy0", 0, SET_DEFAULT, 0x0, 0L, 168L);
- assertStatsEntry(stats, "lo", 0, SET_DEFAULT, 0x0, 1288L, 1288L);
-
- assertNoStatsEntry(stats, "wlan0", 1029, SET_DEFAULT, 0x0);
- }
-
- @Test
- public void testDoubleClatAccounting100MBDownload() throws Exception {
- // Downloading 100mb from an ipv4 only destination in a foreground activity
-
- long appRxBytesBefore = 328684029L;
- long appRxBytesAfter = 439237478L;
- assertEquals("App traffic should be ~100MB", 110553449, appRxBytesAfter - appRxBytesBefore);
-
- long rootRxBytes = 330187296L;
-
- mFactory.noteStackedIface("v4-wlan0", "wlan0");
- NetworkStats stats;
-
- // Stats snapshot before the download
- stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_100mb_download_before);
- assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesBefore, 5199872L);
- assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytes, 0L);
-
- // Stats snapshot after the download
- stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_100mb_download_after);
- assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesAfter, 7867488L);
- assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytes, 0L);
- }
-
- /**
- * Copy a {@link Resources#openRawResource(int)} into {@link File} for
- * testing purposes.
- */
- private void stageFile(int rawId, File file) throws Exception {
- new File(file.getParent()).mkdirs();
- InputStream in = null;
- OutputStream out = null;
- try {
- in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
- out = new FileOutputStream(file);
- Streams.copy(in, out);
- } finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(out);
- }
- }
-
- private void stageLong(long value, File file) throws Exception {
- new File(file.getParent()).mkdirs();
- FileWriter out = null;
- try {
- out = new FileWriter(file);
- out.write(Long.toString(value));
- } finally {
- IoUtils.closeQuietly(out);
- }
- }
-
- private File file(String path) throws Exception {
- return new File(mTestProc, path);
- }
-
- private NetworkStats parseDetailedStats(int resourceId) throws Exception {
- stageFile(resourceId, file("net/xt_qtaguid/stats"));
- return mFactory.readNetworkStatsDetail();
- }
-
- private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
- int tag, long rxBytes, long txBytes) {
- final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO);
- if (i < 0) {
- fail(String.format("no NetworkStats for (iface: %s, uid: %d, set: %d, tag: %d)",
- iface, uid, set, tag));
- }
- final NetworkStats.Entry entry = stats.getValues(i, null);
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- }
-
- private static void assertNoStatsEntry(NetworkStats stats, String iface, int uid, int set,
- int tag) {
- final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO);
- if (i >= 0) {
- fail("unexpected NetworkStats entry at " + i);
- }
- }
-
- private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
- int tag, long rxBytes, long rxPackets, long txBytes, long txPackets) {
- assertStatsEntry(stats, iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
- rxBytes, rxPackets, txBytes, txPackets);
- }
-
- private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
- int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
- long txBytes, long txPackets) {
- final int i = stats.findIndex(iface, uid, set, tag, metered, roaming, defaultNetwork);
-
- if (i < 0) {
- fail(String.format("no NetworkStats for (iface: %s, uid: %d, set: %d, tag: %d, metered:"
- + " %d, roaming: %d, defaultNetwork: %d)",
- iface, uid, set, tag, metered, roaming, defaultNetwork));
- }
- final NetworkStats.Entry entry = stats.getValues(i, null);
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- assertEquals("unexpected txPackets", txPackets, entry.txPackets);
- }
-}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
deleted file mode 100644
index a6f7a36ff01b..000000000000
--- a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
-import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
-import static android.net.NetworkStats.METERED_NO;
-import static android.net.NetworkStats.ROAMING_NO;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkTemplate.buildTemplateMobileAll;
-import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
-import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-
-import android.app.usage.NetworkStatsManager;
-import android.net.DataUsageRequest;
-import android.net.NetworkIdentity;
-import android.net.NetworkStats;
-import android.net.NetworkTemplate;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Messenger;
-import android.os.Process;
-import android.os.UserHandle;
-import android.telephony.TelephonyManager;
-import android.util.ArrayMap;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.net.NetworkStatsServiceTest.LatchedHandler;
-import com.android.testutils.HandlerUtilsKt;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Objects;
-
-/**
- * Tests for {@link NetworkStatsObservers}.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkStatsObserversTest {
- private static final String TEST_IFACE = "test0";
- private static final String TEST_IFACE2 = "test1";
- private static final long TEST_START = 1194220800000L;
-
- private static final String IMSI_1 = "310004";
- private static final String IMSI_2 = "310260";
- private static final String TEST_SSID = "AndroidAP";
-
- private static NetworkTemplate sTemplateWifi = buildTemplateWifiWildcard();
- private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
- private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
-
- private static final int UID_RED = UserHandle.PER_USER_RANGE + 1;
- private static final int UID_BLUE = UserHandle.PER_USER_RANGE + 2;
- private static final int UID_GREEN = UserHandle.PER_USER_RANGE + 3;
- private static final int UID_ANOTHER_USER = 2 * UserHandle.PER_USER_RANGE + 4;
-
- private static final long WAIT_TIMEOUT_MS = 500;
- private static final long THRESHOLD_BYTES = 2 * MB_IN_BYTES;
- private static final long BASE_BYTES = 7 * MB_IN_BYTES;
- private static final int INVALID_TYPE = -1;
-
- private long mElapsedRealtime;
-
- private HandlerThread mObserverHandlerThread;
- private Handler mObserverNoopHandler;
-
- private LatchedHandler mHandler;
-
- private NetworkStatsObservers mStatsObservers;
- private Messenger mMessenger;
- private ArrayMap<String, NetworkIdentitySet> mActiveIfaces;
- private ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces;
-
- @Mock private IBinder mockBinder;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- mObserverHandlerThread = new HandlerThread("HandlerThread");
- mObserverHandlerThread.start();
- final Looper observerLooper = mObserverHandlerThread.getLooper();
- mStatsObservers = new NetworkStatsObservers() {
- @Override
- protected Looper getHandlerLooperLocked() {
- return observerLooper;
- }
- };
-
- mHandler = new LatchedHandler(Looper.getMainLooper(), new ConditionVariable());
- mMessenger = new Messenger(mHandler);
-
- mActiveIfaces = new ArrayMap<>();
- mActiveUidIfaces = new ArrayMap<>();
- }
-
- @Test
- public void testRegister_thresholdTooLow_setsDefaultThreshold() throws Exception {
- long thresholdTooLowBytes = 1L;
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, thresholdTooLowBytes);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateWifi, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
- }
-
- @Test
- public void testRegister_highThreshold_accepted() throws Exception {
- long highThresholdBytes = 2 * THRESHOLD_BYTES;
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, highThresholdBytes);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateWifi, request.template));
- assertEquals(highThresholdBytes, request.thresholdInBytes);
- }
-
- @Test
- public void testRegister_twoRequests_twoIds() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, THRESHOLD_BYTES);
-
- DataUsageRequest request1 = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request1.requestId > 0);
- assertTrue(Objects.equals(sTemplateWifi, request1.template));
- assertEquals(THRESHOLD_BYTES, request1.thresholdInBytes);
-
- DataUsageRequest request2 = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request2.requestId > request1.requestId);
- assertTrue(Objects.equals(sTemplateWifi, request2.template));
- assertEquals(THRESHOLD_BYTES, request2.thresholdInBytes);
- }
-
- @Test
- public void testUnregister_unknownRequest_noop() throws Exception {
- DataUsageRequest unknownRequest = new DataUsageRequest(
- 123456 /* id */, sTemplateWifi, THRESHOLD_BYTES);
-
- mStatsObservers.unregister(unknownRequest, UID_RED);
- }
-
- @Test
- public void testUnregister_knownRequest_releasesCaller() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
- Mockito.verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
-
- mStatsObservers.unregister(request, Process.SYSTEM_UID);
- waitForObserverToIdle();
-
- Mockito.verify(mockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
- }
-
- @Test
- public void testUnregister_knownRequest_invalidUid_doesNotUnregister() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- UID_RED, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
- Mockito.verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
-
- mStatsObservers.unregister(request, UID_BLUE);
- waitForObserverToIdle();
-
- Mockito.verifyZeroInteractions(mockBinder);
- }
-
- private NetworkIdentitySet makeTestIdentSet() {
- NetworkIdentitySet identSet = new NetworkIdentitySet();
- identSet.add(new NetworkIdentity(
- TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- IMSI_1, null /* networkId */, false /* roaming */, true /* metered */,
- true /* defaultNetwork */));
- return identSet;
- }
-
- @Test
- public void testUpdateStats_initialSample_doesNotNotify() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-
- NetworkIdentitySet identSet = makeTestIdentSet();
- mActiveIfaces.put(TEST_IFACE, identSet);
-
- // Baseline
- NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
- .insertEntry(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
- NetworkStats uidSnapshot = null;
-
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
- waitForObserverToIdle();
- }
-
- @Test
- public void testUpdateStats_belowThreshold_doesNotNotify() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-
- NetworkIdentitySet identSet = makeTestIdentSet();
- mActiveIfaces.put(TEST_IFACE, identSet);
-
- // Baseline
- NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
- .insertEntry(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
- NetworkStats uidSnapshot = null;
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
-
- // Delta
- xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
- .insertEntry(TEST_IFACE, BASE_BYTES + 1024L, 10L, BASE_BYTES + 2048L, 20L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
- waitForObserverToIdle();
- }
-
-
- @Test
- public void testUpdateStats_deviceAccess_notifies() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-
- NetworkIdentitySet identSet = makeTestIdentSet();
- mActiveIfaces.put(TEST_IFACE, identSet);
-
- // Baseline
- NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
- .insertEntry(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
- NetworkStats uidSnapshot = null;
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
-
- // Delta
- xtSnapshot = new NetworkStats(TEST_START + MINUTE_IN_MILLIS, 1 /* initialSize */)
- .insertEntry(TEST_IFACE, BASE_BYTES + THRESHOLD_BYTES, 12L,
- BASE_BYTES + THRESHOLD_BYTES, 22L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
- waitForObserverToIdle();
- assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.lastMessageType);
- }
-
- @Test
- public void testUpdateStats_defaultAccess_notifiesSameUid() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- UID_RED, NetworkStatsAccess.Level.DEFAULT);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-
- NetworkIdentitySet identSet = makeTestIdentSet();
- mActiveUidIfaces.put(TEST_IFACE, identSet);
-
- // Baseline
- NetworkStats xtSnapshot = null;
- NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
-
- // Delta
- uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
- BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
- waitForObserverToIdle();
- assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.lastMessageType);
- }
-
- @Test
- public void testUpdateStats_defaultAccess_usageOtherUid_doesNotNotify() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- UID_BLUE, NetworkStatsAccess.Level.DEFAULT);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-
- NetworkIdentitySet identSet = makeTestIdentSet();
- mActiveUidIfaces.put(TEST_IFACE, identSet);
-
- // Baseline
- NetworkStats xtSnapshot = null;
- NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
-
- // Delta
- uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
- BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
- waitForObserverToIdle();
- }
-
- @Test
- public void testUpdateStats_userAccess_usageSameUser_notifies() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- UID_BLUE, NetworkStatsAccess.Level.USER);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-
- NetworkIdentitySet identSet = makeTestIdentSet();
- mActiveUidIfaces.put(TEST_IFACE, identSet);
-
- // Baseline
- NetworkStats xtSnapshot = null;
- NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
-
- // Delta
- uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, BASE_BYTES + THRESHOLD_BYTES, 2L,
- BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
- waitForObserverToIdle();
- assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.lastMessageType);
- }
-
- @Test
- public void testUpdateStats_userAccess_usageAnotherUser_doesNotNotify() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- UID_RED, NetworkStatsAccess.Level.USER);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-
- NetworkIdentitySet identSet = makeTestIdentSet();
- mActiveUidIfaces.put(TEST_IFACE, identSet);
-
- // Baseline
- NetworkStats xtSnapshot = null;
- NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .insertEntry(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
-
- // Delta
- uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .insertEntry(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
- BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
- waitForObserverToIdle();
- }
-
- private void waitForObserverToIdle() {
- HandlerUtilsKt.waitForIdle(mObserverHandlerThread, WAIT_TIMEOUT_MS);
- HandlerUtilsKt.waitForIdle(mHandler, WAIT_TIMEOUT_MS);
- }
-}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
deleted file mode 100644
index a1bb0d586916..000000000000
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ /dev/null
@@ -1,1425 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.net;
-
-import static android.content.Intent.ACTION_UID_REMOVED;
-import static android.content.Intent.EXTRA_UID;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_VPN;
-import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.ConnectivityManager.TYPE_WIMAX;
-import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
-import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
-import static android.net.NetworkStats.IFACE_ALL;
-import static android.net.NetworkStats.INTERFACES_ALL;
-import static android.net.NetworkStats.METERED_ALL;
-import static android.net.NetworkStats.METERED_NO;
-import static android.net.NetworkStats.METERED_YES;
-import static android.net.NetworkStats.ROAMING_ALL;
-import static android.net.NetworkStats.ROAMING_NO;
-import static android.net.NetworkStats.ROAMING_YES;
-import static android.net.NetworkStats.SET_ALL;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.SET_FOREGROUND;
-import static android.net.NetworkStats.STATS_PER_IFACE;
-import static android.net.NetworkStats.STATS_PER_UID;
-import static android.net.NetworkStats.TAG_ALL;
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkStatsHistory.FIELD_ALL;
-import static android.net.NetworkTemplate.buildTemplateMobileAll;
-import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
-import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
-import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.net.TrafficStats.UID_REMOVED;
-import static android.net.TrafficStats.UID_TETHERING;
-import static android.text.format.DateUtils.DAY_IN_MILLIS;
-import static android.text.format.DateUtils.HOUR_IN_MILLIS;
-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-import static android.text.format.DateUtils.WEEK_IN_MILLIS;
-
-import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.app.AlarmManager;
-import android.app.usage.NetworkStatsManager;
-import android.content.Context;
-import android.content.Intent;
-import android.net.DataUsageRequest;
-import android.net.INetworkManagementEventObserver;
-import android.net.INetworkStatsSession;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkState;
-import android.net.NetworkStats;
-import android.net.NetworkStatsHistory;
-import android.net.NetworkTemplate;
-import android.net.netstats.provider.INetworkStatsProviderCallback;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.INetworkManagementService;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.PowerManager;
-import android.os.SimpleClock;
-import android.telephony.TelephonyManager;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.net.VpnInfo;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.test.BroadcastInterceptingContext;
-import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
-import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
-import com.android.testutils.HandlerUtilsKt;
-import com.android.testutils.TestableNetworkStatsProviderBinder;
-
-import libcore.io.IoUtils;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.File;
-import java.time.Clock;
-import java.time.ZoneOffset;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-
-/**
- * Tests for {@link NetworkStatsService}.
- *
- * TODO: This test used to be really brittle because it used Easymock - it uses Mockito now, but
- * still uses the Easymock structure, which could be simplified.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
- private static final String TAG = "NetworkStatsServiceTest";
-
- private static final long TEST_START = 1194220800000L;
-
- private static final String IMSI_1 = "310004";
- private static final String IMSI_2 = "310260";
- private static final String TEST_SSID = "AndroidAP";
-
- private static NetworkTemplate sTemplateWifi = buildTemplateWifiWildcard();
- private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
- private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
-
- private static final Network WIFI_NETWORK = new Network(100);
- private static final Network MOBILE_NETWORK = new Network(101);
- private static final Network VPN_NETWORK = new Network(102);
-
- private static final Network[] NETWORKS_WIFI = new Network[]{ WIFI_NETWORK };
- private static final Network[] NETWORKS_MOBILE = new Network[]{ MOBILE_NETWORK };
-
- private static final long WAIT_TIMEOUT = 2 * 1000; // 2 secs
- private static final int INVALID_TYPE = -1;
-
- private long mElapsedRealtime;
-
- private BroadcastInterceptingContext mServiceContext;
- private File mStatsDir;
-
- private @Mock INetworkManagementService mNetManager;
- private @Mock NetworkStatsFactory mStatsFactory;
- private @Mock NetworkStatsSettings mSettings;
- private @Mock IBinder mBinder;
- private @Mock AlarmManager mAlarmManager;
- @Mock
- private NetworkStatsSubscriptionsMonitor mNetworkStatsSubscriptionsMonitor;
- private HandlerThread mHandlerThread;
-
- private NetworkStatsService mService;
- private INetworkStatsSession mSession;
- private INetworkManagementEventObserver mNetworkObserver;
-
- private final Clock mClock = new SimpleClock(ZoneOffset.UTC) {
- @Override
- public long millis() {
- return currentTimeMillis();
- }
- };
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- final Context context = InstrumentationRegistry.getContext();
-
- mServiceContext = new BroadcastInterceptingContext(context);
- mStatsDir = context.getFilesDir();
- if (mStatsDir.exists()) {
- IoUtils.deleteContents(mStatsDir);
- }
-
- PowerManager powerManager = (PowerManager) mServiceContext.getSystemService(
- Context.POWER_SERVICE);
- PowerManager.WakeLock wakeLock =
- powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-
- mHandlerThread = new HandlerThread("HandlerThread");
- final NetworkStatsService.Dependencies deps = makeDependencies();
- mService = new NetworkStatsService(mServiceContext, mNetManager, mAlarmManager, wakeLock,
- mClock, mSettings, mStatsFactory, new NetworkStatsObservers(), mStatsDir,
- getBaseDir(mStatsDir), deps);
-
- mElapsedRealtime = 0L;
-
- expectDefaultSettings();
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectSystemReady();
-
- mService.systemReady();
- // Verify that system ready fetches realtime stats
- verify(mStatsFactory).readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL);
-
- mSession = mService.openSession();
- assertNotNull("openSession() failed", mSession);
-
- // catch INetworkManagementEventObserver during systemReady()
- ArgumentCaptor<INetworkManagementEventObserver> networkObserver =
- ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
- verify(mNetManager).registerObserver(networkObserver.capture());
- mNetworkObserver = networkObserver.getValue();
- }
-
- @NonNull
- private NetworkStatsService.Dependencies makeDependencies() {
- return new NetworkStatsService.Dependencies() {
- @Override
- public HandlerThread makeHandlerThread() {
- return mHandlerThread;
- }
-
- @Override
- public NetworkStatsSubscriptionsMonitor makeSubscriptionsMonitor(
- @NonNull Context context, @NonNull Executor executor,
- @NonNull NetworkStatsService service) {
-
- return mNetworkStatsSubscriptionsMonitor;
- }
- };
- }
-
- @After
- public void tearDown() throws Exception {
- IoUtils.deleteContents(mStatsDir);
-
- mServiceContext = null;
- mStatsDir = null;
-
- mNetManager = null;
- mSettings = null;
-
- mSession.close();
- mService = null;
-
- mHandlerThread.quitSafely();
- }
-
- @Test
- public void testNetworkStatsWifi() throws Exception {
- // pretend that wifi network comes online; service should ask about full
- // network state, and poll any existing interfaces before updating.
- expectDefaultSettings();
- NetworkState[] states = new NetworkState[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
-
- // verify service has empty history for wifi
- assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
-
-
- // modify some number on wifi, and trigger poll event
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 1024L, 1L, 2048L, 2L));
- expectNetworkStatsUidDetail(buildEmptyStats());
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0);
-
-
- // and bump forward again, with counters going higher. this is
- // important, since polling should correctly subtract last snapshot.
- incrementCurrentTime(DAY_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 4096L, 4L, 8192L, 8L));
- expectNetworkStatsUidDetail(buildEmptyStats());
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertNetworkTotal(sTemplateWifi, 4096L, 4L, 8192L, 8L, 0);
-
- }
-
- @Test
- public void testStatsRebootPersist() throws Exception {
- assertStatsFilesExist(false);
-
- // pretend that wifi network comes online; service should ask about full
- // network state, and poll any existing interfaces before updating.
- expectDefaultSettings();
- NetworkState[] states = new NetworkState[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
-
- // verify service has empty history for wifi
- assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
-
-
- // modify some number on wifi, and trigger poll event
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 1024L, 8L, 2048L, 16L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L));
- mService.setUidForeground(UID_RED, false);
- mService.incrementOperationCount(UID_RED, 0xFAAD, 4);
- mService.setUidForeground(UID_RED, true);
- mService.incrementOperationCount(UID_RED, 0xFAAD, 6);
-
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
- assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10);
- assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 512L, 4L, 256L, 2L, 4);
- assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 512L, 4L, 256L, 2L, 6);
- assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
-
-
- // graceful shutdown system, which should trigger persist of stats, and
- // clear any values in memory.
- expectDefaultSettings();
- mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN));
- assertStatsFilesExist(true);
-
- // boot through serviceReady() again
- expectDefaultSettings();
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectSystemReady();
-
- mService.systemReady();
-
- // after systemReady(), we should have historical stats loaded again
- assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
- assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10);
- assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 512L, 4L, 256L, 2L, 4);
- assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 512L, 4L, 256L, 2L, 6);
- assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
-
- }
-
- // TODO: simulate reboot to test bucket resize
- @Test
- @Ignore
- public void testStatsBucketResize() throws Exception {
- NetworkStatsHistory history = null;
-
- assertStatsFilesExist(false);
-
- // pretend that wifi network comes online; service should ask about full
- // network state, and poll any existing interfaces before updating.
- expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
- NetworkState[] states = new NetworkState[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
-
- // modify some number on wifi, and trigger poll event
- incrementCurrentTime(2 * HOUR_IN_MILLIS);
- expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 512L, 4L, 512L, 4L));
- expectNetworkStatsUidDetail(buildEmptyStats());
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- history = mSession.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
- assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
- assertEquals(HOUR_IN_MILLIS, history.getBucketDuration());
- assertEquals(2, history.size());
-
-
- // now change bucket duration setting and trigger another poll with
- // exact same values, which should resize existing buckets.
- expectSettings(0L, 30 * MINUTE_IN_MILLIS, WEEK_IN_MILLIS);
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
- forcePollAndWaitForIdle();
-
- // verify identical stats, but spread across 4 buckets now
- history = mSession.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
- assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
- assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration());
- assertEquals(4, history.size());
-
- }
-
- @Test
- public void testUidStatsAcrossNetworks() throws Exception {
- // pretend first mobile network comes online
- expectDefaultSettings();
- NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
-
- // create some traffic on first network
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 2048L, 16L, 512L, 4L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
- mService.incrementOperationCount(UID_RED, 0xF00D, 10);
-
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
- assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
- assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 512L, 4L, 10);
- assertUidTotal(sTemplateImsi1, UID_BLUE, 512L, 4L, 0L, 0L, 0);
-
-
- // now switch networks; this also tests that we're okay with interfaces
- // disappearing, to verify we don't count backwards.
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- states = new NetworkState[] {buildMobile3gState(IMSI_2)};
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 2048L, 16L, 512L, 4L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
-
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
- forcePollAndWaitForIdle();
-
-
- // create traffic on second network
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 2176L, 17L, 1536L, 12L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L));
- mService.incrementOperationCount(UID_BLUE, 0xFAAD, 10);
-
- forcePollAndWaitForIdle();
-
- // verify original history still intact
- assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
- assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 512L, 4L, 10);
- assertUidTotal(sTemplateImsi1, UID_BLUE, 512L, 4L, 0L, 0L, 0);
-
- // and verify new history also recorded under different template, which
- // verifies that we didn't cross the streams.
- assertNetworkTotal(sTemplateImsi2, 128L, 1L, 1024L, 8L, 0);
- assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
- assertUidTotal(sTemplateImsi2, UID_BLUE, 128L, 1L, 1024L, 8L, 10);
-
- }
-
- @Test
- public void testUidRemovedIsMoved() throws Exception {
- // pretend that network comes online
- expectDefaultSettings();
- NetworkState[] states = new NetworkState[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
-
- // create some traffic
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 4128L, 258L, 544L, 34L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE,
- 4096L, 258L, 512L, 32L, 0L)
- .insertEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
- mService.incrementOperationCount(UID_RED, 0xFAAD, 10);
-
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertNetworkTotal(sTemplateWifi, 4128L, 258L, 544L, 34L, 0);
- assertUidTotal(sTemplateWifi, UID_RED, 16L, 1L, 16L, 1L, 10);
- assertUidTotal(sTemplateWifi, UID_BLUE, 4096L, 258L, 512L, 32L, 0);
- assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 1L, 16L, 1L, 0);
-
-
- // now pretend two UIDs are uninstalled, which should migrate stats to
- // special "removed" bucket.
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 4128L, 258L, 544L, 34L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE,
- 4096L, 258L, 512L, 32L, 0L)
- .insertEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
- final Intent intent = new Intent(ACTION_UID_REMOVED);
- intent.putExtra(EXTRA_UID, UID_BLUE);
- mServiceContext.sendBroadcast(intent);
- intent.putExtra(EXTRA_UID, UID_RED);
- mServiceContext.sendBroadcast(intent);
-
- // existing uid and total should remain unchanged; but removed UID
- // should be gone completely.
- assertNetworkTotal(sTemplateWifi, 4128L, 258L, 544L, 34L, 0);
- assertUidTotal(sTemplateWifi, UID_RED, 0L, 0L, 0L, 0L, 0);
- assertUidTotal(sTemplateWifi, UID_BLUE, 0L, 0L, 0L, 0L, 0);
- assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 1L, 16L, 1L, 0);
- assertUidTotal(sTemplateWifi, UID_REMOVED, 4112L, 259L, 528L, 33L, 10);
-
- }
-
- @Test
- public void testUid3gWimaxCombinedByTemplate() throws Exception {
- // pretend that network comes online
- expectDefaultSettings();
- NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
-
- // create some traffic
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
- mService.incrementOperationCount(UID_RED, 0xF00D, 5);
-
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertUidTotal(sTemplateImsi1, UID_RED, 1024L, 8L, 1024L, 8L, 5);
-
-
- // now switch over to wimax network
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- states = new NetworkState[] {buildWimaxState(TEST_IFACE2)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
-
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
- forcePollAndWaitForIdle();
-
-
- // create traffic on second network
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
- .insertEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
- .insertEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L));
- mService.incrementOperationCount(UID_RED, 0xFAAD, 5);
-
- forcePollAndWaitForIdle();
-
- // verify that ALL_MOBILE template combines both
- assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 1280L, 10L, 10);
- }
-
- @Test
- public void testMobileStatsByRatType() throws Exception {
- final NetworkTemplate template3g =
- buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS);
- final NetworkTemplate template4g =
- buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_LTE);
- final NetworkTemplate template5g =
- buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_NR);
- final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)};
-
- // 3G network comes online.
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
- new VpnInfo[0]);
-
- // Create some traffic.
- incrementCurrentTime(MINUTE_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 12L, 18L, 14L, 1L, 0L)));
- forcePollAndWaitForIdle();
-
- // Verify 3g templates gets stats.
- assertUidTotal(sTemplateImsi1, UID_RED, 12L, 18L, 14L, 1L, 0);
- assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0);
- assertUidTotal(template4g, UID_RED, 0L, 0L, 0L, 0L, 0);
- assertUidTotal(template5g, UID_RED, 0L, 0L, 0L, 0L, 0);
-
- // 4G network comes online.
- incrementCurrentTime(MINUTE_IN_MILLIS);
- setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_LTE);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- // Append more traffic on existing 3g stats entry.
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 16L, 22L, 17L, 2L, 0L))
- // Add entry that is new on 4g.
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
- 33L, 27L, 8L, 10L, 1L)));
- forcePollAndWaitForIdle();
-
- // Verify ALL_MOBILE template gets all. 3g template counters do not increase.
- assertUidTotal(sTemplateImsi1, UID_RED, 49L, 49L, 25L, 12L, 1);
- assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0);
- // Verify 4g template counts appended stats on existing entry and newly created entry.
- assertUidTotal(template4g, UID_RED, 4L + 33L, 4L + 27L, 3L + 8L, 1L + 10L, 1);
- // Verify 5g template doesn't get anything since no traffic is generated on 5g.
- assertUidTotal(template5g, UID_RED, 0L, 0L, 0L, 0L, 0);
-
- // 5g network comes online.
- incrementCurrentTime(MINUTE_IN_MILLIS);
- setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_NR);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- // Existing stats remains.
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 16L, 22L, 17L, 2L, 0L))
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
- 33L, 27L, 8L, 10L, 1L))
- // Add some traffic on 5g.
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 5L, 13L, 31L, 9L, 2L)));
- forcePollAndWaitForIdle();
-
- // Verify ALL_MOBILE template gets all.
- assertUidTotal(sTemplateImsi1, UID_RED, 54L, 62L, 56L, 21L, 3);
- // 3g/4g template counters do not increase.
- assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0);
- assertUidTotal(template4g, UID_RED, 4L + 33L, 4L + 27L, 3L + 8L, 1L + 10L, 1);
- // Verify 5g template gets the 5g count.
- assertUidTotal(template5g, UID_RED, 5L, 13L, 31L, 9L, 2);
- }
-
- // TODO: support per IMSI state
- private void setMobileRatTypeAndWaitForIdle(int ratType) {
- when(mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(anyString()))
- .thenReturn(ratType);
- mService.handleOnCollapsedRatTypeChanged();
- HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
- }
-
- @Test
- public void testSummaryForAllUid() throws Exception {
- // pretend that network comes online
- expectDefaultSettings();
- NetworkState[] states = new NetworkState[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
-
- // create some traffic for two apps
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L));
- mService.incrementOperationCount(UID_RED, 0xF00D, 1);
-
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertUidTotal(sTemplateWifi, UID_RED, 50L, 5L, 50L, 5L, 1);
- assertUidTotal(sTemplateWifi, UID_BLUE, 1024L, 8L, 512L, 4L, 0);
-
-
- // now create more traffic in next hour, but only for one app
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE,
- 2048L, 16L, 1024L, 8L, 0L));
- forcePollAndWaitForIdle();
-
- // first verify entire history present
- NetworkStats stats = mSession.getSummaryForAllUid(
- sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
- assertEquals(3, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 50L, 5L, 50L, 5L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 10L, 1L, 10L, 1L, 1);
- assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 2048L, 16L, 1024L, 8L, 0);
-
- // now verify that recent history only contains one uid
- final long currentTime = currentTimeMillis();
- stats = mSession.getSummaryForAllUid(
- sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true);
- assertEquals(1, stats.size());
- assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1024L, 8L, 512L, 4L, 0);
- }
-
- @Test
- public void testDetailedUidStats() throws Exception {
- // pretend that network comes online
- expectDefaultSettings();
- NetworkState[] states = new NetworkState[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
-
- NetworkStats.Entry entry1 = new NetworkStats.Entry(
- TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L);
- NetworkStats.Entry entry2 = new NetworkStats.Entry(
- TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 50L, 5L, 50L, 5L, 0L);
- NetworkStats.Entry entry3 = new NetworkStats.Entry(
- TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xBEEF, 1024L, 8L, 512L, 4L, 0L);
-
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
- .insertEntry(entry1)
- .insertEntry(entry2)
- .insertEntry(entry3));
- mService.incrementOperationCount(UID_RED, 0xF00D, 1);
-
- NetworkStats stats = mService.getDetailedUidStats(INTERFACES_ALL);
-
- assertEquals(3, stats.size());
- entry1.operations = 1;
- assertEquals(entry1, stats.getValues(0, null));
- entry2.operations = 1;
- assertEquals(entry2, stats.getValues(1, null));
- assertEquals(entry3, stats.getValues(2, null));
- }
-
- @Test
- public void testDetailedUidStats_Filtered() throws Exception {
- // pretend that network comes online
- expectDefaultSettings();
-
- final String stackedIface = "stacked-test0";
- final LinkProperties stackedProp = new LinkProperties();
- stackedProp.setInterfaceName(stackedIface);
- final NetworkState wifiState = buildWifiState();
- wifiState.linkProperties.addStackedLink(stackedProp);
- NetworkState[] states = new NetworkState[] {wifiState};
-
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
-
- NetworkStats.Entry uidStats = new NetworkStats.Entry(
- TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
- // Stacked on matching interface
- NetworkStats.Entry tetheredStats1 = new NetworkStats.Entry(
- stackedIface, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
- // Different interface
- NetworkStats.Entry tetheredStats2 = new NetworkStats.Entry(
- "otherif", UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
-
- final String[] ifaceFilter = new String[] { TEST_IFACE };
- final String[] augmentedIfaceFilter = new String[] { stackedIface, TEST_IFACE };
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- when(mStatsFactory.augmentWithStackedInterfaces(eq(ifaceFilter)))
- .thenReturn(augmentedIfaceFilter);
- when(mStatsFactory.readNetworkStatsDetail(eq(UID_ALL), any(), eq(TAG_ALL)))
- .thenReturn(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(uidStats));
- when(mNetManager.getNetworkStatsTethering(STATS_PER_UID))
- .thenReturn(new NetworkStats(getElapsedRealtime(), 2)
- .insertEntry(tetheredStats1)
- .insertEntry(tetheredStats2));
-
- NetworkStats stats = mService.getDetailedUidStats(ifaceFilter);
-
- // mStatsFactory#readNetworkStatsDetail() has the following invocations:
- // 1) NetworkStatsService#systemReady from #setUp.
- // 2) mService#forceUpdateIfaces in the test above.
- //
- // Additionally, we should have one call from the above call to mService#getDetailedUidStats
- // with the augmented ifaceFilter.
- verify(mStatsFactory, times(2)).readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL);
- verify(mStatsFactory, times(1)).readNetworkStatsDetail(
- eq(UID_ALL),
- eq(augmentedIfaceFilter),
- eq(TAG_ALL));
- assertTrue(ArrayUtils.contains(stats.getUniqueIfaces(), TEST_IFACE));
- assertTrue(ArrayUtils.contains(stats.getUniqueIfaces(), stackedIface));
- assertEquals(2, stats.size());
- assertEquals(uidStats, stats.getValues(0, null));
- assertEquals(tetheredStats1, stats.getValues(1, null));
- }
-
- @Test
- public void testForegroundBackground() throws Exception {
- // pretend that network comes online
- expectDefaultSettings();
- NetworkState[] states = new NetworkState[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
-
- // create some initial traffic
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L));
- mService.incrementOperationCount(UID_RED, 0xF00D, 1);
-
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1);
-
-
- // now switch to foreground
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L));
- mService.setUidForeground(UID_RED, true);
- mService.incrementOperationCount(UID_RED, 0xFAAD, 1);
-
- forcePollAndWaitForIdle();
-
- // test that we combined correctly
- assertUidTotal(sTemplateWifi, UID_RED, 160L, 4L, 160L, 4L, 2);
-
- // verify entire history present
- final NetworkStats stats = mSession.getSummaryForAllUid(
- sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
- assertEquals(4, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 32L, 2L, 32L, 2L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1L, 1L, 1L, 1L, 1);
- }
-
- @Test
- public void testMetered() throws Exception {
- // pretend that network comes online
- expectDefaultSettings();
- NetworkState[] states = new NetworkState[] {buildWifiState(true /* isMetered */)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
-
- // create some initial traffic
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- // Note that all traffic from NetworkManagementService is tagged as METERED_NO, ROAMING_NO
- // and DEFAULT_NETWORK_YES, because these three properties aren't tracked at that layer.
- // We layer them on top by inspecting the iface properties.
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0L));
- mService.incrementOperationCount(UID_RED, 0xF00D, 1);
-
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1);
- // verify entire history present
- final NetworkStats stats = mSession.getSummaryForAllUid(
- sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
- assertEquals(2, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 1);
- }
-
- @Test
- public void testRoaming() throws Exception {
- // pretend that network comes online
- expectDefaultSettings();
- NetworkState[] states =
- new NetworkState[] {buildMobile3gState(IMSI_1, true /* isRoaming */)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
-
- // Create some traffic
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- // Note that all traffic from NetworkManagementService is tagged as METERED_NO and
- // ROAMING_NO, because metered and roaming isn't tracked at that layer. We layer it
- // on top by inspecting the iface properties.
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0L));
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
-
- // verify entire history present
- final NetworkStats stats = mSession.getSummaryForAllUid(
- sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
- assertEquals(2, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_YES,
- DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_YES,
- DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0);
- }
-
- @Test
- public void testTethering() throws Exception {
- // pretend first mobile network comes online
- expectDefaultSettings();
- NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
-
- // create some tethering traffic
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
-
- // Traffic seen by kernel counters (includes software tethering).
- final NetworkStats ifaceStats = new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 1536L, 12L, 384L, 3L);
- // Hardware tethering traffic, not seen by kernel counters.
- final NetworkStats tetherStatsHardware = new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 512L, 4L, 128L, 1L);
-
- // Traffic for UID_RED.
- final NetworkStats uidStats = new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L);
- // All tethering traffic, both hardware and software.
- final NetworkStats tetherStats = new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L,
- 0L);
-
- expectNetworkStatsSummary(ifaceStats, tetherStatsHardware);
- expectNetworkStatsUidDetail(uidStats, tetherStats);
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
- assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
- assertUidTotal(sTemplateImsi1, UID_TETHERING, 1920L, 14L, 384L, 2L, 0);
- }
-
- @Test
- public void testRegisterUsageCallback() throws Exception {
- // pretend that wifi network comes online; service should ask about full
- // network state, and poll any existing interfaces before updating.
- expectDefaultSettings();
- NetworkState[] states = new NetworkState[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
-
- // verify service has empty history for wifi
- assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
- long thresholdInBytes = 1L; // very small; should be overriden by framework
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, thresholdInBytes);
-
- // Create a messenger that waits for callback activity
- ConditionVariable cv = new ConditionVariable(false);
- LatchedHandler latchedHandler = new LatchedHandler(Looper.getMainLooper(), cv);
- Messenger messenger = new Messenger(latchedHandler);
-
- // Force poll
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- // Register and verify request and that binder was called
- DataUsageRequest request =
- mService.registerUsageCallback(mServiceContext.getOpPackageName(), inputRequest,
- messenger, mBinder);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateWifi, request.template));
- long minThresholdInBytes = 2 * 1024 * 1024; // 2 MB
- assertEquals(minThresholdInBytes, request.thresholdInBytes);
-
- HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
-
- // Make sure that the caller binder gets connected
- verify(mBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
-
- // modify some number on wifi, and trigger poll event
- // not enough traffic to call data usage callback
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 1024L, 1L, 2048L, 2L));
- expectNetworkStatsUidDetail(buildEmptyStats());
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0);
-
- // make sure callback has not being called
- assertEquals(INVALID_TYPE, latchedHandler.lastMessageType);
-
- // and bump forward again, with counters going higher. this is
- // important, since it will trigger the data usage callback
- incrementCurrentTime(DAY_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 4096000L, 4L, 8192000L, 8L));
- expectNetworkStatsUidDetail(buildEmptyStats());
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertNetworkTotal(sTemplateWifi, 4096000L, 4L, 8192000L, 8L, 0);
-
-
- // Wait for the caller to ack receipt of CALLBACK_LIMIT_REACHED
- assertTrue(cv.block(WAIT_TIMEOUT));
- assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, latchedHandler.lastMessageType);
- cv.close();
-
- // Allow binder to disconnect
- when(mBinder.unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt())).thenReturn(true);
-
- // Unregister request
- mService.unregisterUsageRequest(request);
-
- // Wait for the caller to ack receipt of CALLBACK_RELEASED
- assertTrue(cv.block(WAIT_TIMEOUT));
- assertEquals(NetworkStatsManager.CALLBACK_RELEASED, latchedHandler.lastMessageType);
-
- // Make sure that the caller binder gets disconnected
- verify(mBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
- }
-
- @Test
- public void testUnregisterUsageCallback_unknown_noop() throws Exception {
- String callingPackage = "the.calling.package";
- long thresholdInBytes = 10 * 1024 * 1024; // 10 MB
- DataUsageRequest unknownRequest = new DataUsageRequest(
- 2 /* requestId */, sTemplateImsi1, thresholdInBytes);
-
- mService.unregisterUsageRequest(unknownRequest);
- }
-
- @Test
- public void testStatsProviderUpdateStats() throws Exception {
- // Pretend that network comes online.
- expectDefaultSettings();
- final NetworkState[] states = new NetworkState[]{buildWifiState(true /* isMetered */)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- // Register custom provider and retrieve callback.
- final TestableNetworkStatsProviderBinder provider =
- new TestableNetworkStatsProviderBinder();
- final INetworkStatsProviderCallback cb =
- mService.registerNetworkStatsProvider("TEST", provider);
- assertNotNull(cb);
-
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
-
- // Verifies that one requestStatsUpdate will be called during iface update.
- provider.expectOnRequestStatsUpdate(0 /* unused */);
-
- // Create some initial traffic and report to the service.
- incrementCurrentTime(HOUR_IN_MILLIS);
- final NetworkStats expectedStats = new NetworkStats(0L, 1)
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT,
- TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
- 128L, 2L, 128L, 2L, 1L))
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT,
- 0xF00D, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
- 64L, 1L, 64L, 1L, 1L));
- cb.notifyStatsUpdated(0 /* unused */, expectedStats, expectedStats);
-
- // Make another empty mutable stats object. This is necessary since the new NetworkStats
- // object will be used to compare with the old one in NetworkStatsRecoder, two of them
- // cannot be the same object.
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- forcePollAndWaitForIdle();
-
- // Verifies that one requestStatsUpdate and setAlert will be called during polling.
- provider.expectOnRequestStatsUpdate(0 /* unused */);
- provider.expectOnSetAlert(MB_IN_BYTES);
-
- // Verifies that service recorded history, does not verify uid tag part.
- assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1);
-
- // Verifies that onStatsUpdated updates the stats accordingly.
- final NetworkStats stats = mSession.getSummaryForAllUid(
- sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
- assertEquals(2, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 1L);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 1L);
-
- // Verifies that unregister the callback will remove the provider from service.
- cb.unregister();
- forcePollAndWaitForIdle();
- provider.assertNoCallback();
- }
-
- @Test
- public void testStatsProviderSetAlert() throws Exception {
- // Pretend that network comes online.
- expectDefaultSettings();
- NetworkState[] states = new NetworkState[]{buildWifiState(true /* isMetered */)};
- mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
-
- // Register custom provider and retrieve callback.
- final TestableNetworkStatsProviderBinder provider =
- new TestableNetworkStatsProviderBinder();
- final INetworkStatsProviderCallback cb =
- mService.registerNetworkStatsProvider("TEST", provider);
- assertNotNull(cb);
-
- // Simulates alert quota of the provider has been reached.
- cb.notifyAlertReached();
- HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
-
- // Verifies that polling is triggered by alert reached.
- provider.expectOnRequestStatsUpdate(0 /* unused */);
- // Verifies that global alert will be re-armed.
- provider.expectOnSetAlert(MB_IN_BYTES);
- }
-
- private static File getBaseDir(File statsDir) {
- File baseDir = new File(statsDir, "netstats");
- baseDir.mkdirs();
- return baseDir;
- }
-
- private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long rxPackets,
- long txBytes, long txPackets, int operations) throws Exception {
- assertNetworkTotal(template, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
- txPackets, operations);
- }
-
- private void assertNetworkTotal(NetworkTemplate template, long start, long end, long rxBytes,
- long rxPackets, long txBytes, long txPackets, int operations) throws Exception {
- // verify history API
- final NetworkStatsHistory history = mSession.getHistoryForNetwork(template, FIELD_ALL);
- assertValues(history, start, end, rxBytes, rxPackets, txBytes, txPackets, operations);
-
- // verify summary API
- final NetworkStats stats = mSession.getSummaryForNetwork(template, start, end);
- assertValues(stats, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, rxBytes, rxPackets, txBytes, txPackets, operations);
- }
-
- private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long rxPackets,
- long txBytes, long txPackets, int operations) throws Exception {
- assertUidTotal(template, uid, SET_ALL, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
- rxBytes, rxPackets, txBytes, txPackets, operations);
- }
-
- private void assertUidTotal(NetworkTemplate template, int uid, int set, int metered,
- int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes,
- long txPackets, int operations) throws Exception {
- // verify history API
- final NetworkStatsHistory history = mSession.getHistoryForUid(
- template, uid, set, TAG_NONE, FIELD_ALL);
- assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
- txPackets, operations);
-
- // verify summary API
- final NetworkStats stats = mSession.getSummaryForAllUid(
- template, Long.MIN_VALUE, Long.MAX_VALUE, false);
- assertValues(stats, IFACE_ALL, uid, set, TAG_NONE, metered, roaming, defaultNetwork,
- rxBytes, rxPackets, txBytes, txPackets, operations);
- }
-
- private void expectSystemReady() throws Exception {
- expectNetworkStatsSummary(buildEmptyStats());
- }
-
- private String getActiveIface(NetworkState... states) throws Exception {
- if (states == null || states.length == 0 || states[0].linkProperties == null) {
- return null;
- }
- return states[0].linkProperties.getInterfaceName();
- }
-
- private void expectNetworkStatsSummary(NetworkStats summary) throws Exception {
- expectNetworkStatsSummary(summary, new NetworkStats(0L, 0));
- }
-
- private void expectNetworkStatsSummary(NetworkStats summary, NetworkStats tetherStats)
- throws Exception {
- expectNetworkStatsTethering(STATS_PER_IFACE, tetherStats);
- expectNetworkStatsSummaryDev(summary.clone());
- expectNetworkStatsSummaryXt(summary.clone());
- }
-
- private void expectNetworkStatsSummaryDev(NetworkStats summary) throws Exception {
- when(mStatsFactory.readNetworkStatsSummaryDev()).thenReturn(summary);
- }
-
- private void expectNetworkStatsSummaryXt(NetworkStats summary) throws Exception {
- when(mStatsFactory.readNetworkStatsSummaryXt()).thenReturn(summary);
- }
-
- private void expectNetworkStatsTethering(int how, NetworkStats stats)
- throws Exception {
- when(mNetManager.getNetworkStatsTethering(how)).thenReturn(stats);
- }
-
- private void expectNetworkStatsUidDetail(NetworkStats detail) throws Exception {
- expectNetworkStatsUidDetail(detail, new NetworkStats(0L, 0));
- }
-
- private void expectNetworkStatsUidDetail(NetworkStats detail, NetworkStats tetherStats)
- throws Exception {
- when(mStatsFactory.readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL))
- .thenReturn(detail);
-
- // also include tethering details, since they are folded into UID
- when(mNetManager.getNetworkStatsTethering(STATS_PER_UID)).thenReturn(tetherStats);
- }
-
- private void expectDefaultSettings() throws Exception {
- expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
- }
-
- private void expectSettings(long persistBytes, long bucketDuration, long deleteAge)
- throws Exception {
- when(mSettings.getPollInterval()).thenReturn(HOUR_IN_MILLIS);
- when(mSettings.getPollDelay()).thenReturn(0L);
- when(mSettings.getSampleEnabled()).thenReturn(true);
- when(mSettings.getCombineSubtypeEnabled()).thenReturn(false);
-
- final Config config = new Config(bucketDuration, deleteAge, deleteAge);
- when(mSettings.getDevConfig()).thenReturn(config);
- when(mSettings.getXtConfig()).thenReturn(config);
- when(mSettings.getUidConfig()).thenReturn(config);
- when(mSettings.getUidTagConfig()).thenReturn(config);
-
- when(mSettings.getGlobalAlertBytes(anyLong())).thenReturn(MB_IN_BYTES);
- when(mSettings.getDevPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
- when(mSettings.getXtPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
- when(mSettings.getUidPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
- when(mSettings.getUidTagPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
- }
-
- private void assertStatsFilesExist(boolean exist) {
- final File basePath = new File(mStatsDir, "netstats");
- if (exist) {
- assertTrue(basePath.list().length > 0);
- } else {
- assertTrue(basePath.list().length == 0);
- }
- }
-
- private static void assertValues(NetworkStatsHistory stats, long start, long end, long rxBytes,
- long rxPackets, long txBytes, long txPackets, int operations) {
- final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- assertEquals("unexpected txPackets", txPackets, entry.txPackets);
- assertEquals("unexpected operations", operations, entry.operations);
- }
-
- private static NetworkState buildWifiState() {
- return buildWifiState(false);
- }
-
- private static NetworkState buildWifiState(boolean isMetered) {
- final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
- info.setDetailedState(DetailedState.CONNECTED, null, null);
- final LinkProperties prop = new LinkProperties();
- prop.setInterfaceName(TEST_IFACE);
- final NetworkCapabilities capabilities = new NetworkCapabilities();
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, !isMetered);
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
- capabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- return new NetworkState(info, prop, capabilities, WIFI_NETWORK, null, TEST_SSID);
- }
-
- private static NetworkState buildMobile3gState(String subscriberId) {
- return buildMobile3gState(subscriberId, false /* isRoaming */);
- }
-
- private static NetworkState buildMobile3gState(String subscriberId, boolean isRoaming) {
- final NetworkInfo info = new NetworkInfo(
- TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UMTS, null, null);
- info.setDetailedState(DetailedState.CONNECTED, null, null);
- info.setRoaming(isRoaming);
- final LinkProperties prop = new LinkProperties();
- prop.setInterfaceName(TEST_IFACE);
- final NetworkCapabilities capabilities = new NetworkCapabilities();
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
- capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
- return new NetworkState(info, prop, capabilities, MOBILE_NETWORK, subscriberId, null);
- }
-
- private static NetworkState buildWimaxState(@NonNull String iface) {
- final NetworkInfo info = new NetworkInfo(TYPE_WIMAX, 0, null, null);
- info.setDetailedState(DetailedState.CONNECTED, null, null);
- final LinkProperties prop = new LinkProperties();
- prop.setInterfaceName(iface);
- final NetworkCapabilities capabilities = new NetworkCapabilities();
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
- return new NetworkState(info, prop, capabilities, MOBILE_NETWORK, null, null);
- }
-
- private NetworkStats buildEmptyStats() {
- return new NetworkStats(getElapsedRealtime(), 0);
- }
-
- private static NetworkState buildVpnState() {
- final NetworkInfo info = new NetworkInfo(TYPE_VPN, 0, null, null);
- info.setDetailedState(DetailedState.CONNECTED, null, null);
- final LinkProperties prop = new LinkProperties();
- prop.setInterfaceName(TUN_IFACE);
- return new NetworkState(info, prop, new NetworkCapabilities(), VPN_NETWORK, null, null);
- }
-
- private long getElapsedRealtime() {
- return mElapsedRealtime;
- }
-
- private long startTimeMillis() {
- return TEST_START;
- }
-
- private long currentTimeMillis() {
- return startTimeMillis() + mElapsedRealtime;
- }
-
- private void incrementCurrentTime(long duration) {
- mElapsedRealtime += duration;
- }
-
- private void forcePollAndWaitForIdle() {
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
- HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
- }
-
- static class LatchedHandler extends Handler {
- private final ConditionVariable mCv;
- int lastMessageType = INVALID_TYPE;
-
- LatchedHandler(Looper looper, ConditionVariable cv) {
- super(looper);
- mCv = cv;
- }
-
- @Override
- public void handleMessage(Message msg) {
- lastMessageType = msg.what;
- mCv.open();
- super.handleMessage(msg);
- }
- }
-}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
deleted file mode 100644
index 7726c6637e0a..000000000000
--- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.net.NetworkTemplate;
-import android.os.Looper;
-import android.telephony.NetworkRegistrationInfo;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.util.CollectionUtils;
-import com.android.server.net.NetworkStatsSubscriptionsMonitor.Delegate;
-import com.android.server.net.NetworkStatsSubscriptionsMonitor.RatTypeListener;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-
-@RunWith(JUnit4.class)
-public final class NetworkStatsSubscriptionsMonitorTest {
- private static final int TEST_SUBID1 = 3;
- private static final int TEST_SUBID2 = 5;
- private static final String TEST_IMSI1 = "466921234567890";
- private static final String TEST_IMSI2 = "466920987654321";
- private static final String TEST_IMSI3 = "466929999999999";
-
- @Mock private Context mContext;
- @Mock private SubscriptionManager mSubscriptionManager;
- @Mock private TelephonyManager mTelephonyManager;
- @Mock private Delegate mDelegate;
- private final List<Integer> mTestSubList = new ArrayList<>();
-
- private final Executor mExecutor = Executors.newSingleThreadExecutor();
- private NetworkStatsSubscriptionsMonitor mMonitor;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
-
- when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
-
- when(mContext.getSystemService(eq(Context.TELEPHONY_SUBSCRIPTION_SERVICE)))
- .thenReturn(mSubscriptionManager);
- when(mContext.getSystemService(eq(Context.TELEPHONY_SERVICE)))
- .thenReturn(mTelephonyManager);
-
- mMonitor = new NetworkStatsSubscriptionsMonitor(mContext, mExecutor, mDelegate);
- }
-
- @Test
- public void testStartStop() {
- // Verify that addOnSubscriptionsChangedListener() is never called before start().
- verify(mSubscriptionManager, never())
- .addOnSubscriptionsChangedListener(mExecutor, mMonitor);
- mMonitor.start();
- verify(mSubscriptionManager).addOnSubscriptionsChangedListener(mExecutor, mMonitor);
-
- // Verify that removeOnSubscriptionsChangedListener() is never called before stop()
- verify(mSubscriptionManager, never()).removeOnSubscriptionsChangedListener(mMonitor);
- mMonitor.stop();
- verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(mMonitor);
- }
-
- @NonNull
- private static int[] convertArrayListToIntArray(@NonNull List<Integer> arrayList) {
- final int[] list = new int[arrayList.size()];
- for (int i = 0; i < arrayList.size(); i++) {
- list[i] = arrayList.get(i);
- }
- return list;
- }
-
- private void setRatTypeForSub(List<RatTypeListener> listeners,
- int subId, int type) {
- final ServiceState serviceState = mock(ServiceState.class);
- when(serviceState.getDataNetworkType()).thenReturn(type);
- final RatTypeListener match = CollectionUtils
- .find(listeners, it -> it.getSubId() == subId);
- if (match != null) {
- match.onServiceStateChanged(serviceState);
- }
- }
-
- private void addTestSub(int subId, String subscriberId) {
- // add SubId to TestSubList.
- if (!mTestSubList.contains(subId)) {
- mTestSubList.add(subId);
- }
- final int[] subList = convertArrayListToIntArray(mTestSubList);
- when(mSubscriptionManager.getCompleteActiveSubscriptionIdList()).thenReturn(subList);
- when(mTelephonyManager.getSubscriberId(subId)).thenReturn(subscriberId);
- mMonitor.onSubscriptionsChanged();
- }
-
- private void updateSubscriberIdForTestSub(int subId, @Nullable final String subscriberId) {
- when(mTelephonyManager.getSubscriberId(subId)).thenReturn(subscriberId);
- mMonitor.onSubscriptionsChanged();
- }
-
- private void removeTestSub(int subId) {
- // Remove subId from TestSubList.
- mTestSubList.removeIf(it -> it == subId);
- final int[] subList = convertArrayListToIntArray(mTestSubList);
- when(mSubscriptionManager.getCompleteActiveSubscriptionIdList()).thenReturn(subList);
- mMonitor.onSubscriptionsChanged();
- }
-
- private void assertRatTypeChangedForSub(String subscriberId, int ratType) {
- assertEquals(mMonitor.getRatTypeForSubscriberId(subscriberId), ratType);
- final ArgumentCaptor<Integer> typeCaptor = ArgumentCaptor.forClass(Integer.class);
- // Verify callback with the subscriberId and the RAT type should be as expected.
- // It will fail if get a callback with an unexpected RAT type.
- verify(mDelegate).onCollapsedRatTypeChanged(eq(subscriberId), typeCaptor.capture());
- final int type = typeCaptor.getValue();
- assertEquals(ratType, type);
- }
-
- private void assertRatTypeNotChangedForSub(String subscriberId, int ratType) {
- assertEquals(mMonitor.getRatTypeForSubscriberId(subscriberId), ratType);
- // Should never get callback with any RAT type.
- verify(mDelegate, never()).onCollapsedRatTypeChanged(eq(subscriberId), anyInt());
- }
-
- @Test
- public void testSubChangedAndRatTypeChanged() {
- final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
- ArgumentCaptor.forClass(RatTypeListener.class);
-
- mMonitor.start();
- // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback
- // before changing RAT type.
- addTestSub(TEST_SUBID1, TEST_IMSI1);
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
-
- // Insert sim2.
- addTestSub(TEST_SUBID2, TEST_IMSI2);
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- verify(mTelephonyManager, times(2)).listen(ratTypeListenerCaptor.capture(),
- eq(PhoneStateListener.LISTEN_SERVICE_STATE));
- reset(mDelegate);
-
- // Set RAT type of sim1 to UMTS.
- // Verify RAT type of sim1 after subscription gets onCollapsedRatTypeChanged() callback
- // and others remain untouched.
- setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
- TelephonyManager.NETWORK_TYPE_UMTS);
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
- assertRatTypeNotChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- assertRatTypeNotChangedForSub(TEST_IMSI3, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- reset(mDelegate);
-
- // Set RAT type of sim2 to LTE.
- // Verify RAT type of sim2 after subscription gets onCollapsedRatTypeChanged() callback
- // and others remain untouched.
- setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID2,
- TelephonyManager.NETWORK_TYPE_LTE);
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
- assertRatTypeChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_LTE);
- assertRatTypeNotChangedForSub(TEST_IMSI3, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- reset(mDelegate);
-
- // Remove sim2 and verify that callbacks are fired and RAT type is correct for sim2.
- // while the other two remain untouched.
- removeTestSub(TEST_SUBID2);
- verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_NONE));
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
- assertRatTypeChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- assertRatTypeNotChangedForSub(TEST_IMSI3, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- reset(mDelegate);
-
- // Set RAT type of sim1 to UNKNOWN. Then stop monitoring subscription changes
- // and verify that the listener for sim1 is removed.
- setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
- TelephonyManager.NETWORK_TYPE_UNKNOWN);
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- reset(mDelegate);
-
- mMonitor.stop();
- verify(mTelephonyManager, times(2)).listen(any(), eq(PhoneStateListener.LISTEN_NONE));
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- }
-
-
- @Test
- public void test5g() {
- mMonitor.start();
- // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback
- // before changing RAT type. Also capture listener for later use.
- addTestSub(TEST_SUBID1, TEST_IMSI1);
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
- ArgumentCaptor.forClass(RatTypeListener.class);
- verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(),
- eq(PhoneStateListener.LISTEN_SERVICE_STATE));
- final RatTypeListener listener = CollectionUtils
- .find(ratTypeListenerCaptor.getAllValues(), it -> it.getSubId() == TEST_SUBID1);
- assertNotNull(listener);
-
- // Set RAT type to 5G NSA (non-standalone) mode, verify the monitor outputs
- // NETWORK_TYPE_5G_NSA.
- final ServiceState serviceState = mock(ServiceState.class);
- when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_LTE);
- when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED);
- listener.onServiceStateChanged(serviceState);
- assertRatTypeChangedForSub(TEST_IMSI1, NetworkTemplate.NETWORK_TYPE_5G_NSA);
- reset(mDelegate);
-
- // Set RAT type to LTE without NR connected, the RAT type should be downgraded to LTE.
- when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_NONE);
- listener.onServiceStateChanged(serviceState);
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE);
- reset(mDelegate);
-
- // Verify NR connected with other RAT type does not take effect.
- when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_UMTS);
- when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED);
- listener.onServiceStateChanged(serviceState);
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
- reset(mDelegate);
-
- // Set RAT type to 5G standalone mode, the RAT type should be NR.
- setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
- TelephonyManager.NETWORK_TYPE_NR);
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR);
- reset(mDelegate);
-
- // Set NR state to none in standalone mode does not change anything.
- when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_NR);
- when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_NONE);
- listener.onServiceStateChanged(serviceState);
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR);
- }
-
- @Test
- public void testSubscriberIdUnavailable() {
- final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
- ArgumentCaptor.forClass(RatTypeListener.class);
-
- mMonitor.start();
- // Insert sim1, set subscriberId to null which is normal in SIM PIN locked case.
- // Verify RAT type is NETWORK_TYPE_UNKNOWN and service will not perform listener
- // registration.
- addTestSub(TEST_SUBID1, null);
- verify(mTelephonyManager, never()).listen(any(), anyInt());
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
-
- // Set IMSI for sim1, verify the listener will be registered.
- updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI1);
- verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(),
- eq(PhoneStateListener.LISTEN_SERVICE_STATE));
- reset(mTelephonyManager);
- when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
-
- // Set RAT type of sim1 to UMTS. Verify RAT type of sim1 is changed.
- setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
- TelephonyManager.NETWORK_TYPE_UMTS);
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
- reset(mDelegate);
-
- // Set IMSI to null again to simulate somehow IMSI is not available, such as
- // modem crash. Verify service should not unregister listener.
- updateSubscriberIdForTestSub(TEST_SUBID1, null);
- verify(mTelephonyManager, never()).listen(any(), anyInt());
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
- reset(mDelegate);
-
- // Set RAT type of sim1 to LTE. Verify RAT type of sim1 is still changed even if the IMSI
- // is not available. The monitor keeps the listener even if the IMSI disappears because
- // the IMSI can never change for any given subId, therefore even if the IMSI is updated
- // to null, the monitor should continue accepting updates of the RAT type. However,
- // telephony is never actually supposed to do this, if the IMSI disappears there should
- // not be updates, but it's still the right thing to do theoretically.
- setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
- TelephonyManager.NETWORK_TYPE_LTE);
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE);
- reset(mDelegate);
-
- mMonitor.stop();
- verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()),
- eq(PhoneStateListener.LISTEN_NONE));
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- }
-}
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
deleted file mode 100644
index fb84611cb662..000000000000
--- a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net.ipmemorystore;
-
-import static org.junit.Assert.assertEquals;
-
-import android.net.ipmemorystore.NetworkAttributes;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.lang.reflect.Field;
-import java.net.Inet4Address;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-
-/** Unit tests for {@link NetworkAttributes}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class NetworkAttributesTest {
- private static final String WEIGHT_FIELD_NAME_PREFIX = "WEIGHT_";
- private static final float EPSILON = 0.0001f;
-
- // This is running two tests to make sure the total weight is the sum of all weights. To be
- // sure this is not fireproof, but you'd kind of need to do it on purpose to pass.
- @Test
- public void testTotalWeight() throws IllegalAccessException, UnknownHostException {
- // Make sure that TOTAL_WEIGHT is equal to the sum of the fields starting with WEIGHT_
- float sum = 0f;
- final Field[] fieldList = NetworkAttributes.class.getDeclaredFields();
- for (final Field field : fieldList) {
- if (!field.getName().startsWith(WEIGHT_FIELD_NAME_PREFIX)) continue;
- field.setAccessible(true);
- sum += (float) field.get(null);
- }
- assertEquals(sum, NetworkAttributes.TOTAL_WEIGHT, EPSILON);
-
- // Use directly the constructor with all attributes, and make sure that when compared
- // to itself the score is a clean 1.0f.
- final NetworkAttributes na =
- new NetworkAttributes(
- (Inet4Address) Inet4Address.getByAddress(new byte[] {1, 2, 3, 4}),
- System.currentTimeMillis() + 7_200_000,
- "some hint",
- Arrays.asList(Inet4Address.getByAddress(new byte[] {5, 6, 7, 8}),
- Inet4Address.getByAddress(new byte[] {9, 0, 1, 2})),
- 98);
- assertEquals(1.0f, na.getNetworkGroupSamenessConfidence(na), EPSILON);
- }
-}
diff --git a/tests/net/jni/Android.bp b/tests/net/jni/Android.bp
deleted file mode 100644
index 9225ffb24bd8..000000000000
--- a/tests/net/jni/Android.bp
+++ /dev/null
@@ -1,23 +0,0 @@
-cc_library_shared {
- name: "libnetworkstatsfactorytestjni",
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-unused-parameter",
- "-Wthread-safety",
- ],
-
- srcs: [
- ":lib_networkStatsFactory_native",
- "test_onload.cpp",
- ],
-
- shared_libs: [
- "libbpf_android",
- "liblog",
- "libnativehelper",
- "libnetdbpf",
- "libnetdutils",
- ],
-}
diff --git a/tests/net/jni/test_onload.cpp b/tests/net/jni/test_onload.cpp
deleted file mode 100644
index 5194ddb0d882..000000000000
--- a/tests/net/jni/test_onload.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * this is a mini native libaray for NetworkStatsFactoryTest to run properly. It
- * load all the native method related to NetworkStatsFactory when test run
- */
-#include <nativehelper/JNIHelp.h>
-#include "jni.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
-
-namespace android {
-int register_android_server_net_NetworkStatsFactory(JNIEnv* env);
-};
-
-using namespace android;
-
-extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
-{
- JNIEnv* env = NULL;
- jint result = -1;
-
- if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
- ALOGE("GetEnv failed!");
- return result;
- }
- ALOG_ASSERT(env, "Could not retrieve the env!");
- register_android_server_net_NetworkStatsFactory(env);
- return JNI_VERSION_1_4;
-}
diff --git a/tests/net/res/raw/history_v1 b/tests/net/res/raw/history_v1
deleted file mode 100644
index de79491c032e..000000000000
--- a/tests/net/res/raw/history_v1
+++ /dev/null
Binary files differ
diff --git a/tests/net/res/raw/net_dev_typical b/tests/net/res/raw/net_dev_typical
deleted file mode 100644
index 290bf03eb9b4..000000000000
--- a/tests/net/res/raw/net_dev_typical
+++ /dev/null
@@ -1,8 +0,0 @@
-Inter-| Receive | Transmit
- face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
- lo: 8308 116 0 0 0 0 0 0 8308 116 0 0 0 0 0 0
-rmnet0: 1507570 2205 0 0 0 0 0 0 489339 2237 0 0 0 0 0 0
- ifb0: 52454 151 0 151 0 0 0 0 0 0 0 0 0 0 0 0
- ifb1: 52454 151 0 151 0 0 0 0 0 0 0 0 0 0 0 0
- sit0: 0 0 0 0 0 0 0 0 0 0 148 0 0 0 0 0
-ip6tnl0: 0 0 0 0 0 0 0 0 0 0 151 151 0 0 0 0
diff --git a/tests/net/res/raw/netstats_uid_v4 b/tests/net/res/raw/netstats_uid_v4
deleted file mode 100644
index e75fc1ca5c2e..000000000000
--- a/tests/net/res/raw/netstats_uid_v4
+++ /dev/null
Binary files differ
diff --git a/tests/net/res/raw/netstats_v1 b/tests/net/res/raw/netstats_v1
deleted file mode 100644
index e80860a6b959..000000000000
--- a/tests/net/res/raw/netstats_v1
+++ /dev/null
Binary files differ
diff --git a/tests/net/res/raw/xt_qtaguid_iface_fmt_typical b/tests/net/res/raw/xt_qtaguid_iface_fmt_typical
deleted file mode 100644
index 656d5bb82da4..000000000000
--- a/tests/net/res/raw/xt_qtaguid_iface_fmt_typical
+++ /dev/null
@@ -1,4 +0,0 @@
-ifname total_skb_rx_bytes total_skb_rx_packets total_skb_tx_bytes total_skb_tx_packets
-rmnet2 4968 35 3081 39
-rmnet1 11153922 8051 190226 2468
-rmnet0 6824 16 5692 10
diff --git a/tests/net/res/raw/xt_qtaguid_iface_typical b/tests/net/res/raw/xt_qtaguid_iface_typical
deleted file mode 100644
index 610723aef2f2..000000000000
--- a/tests/net/res/raw/xt_qtaguid_iface_typical
+++ /dev/null
@@ -1,6 +0,0 @@
-rmnet3 1 0 0 0 0 20822 501 1149991 815
-rmnet2 1 0 0 0 0 1594 15 1313 15
-rmnet1 1 0 0 0 0 207398 458 166918 565
-rmnet0 1 0 0 0 0 2112 24 700 10
-test1 1 1 2 3 4 5 6 7 8
-test2 0 1 2 3 4 5 6 7 8
diff --git a/tests/net/res/raw/xt_qtaguid_typical b/tests/net/res/raw/xt_qtaguid_typical
deleted file mode 100644
index c1b0d259955c..000000000000
--- a/tests/net/res/raw/xt_qtaguid_typical
+++ /dev/null
@@ -1,71 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 wlan0 0x0 0 0 18621 96 2898 44 312 6 15897 58 2412 32 312 6 1010 16 1576 22
-3 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-4 wlan0 0x0 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-5 wlan0 0x0 1000 1 1949 13 1078 14 0 0 1600 10 349 3 0 0 600 10 478 4
-6 wlan0 0x0 10005 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-7 wlan0 0x0 10005 1 32081 38 5315 50 32081 38 0 0 0 0 5315 50 0 0 0 0
-8 wlan0 0x0 10011 0 35777 53 5718 57 0 0 0 0 35777 53 0 0 0 0 5718 57
-9 wlan0 0x0 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-10 wlan0 0x0 10014 0 0 0 1098 13 0 0 0 0 0 0 0 0 0 0 1098 13
-11 wlan0 0x0 10014 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-12 wlan0 0x0 10021 0 562386 573 49228 549 0 0 0 0 562386 573 0 0 0 0 49228 549
-13 wlan0 0x0 10021 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-14 wlan0 0x0 10031 0 3425 5 586 6 0 0 0 0 3425 5 0 0 0 0 586 6
-15 wlan0 0x0 10031 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-16 wlan0 0x7fffff0100000000 10021 0 562386 573 49228 549 0 0 0 0 562386 573 0 0 0 0 49228 549
-17 wlan0 0x7fffff0100000000 10021 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-18 wlan0 0x7fffff0100000000 10031 0 3425 5 586 6 0 0 0 0 3425 5 0 0 0 0 586 6
-19 wlan0 0x7fffff0100000000 10031 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-20 rmnet2 0x0 0 0 547 5 118 2 40 1 243 1 264 3 0 0 62 1 56 1
-21 rmnet2 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-22 rmnet2 0x0 10001 0 1125899906842624 5 984 11 632 5 0 0 0 0 984 11 0 0 0 0
-23 rmnet2 0x0 10001 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-24 rmnet1 0x0 0 0 26736 174 7098 130 7210 97 18382 64 1144 13 2932 64 4054 64 112 2
-25 rmnet1 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-26 rmnet1 0x0 1000 0 75774 77 18038 78 75335 72 439 5 0 0 17668 73 370 5 0 0
-27 rmnet1 0x0 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-28 rmnet1 0x0 10007 0 269945 578 111632 586 269945 578 0 0 0 0 111632 586 0 0 0 0
-29 rmnet1 0x0 10007 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-30 rmnet1 0x0 10011 0 1741256 6918 769778 7019 1741256 6918 0 0 0 0 769778 7019 0 0 0 0
-31 rmnet1 0x0 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-32 rmnet1 0x0 10014 0 0 0 786 12 0 0 0 0 0 0 786 12 0 0 0 0
-33 rmnet1 0x0 10014 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-34 rmnet1 0x0 10021 0 433533 1454 393420 1604 433533 1454 0 0 0 0 393420 1604 0 0 0 0
-35 rmnet1 0x0 10021 1 21215 33 10278 33 21215 33 0 0 0 0 10278 33 0 0 0 0
-36 rmnet1 0x0 10036 0 6310 25 3284 29 6310 25 0 0 0 0 3284 29 0 0 0 0
-37 rmnet1 0x0 10036 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-38 rmnet1 0x0 10047 0 34264 47 3936 34 34264 47 0 0 0 0 3936 34 0 0 0 0
-39 rmnet1 0x0 10047 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-40 rmnet1 0x4e7700000000 10011 0 9187 27 4248 33 9187 27 0 0 0 0 4248 33 0 0 0 0
-41 rmnet1 0x4e7700000000 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-42 rmnet1 0x1000000000000000 10007 0 2109 4 791 4 2109 4 0 0 0 0 791 4 0 0 0 0
-43 rmnet1 0x1000000000000000 10007 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-44 rmnet1 0x1000000400000000 10007 0 9811 22 6286 22 9811 22 0 0 0 0 6286 22 0 0 0 0
-45 rmnet1 0x1000000400000000 10007 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-46 rmnet1 0x1010000000000000 10021 0 164833 426 135392 527 164833 426 0 0 0 0 135392 527 0 0 0 0
-47 rmnet1 0x1010000000000000 10021 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-48 rmnet1 0x1144000400000000 10011 0 10112 18 3334 17 10112 18 0 0 0 0 3334 17 0 0 0 0
-49 rmnet1 0x1144000400000000 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-50 rmnet1 0x1244000400000000 10011 0 1300 3 848 2 1300 3 0 0 0 0 848 2 0 0 0 0
-51 rmnet1 0x1244000400000000 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-52 rmnet1 0x3000000000000000 10007 0 10389 14 1521 12 10389 14 0 0 0 0 1521 12 0 0 0 0
-53 rmnet1 0x3000000000000000 10007 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-54 rmnet1 0x3000000400000000 10007 0 238070 380 93938 404 238070 380 0 0 0 0 93938 404 0 0 0 0
-55 rmnet1 0x3000000400000000 10007 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-56 rmnet1 0x3010000000000000 10021 0 219110 578 227423 676 219110 578 0 0 0 0 227423 676 0 0 0 0
-57 rmnet1 0x3010000000000000 10021 1 742 3 1265 3 742 3 0 0 0 0 1265 3 0 0 0 0
-58 rmnet1 0x3020000000000000 10021 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-59 rmnet1 0x3020000000000000 10021 1 20473 30 9013 30 20473 30 0 0 0 0 9013 30 0 0 0 0
-60 rmnet1 0x3144000400000000 10011 0 43963 92 34414 116 43963 92 0 0 0 0 34414 116 0 0 0 0
-61 rmnet1 0x3144000400000000 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-62 rmnet1 0x3244000400000000 10011 0 3486 8 1520 9 3486 8 0 0 0 0 1520 9 0 0 0 0
-63 rmnet1 0x3244000400000000 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-64 rmnet1 0x7fffff0100000000 10021 0 29102 56 8865 60 29102 56 0 0 0 0 8865 60 0 0 0 0
-65 rmnet1 0x7fffff0100000000 10021 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-66 rmnet1 0x7fffff0300000000 1000 0 995 13 14145 14 995 13 0 0 0 0 14145 14 0 0 0 0
-67 rmnet1 0x7fffff0300000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-68 rmnet0 0x0 0 0 4312 49 1288 23 0 0 0 0 4312 49 0 0 0 0 1288 23
-69 rmnet0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-70 rmnet0 0x0 10080 0 22266 30 20976 30 0 0 0 0 22266 30 0 0 0 0 20976 30
-71 rmnet0 0x0 10080 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_incorrect_iface b/tests/net/res/raw/xt_qtaguid_vpn_incorrect_iface
deleted file mode 100644
index fc92715253ed..000000000000
--- a/tests/net/res/raw/xt_qtaguid_vpn_incorrect_iface
+++ /dev/null
@@ -1,3 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test1 0x0 1004 0 1100 100 1100 100 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying b/tests/net/res/raw/xt_qtaguid_vpn_one_underlying
deleted file mode 100644
index 1ef18894b669..000000000000
--- a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying
+++ /dev/null
@@ -1,5 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 2000 200 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test_nss_tun0 0x0 1002 0 1000 100 500 50 0 0 0 0 0 0 0 0 0 0 0 0
-4 test0 0x0 1004 0 3300 300 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-5 test0 0x0 1004 1 0 0 1650 150 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_compression b/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_compression
deleted file mode 100644
index 6d6bf550bbfa..000000000000
--- a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_compression
+++ /dev/null
@@ -1,4 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test_nss_tun0 0x0 1002 0 3000 300 3000 300 0 0 0 0 0 0 0 0 0 0 0 0
-4 test0 0x0 1004 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic b/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic
deleted file mode 100644
index 2c2e5d2555f6..000000000000
--- a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic
+++ /dev/null
@@ -1,6 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 2000 200 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test_nss_tun0 0x0 1002 0 1000 100 500 50 0 0 0 0 0 0 0 0 0 0 0 0
-4 test_nss_tun0 0x0 1004 0 5000 500 6000 600 0 0 0 0 0 0 0 0 0 0 0 0
-5 test0 0x0 1004 0 8800 800 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-6 test0 0x0 1004 1 0 0 8250 750 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn b/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn
deleted file mode 100644
index eb0513b10049..000000000000
--- a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn
+++ /dev/null
@@ -1,9 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 2000 200 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test_nss_tun0 0x0 1002 0 1000 100 500 50 0 0 0 0 0 0 0 0 0 0 0 0
-4 test_nss_tun1 0x0 1001 0 3000 300 700 70 0 0 0 0 0 0 0 0 0 0 0 0
-5 test_nss_tun1 0x0 1002 0 500 50 250 25 0 0 0 0 0 0 0 0 0 0 0 0
-6 test0 0x0 1004 0 3300 300 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-7 test0 0x0 1004 1 0 0 1650 150 0 0 0 0 0 0 0 0 0 0 0 0
-8 test1 0x0 1004 0 3850 350 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-9 test1 0x0 1004 1 0 0 1045 95 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_rewrite_through_self b/tests/net/res/raw/xt_qtaguid_vpn_rewrite_through_self
deleted file mode 100644
index afcdd7199026..000000000000
--- a/tests/net/res/raw/xt_qtaguid_vpn_rewrite_through_self
+++ /dev/null
@@ -1,6 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 2000 200 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test_nss_tun0 0x0 1002 0 1000 100 500 50 0 0 0 0 0 0 0 0 0 0 0 0
-4 test_nss_tun0 0x0 1004 0 0 0 1600 160 0 0 0 0 0 0 0 0 0 0 0 0
-5 test0 0x0 1004 1 0 0 1760 176 0 0 0 0 0 0 0 0 0 0 0 0
-6 test0 0x0 1004 0 3300 300 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_duplication b/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_duplication
deleted file mode 100644
index d7c7eb9f4ae8..000000000000
--- a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_duplication
+++ /dev/null
@@ -1,5 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test_nss_tun0 0x0 1002 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-4 test0 0x0 1004 0 2200 200 2200 200 0 0 0 0 0 0 0 0 0 0 0 0
-5 test1 0x0 1004 0 2200 200 2200 200 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split b/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split
deleted file mode 100644
index 38a3dce4a834..000000000000
--- a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split
+++ /dev/null
@@ -1,4 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 500 50 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test0 0x0 1004 0 330 30 660 60 0 0 0 0 0 0 0 0 0 0 0 0
-4 test1 0x0 1004 0 220 20 440 40 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split_compression b/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split_compression
deleted file mode 100644
index d35244b3b4f2..000000000000
--- a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split_compression
+++ /dev/null
@@ -1,4 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test0 0x0 1004 0 600 60 600 60 0 0 0 0 0 0 0 0 0 0 0 0
-4 test1 0x0 1004 0 200 20 200 20 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_with_clat b/tests/net/res/raw/xt_qtaguid_vpn_with_clat
deleted file mode 100644
index 0d893d515ca2..000000000000
--- a/tests/net/res/raw/xt_qtaguid_vpn_with_clat
+++ /dev/null
@@ -1,8 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 2000 200 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test_nss_tun0 0x0 1002 0 1000 100 500 50 0 0 0 0 0 0 0 0 0 0 0 0
-4 v4-test0 0x0 1004 0 3300 300 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-5 v4-test0 0x0 1004 1 0 0 1650 150 0 0 0 0 0 0 0 0 0 0 0 0
-6 test0 0x0 0 0 9300 300 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-7 test0 0x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-8 test0 0x0 1029 0 0 0 4650 150 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat b/tests/net/res/raw/xt_qtaguid_with_clat
deleted file mode 100644
index f04b32f08332..000000000000
--- a/tests/net/res/raw/xt_qtaguid_with_clat
+++ /dev/null
@@ -1,43 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 v4-wlan0 0x0 0 0 256 5 196 4 256 5 0 0 0 0 196 4 0 0 0 0
-3 v4-wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-4 v4-wlan0 0x0 1000 0 30312 25 1770 27 30236 24 76 1 0 0 1694 26 76 1 0 0
-5 v4-wlan0 0x0 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-6 v4-wlan0 0x0 10060 0 9398432 6717 169412 4235 9398432 6717 0 0 0 0 169412 4235 0 0 0 0
-7 v4-wlan0 0x0 10060 1 1448660 1041 31192 753 1448660 1041 0 0 0 0 31192 753 0 0 0 0
-8 v4-wlan0 0x0 10102 0 9702 16 2870 23 9702 16 0 0 0 0 2870 23 0 0 0 0
-9 v4-wlan0 0x0 10102 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-10 wlan0 0x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-11 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-12 wlan0 0x0 1000 0 6126 13 2013 16 5934 11 192 2 0 0 1821 14 192 2 0 0
-13 wlan0 0x0 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-14 wlan0 0x0 10013 0 0 0 144 2 0 0 0 0 0 0 144 2 0 0 0 0
-15 wlan0 0x0 10013 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-16 wlan0 0x0 10018 0 5980263 4715 167667 1922 5972583 4709 0 0 7680 6 167667 1922 0 0 0 0
-17 wlan0 0x0 10018 1 43995 37 2766 27 43995 37 0 0 0 0 2766 27 0 0 0 0
-18 wlan0 0x0 10060 0 134356 133 8705 74 134356 133 0 0 0 0 8705 74 0 0 0 0
-19 wlan0 0x0 10060 1 294709 326 26448 256 294709 326 0 0 0 0 26448 256 0 0 0 0
-20 wlan0 0x0 10079 0 10926 13 1507 13 10926 13 0 0 0 0 1507 13 0 0 0 0
-21 wlan0 0x0 10079 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-22 wlan0 0x0 10102 0 25038 42 8245 57 25038 42 0 0 0 0 8245 57 0 0 0 0
-23 wlan0 0x0 10102 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-24 wlan0 0x0 10103 0 0 0 192 2 0 0 0 0 0 0 0 0 192 2 0 0
-25 wlan0 0x0 10103 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-26 wlan0 0x1000040700000000 10018 0 831 6 655 5 831 6 0 0 0 0 655 5 0 0 0 0
-27 wlan0 0x1000040700000000 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-28 wlan0 0x1000040b00000000 10018 0 1714 8 1561 7 1714 8 0 0 0 0 1561 7 0 0 0 0
-29 wlan0 0x1000040b00000000 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-30 wlan0 0x1000120300000000 10018 0 8243 11 2234 12 8243 11 0 0 0 0 2234 12 0 0 0 0
-31 wlan0 0x1000120300000000 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-32 wlan0 0x1000180300000000 10018 0 56368 49 4790 39 56368 49 0 0 0 0 4790 39 0 0 0 0
-33 wlan0 0x1000180300000000 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-34 wlan0 0x1000300000000000 10018 0 9488 17 18813 25 1808 11 0 0 7680 6 18813 25 0 0 0 0
-35 wlan0 0x1000300000000000 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-36 wlan0 0x3000180400000000 10018 0 131262 103 7416 103 131262 103 0 0 0 0 7416 103 0 0 0 0
-37 wlan0 0x3000180400000000 10018 1 43995 37 2766 27 43995 37 0 0 0 0 2766 27 0 0 0 0
-38 wlan0 0xffffff0100000000 10018 0 5771986 4518 131190 1725 5771986 4518 0 0 0 0 131190 1725 0 0 0 0
-39 wlan0 0xffffff0100000000 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-40 dummy0 0x0 0 0 0 0 168 3 0 0 0 0 0 0 0 0 0 0 168 3
-41 dummy0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-42 lo 0x0 0 0 1288 16 1288 16 0 0 532 8 756 8 0 0 532 8 756 8
-43 lo 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after b/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after
deleted file mode 100644
index 12d98ca29f57..000000000000
--- a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after
+++ /dev/null
@@ -1,189 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 r_rmnet_data0 0x0 0 0 0 0 392 6 0 0 0 0 0 0 0 0 0 0 392 6
-3 r_rmnet_data0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-4 v4-wlan0 0x0 0 0 58952 2072 2888 65 264 6 0 0 58688 2066 132 3 0 0 2756 62
-5 v4-wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-6 v4-wlan0 0x0 10034 0 6192 11 1445 11 6192 11 0 0 0 0 1445 11 0 0 0 0
-7 v4-wlan0 0x0 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-8 v4-wlan0 0x0 10057 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-9 v4-wlan0 0x0 10057 1 728 7 392 7 0 0 728 7 0 0 0 0 392 7 0 0
-10 v4-wlan0 0x0 10106 0 2232 18 2232 18 0 0 2232 18 0 0 0 0 2232 18 0 0
-11 v4-wlan0 0x0 10106 1 432952718 314238 5442288 121260 432950238 314218 2480 20 0 0 5433900 121029 8388 231 0 0
-12 wlan0 0x0 0 0 330187296 250652 0 0 329106990 236273 226202 1255 854104 13124 0 0 0 0 0 0
-13 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-14 wlan0 0x0 1000 0 77113 272 56151 575 77113 272 0 0 0 0 19191 190 36960 385 0 0
-15 wlan0 0x0 1000 1 20227 80 8356 72 18539 74 1688 6 0 0 7562 66 794 6 0 0
-16 wlan0 0x0 10006 0 80755 92 9122 99 80755 92 0 0 0 0 9122 99 0 0 0 0
-17 wlan0 0x0 10006 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-18 wlan0 0x0 10015 0 4390 7 14824 252 4390 7 0 0 0 0 14824 252 0 0 0 0
-19 wlan0 0x0 10015 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-20 wlan0 0x0 10018 0 4928 11 1741 14 4928 11 0 0 0 0 1741 14 0 0 0 0
-21 wlan0 0x0 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-22 wlan0 0x0 10020 0 21163552 34395 2351650 15326 21162947 34390 605 5 0 0 2351045 15321 605 5 0 0
-23 wlan0 0x0 10020 1 13835740 12938 1548795 6365 13833754 12920 1986 18 0 0 1546809 6347 1986 18 0 0
-24 wlan0 0x0 10023 0 13405 40 5042 44 13405 40 0 0 0 0 5042 44 0 0 0 0
-25 wlan0 0x0 10023 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-26 wlan0 0x0 10034 0 436394741 342648 6237981 80442 436394741 342648 0 0 0 0 6237981 80442 0 0 0 0
-27 wlan0 0x0 10034 1 64860872 51297 1335539 15546 64860872 51297 0 0 0 0 1335539 15546 0 0 0 0
-28 wlan0 0x0 10044 0 17614444 14774 521004 5694 17329882 14432 284562 342 0 0 419974 5408 101030 286 0 0
-29 wlan0 0x0 10044 1 17701 33 3100 28 17701 33 0 0 0 0 3100 28 0 0 0 0
-30 wlan0 0x0 10057 0 12312074 9339 436098 5450 12248060 9263 64014 76 0 0 414224 5388 21874 62 0 0
-31 wlan0 0x0 10057 1 1332953195 954797 31849632 457698 1331933207 953569 1019988 1228 0 0 31702284 456899 147348 799 0 0
-32 wlan0 0x0 10060 0 32972 200 433705 380 32972 200 0 0 0 0 433705 380 0 0 0 0
-33 wlan0 0x0 10060 1 32106 66 37789 87 32106 66 0 0 0 0 37789 87 0 0 0 0
-34 wlan0 0x0 10061 0 7675 23 2509 22 7675 23 0 0 0 0 2509 22 0 0 0 0
-35 wlan0 0x0 10061 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-36 wlan0 0x0 10074 0 38355 82 10447 97 38355 82 0 0 0 0 10447 97 0 0 0 0
-37 wlan0 0x0 10074 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-38 wlan0 0x0 10078 0 49013 79 7167 69 49013 79 0 0 0 0 7167 69 0 0 0 0
-39 wlan0 0x0 10078 1 5872 8 1236 10 5872 8 0 0 0 0 1236 10 0 0 0 0
-40 wlan0 0x0 10082 0 8301 13 1981 15 8301 13 0 0 0 0 1981 15 0 0 0 0
-41 wlan0 0x0 10082 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-42 wlan0 0x0 10086 0 7001 14 1579 15 7001 14 0 0 0 0 1579 15 0 0 0 0
-43 wlan0 0x0 10086 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-44 wlan0 0x0 10090 0 24327795 20224 920502 14661 24327795 20224 0 0 0 0 920502 14661 0 0 0 0
-45 wlan0 0x0 10090 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-46 wlan0 0x0 10092 0 36849 78 12449 81 36849 78 0 0 0 0 12449 81 0 0 0 0
-47 wlan0 0x0 10092 1 60 1 103 1 60 1 0 0 0 0 103 1 0 0 0 0
-48 wlan0 0x0 10095 0 131962 223 37069 241 131962 223 0 0 0 0 37069 241 0 0 0 0
-49 wlan0 0x0 10095 1 12949 21 3930 21 12949 21 0 0 0 0 3930 21 0 0 0 0
-50 wlan0 0x0 10106 0 30899554 22679 632476 12296 30895334 22645 4220 34 0 0 628256 12262 4220 34 0 0
-51 wlan0 0x0 10106 1 88923475 64963 1606962 35612 88917201 64886 3586 29 2688 48 1602032 35535 4930 77 0 0
-52 wlan0 0x40700000000 10020 0 705732 10589 404428 5504 705732 10589 0 0 0 0 404428 5504 0 0 0 0
-53 wlan0 0x40700000000 10020 1 2376 36 1296 18 2376 36 0 0 0 0 1296 18 0 0 0 0
-54 wlan0 0x40800000000 10020 0 34624 146 122525 160 34624 146 0 0 0 0 122525 160 0 0 0 0
-55 wlan0 0x40800000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-56 wlan0 0x40b00000000 10020 0 22411 85 7364 57 22411 85 0 0 0 0 7364 57 0 0 0 0
-57 wlan0 0x40b00000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-58 wlan0 0x120300000000 10020 0 76641 241 32783 169 76641 241 0 0 0 0 32783 169 0 0 0 0
-59 wlan0 0x120300000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-60 wlan0 0x130100000000 10020 0 73101 287 23236 203 73101 287 0 0 0 0 23236 203 0 0 0 0
-61 wlan0 0x130100000000 10020 1 264 4 144 2 264 4 0 0 0 0 144 2 0 0 0 0
-62 wlan0 0x180300000000 10020 0 330648 399 24736 232 330648 399 0 0 0 0 24736 232 0 0 0 0
-63 wlan0 0x180300000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-64 wlan0 0x180400000000 10020 0 21865 59 5022 42 21865 59 0 0 0 0 5022 42 0 0 0 0
-65 wlan0 0x180400000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-66 wlan0 0x300000000000 10020 0 15984 65 26927 57 15984 65 0 0 0 0 26927 57 0 0 0 0
-67 wlan0 0x300000000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-68 wlan0 0x1065fff00000000 10020 0 131871 599 93783 445 131871 599 0 0 0 0 93783 445 0 0 0 0
-69 wlan0 0x1065fff00000000 10020 1 264 4 144 2 264 4 0 0 0 0 144 2 0 0 0 0
-70 wlan0 0x1b24f4600000000 10034 0 15445 42 23329 45 15445 42 0 0 0 0 23329 45 0 0 0 0
-71 wlan0 0x1b24f4600000000 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-72 wlan0 0x1000010000000000 10020 0 5542 9 1364 10 5542 9 0 0 0 0 1364 10 0 0 0 0
-73 wlan0 0x1000010000000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-74 wlan0 0x1000040100000000 10020 0 47196 184 213319 257 47196 184 0 0 0 0 213319 257 0 0 0 0
-75 wlan0 0x1000040100000000 10020 1 60 1 103 1 60 1 0 0 0 0 103 1 0 0 0 0
-76 wlan0 0x1000040700000000 10020 0 11599 50 10786 47 11599 50 0 0 0 0 10786 47 0 0 0 0
-77 wlan0 0x1000040700000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-78 wlan0 0x1000040800000000 10020 0 21902 145 174139 166 21902 145 0 0 0 0 174139 166 0 0 0 0
-79 wlan0 0x1000040800000000 10020 1 8568 88 105743 90 8568 88 0 0 0 0 105743 90 0 0 0 0
-80 wlan0 0x1000100300000000 10020 0 55213 118 194551 199 55213 118 0 0 0 0 194551 199 0 0 0 0
-81 wlan0 0x1000100300000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-82 wlan0 0x1000120300000000 10020 0 50826 74 21153 70 50826 74 0 0 0 0 21153 70 0 0 0 0
-83 wlan0 0x1000120300000000 10020 1 72 1 175 2 72 1 0 0 0 0 175 2 0 0 0 0
-84 wlan0 0x1000180300000000 10020 0 744198 657 65437 592 744198 657 0 0 0 0 65437 592 0 0 0 0
-85 wlan0 0x1000180300000000 10020 1 144719 132 10989 108 144719 132 0 0 0 0 10989 108 0 0 0 0
-86 wlan0 0x1000180600000000 10020 0 4599 8 1928 10 4599 8 0 0 0 0 1928 10 0 0 0 0
-87 wlan0 0x1000180600000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-88 wlan0 0x1000250000000000 10020 0 57740 98 13076 88 57740 98 0 0 0 0 13076 88 0 0 0 0
-89 wlan0 0x1000250000000000 10020 1 328 3 414 4 207 2 121 1 0 0 293 3 121 1 0 0
-90 wlan0 0x1000300000000000 10020 0 7675 30 31331 32 7675 30 0 0 0 0 31331 32 0 0 0 0
-91 wlan0 0x1000300000000000 10020 1 30173 97 101335 100 30173 97 0 0 0 0 101335 100 0 0 0 0
-92 wlan0 0x1000310200000000 10020 0 1681 9 2194 9 1681 9 0 0 0 0 2194 9 0 0 0 0
-93 wlan0 0x1000310200000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-94 wlan0 0x1000360000000000 10020 0 5606 20 2831 20 5606 20 0 0 0 0 2831 20 0 0 0 0
-95 wlan0 0x1000360000000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-96 wlan0 0x11065fff00000000 10020 0 18363 91 83367 104 18363 91 0 0 0 0 83367 104 0 0 0 0
-97 wlan0 0x11065fff00000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-98 wlan0 0x3000009600000000 10020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-99 wlan0 0x3000009600000000 10020 1 6163 18 2424 18 6163 18 0 0 0 0 2424 18 0 0 0 0
-100 wlan0 0x3000009800000000 10020 0 23337 46 8723 39 23337 46 0 0 0 0 8723 39 0 0 0 0
-101 wlan0 0x3000009800000000 10020 1 33744 93 72437 89 33744 93 0 0 0 0 72437 89 0 0 0 0
-102 wlan0 0x3000020000000000 10020 0 4124 11 8969 19 4124 11 0 0 0 0 8969 19 0 0 0 0
-103 wlan0 0x3000020000000000 10020 1 5993 11 3815 14 5993 11 0 0 0 0 3815 14 0 0 0 0
-104 wlan0 0x3000040100000000 10020 0 113809 342 135666 308 113809 342 0 0 0 0 135666 308 0 0 0 0
-105 wlan0 0x3000040100000000 10020 1 142508 642 500579 637 142508 642 0 0 0 0 500579 637 0 0 0 0
-106 wlan0 0x3000040700000000 10020 0 365815 5119 213340 2733 365815 5119 0 0 0 0 213340 2733 0 0 0 0
-107 wlan0 0x3000040700000000 10020 1 30747 130 18408 100 30747 130 0 0 0 0 18408 100 0 0 0 0
-108 wlan0 0x3000040800000000 10020 0 34672 112 68623 92 34672 112 0 0 0 0 68623 92 0 0 0 0
-109 wlan0 0x3000040800000000 10020 1 78443 199 140944 192 78443 199 0 0 0 0 140944 192 0 0 0 0
-110 wlan0 0x3000040b00000000 10020 0 14949 33 4017 26 14949 33 0 0 0 0 4017 26 0 0 0 0
-111 wlan0 0x3000040b00000000 10020 1 996 15 576 8 996 15 0 0 0 0 576 8 0 0 0 0
-112 wlan0 0x3000090000000000 10020 0 11826 67 7309 52 11826 67 0 0 0 0 7309 52 0 0 0 0
-113 wlan0 0x3000090000000000 10020 1 24805 41 4785 41 24805 41 0 0 0 0 4785 41 0 0 0 0
-114 wlan0 0x3000100300000000 10020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-115 wlan0 0x3000100300000000 10020 1 3112 10 1628 10 3112 10 0 0 0 0 1628 10 0 0 0 0
-116 wlan0 0x3000120300000000 10020 0 38249 107 20374 85 38249 107 0 0 0 0 20374 85 0 0 0 0
-117 wlan0 0x3000120300000000 10020 1 122581 174 36792 143 122581 174 0 0 0 0 36792 143 0 0 0 0
-118 wlan0 0x3000130100000000 10020 0 2700 41 1524 21 2700 41 0 0 0 0 1524 21 0 0 0 0
-119 wlan0 0x3000130100000000 10020 1 22515 59 8366 52 22515 59 0 0 0 0 8366 52 0 0 0 0
-120 wlan0 0x3000180200000000 10020 0 6411 18 14511 20 6411 18 0 0 0 0 14511 20 0 0 0 0
-121 wlan0 0x3000180200000000 10020 1 336 5 319 4 336 5 0 0 0 0 319 4 0 0 0 0
-122 wlan0 0x3000180300000000 10020 0 129301 136 17622 97 129301 136 0 0 0 0 17622 97 0 0 0 0
-123 wlan0 0x3000180300000000 10020 1 464787 429 41703 336 464787 429 0 0 0 0 41703 336 0 0 0 0
-124 wlan0 0x3000180400000000 10020 0 11014 39 2787 25 11014 39 0 0 0 0 2787 25 0 0 0 0
-125 wlan0 0x3000180400000000 10020 1 144040 139 7540 80 144040 139 0 0 0 0 7540 80 0 0 0 0
-126 wlan0 0x3000210100000000 10020 0 10278 44 4579 33 10278 44 0 0 0 0 4579 33 0 0 0 0
-127 wlan0 0x3000210100000000 10020 1 31151 73 14159 47 31151 73 0 0 0 0 14159 47 0 0 0 0
-128 wlan0 0x3000250000000000 10020 0 132 2 72 1 132 2 0 0 0 0 72 1 0 0 0 0
-129 wlan0 0x3000250000000000 10020 1 76614 143 17711 130 76080 137 534 6 0 0 17177 124 534 6 0 0
-130 wlan0 0x3000260100000000 10020 0 9426 26 3535 20 9426 26 0 0 0 0 3535 20 0 0 0 0
-131 wlan0 0x3000260100000000 10020 1 468 7 288 4 468 7 0 0 0 0 288 4 0 0 0 0
-132 wlan0 0x3000300000000000 10020 0 7241 29 12055 26 7241 29 0 0 0 0 12055 26 0 0 0 0
-133 wlan0 0x3000300000000000 10020 1 3273 23 11232 21 3273 23 0 0 0 0 11232 21 0 0 0 0
-134 wlan0 0x3000310000000000 10020 0 132 2 72 1 132 2 0 0 0 0 72 1 0 0 0 0
-135 wlan0 0x3000310000000000 10020 1 53425 64 8721 62 53425 64 0 0 0 0 8721 62 0 0 0 0
-136 wlan0 0x3000310500000000 10020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-137 wlan0 0x3000310500000000 10020 1 9929 16 3879 18 9929 16 0 0 0 0 3879 18 0 0 0 0
-138 wlan0 0x3000320100000000 10020 0 6844 14 3745 13 6844 14 0 0 0 0 3745 13 0 0 0 0
-139 wlan0 0x3000320100000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-140 wlan0 0x3000360000000000 10020 0 8855 43 4749 31 8855 43 0 0 0 0 4749 31 0 0 0 0
-141 wlan0 0x3000360000000000 10020 1 5597 19 2456 19 5597 19 0 0 0 0 2456 19 0 0 0 0
-142 wlan0 0x3010000000000000 10090 0 605140 527 38435 429 605140 527 0 0 0 0 38435 429 0 0 0 0
-143 wlan0 0x3010000000000000 10090 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-144 wlan0 0x31065fff00000000 10020 0 22011 67 29665 64 22011 67 0 0 0 0 29665 64 0 0 0 0
-145 wlan0 0x31065fff00000000 10020 1 10695 34 18347 35 10695 34 0 0 0 0 18347 35 0 0 0 0
-146 wlan0 0x32e544f900000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-147 wlan0 0x32e544f900000000 10034 1 40143 54 7299 61 40143 54 0 0 0 0 7299 61 0 0 0 0
-148 wlan0 0x58872a4400000000 10018 0 4928 11 1669 13 4928 11 0 0 0 0 1669 13 0 0 0 0
-149 wlan0 0x58872a4400000000 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-150 wlan0 0x5caeaa7b00000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-151 wlan0 0x5caeaa7b00000000 10034 1 74971 73 7103 75 74971 73 0 0 0 0 7103 75 0 0 0 0
-152 wlan0 0x9e00923800000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-153 wlan0 0x9e00923800000000 10034 1 72385 98 13072 110 72385 98 0 0 0 0 13072 110 0 0 0 0
-154 wlan0 0xb972bdd400000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-155 wlan0 0xb972bdd400000000 10034 1 15282 24 3034 27 15282 24 0 0 0 0 3034 27 0 0 0 0
-156 wlan0 0xc7c9f7ba00000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-157 wlan0 0xc7c9f7ba00000000 10034 1 194915 185 13316 138 194915 185 0 0 0 0 13316 138 0 0 0 0
-158 wlan0 0xc9395b2600000000 10034 0 6991 13 6215 14 6991 13 0 0 0 0 6215 14 0 0 0 0
-159 wlan0 0xc9395b2600000000 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-160 wlan0 0xdaddf21100000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-161 wlan0 0xdaddf21100000000 10034 1 928676 849 81570 799 928676 849 0 0 0 0 81570 799 0 0 0 0
-162 wlan0 0xe8d195d100000000 10020 0 516 8 288 4 516 8 0 0 0 0 288 4 0 0 0 0
-163 wlan0 0xe8d195d100000000 10020 1 5905 15 2622 15 5905 15 0 0 0 0 2622 15 0 0 0 0
-164 wlan0 0xe8d195d100000000 10034 0 236640 524 312523 555 236640 524 0 0 0 0 312523 555 0 0 0 0
-165 wlan0 0xe8d195d100000000 10034 1 319028 539 188776 553 319028 539 0 0 0 0 188776 553 0 0 0 0
-166 wlan0 0xffffff0100000000 10006 0 80755 92 9122 99 80755 92 0 0 0 0 9122 99 0 0 0 0
-167 wlan0 0xffffff0100000000 10006 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-168 wlan0 0xffffff0100000000 10020 0 17874405 14068 223987 3065 17874405 14068 0 0 0 0 223987 3065 0 0 0 0
-169 wlan0 0xffffff0100000000 10020 1 11011258 8672 177693 2407 11011258 8672 0 0 0 0 177693 2407 0 0 0 0
-170 wlan0 0xffffff0100000000 10034 0 436062595 341880 5843990 79630 436062595 341880 0 0 0 0 5843990 79630 0 0 0 0
-171 wlan0 0xffffff0100000000 10034 1 63201220 49447 1005882 13713 63201220 49447 0 0 0 0 1005882 13713 0 0 0 0
-172 wlan0 0xffffff0100000000 10044 0 17159287 13702 356212 4778 17159287 13702 0 0 0 0 356212 4778 0 0 0 0
-173 wlan0 0xffffff0100000000 10044 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-174 wlan0 0xffffff0100000000 10078 0 10439 17 1665 15 10439 17 0 0 0 0 1665 15 0 0 0 0
-175 wlan0 0xffffff0100000000 10078 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-176 wlan0 0xffffff0100000000 10090 0 23722655 19697 881995 14231 23722655 19697 0 0 0 0 881995 14231 0 0 0 0
-177 wlan0 0xffffff0100000000 10090 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-178 wlan0 0xffffff0500000000 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-179 wlan0 0xffffff0500000000 1000 1 1592 5 314 1 0 0 1592 5 0 0 0 0 314 1 0 0
-180 wlan0 0xffffff0600000000 1000 0 0 0 36960 385 0 0 0 0 0 0 0 0 36960 385 0 0
-181 wlan0 0xffffff0600000000 1000 1 96 1 480 5 0 0 96 1 0 0 0 0 480 5 0 0
-182 wlan0 0xffffff0700000000 1000 0 38732 229 16567 163 38732 229 0 0 0 0 16567 163 0 0 0 0
-183 wlan0 0xffffff0700000000 1000 1 18539 74 7562 66 18539 74 0 0 0 0 7562 66 0 0 0 0
-184 wlan0 0xffffff0900000000 1000 0 38381 43 2624 27 38381 43 0 0 0 0 2624 27 0 0 0 0
-185 wlan0 0xffffff0900000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-186 dummy0 0x0 0 0 0 0 168 3 0 0 0 0 0 0 0 0 0 0 168 3
-187 dummy0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-188 wlan0 0x0 1029 0 0 0 8524052 130894 0 0 0 0 0 0 7871216 121284 108568 1325 544268 8285
-189 wlan0 0x0 1029 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before b/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before
deleted file mode 100644
index ce4bcc3a3b43..000000000000
--- a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before
+++ /dev/null
@@ -1,187 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 r_rmnet_data0 0x0 0 0 0 0 392 6 0 0 0 0 0 0 0 0 0 0 392 6
-3 r_rmnet_data0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-4 v4-wlan0 0x0 0 0 58848 2070 2836 64 160 4 0 0 58688 2066 80 2 0 0 2756 62
-5 v4-wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-6 v4-wlan0 0x0 10034 0 6192 11 1445 11 6192 11 0 0 0 0 1445 11 0 0 0 0
-7 v4-wlan0 0x0 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-8 v4-wlan0 0x0 10057 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-9 v4-wlan0 0x0 10057 1 728 7 392 7 0 0 728 7 0 0 0 0 392 7 0 0
-10 v4-wlan0 0x0 10106 0 1488 12 1488 12 0 0 1488 12 0 0 0 0 1488 12 0 0
-11 v4-wlan0 0x0 10106 1 323981189 235142 3509032 84542 323979453 235128 1736 14 0 0 3502676 84363 6356 179 0 0
-12 wlan0 0x0 0 0 330187296 250652 0 0 329106990 236273 226202 1255 854104 13124 0 0 0 0 0 0
-13 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-14 wlan0 0x0 1000 0 77113 272 56151 575 77113 272 0 0 0 0 19191 190 36960 385 0 0
-15 wlan0 0x0 1000 1 20227 80 8356 72 18539 74 1688 6 0 0 7562 66 794 6 0 0
-16 wlan0 0x0 10006 0 80755 92 9122 99 80755 92 0 0 0 0 9122 99 0 0 0 0
-17 wlan0 0x0 10006 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-18 wlan0 0x0 10015 0 4390 7 14824 252 4390 7 0 0 0 0 14824 252 0 0 0 0
-19 wlan0 0x0 10015 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-20 wlan0 0x0 10018 0 4928 11 1741 14 4928 11 0 0 0 0 1741 14 0 0 0 0
-21 wlan0 0x0 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-22 wlan0 0x0 10020 0 21141412 34316 2329881 15262 21140807 34311 605 5 0 0 2329276 15257 605 5 0 0
-23 wlan0 0x0 10020 1 13835740 12938 1548555 6362 13833754 12920 1986 18 0 0 1546569 6344 1986 18 0 0
-24 wlan0 0x0 10023 0 13405 40 5042 44 13405 40 0 0 0 0 5042 44 0 0 0 0
-25 wlan0 0x0 10023 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-26 wlan0 0x0 10034 0 436394741 342648 6237981 80442 436394741 342648 0 0 0 0 6237981 80442 0 0 0 0
-27 wlan0 0x0 10034 1 64860872 51297 1335539 15546 64860872 51297 0 0 0 0 1335539 15546 0 0 0 0
-28 wlan0 0x0 10044 0 17614444 14774 521004 5694 17329882 14432 284562 342 0 0 419974 5408 101030 286 0 0
-29 wlan0 0x0 10044 1 17701 33 3100 28 17701 33 0 0 0 0 3100 28 0 0 0 0
-30 wlan0 0x0 10057 0 12311735 9335 435954 5448 12247721 9259 64014 76 0 0 414080 5386 21874 62 0 0
-31 wlan0 0x0 10057 1 1332953195 954797 31849632 457698 1331933207 953569 1019988 1228 0 0 31702284 456899 147348 799 0 0
-32 wlan0 0x0 10060 0 32972 200 433705 380 32972 200 0 0 0 0 433705 380 0 0 0 0
-33 wlan0 0x0 10060 1 32106 66 37789 87 32106 66 0 0 0 0 37789 87 0 0 0 0
-34 wlan0 0x0 10061 0 7675 23 2509 22 7675 23 0 0 0 0 2509 22 0 0 0 0
-35 wlan0 0x0 10061 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-36 wlan0 0x0 10074 0 38355 82 10447 97 38355 82 0 0 0 0 10447 97 0 0 0 0
-37 wlan0 0x0 10074 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-38 wlan0 0x0 10078 0 49013 79 7167 69 49013 79 0 0 0 0 7167 69 0 0 0 0
-39 wlan0 0x0 10078 1 5872 8 1236 10 5872 8 0 0 0 0 1236 10 0 0 0 0
-40 wlan0 0x0 10082 0 8301 13 1981 15 8301 13 0 0 0 0 1981 15 0 0 0 0
-41 wlan0 0x0 10082 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-42 wlan0 0x0 10086 0 7001 14 1579 15 7001 14 0 0 0 0 1579 15 0 0 0 0
-43 wlan0 0x0 10086 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-44 wlan0 0x0 10090 0 24327795 20224 920502 14661 24327795 20224 0 0 0 0 920502 14661 0 0 0 0
-45 wlan0 0x0 10090 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-46 wlan0 0x0 10092 0 36849 78 12449 81 36849 78 0 0 0 0 12449 81 0 0 0 0
-47 wlan0 0x0 10092 1 60 1 103 1 60 1 0 0 0 0 103 1 0 0 0 0
-48 wlan0 0x0 10095 0 131962 223 37069 241 131962 223 0 0 0 0 37069 241 0 0 0 0
-49 wlan0 0x0 10095 1 12949 21 3930 21 12949 21 0 0 0 0 3930 21 0 0 0 0
-50 wlan0 0x0 10106 0 30899554 22679 632476 12296 30895334 22645 4220 34 0 0 628256 12262 4220 34 0 0
-51 wlan0 0x0 10106 1 88922349 64952 1605126 35599 88916075 64875 3586 29 2688 48 1600196 35522 4930 77 0 0
-52 wlan0 0x40700000000 10020 0 705732 10589 404428 5504 705732 10589 0 0 0 0 404428 5504 0 0 0 0
-53 wlan0 0x40700000000 10020 1 2376 36 1296 18 2376 36 0 0 0 0 1296 18 0 0 0 0
-54 wlan0 0x40800000000 10020 0 34624 146 122525 160 34624 146 0 0 0 0 122525 160 0 0 0 0
-55 wlan0 0x40800000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-56 wlan0 0x40b00000000 10020 0 22411 85 7364 57 22411 85 0 0 0 0 7364 57 0 0 0 0
-57 wlan0 0x40b00000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-58 wlan0 0x120300000000 10020 0 76641 241 32783 169 76641 241 0 0 0 0 32783 169 0 0 0 0
-59 wlan0 0x120300000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-60 wlan0 0x130100000000 10020 0 73101 287 23236 203 73101 287 0 0 0 0 23236 203 0 0 0 0
-61 wlan0 0x130100000000 10020 1 264 4 144 2 264 4 0 0 0 0 144 2 0 0 0 0
-62 wlan0 0x180300000000 10020 0 330648 399 24736 232 330648 399 0 0 0 0 24736 232 0 0 0 0
-63 wlan0 0x180300000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-64 wlan0 0x180400000000 10020 0 21865 59 5022 42 21865 59 0 0 0 0 5022 42 0 0 0 0
-65 wlan0 0x180400000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-66 wlan0 0x300000000000 10020 0 15984 65 26927 57 15984 65 0 0 0 0 26927 57 0 0 0 0
-67 wlan0 0x300000000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-68 wlan0 0x1065fff00000000 10020 0 131871 599 93783 445 131871 599 0 0 0 0 93783 445 0 0 0 0
-69 wlan0 0x1065fff00000000 10020 1 264 4 144 2 264 4 0 0 0 0 144 2 0 0 0 0
-70 wlan0 0x1b24f4600000000 10034 0 15445 42 23329 45 15445 42 0 0 0 0 23329 45 0 0 0 0
-71 wlan0 0x1b24f4600000000 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-72 wlan0 0x1000010000000000 10020 0 5542 9 1364 10 5542 9 0 0 0 0 1364 10 0 0 0 0
-73 wlan0 0x1000010000000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-74 wlan0 0x1000040100000000 10020 0 47196 184 213319 257 47196 184 0 0 0 0 213319 257 0 0 0 0
-75 wlan0 0x1000040100000000 10020 1 60 1 103 1 60 1 0 0 0 0 103 1 0 0 0 0
-76 wlan0 0x1000040700000000 10020 0 11599 50 10786 47 11599 50 0 0 0 0 10786 47 0 0 0 0
-77 wlan0 0x1000040700000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-78 wlan0 0x1000040800000000 10020 0 21902 145 174139 166 21902 145 0 0 0 0 174139 166 0 0 0 0
-79 wlan0 0x1000040800000000 10020 1 8568 88 105743 90 8568 88 0 0 0 0 105743 90 0 0 0 0
-80 wlan0 0x1000100300000000 10020 0 55213 118 194551 199 55213 118 0 0 0 0 194551 199 0 0 0 0
-81 wlan0 0x1000100300000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-82 wlan0 0x1000120300000000 10020 0 50826 74 21153 70 50826 74 0 0 0 0 21153 70 0 0 0 0
-83 wlan0 0x1000120300000000 10020 1 72 1 175 2 72 1 0 0 0 0 175 2 0 0 0 0
-84 wlan0 0x1000180300000000 10020 0 744198 657 65437 592 744198 657 0 0 0 0 65437 592 0 0 0 0
-85 wlan0 0x1000180300000000 10020 1 144719 132 10989 108 144719 132 0 0 0 0 10989 108 0 0 0 0
-86 wlan0 0x1000180600000000 10020 0 4599 8 1928 10 4599 8 0 0 0 0 1928 10 0 0 0 0
-87 wlan0 0x1000180600000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-88 wlan0 0x1000250000000000 10020 0 57740 98 13076 88 57740 98 0 0 0 0 13076 88 0 0 0 0
-89 wlan0 0x1000250000000000 10020 1 328 3 414 4 207 2 121 1 0 0 293 3 121 1 0 0
-90 wlan0 0x1000300000000000 10020 0 7675 30 31331 32 7675 30 0 0 0 0 31331 32 0 0 0 0
-91 wlan0 0x1000300000000000 10020 1 30173 97 101335 100 30173 97 0 0 0 0 101335 100 0 0 0 0
-92 wlan0 0x1000310200000000 10020 0 1681 9 2194 9 1681 9 0 0 0 0 2194 9 0 0 0 0
-93 wlan0 0x1000310200000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-94 wlan0 0x1000360000000000 10020 0 5606 20 2831 20 5606 20 0 0 0 0 2831 20 0 0 0 0
-95 wlan0 0x1000360000000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-96 wlan0 0x11065fff00000000 10020 0 18363 91 83367 104 18363 91 0 0 0 0 83367 104 0 0 0 0
-97 wlan0 0x11065fff00000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-98 wlan0 0x3000009600000000 10020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-99 wlan0 0x3000009600000000 10020 1 6163 18 2424 18 6163 18 0 0 0 0 2424 18 0 0 0 0
-100 wlan0 0x3000009800000000 10020 0 23337 46 8723 39 23337 46 0 0 0 0 8723 39 0 0 0 0
-101 wlan0 0x3000009800000000 10020 1 33744 93 72437 89 33744 93 0 0 0 0 72437 89 0 0 0 0
-102 wlan0 0x3000020000000000 10020 0 4124 11 8969 19 4124 11 0 0 0 0 8969 19 0 0 0 0
-103 wlan0 0x3000020000000000 10020 1 5993 11 3815 14 5993 11 0 0 0 0 3815 14 0 0 0 0
-104 wlan0 0x3000040100000000 10020 0 106718 322 121557 287 106718 322 0 0 0 0 121557 287 0 0 0 0
-105 wlan0 0x3000040100000000 10020 1 142508 642 500579 637 142508 642 0 0 0 0 500579 637 0 0 0 0
-106 wlan0 0x3000040700000000 10020 0 365419 5113 213124 2730 365419 5113 0 0 0 0 213124 2730 0 0 0 0
-107 wlan0 0x3000040700000000 10020 1 30747 130 18408 100 30747 130 0 0 0 0 18408 100 0 0 0 0
-108 wlan0 0x3000040800000000 10020 0 34672 112 68623 92 34672 112 0 0 0 0 68623 92 0 0 0 0
-109 wlan0 0x3000040800000000 10020 1 78443 199 140944 192 78443 199 0 0 0 0 140944 192 0 0 0 0
-110 wlan0 0x3000040b00000000 10020 0 14949 33 4017 26 14949 33 0 0 0 0 4017 26 0 0 0 0
-111 wlan0 0x3000040b00000000 10020 1 996 15 576 8 996 15 0 0 0 0 576 8 0 0 0 0
-112 wlan0 0x3000090000000000 10020 0 4017 28 3610 25 4017 28 0 0 0 0 3610 25 0 0 0 0
-113 wlan0 0x3000090000000000 10020 1 24805 41 4545 38 24805 41 0 0 0 0 4545 38 0 0 0 0
-114 wlan0 0x3000100300000000 10020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-115 wlan0 0x3000100300000000 10020 1 3112 10 1628 10 3112 10 0 0 0 0 1628 10 0 0 0 0
-116 wlan0 0x3000120300000000 10020 0 38249 107 20374 85 38249 107 0 0 0 0 20374 85 0 0 0 0
-117 wlan0 0x3000120300000000 10020 1 122581 174 36792 143 122581 174 0 0 0 0 36792 143 0 0 0 0
-118 wlan0 0x3000130100000000 10020 0 2700 41 1524 21 2700 41 0 0 0 0 1524 21 0 0 0 0
-119 wlan0 0x3000130100000000 10020 1 22515 59 8366 52 22515 59 0 0 0 0 8366 52 0 0 0 0
-120 wlan0 0x3000180200000000 10020 0 6411 18 14511 20 6411 18 0 0 0 0 14511 20 0 0 0 0
-121 wlan0 0x3000180200000000 10020 1 336 5 319 4 336 5 0 0 0 0 319 4 0 0 0 0
-122 wlan0 0x3000180300000000 10020 0 129301 136 17622 97 129301 136 0 0 0 0 17622 97 0 0 0 0
-123 wlan0 0x3000180300000000 10020 1 464787 429 41703 336 464787 429 0 0 0 0 41703 336 0 0 0 0
-124 wlan0 0x3000180400000000 10020 0 11014 39 2787 25 11014 39 0 0 0 0 2787 25 0 0 0 0
-125 wlan0 0x3000180400000000 10020 1 144040 139 7540 80 144040 139 0 0 0 0 7540 80 0 0 0 0
-126 wlan0 0x3000210100000000 10020 0 10278 44 4579 33 10278 44 0 0 0 0 4579 33 0 0 0 0
-127 wlan0 0x3000210100000000 10020 1 31151 73 14159 47 31151 73 0 0 0 0 14159 47 0 0 0 0
-128 wlan0 0x3000250000000000 10020 0 132 2 72 1 132 2 0 0 0 0 72 1 0 0 0 0
-129 wlan0 0x3000250000000000 10020 1 76614 143 17711 130 76080 137 534 6 0 0 17177 124 534 6 0 0
-130 wlan0 0x3000260100000000 10020 0 9426 26 3535 20 9426 26 0 0 0 0 3535 20 0 0 0 0
-131 wlan0 0x3000260100000000 10020 1 468 7 288 4 468 7 0 0 0 0 288 4 0 0 0 0
-132 wlan0 0x3000300000000000 10020 0 7241 29 12055 26 7241 29 0 0 0 0 12055 26 0 0 0 0
-133 wlan0 0x3000300000000000 10020 1 3273 23 11232 21 3273 23 0 0 0 0 11232 21 0 0 0 0
-134 wlan0 0x3000310000000000 10020 0 132 2 72 1 132 2 0 0 0 0 72 1 0 0 0 0
-135 wlan0 0x3000310000000000 10020 1 53425 64 8721 62 53425 64 0 0 0 0 8721 62 0 0 0 0
-136 wlan0 0x3000310500000000 10020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-137 wlan0 0x3000310500000000 10020 1 9929 16 3879 18 9929 16 0 0 0 0 3879 18 0 0 0 0
-138 wlan0 0x3000360000000000 10020 0 8855 43 4749 31 8855 43 0 0 0 0 4749 31 0 0 0 0
-139 wlan0 0x3000360000000000 10020 1 5597 19 2456 19 5597 19 0 0 0 0 2456 19 0 0 0 0
-140 wlan0 0x3010000000000000 10090 0 605140 527 38435 429 605140 527 0 0 0 0 38435 429 0 0 0 0
-141 wlan0 0x3010000000000000 10090 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-142 wlan0 0x31065fff00000000 10020 0 22011 67 29665 64 22011 67 0 0 0 0 29665 64 0 0 0 0
-143 wlan0 0x31065fff00000000 10020 1 10695 34 18347 35 10695 34 0 0 0 0 18347 35 0 0 0 0
-144 wlan0 0x32e544f900000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-145 wlan0 0x32e544f900000000 10034 1 40143 54 7299 61 40143 54 0 0 0 0 7299 61 0 0 0 0
-146 wlan0 0x58872a4400000000 10018 0 4928 11 1669 13 4928 11 0 0 0 0 1669 13 0 0 0 0
-147 wlan0 0x58872a4400000000 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-148 wlan0 0x5caeaa7b00000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-149 wlan0 0x5caeaa7b00000000 10034 1 74971 73 7103 75 74971 73 0 0 0 0 7103 75 0 0 0 0
-150 wlan0 0x9e00923800000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-151 wlan0 0x9e00923800000000 10034 1 72385 98 13072 110 72385 98 0 0 0 0 13072 110 0 0 0 0
-152 wlan0 0xb972bdd400000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-153 wlan0 0xb972bdd400000000 10034 1 15282 24 3034 27 15282 24 0 0 0 0 3034 27 0 0 0 0
-154 wlan0 0xc7c9f7ba00000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-155 wlan0 0xc7c9f7ba00000000 10034 1 194915 185 13316 138 194915 185 0 0 0 0 13316 138 0 0 0 0
-156 wlan0 0xc9395b2600000000 10034 0 6991 13 6215 14 6991 13 0 0 0 0 6215 14 0 0 0 0
-157 wlan0 0xc9395b2600000000 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-158 wlan0 0xdaddf21100000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-159 wlan0 0xdaddf21100000000 10034 1 928676 849 81570 799 928676 849 0 0 0 0 81570 799 0 0 0 0
-160 wlan0 0xe8d195d100000000 10020 0 516 8 288 4 516 8 0 0 0 0 288 4 0 0 0 0
-161 wlan0 0xe8d195d100000000 10020 1 5905 15 2622 15 5905 15 0 0 0 0 2622 15 0 0 0 0
-162 wlan0 0xe8d195d100000000 10034 0 236640 524 312523 555 236640 524 0 0 0 0 312523 555 0 0 0 0
-163 wlan0 0xe8d195d100000000 10034 1 319028 539 188776 553 319028 539 0 0 0 0 188776 553 0 0 0 0
-164 wlan0 0xffffff0100000000 10006 0 80755 92 9122 99 80755 92 0 0 0 0 9122 99 0 0 0 0
-165 wlan0 0xffffff0100000000 10006 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-166 wlan0 0xffffff0100000000 10020 0 17874405 14068 223987 3065 17874405 14068 0 0 0 0 223987 3065 0 0 0 0
-167 wlan0 0xffffff0100000000 10020 1 11011258 8672 177693 2407 11011258 8672 0 0 0 0 177693 2407 0 0 0 0
-168 wlan0 0xffffff0100000000 10034 0 436062595 341880 5843990 79630 436062595 341880 0 0 0 0 5843990 79630 0 0 0 0
-169 wlan0 0xffffff0100000000 10034 1 63201220 49447 1005882 13713 63201220 49447 0 0 0 0 1005882 13713 0 0 0 0
-170 wlan0 0xffffff0100000000 10044 0 17159287 13702 356212 4778 17159287 13702 0 0 0 0 356212 4778 0 0 0 0
-171 wlan0 0xffffff0100000000 10044 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-172 wlan0 0xffffff0100000000 10078 0 10439 17 1665 15 10439 17 0 0 0 0 1665 15 0 0 0 0
-173 wlan0 0xffffff0100000000 10078 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-174 wlan0 0xffffff0100000000 10090 0 23722655 19697 881995 14231 23722655 19697 0 0 0 0 881995 14231 0 0 0 0
-175 wlan0 0xffffff0100000000 10090 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-176 wlan0 0xffffff0500000000 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-177 wlan0 0xffffff0500000000 1000 1 1592 5 314 1 0 0 1592 5 0 0 0 0 314 1 0 0
-178 wlan0 0xffffff0600000000 1000 0 0 0 36960 385 0 0 0 0 0 0 0 0 36960 385 0 0
-179 wlan0 0xffffff0600000000 1000 1 96 1 480 5 0 0 96 1 0 0 0 0 480 5 0 0
-180 wlan0 0xffffff0700000000 1000 0 38732 229 16567 163 38732 229 0 0 0 0 16567 163 0 0 0 0
-181 wlan0 0xffffff0700000000 1000 1 18539 74 7562 66 18539 74 0 0 0 0 7562 66 0 0 0 0
-182 wlan0 0xffffff0900000000 1000 0 38381 43 2624 27 38381 43 0 0 0 0 2624 27 0 0 0 0
-183 wlan0 0xffffff0900000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-184 dummy0 0x0 0 0 0 0 168 3 0 0 0 0 0 0 0 0 0 0 168 3
-185 dummy0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-186 wlan0 0x0 1029 0 0 0 5855801 94173 0 0 0 0 0 0 5208040 84634 103637 1256 544124 8283
-187 wlan0 0x0 1029 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_simple b/tests/net/res/raw/xt_qtaguid_with_clat_simple
deleted file mode 100644
index a1d6d411bad8..000000000000
--- a/tests/net/res/raw/xt_qtaguid_with_clat_simple
+++ /dev/null
@@ -1,4 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 v4-wlan0 0x0 10060 0 42600 213 4100 41 42600 213 0 0 0 0 4100 41 0 0 0 0
-3 v4-wlan0 0x0 10060 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-4 wlan0 0x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/tests/net/smoketest/Android.bp b/tests/net/smoketest/Android.bp
deleted file mode 100644
index 84ae2b5d845e..000000000000
--- a/tests/net/smoketest/Android.bp
+++ /dev/null
@@ -1,22 +0,0 @@
-// This test exists only because the jni_libs list for these tests is difficult to
-// maintain: the test itself only depends on libnetworkstatsfactorytestjni, but the test
-// fails to load that library unless *all* the dependencies of that library are explicitly
-// listed in jni_libs. This means that whenever any of the dependencies changes the test
-// starts failing and breaking presubmits in frameworks/base. We cannot easily put
-// FrameworksNetTests into global presubmit because they are at times flaky, but this
-// test is effectively empty beyond validating that the libraries load correctly, and
-// thus should be stable enough to put in global presubmit.
-//
-// TODO: remove this hack when there is a better solution for jni_libs that includes
-// dependent libraries.
-android_test {
- name: "FrameworksNetSmokeTests",
- defaults: ["FrameworksNetTests-jni-defaults"],
- srcs: ["java/SmokeTest.java"],
- test_suites: ["device-tests"],
- static_libs: [
- "androidx.test.rules",
- "mockito-target-minus-junit4",
- "services.core",
- ],
-} \ No newline at end of file
diff --git a/tests/net/smoketest/java/SmokeTest.java b/tests/net/smoketest/java/SmokeTest.java
deleted file mode 100644
index 7d6655fde15e..000000000000
--- a/tests/net/smoketest/java/SmokeTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class SmokeTest {
-
- @Test
- public void testLoadJni() {
- System.loadLibrary("networkstatsfactorytestjni");
- assertEquals(0, 0x00);
- }
-}
diff --git a/tests/notification/Android.bp b/tests/notification/Android.bp
index f05edafbf8b7..1c1b5a231e86 100644
--- a/tests/notification/Android.bp
+++ b/tests/notification/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_test {
name: "NotificationTests",
// Include all test java files.
diff --git a/tests/notification/OWNERS b/tests/notification/OWNERS
new file mode 100644
index 000000000000..396fd1213aca
--- /dev/null
+++ b/tests/notification/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/notification/OWNERS
diff --git a/tests/permission/Android.bp b/tests/permission/Android.bp
index bd07009de7b3..d06809b209a0 100644
--- a/tests/permission/Android.bp
+++ b/tests/permission/Android.bp
@@ -1,12 +1,26 @@
+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"],
+}
+
android_test {
name: "FrameworkPermissionTests",
// Include all test java files.
srcs: ["src/**/*.java"],
libs: [
"android.test.runner",
- "telephony-common",
"android.test.base",
+ "telephony-common",
+ ],
+ static_libs: [
+ "androidx.test.runner",
+ "junit",
+ "platform-test-annotations",
],
- static_libs: ["junit"],
platform_apis: true,
+ test_suites: ["device-tests"],
}
diff --git a/tests/permission/AndroidManifest.xml b/tests/permission/AndroidManifest.xml
index b19bf006cfeb..9ff5fb39bc4b 100644
--- a/tests/permission/AndroidManifest.xml
+++ b/tests/permission/AndroidManifest.xml
@@ -24,9 +24,10 @@
<!--
The test declared in this instrumentation can be run via this command
- "adb shell am instrument -w com.android.framework.permission.tests/android.test.InstrumentationTestRunner"
+ $ adb shell am instrument \
+ -w com.android.framework.permission.tests/androidx.test.runner.AndroidJUnitRunner
-->
- <instrumentation android:name="android.test.InstrumentationTestRunner"
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.framework.permission.tests"
android:label="Tests for private API framework permissions"/>
diff --git a/tests/permission/OWNERS b/tests/permission/OWNERS
new file mode 100644
index 000000000000..999ea0e62a0a
--- /dev/null
+++ b/tests/permission/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/permission/OWNERS
diff --git a/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java
new file mode 100644
index 000000000000..e0f3f03e9cb7
--- /dev/null
+++ b/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.framework.permission.tests;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static junit.framework.Assert.fail;
+
+import android.Manifest;
+import android.content.Context;
+import android.os.Binder;
+import android.os.CombinedVibration;
+import android.os.IVibratorManagerService;
+import android.os.IVibratorStateListener;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+
+/**
+ * Verify that Hardware apis cannot be called without required permissions.
+ */
+@Presubmit
+@RunWith(JUnit4.class)
+public class VibratorManagerServicePermissionTest {
+
+ private static final String PACKAGE_NAME = "com.android.framework.permission.tests";
+ private static final CombinedVibration EFFECT =
+ CombinedVibration.createParallel(
+ VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
+ private static final VibrationAttributes ATTRS = new VibrationAttributes.Builder()
+ .setUsage(VibrationAttributes.USAGE_ALARM)
+ .build();
+
+ @Rule
+ public ExpectedException exceptionRule = ExpectedException.none();
+
+ private IVibratorManagerService mVibratorService;
+
+ @Before
+ public void setUp() throws Exception {
+ mVibratorService = IVibratorManagerService.Stub.asInterface(
+ ServiceManager.getService(Context.VIBRATOR_MANAGER_SERVICE));
+ }
+
+ @After
+ public void cleanUp() {
+ getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
+ }
+
+ @Test
+ public void testIsVibratingFails() throws RemoteException {
+ expectSecurityException("ACCESS_VIBRATOR_STATE");
+ mVibratorService.isVibrating(1);
+ }
+
+ @Test
+ public void testRegisterVibratorStateListenerFails() throws RemoteException {
+ expectSecurityException("ACCESS_VIBRATOR_STATE");
+ IVibratorStateListener listener = new IVibratorStateListener.Stub() {
+ @Override
+ public void onVibrating(boolean vibrating) {
+ fail("Listener callback was not expected.");
+ }
+ };
+ mVibratorService.registerVibratorStateListener(1, listener);
+ }
+
+ @Test
+ public void testUnregisterVibratorStateListenerFails() throws RemoteException {
+ expectSecurityException("ACCESS_VIBRATOR_STATE");
+ mVibratorService.unregisterVibratorStateListener(1, null);
+ }
+
+ @Test
+ public void testSetAlwaysOnEffectFails() throws RemoteException {
+ expectSecurityException("VIBRATE_ALWAYS_ON");
+ mVibratorService.setAlwaysOnEffect(Process.myUid(), PACKAGE_NAME, 1, EFFECT, ATTRS);
+ }
+
+ @Test
+ public void testVibrateWithoutPermissionFails() throws RemoteException {
+ expectSecurityException("VIBRATE");
+ mVibratorService.vibrate(Process.myUid(), PACKAGE_NAME, EFFECT, ATTRS, "testVibrate",
+ new Binder());
+ }
+
+ @Test
+ public void testVibrateWithVibratePermissionAndSameProcessUidIsAllowed()
+ throws RemoteException {
+ getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+ Manifest.permission.VIBRATE);
+ mVibratorService.vibrate(Process.myUid(), PACKAGE_NAME, EFFECT, ATTRS, "testVibrate",
+ new Binder());
+ }
+
+ @Test
+ public void testVibrateWithVibratePermissionAndDifferentUidsFails() throws RemoteException {
+ expectSecurityException("UPDATE_APP_OPS_STATS");
+ getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+ Manifest.permission.VIBRATE);
+ mVibratorService.vibrate(Process.SYSTEM_UID, "android", EFFECT, ATTRS, "testVibrate",
+ new Binder());
+ }
+
+ @Test
+ public void testVibrateWithAllPermissionsAndDifferentUidsIsAllowed() throws RemoteException {
+ getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+ Manifest.permission.VIBRATE,
+ Manifest.permission.UPDATE_APP_OPS_STATS);
+ mVibratorService.vibrate(Process.SYSTEM_UID, "android", EFFECT, ATTRS, "testVibrate",
+ new Binder());
+ }
+
+ @Test
+ public void testCancelVibrateFails() throws RemoteException {
+ expectSecurityException("VIBRATE");
+ mVibratorService.cancelVibrate(/* usageFilter= */ -1, new Binder());
+ }
+
+ private void expectSecurityException(String expectedPermission) {
+ exceptionRule.expect(SecurityException.class);
+ exceptionRule.expectMessage("permission." + expectedPermission);
+ }
+}
diff --git a/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java
deleted file mode 100644
index d1d6a26790fd..000000000000
--- a/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.framework.permission.tests;
-
-import android.os.Binder;
-import android.os.IVibratorService;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.VibrationAttributes;
-import android.os.VibrationEffect;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.TestCase;
-
-
-/**
- * Verify that Hardware apis cannot be called without required permissions.
- */
-@SmallTest
-public class VibratorServicePermissionTest extends TestCase {
-
- private IVibratorService mVibratorService;
-
- @Override
- protected void setUp() throws Exception {
- mVibratorService = IVibratorService.Stub.asInterface(
- ServiceManager.getService("vibrator"));
- }
-
- /**
- * Test that calling {@link android.os.IVibratorService#vibrate(long)} requires permissions.
- * <p>Tests permission:
- * {@link android.Manifest.permission#VIBRATE}
- * @throws RemoteException
- */
- public void testVibrate() throws RemoteException {
- try {
- final VibrationEffect effect =
- VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE);
- final VibrationAttributes attrs = new VibrationAttributes.Builder()
- .setUsage(VibrationAttributes.USAGE_ALARM)
- .build();
- mVibratorService.vibrate(Process.myUid(), null, effect, attrs,
- "testVibrate", new Binder());
- fail("vibrate did not throw SecurityException as expected");
- } catch (SecurityException e) {
- // expected
- }
- }
-
- /**
- * Test that calling {@link android.os.IVibratorService#cancelVibrate()} requires permissions.
- * <p>Tests permission:
- * {@link android.Manifest.permission#VIBRATE}
- * @throws RemoteException
- */
- public void testCancelVibrate() throws RemoteException {
- try {
- mVibratorService.cancelVibrate(new Binder());
- fail("cancelVibrate did not throw SecurityException as expected");
- } catch (SecurityException e) {
- // expected
- }
- }
-}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 737665fb97e4..1fe13fe97fbe 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -28,8 +28,6 @@ import android.view.IWindowManager;
import junit.framework.TestCase;
-import org.junit.Test;
-
/**
* TODO: Remove this. This is only a placeholder, need to implement this.
*/
@@ -56,7 +54,7 @@ public class WindowManagerPermissionTests extends TestCase {
}
try {
- mWm.addWindowToken(null, TYPE_APPLICATION, DEFAULT_DISPLAY);
+ mWm.addWindowToken(null, TYPE_APPLICATION, DEFAULT_DISPLAY, null /* options */);
fail("IWindowManager.addWindowToken did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
@@ -64,26 +62,6 @@ public class WindowManagerPermissionTests extends TestCase {
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
- try {
- mWm.prepareAppTransition(0, false);
- fail("IWindowManager.prepareAppTransition did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
- mWm.executeAppTransition();
- fail("IWindowManager.executeAppTransition did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
}
@SmallTest
@@ -175,29 +153,4 @@ public class WindowManagerPermissionTests extends TestCase {
fail("Unexpected remote exception");
}
}
-
- @Test
- public void testADD_WINDOW_TOKEN_WITH_OPTIONS() {
- // Verify if addWindowTokenWithOptions throw SecurityException for privileged window type.
- try {
- mWm.addWindowTokenWithOptions(null, TYPE_APPLICATION, DEFAULT_DISPLAY, null, "");
- fail("IWindowManager.addWindowTokenWithOptions did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- // Verify if addWindowTokenWithOptions throw SecurityException for null packageName.
- try {
- mWm.addWindowTokenWithOptions(null, TYPE_APPLICATION, DEFAULT_DISPLAY, null, null);
- fail("IWindowManager.addWindowTokenWithOptions did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
- }
}
diff --git a/tests/privapp-permissions/Android.bp b/tests/privapp-permissions/Android.bp
index b6618508d95d..082b08dea91f 100644
--- a/tests/privapp-permissions/Android.bp
+++ b/tests/privapp-permissions/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
android_app {
name: "PrivAppPermissionTest",
sdk_version: "current",
diff --git a/tests/testables/Android.bp b/tests/testables/Android.bp
index eb6811cf490e..c0e3d630d1ab 100644
--- a/tests/testables/Android.bp
+++ b/tests/testables/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
java_library {
name: "testables",
srcs: ["src/**/*.java"],
diff --git a/tests/testables/tests/Android.bp b/tests/testables/tests/Android.bp
index e1a58be7bd68..ba323d3fe47a 100644
--- a/tests/testables/tests/Android.bp
+++ b/tests/testables/tests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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"],
+}
+
android_test {
name: "TestablesTests",
platform_apis: true,
diff --git a/tests/utils/DummyIME/OWNERS b/tests/utils/DummyIME/OWNERS
new file mode 100644
index 000000000000..5deb2ce8f24b
--- /dev/null
+++ b/tests/utils/DummyIME/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/inputmethod/OWNERS
diff --git a/tests/utils/DummyIME/Android.bp b/tests/utils/StubIME/Android.bp
index 4a44b3b27992..d86068cef8b4 100644
--- a/tests/utils/DummyIME/Android.bp
+++ b/tests/utils/StubIME/Android.bp
@@ -14,8 +14,17 @@
// limitations under the License.
//
+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"],
+}
+
android_test {
- name: "DummyIME",
+ name: "StubIME",
srcs: ["src/**/*.java"],
sdk_version: "current",
}
diff --git a/tests/utils/DummyIME/AndroidManifest.xml b/tests/utils/StubIME/AndroidManifest.xml
index fd17a52cb7d9..bc64c671d9be 100644
--- a/tests/utils/DummyIME/AndroidManifest.xml
+++ b/tests/utils/StubIME/AndroidManifest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright 2006, The Android Open Source Project
@@ -17,16 +18,20 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.testing.dummyime">
+ package="com.android.testing.stubime">
<application android:label="Dummy IME">
<service android:name="DummyIme"
- android:permission="android.permission.BIND_INPUT_METHOD">
+ android:permission="android.permission.BIND_INPUT_METHOD"
+ android:exported="true">
<intent-filter>
- <action android:name="android.view.InputMethod" />
+ <action android:name="android.view.InputMethod"/>
</intent-filter>
- <meta-data android:name="android.view.im" android:resource="@xml/method" />
+ <meta-data android:name="android.view.im"
+ android:resource="@xml/method"/>
</service>
- <activity android:name=".ImePreferences" android:label="Dummy IME Settings">
+ <activity android:name=".ImePreferences"
+ android:label="Stub IME Settings"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
diff --git a/tests/utils/StubIME/OWNERS b/tests/utils/StubIME/OWNERS
new file mode 100644
index 000000000000..5deb2ce8f24b
--- /dev/null
+++ b/tests/utils/StubIME/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/inputmethod/OWNERS
diff --git a/tests/utils/DummyIME/res/xml/method.xml b/tests/utils/StubIME/res/xml/method.xml
index 43a330e2bc93..1bb4bcd3480b 100644
--- a/tests/utils/DummyIME/res/xml/method.xml
+++ b/tests/utils/StubIME/res/xml/method.xml
@@ -21,9 +21,9 @@
<!-- for the Search Manager. -->
<input-method xmlns:android="http://schemas.android.com/apk/res/android"
- android:settingsActivity="com.android.testing.dummyime.ImePreferences">
+ android:settingsActivity="com.android.testing.stubime.ImePreferences">
<subtype
android:label="Generic"
android:imeSubtypeLocale="en_US"
android:imeSubtypeMode="keyboard" />
-</input-method> \ No newline at end of file
+</input-method>
diff --git a/tests/utils/DummyIME/src/com/android/testing/dummyime/ImePreferences.java b/tests/utils/StubIME/src/com/android/testing/stubime/ImePreferences.java
index 41036ab86596..b77525ad0a43 100644
--- a/tests/utils/DummyIME/src/com/android/testing/dummyime/ImePreferences.java
+++ b/tests/utils/StubIME/src/com/android/testing/stubime/ImePreferences.java
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package com.android.testing.dummyime;
+package com.android.testing.stubime;
import android.preference.PreferenceActivity;
/**
- * Dummy IME preference activity
+ * Stub IME preference activity
*/
public class ImePreferences extends PreferenceActivity {
diff --git a/tests/utils/DummyIME/src/com/android/testing/dummyime/DummyIme.java b/tests/utils/StubIME/src/com/android/testing/stubime/StubIme.java
index 7b7a39a702e5..8795202b3283 100644
--- a/tests/utils/DummyIME/src/com/android/testing/dummyime/DummyIme.java
+++ b/tests/utils/StubIME/src/com/android/testing/stubime/StubIme.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.android.testing.dummyime;
+package com.android.testing.stubime;
import android.inputmethodservice.InputMethodService;
/**
- * Dummy IME implementation that basically does nothing
+ * Stub IME implementation that basically does nothing
*/
-public class DummyIme extends InputMethodService {
+public class StubIme extends InputMethodService {
@Override
public boolean onEvaluateFullscreenMode() {
diff --git a/tests/utils/hostutils/Android.bp b/tests/utils/hostutils/Android.bp
index c9ad70280aa6..05f3c74218c6 100644
--- a/tests/utils/hostutils/Android.bp
+++ b/tests/utils/hostutils/Android.bp
@@ -13,6 +13,15 @@
// limitations under the License.
//
+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"],
+}
+
java_library_host {
name: "frameworks-base-hostutils",
diff --git a/tests/utils/hostutils/src/com/android/fsverity/AddFsVerityCertRule.java b/tests/utils/hostutils/src/com/android/fsverity/AddFsVerityCertRule.java
new file mode 100644
index 000000000000..5ab4dc60e2ac
--- /dev/null
+++ b/tests/utils/hostutils/src/com/android/fsverity/AddFsVerityCertRule.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 com.android.fsverity;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
+
+import org.junit.rules.ExternalResource;
+
+public final class AddFsVerityCertRule extends ExternalResource {
+
+ private static final String APK_VERITY_STANDARD_MODE = "2";
+
+ private final BaseHostJUnit4Test mHost;
+ private final String mCertPath;
+ private String mKeyId;
+
+ public AddFsVerityCertRule(BaseHostJUnit4Test host, String certPath) {
+ mHost = host;
+ mCertPath = certPath;
+ }
+
+ @Override
+ protected void before() throws Throwable {
+ ITestDevice device = mHost.getDevice();
+ String apkVerityMode = device.getProperty("ro.apk_verity.mode");
+ assumeTrue(device.getLaunchApiLevel() >= 30
+ || APK_VERITY_STANDARD_MODE.equals(apkVerityMode));
+
+ String keyId = executeCommand(
+ "mini-keyctl padd asymmetric fsv_test .fs-verity < " + mCertPath).trim();
+ assertThat(keyId).matches("^\\d+$");
+ mKeyId = keyId;
+ }
+
+ @Override
+ protected void after() {
+ if (mKeyId == null) return;
+ try {
+ executeCommand("mini-keyctl unlink " + mKeyId + " .fs-verity");
+ } catch (DeviceNotAvailableException e) {
+ LogUtil.CLog.e(e);
+ }
+ mKeyId = null;
+ }
+
+ private String executeCommand(String cmd) throws DeviceNotAvailableException {
+ CommandResult result = mHost.getDevice().executeShellV2Command(cmd);
+ assertWithMessage("`" + cmd + "` failed: " + result.getStderr())
+ .that(result.getStatus())
+ .isEqualTo(CommandStatus.SUCCESS);
+ return result.getStdout();
+ }
+}
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 f30c35aca8da..84448333a8c6 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
@@ -16,6 +16,7 @@
package com.android.internal.util.test;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -34,6 +35,8 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import javax.annotation.Nullable;
@@ -49,7 +52,7 @@ import javax.annotation.Nullable;
public class SystemPreparer extends ExternalResource {
private static final long OVERLAY_ENABLE_TIMEOUT_MS = 30000;
- // The paths of the files pushed onto the device through this rule.
+ // The paths of the files pushed onto the device through this rule to be removed after.
private ArrayList<String> mPushedFiles = new ArrayList<>();
// The package names of packages installed through this rule.
@@ -60,12 +63,22 @@ public class SystemPreparer extends ExternalResource {
private final RebootStrategy mRebootStrategy;
private final TearDownRule mTearDownRule;
+ // When debugging, it may be useful to run a test case without rebooting the device afterwards,
+ // to manually verify the device state.
+ private boolean mDebugSkipAfterReboot;
+
public SystemPreparer(TemporaryFolder hostTempFolder, DeviceProvider deviceProvider) {
this(hostTempFolder, RebootStrategy.FULL, null, deviceProvider);
}
public SystemPreparer(TemporaryFolder hostTempFolder, RebootStrategy rebootStrategy,
@Nullable TestRuleDelegate testRuleDelegate, DeviceProvider deviceProvider) {
+ this(hostTempFolder, rebootStrategy, testRuleDelegate, false, deviceProvider);
+ }
+
+ public SystemPreparer(TemporaryFolder hostTempFolder, RebootStrategy rebootStrategy,
+ @Nullable TestRuleDelegate testRuleDelegate, boolean debugSkipAfterReboot,
+ DeviceProvider deviceProvider) {
mHostTempFolder = hostTempFolder;
mDeviceProvider = deviceProvider;
mRebootStrategy = rebootStrategy;
@@ -73,6 +86,7 @@ public class SystemPreparer extends ExternalResource {
if (testRuleDelegate != null) {
testRuleDelegate.setDelegate(mTearDownRule);
}
+ mDebugSkipAfterReboot = debugSkipAfterReboot;
}
/** Copies a file within the host test jar to a path on device. */
@@ -81,7 +95,7 @@ public class SystemPreparer extends ExternalResource {
final ITestDevice device = mDeviceProvider.getDevice();
remount();
assertTrue(device.pushFile(copyResourceToTemp(filePath), outputPath));
- mPushedFiles.add(outputPath);
+ addPushedFile(device, outputPath);
return this;
}
@@ -91,10 +105,23 @@ public class SystemPreparer extends ExternalResource {
final ITestDevice device = mDeviceProvider.getDevice();
remount();
assertTrue(device.pushFile(file, outputPath));
- mPushedFiles.add(outputPath);
+ addPushedFile(device, outputPath);
return this;
}
+ private void addPushedFile(ITestDevice device, String outputPath)
+ throws DeviceNotAvailableException {
+ Path pathCreated = Paths.get(outputPath);
+
+ // Find the top most parent that is new to the device
+ while (pathCreated.getParent() != null
+ && !device.doesFileExist(pathCreated.getParent().toString())) {
+ pathCreated = pathCreated.getParent();
+ }
+
+ mPushedFiles.add(pathCreated.toString());
+ }
+
/** Deletes the given path from the device */
public SystemPreparer deleteFile(String file) throws DeviceNotAvailableException {
final ITestDevice device = mDeviceProvider.getDevice();
@@ -114,6 +141,24 @@ public class SystemPreparer extends ExternalResource {
return this;
}
+ /** Stages multiple APEXs within the host test jar onto the device. */
+ public SystemPreparer stageMultiplePackages(String[] resourcePaths, String[] packageNames)
+ throws DeviceNotAvailableException, IOException {
+ assertEquals(resourcePaths.length, packageNames.length);
+ final ITestDevice device = mDeviceProvider.getDevice();
+ final String[] adbCommandLine = new String[resourcePaths.length + 2];
+ adbCommandLine[0] = "install-multi-package";
+ adbCommandLine[1] = "--staged";
+ for (int i = 0; i < resourcePaths.length; i++) {
+ final File tmpFile = copyResourceToTemp(resourcePaths[i]);
+ adbCommandLine[i + 2] = tmpFile.getAbsolutePath();
+ mInstalledPackages.add(packageNames[i]);
+ }
+ final String output = device.executeAdbCommand(adbCommandLine);
+ assertTrue(output.contains("Success. Reboot device to apply staged session"));
+ return this;
+ }
+
/** Sets the enable state of an overlay package. */
public SystemPreparer setOverlayEnabled(String packageName, boolean enabled)
throws DeviceNotAvailableException {
@@ -157,7 +202,9 @@ public class SystemPreparer extends ExternalResource {
case USERSPACE_UNTIL_ONLINE:
device.rebootUserspaceUntilOnline();
break;
- case START_STOP:
+ // TODO(b/159540015): Make this START_STOP instead of default once it's fixed. Can't
+ // currently be done because START_STOP is commented out.
+ default:
device.executeShellCommand("stop");
device.executeShellCommand("start");
ITestDevice.RecoveryMode cachedRecoveryMode = device.getRecoveryMode();
@@ -182,11 +229,29 @@ public class SystemPreparer extends ExternalResource {
return this;
}
+ private static @Nullable String getFileExtension(@Nullable String path) {
+ if (path == null) {
+ return null;
+ }
+ final int lastDot = path.lastIndexOf('.');
+ if (lastDot >= 0) {
+ return path.substring(lastDot + 1);
+ } else {
+ return null;
+ }
+ }
+
/** Copies a file within the host test jar to a temporary file on the host machine. */
private File copyResourceToTemp(String resourcePath) throws IOException {
- final File tempFile = mHostTempFolder.newFile();
+ final String ext = getFileExtension(resourcePath);
+ final File tempFile;
+ if (ext != null) {
+ tempFile = File.createTempFile("junit", "." + ext, mHostTempFolder.getRoot());
+ } else {
+ tempFile = mHostTempFolder.newFile();
+ }
final ClassLoader classLoader = getClass().getClassLoader();
- try (InputStream assetIs = classLoader.getResource(resourcePath).openStream();
+ try (InputStream assetIs = classLoader.getResourceAsStream(resourcePath);
FileOutputStream assetOs = new FileOutputStream(tempFile)) {
if (assetIs == null) {
throw new IllegalStateException("Failed to find resource " + resourcePath);
@@ -203,7 +268,7 @@ public class SystemPreparer extends ExternalResource {
/** Removes installed packages and files that were pushed to the device. */
@Override
- protected void after() {
+ public void after() {
final ITestDevice device = mDeviceProvider.getDevice();
try {
remount();
@@ -213,7 +278,9 @@ public class SystemPreparer extends ExternalResource {
for (final String packageName : mInstalledPackages) {
device.uninstallPackage(packageName);
}
- reboot();
+ if (!mDebugSkipAfterReboot) {
+ reboot();
+ }
} catch (DeviceNotAvailableException e) {
Assert.fail(e.toString());
}
@@ -340,6 +407,7 @@ public class SystemPreparer extends ExternalResource {
/**
* How to reboot the device. Ordered from slowest to fastest.
*/
+ @SuppressWarnings("DanglingJavadoc")
public enum RebootStrategy {
/** @see ITestDevice#reboot() */
FULL,
@@ -359,7 +427,15 @@ public class SystemPreparer extends ExternalResource {
*
* TODO(b/159540015): There's a bug with this causing unnecessary disk space usage, which
* can eventually lead to an insufficient storage space error.
+ *
+ * This can be uncommented for local development, but should be left out when merging.
+ * It is done this way to hopefully be caught by code review, since merging this will
+ * break all of postsubmit. But the nearly 50% reduction in test runtime is worth having
+ * this option exist.
+ *
+ * @deprecated do not use this in merged code until bug is resolved
*/
- START_STOP
+// @Deprecated
+// START_STOP
}
}
diff --git a/tests/utils/hostutils/src/com/android/tests/rollback/OWNERS b/tests/utils/hostutils/src/com/android/tests/rollback/OWNERS
new file mode 100644
index 000000000000..d04a70619caa
--- /dev/null
+++ b/tests/utils/hostutils/src/com/android/tests/rollback/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/rollback/OWNERS
diff --git a/tests/utils/hostutils/src/com/android/tests/rollback/host/AbandonSessionsRule.java b/tests/utils/hostutils/src/com/android/tests/rollback/host/AbandonSessionsRule.java
index 5bfc75203ae3..b08621314ee0 100644
--- a/tests/utils/hostutils/src/com/android/tests/rollback/host/AbandonSessionsRule.java
+++ b/tests/utils/hostutils/src/com/android/tests/rollback/host/AbandonSessionsRule.java
@@ -16,14 +16,12 @@
package com.android.tests.rollback.host;
-import com.android.ddmlib.Log;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import org.junit.rules.ExternalResource;
-public final class AbandonSessionsRule extends ExternalResource {
- private static final String TAG = "AbandonSessionsRule";
+public class AbandonSessionsRule extends ExternalResource {
private final BaseHostJUnit4Test mHost;
public AbandonSessionsRule(BaseHostJUnit4Test host) {
@@ -39,9 +37,7 @@ public final class AbandonSessionsRule extends ExternalResource {
protected void after() {
try {
abandonSessions(mHost.getDevice());
- } catch (Exception e) {
- mHost.getDevice().logOnDevice(TAG, Log.LogLevel.ERROR,
- "%s", "Failed to abandon sessions");
+ } catch (Exception ignore) {
}
}
diff --git a/tests/utils/testutils/Android.bp b/tests/utils/testutils/Android.bp
index a6625ab9c17f..af9786b92f40 100644
--- a/tests/utils/testutils/Android.bp
+++ b/tests/utils/testutils/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+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"],
+}
+
java_library {
name: "frameworks-base-testutils",
diff --git a/tests/utils/testutils/java/android/view/test/InsetsModeSession.java b/tests/utils/testutils/java/android/view/test/InsetsModeSession.java
deleted file mode 100644
index e05fdce0ca0c..000000000000
--- a/tests/utils/testutils/java/android/view/test/InsetsModeSession.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.test;
-
-import android.view.ViewRootImpl;
-
-/**
- * Session to set insets mode for {@link ViewRootImpl#sNewInsetsMode}.
- */
-public class InsetsModeSession implements AutoCloseable {
-
- private int mOldMode;
-
- public InsetsModeSession(int flag) {
- mOldMode = ViewRootImpl.sNewInsetsMode;
- ViewRootImpl.sNewInsetsMode = flag;
- }
-
- @Override
- public void close() {
- ViewRootImpl.sNewInsetsMode = mOldMode;
- }
-}
diff --git a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
index 25bd7c06be49..3da8b460df13 100644
--- a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
+++ b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
@@ -29,7 +29,6 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -43,6 +42,8 @@ public class BroadcastInterceptingContext extends ContextWrapper {
private final List<BroadcastInterceptor> mInterceptors = new ArrayList<>();
+ private boolean mUseRegisteredHandlers;
+
public abstract class FutureIntent extends FutureTask<Intent> {
public FutureIntent() {
super(
@@ -62,17 +63,24 @@ public class BroadcastInterceptingContext extends ContextWrapper {
public class BroadcastInterceptor extends FutureIntent {
private final BroadcastReceiver mReceiver;
private final IntentFilter mFilter;
+ private final Handler mHandler;
- public BroadcastInterceptor(BroadcastReceiver receiver, IntentFilter filter) {
+ public BroadcastInterceptor(BroadcastReceiver receiver, IntentFilter filter,
+ Handler handler) {
mReceiver = receiver;
mFilter = filter;
+ mHandler = mUseRegisteredHandlers ? handler : null;
}
public boolean dispatchBroadcast(Intent intent) {
if (mFilter.match(getContentResolver(), intent, false, TAG) > 0) {
if (mReceiver != null) {
final Context context = BroadcastInterceptingContext.this;
- mReceiver.onReceive(context, intent);
+ if (mHandler == null) {
+ mReceiver.onReceive(context, intent);
+ } else {
+ mHandler.post(() -> mReceiver.onReceive(context, intent));
+ }
return false;
} else {
set(intent);
@@ -117,25 +125,38 @@ public class BroadcastInterceptingContext extends ContextWrapper {
}
public FutureIntent nextBroadcastIntent(IntentFilter filter) {
- final BroadcastInterceptor interceptor = new BroadcastInterceptor(null, filter);
+ final BroadcastInterceptor interceptor = new BroadcastInterceptor(null, filter, null);
synchronized (mInterceptors) {
mInterceptors.add(interceptor);
}
return interceptor;
}
- @Override
- public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+ /**
+ * Whether to send broadcasts to registered handlers. By default, receivers are called
+ * synchronously by sendBroadcast. If this method is called with {@code true}, the receiver is
+ * instead called by a runnable posted to the Handler specified when the receiver was
+ * registered. This method applies only to future registrations, already-registered receivers
+ * are unaffected.
+ */
+ public void setUseRegisteredHandlers(boolean use) {
synchronized (mInterceptors) {
- mInterceptors.add(new BroadcastInterceptor(receiver, filter));
+ mUseRegisteredHandlers = use;
}
- return null;
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+ return registerReceiver(receiver, filter, null, null);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
- return registerReceiver(receiver, filter);
+ synchronized (mInterceptors) {
+ mInterceptors.add(new BroadcastInterceptor(receiver, filter, scheduler));
+ }
+ return null;
}
@Override
@@ -175,6 +196,12 @@ public class BroadcastInterceptingContext extends ContextWrapper {
}
@Override
+ public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions,
+ Bundle options) {
+ sendBroadcast(intent);
+ }
+
+ @Override
public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
String[] receiverPermissions) {
sendBroadcast(intent);
@@ -197,6 +224,11 @@ public class BroadcastInterceptingContext extends ContextWrapper {
}
@Override
+ public void sendStickyBroadcast(Intent intent, Bundle options) {
+ sendBroadcast(intent);
+ }
+
+ @Override
public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
sendBroadcast(intent);
}
diff --git a/tests/utils/testutils/java/com/android/internal/util/test/FsUtil.java b/tests/utils/testutils/java/com/android/internal/util/test/FsUtil.java
new file mode 100644
index 000000000000..e65661298b7c
--- /dev/null
+++ b/tests/utils/testutils/java/com/android/internal/util/test/FsUtil.java
@@ -0,0 +1,40 @@
+/*
+ * 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.util.test;
+
+import java.io.File;
+
+public class FsUtil {
+
+ /**
+ * Deletes all files under a given directory. Deliberately ignores errors, on the assumption
+ * that test cleanup is only supposed to be best-effort.
+ *
+ * @param dir directory to clear its contents
+ */
+ public static void deleteContents(File dir) {
+ File[] files = dir.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ if (file.isDirectory()) {
+ deleteContents(file);
+ }
+ file.delete();
+ }
+ }
+ }
+}
diff --git a/tests/utils/testutils/java/com/android/server/accessibility/OWNERS b/tests/utils/testutils/java/com/android/server/accessibility/OWNERS
new file mode 100644
index 000000000000..b74281edbf52
--- /dev/null
+++ b/tests/utils/testutils/java/com/android/server/accessibility/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/accessibility/OWNERS
diff --git a/tests/utils/testutils/java/com/android/server/wm/OWNERS b/tests/utils/testutils/java/com/android/server/wm/OWNERS
new file mode 100644
index 000000000000..0862c05e0ee4
--- /dev/null
+++ b/tests/utils/testutils/java/com/android/server/wm/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
index ea803f2aba8b..bcd6ed73e133 100644
--- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
+++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
@@ -30,12 +30,21 @@ import com.android.test.filters.SelectTest;
* -e selectTest_verbose true \
* com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
* </pre>
+ *
+ * <p>Use this filter when running FrameworksMockingCoreTests as
+ * <pre>
+ * adb shell am instrument -w \
+ * -e filter com.android.server.wm.test.filters.FrameworksTestsFilter \
+ * -e selectTest_verbose true \
+ * com.android.frameworks.mockingcoretests/androidx.test.runner.AndroidJUnitRunner
+ * </pre>
*/
public final class FrameworksTestsFilter extends SelectTest {
private static final String[] SELECTED_TESTS = {
// Test specifications for FrameworksMockingCoreTests.
"android.app.activity.ActivityThreadClientTest",
+ "android.view.DisplayTest",
// Test specifications for FrameworksCoreTests.
"android.app.servertransaction.", // all tests under the package.
"android.view.CutoutSpecificationTest",
@@ -46,10 +55,14 @@ public final class FrameworksTestsFilter extends SelectTest {
"android.view.InsetsSourceTest",
"android.view.InsetsSourceConsumerTest",
"android.view.InsetsStateTest",
+ "android.view.RoundedCornerTest",
+ "android.view.RoundedCornersTest",
"android.view.WindowMetricsTest",
"android.view.PendingInsetsControllerTest",
- "android.app.WindowContextTest",
- "android.window.WindowMetricsHelperTest"
+ "android.window.WindowContextTest",
+ "android.window.WindowMetricsHelperTest",
+ "android.app.activity.ActivityThreadTest",
+ "android.window.WindowContextControllerTest"
};
public FrameworksTestsFilter(Bundle testArgs) {
diff --git a/tests/vcn/Android.bp b/tests/vcn/Android.bp
new file mode 100644
index 000000000000..41f73cd9c706
--- /dev/null
+++ b/tests/vcn/Android.bp
@@ -0,0 +1,37 @@
+//########################################################################
+// Build FrameworksVcnTests package
+//########################################################################
+
+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"],
+}
+
+android_test {
+ name: "FrameworksVcnTests",
+ srcs: [
+ "java/**/*.java",
+ "java/**/*.kt",
+ ],
+ platform_apis: true,
+ test_suites: ["device-tests"],
+ certificate: "platform",
+ static_libs: [
+ "androidx.test.rules",
+ "frameworks-base-testutils",
+ "framework-protos",
+ "mockito-target-minus-junit4",
+ "net-tests-utils",
+ "platform-test-annotations",
+ "services.core",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
+}
diff --git a/tests/net/smoketest/AndroidManifest.xml b/tests/vcn/AndroidManifest.xml
index f1b9febb9f57..2ad9aac67029 100644
--- a/tests/net/smoketest/AndroidManifest.xml
+++ b/tests/vcn/AndroidManifest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
+<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,13 +15,14 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.frameworks.tests.net.smoketest">
+ package="com.android.frameworks.tests.vcn">
+
<application>
<uses-library android:name="android.test.runner" />
</application>
<instrumentation
android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.frameworks.tests.net.smoketest"
- android:label="Frameworks Networking Smoke Tests" />
+ android:targetPackage="com.android.frameworks.tests.vcn"
+ android:label="Frameworks VCN Tests" />
</manifest>
diff --git a/tests/net/AndroidTest.xml b/tests/vcn/AndroidTest.xml
index 939ae493b280..dc521fd7bcd9 100644
--- a/tests/net/AndroidTest.xml
+++ b/tests/vcn/AndroidTest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,15 +13,15 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Runs Frameworks Networking Tests.">
+<configuration description="Runs VCN Tests.">
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
- <option name="test-file-name" value="FrameworksNetTests.apk" />
+ <option name="test-file-name" value="FrameworksVcnTests.apk" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
- <option name="test-tag" value="FrameworksNetTests" />
+ <option name="test-tag" value="FrameworksVcnTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="com.android.frameworks.tests.net" />
+ <option name="package" value="com.android.frameworks.tests.vcn" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
diff --git a/tests/vcn/OWNERS b/tests/vcn/OWNERS
new file mode 100644
index 000000000000..33b9f0f75f81
--- /dev/null
+++ b/tests/vcn/OWNERS
@@ -0,0 +1,7 @@
+set noparent
+
+benedictwong@google.com
+ckesting@google.com
+evitayan@google.com
+nharold@google.com
+jchalard@google.com \ No newline at end of file
diff --git a/tests/vcn/TEST_MAPPING b/tests/vcn/TEST_MAPPING
new file mode 100644
index 000000000000..54fa411e3570
--- /dev/null
+++ b/tests/vcn/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksVcnTests"
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/vcn/assets/client-end-cert.pem b/tests/vcn/assets/client-end-cert.pem
new file mode 100644
index 000000000000..e82da85c50ab
--- /dev/null
+++ b/tests/vcn/assets/client-end-cert.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDaDCCAlCgAwIBAgIIcorRI3n29E4wDQYJKoZIhvcNAQELBQAwQTELMAkGA1UE
+BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxIDAeBgNVBAMTF3R3by5jYS50ZXN0LmFu
+ZHJvaWQubmV0MB4XDTIwMDQxNDA1MDM0OVoXDTIzMDQxNDA1MDM0OVowRTELMAkG
+A1UEBhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxJDAiBgNVBAMTG2NsaWVudC50ZXN0
+LmlrZS5hbmRyb2lkLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AK/cK+sIaiQlJYvy5+Dq70sJbgR7PO1uS2qkLRP7Wb3z5SNvz94nQvZRrFn1AFIE
+CpfESh5kUF6gJe7t7NR3mpQ98iEosCRBMDJT8qB+EeHiL4wkrmCE9sYMTyvaApRc
+6Qzozn/9kKma7Qpj/25AvoPluTERqhZ6AQ77BJeb6FNOAoO1Aoe9GJuB1xmRxjRw
+D0mwusL+ciQ/7uKlsFP5VO5XqACcohXSerzO8jcD9necBvka3SDepqqzn1K0NPRC
+25fMmS5kSjddKtKOif7w2NI3OpVsmP3kHv66If73VURsy0lgXPYyKkq8lAMrtmXG
+R7svFGPbEl+Swkpr3b+dzF8CAwEAAaNgMF4wHwYDVR0jBBgwFoAUcqSu1uRYT/DL
+bLoDNUz38nGvCKQwJgYDVR0RBB8wHYIbY2xpZW50LnRlc3QuaWtlLmFuZHJvaWQu
+bmV0MBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQCa53tK
+I9RM9/MutZ5KNG2Gfs2cqaPyv8ZRhs90HDWZhkFVu7prywJAxOd2hxxHPsvgurio
+4bKAxnT4EXevgz5YoCbj2TPIL9TdFYh59zZ97XXMxk+SRdypgF70M6ETqKPs3hDP
+ZRMMoHvvYaqaPvp4StSBX9A44gSyjHxVYJkrjDZ0uffKg5lFL5IPvqfdmSRSpGab
+SyGTP4OLTy0QiNV3pBsJGdl0h5BzuTPR9OTl4xgeqqBQy2bDjmfJBuiYyCSCkPi7
+T3ohDYCymhuSkuktHPNG1aKllUJaw0tuZuNydlgdAveXPYfM36uvK0sfd9qr9pAy
+rmkYV2MAWguFeckh
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/tests/vcn/assets/client-private-key.key b/tests/vcn/assets/client-private-key.key
new file mode 100644
index 000000000000..22736e98e030
--- /dev/null
+++ b/tests/vcn/assets/client-private-key.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCv3CvrCGokJSWL
+8ufg6u9LCW4EezztbktqpC0T+1m98+Ujb8/eJ0L2UaxZ9QBSBAqXxEoeZFBeoCXu
+7ezUd5qUPfIhKLAkQTAyU/KgfhHh4i+MJK5ghPbGDE8r2gKUXOkM6M5//ZCpmu0K
+Y/9uQL6D5bkxEaoWegEO+wSXm+hTTgKDtQKHvRibgdcZkcY0cA9JsLrC/nIkP+7i
+pbBT+VTuV6gAnKIV0nq8zvI3A/Z3nAb5Gt0g3qaqs59StDT0QtuXzJkuZEo3XSrS
+jon+8NjSNzqVbJj95B7+uiH+91VEbMtJYFz2MipKvJQDK7Zlxke7LxRj2xJfksJK
+a92/ncxfAgMBAAECggEAQztaMvW5lm35J8LKsWs/5qEJRX9T8LWs8W0oqq36Riub
+G2wgvR6ndAIPcSjAYZqX7iOl7m6NZ0+0kN63HxdGqovwKIskpAekBGmhpYftED1n
+zh0r6UyMB3UnQ22KdOv8UOokIDxxdNX8728BdUYdT9Ggdkj5jLRB+VcwD0IUlNvo
+zzTpURV9HEd87uiLqd4AAHXSI0lIHI5U43z24HI/J6/YbYHT3Rlh6CIa/LuwO6vL
+gFkgqg0/oy6yJtjrHtzNVA67F0UaH62hR4YFgbC0d955SJnDidWOv/0j2DMpfdCc
+9kFAcPwUSyykvUSLnGIKWSG4D+6gzIeAeUx4oO7kMQKBgQDVNRkX8AGTHyLg+NXf
+spUWWcodwVioXl30Q7h6+4bt8OI61UbhQ7wX61wvJ1cySpa2KOYa2UdagQVhGhhL
+ADu363R77uXF/jZgzVfmjjyJ2nfDqRgHWRTlSkuq/jCOQCz7VIPHRZg5WL/9D4ms
+TAqMjpzqeMfFZI+w4/+xpcJIuQKBgQDTKBy+ZuerWrVT9icWKvLU58o5EVj/2yFy
+GJvKm+wRAAX2WzjNnR4HVd4DmMREVz1BPYby0j5gqjvtDsxYYu39+NT7JvMioLLK
+QPj+7k5geYgNqVgCxB1vP89RhY2X1RLrN9sTXOodgFPeXOQWNYITkGp3eQpx4nTJ
++K/al3oB1wKBgAjnc8nVIyuyxDEjE0OJYMKTM2a0uXAmqMPXxC+Wq5bqVXhhidlE
+i+lv0eTCPtkB1nN7F8kNQ/aaps/cWCFhvBy9P5shagUvzbOTP9WIIS0cq53HRRKh
+fMbqqGhWv05hjb9dUzeSR341n6cA7B3++v3Nwu3j52vt/DZF/1q68nc5AoGAS0SU
+ImbKE/GsizZGLoe2sZ/CHN+LKwCwhlwxRGKaHmE0vuE7eUeVSaYZEo0lAPtb8WJ+
+NRYueASWgeTxgFwbW5mUScZTirdfo+rPFwhZVdhcYApKPgosN9i2DOgfVcz1BnWN
+mPRY25U/0BaqkyQVruWeneG+kGPZn5kPDktKiVcCgYEAkzwU9vCGhm7ZVALvx/zR
+wARz2zsL9ImBc0P4DK1ld8g90FEnHrEgeI9JEwz0zFHOCMLwlk7kG0Xev7vfjZ7G
+xSqtQYOH33Qp6rtBOgdt8hSyDFvakvDl6bqhAw52gelO3MTpAB1+ZsfZ5gFx13Jf
+idNFcaIrC52PtZIH7QCzdDY=
+-----END PRIVATE KEY----- \ No newline at end of file
diff --git a/tests/vcn/assets/self-signed-ca.pem b/tests/vcn/assets/self-signed-ca.pem
new file mode 100644
index 000000000000..5135ea7077a8
--- /dev/null
+++ b/tests/vcn/assets/self-signed-ca.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDPjCCAiagAwIBAgIICrKLpR7LxlowDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE
+BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxHDAaBgNVBAMTE2NhLnRlc3QuYW5kcm9p
+ZC5uZXQwHhcNMTkwNzE2MTcxNTUyWhcNMjkwNzEzMTcxNTUyWjA9MQswCQYDVQQG
+EwJVUzEQMA4GA1UEChMHQW5kcm9pZDEcMBoGA1UEAxMTY2EudGVzdC5hbmRyb2lk
+Lm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANsvTwad2Nie0VOy
+Xb1VtHL0R760Jm4vr14JWMcX4oiE6jUdTNdXQ0CGb65wvulP2aEeukFH0D/cvBMR
+Bv9+haEwo9/grIXg9ALNKp+GfuZYw/dfnUMHFn3g2+SUgP6BoMZc4lkHktjkDKxp
+99Q6h4NP/ip1labkhBeB9+Z6l78LTixKRKspNITWASJed9bjzshYxKHi6dJy3maQ
+1LwYKmK7PEGRpoDoT8yZhFbxsVDUojGnJKH1RLXVOn/psG6dI/+IsbTipAttj5zc
+g2VAD56PZG2Jd+vsup+g4Dy72hyy242x5c/H2LKZn4X0B0B+IXyii/ZVc+DJldQ5
+JqplOL8CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
+HQYDVR0OBBYEFGYUzuvZUaVJl8mcxejuFiUNGcTfMA0GCSqGSIb3DQEBCwUAA4IB
+AQDQYeqjvHsK2ZqSqxakDp0nu36Plbj48Wvx1ru7GW2faz7i0w/Zkxh06zniILCb
+QJRjDebSTHc5SSbCFrRTvqagaLDhbH42/hQncWqIoJqW+pmznJET4JiBO0sqzm05
+yQWsLI/h9Ir28Y2g5N+XPBU0VVVejQqH4iI0iwQx7y7ABssQ0Xa/K73VPbeGaKd6
+Prt4wjJvTlIL2yE2+0MggJ3F2rNptL5SDpg3g+4/YQ6wVRBFil95kUqplEsCtU4P
+t+8RghiEmsRx/8CywKfZ5Hex87ODhsSDmDApcefbd5gxoWVkqxZUkPcKwYv1ucm8
+u4r44fj4/9W0Zeooav5Yoh1q
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/tests/vcn/java/android/net/vcn/VcnConfigTest.java b/tests/vcn/java/android/net/vcn/VcnConfigTest.java
new file mode 100644
index 000000000000..7ac51b7e3342
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnConfigTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collections;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnConfigTest {
+ private static final String TEST_PACKAGE_NAME = VcnConfigTest.class.getPackage().getName();
+ private static final Set<VcnGatewayConnectionConfig> GATEWAY_CONNECTION_CONFIGS =
+ Collections.singleton(VcnGatewayConnectionConfigTest.buildTestConfig());
+
+ private final Context mContext = mock(Context.class);
+
+ // Public visibility for VcnManagementServiceTest
+ public static VcnConfig buildTestConfig(@NonNull Context context) {
+ VcnConfig.Builder builder = new VcnConfig.Builder(context);
+
+ for (VcnGatewayConnectionConfig gatewayConnectionConfig : GATEWAY_CONNECTION_CONFIGS) {
+ builder.addGatewayConnectionConfig(gatewayConnectionConfig);
+ }
+
+ return builder.build();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ doReturn(TEST_PACKAGE_NAME).when(mContext).getOpPackageName();
+ }
+
+ @Test
+ public void testBuilderConstructorRequiresContext() {
+ try {
+ new VcnConfig.Builder(null);
+ fail("Expected exception due to null context");
+ } catch (NullPointerException e) {
+ }
+ }
+
+ @Test
+ public void testBuilderRequiresGatewayConnectionConfig() {
+ try {
+ new VcnConfig.Builder(mContext).build();
+ fail("Expected exception due to no VcnGatewayConnectionConfigs provided");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @Test
+ public void testBuilderRequiresUniqueGatewayConnectionNames() {
+ final VcnGatewayConnectionConfig config = VcnGatewayConnectionConfigTest.buildTestConfig();
+ try {
+ new VcnConfig.Builder(mContext)
+ .addGatewayConnectionConfig(config)
+ .addGatewayConnectionConfig(config);
+ fail("Expected exception due to duplicate gateway connection name");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @Test
+ public void testBuilderAndGetters() {
+ final VcnConfig config = buildTestConfig(mContext);
+
+ assertEquals(TEST_PACKAGE_NAME, config.getProvisioningPackageName());
+ assertEquals(GATEWAY_CONNECTION_CONFIGS, config.getGatewayConnectionConfigs());
+ }
+
+ @Test
+ public void testPersistableBundle() {
+ final VcnConfig config = buildTestConfig(mContext);
+
+ assertEquals(config, new VcnConfig(config.toPersistableBundle()));
+ }
+
+ @Test
+ public void testParceling() {
+ final VcnConfig config = buildTestConfig(mContext);
+
+ Parcel parcel = Parcel.obtain();
+ config.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ assertEquals(config, VcnConfig.CREATOR.createFromParcel(parcel));
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
new file mode 100644
index 000000000000..dc338ae0fdc7
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn;
+
+import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.net.NetworkCapabilities;
+import android.net.ipsec.ike.IkeSessionParams;
+import android.net.ipsec.ike.IkeTunnelConnectionParams;
+import android.net.vcn.persistablebundleutils.IkeSessionParamsUtilsTest;
+import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtilsTest;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionConfigTest {
+ // Public for use in VcnGatewayConnectionTest
+ public static final int[] EXPOSED_CAPS =
+ new int[] {
+ NetworkCapabilities.NET_CAPABILITY_INTERNET, NetworkCapabilities.NET_CAPABILITY_MMS
+ };
+ public static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN};
+
+ static {
+ Arrays.sort(EXPOSED_CAPS);
+ Arrays.sort(UNDERLYING_CAPS);
+ }
+
+ public static final long[] RETRY_INTERVALS_MS =
+ new long[] {
+ TimeUnit.SECONDS.toMillis(5),
+ TimeUnit.SECONDS.toMillis(30),
+ TimeUnit.MINUTES.toMillis(1),
+ TimeUnit.MINUTES.toMillis(5),
+ TimeUnit.MINUTES.toMillis(15),
+ TimeUnit.MINUTES.toMillis(30)
+ };
+ public static final int MAX_MTU = 1360;
+
+ public static final IkeTunnelConnectionParams TUNNEL_CONNECTION_PARAMS =
+ TunnelConnectionParamsUtilsTest.buildTestParams();
+
+ public static final String GATEWAY_CONNECTION_NAME_PREFIX = "gatewayConnectionName-";
+ private static int sGatewayConnectionConfigCount = 0;
+
+ private static VcnGatewayConnectionConfig buildTestConfig(
+ String gatewayConnectionName, IkeTunnelConnectionParams tunnelConnectionParams) {
+ return buildTestConfigWithExposedCaps(
+ new VcnGatewayConnectionConfig.Builder(
+ gatewayConnectionName, tunnelConnectionParams),
+ EXPOSED_CAPS);
+ }
+
+ // Public for use in VcnGatewayConnectionTest
+ public static VcnGatewayConnectionConfig buildTestConfig() {
+ return buildTestConfigWithExposedCaps(EXPOSED_CAPS);
+ }
+
+ private static VcnGatewayConnectionConfig.Builder newBuilder() {
+ // Append a unique identifier to the name prefix to guarantee that all created
+ // VcnGatewayConnectionConfigs have a unique name (required by VcnConfig).
+ return new VcnGatewayConnectionConfig.Builder(
+ GATEWAY_CONNECTION_NAME_PREFIX + sGatewayConnectionConfigCount++,
+ TUNNEL_CONNECTION_PARAMS);
+ }
+
+ private static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(
+ VcnGatewayConnectionConfig.Builder builder, int... exposedCaps) {
+ builder.setRetryIntervalsMillis(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU);
+
+ for (int caps : exposedCaps) {
+ builder.addExposedCapability(caps);
+ }
+
+ return builder.build();
+ }
+
+ // Public for use in VcnGatewayConnectionTest
+ public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) {
+ return buildTestConfigWithExposedCaps(newBuilder(), exposedCaps);
+ }
+
+ @Test
+ public void testBuilderRequiresNonNullGatewayConnectionName() {
+ try {
+ new VcnGatewayConnectionConfig.Builder(
+ null /* gatewayConnectionName */, TUNNEL_CONNECTION_PARAMS)
+ .build();
+
+ fail("Expected exception due to invalid gateway connection name");
+ } catch (NullPointerException e) {
+ }
+ }
+
+ @Test
+ public void testBuilderRequiresNonNullTunnelConnectionParams() {
+ try {
+ new VcnGatewayConnectionConfig.Builder(
+ GATEWAY_CONNECTION_NAME_PREFIX, null /* tunnelConnectionParams */)
+ .build();
+
+ fail("Expected exception due to the absence of tunnel connection parameters");
+ } catch (NullPointerException e) {
+ }
+ }
+
+ @Test
+ public void testBuilderRequiresMobikeEnabled() {
+ try {
+ final IkeSessionParams ikeParams =
+ IkeSessionParamsUtilsTest.createBuilderMinimum()
+ .removeIkeOption(IKE_OPTION_MOBIKE)
+ .build();
+ final IkeTunnelConnectionParams tunnelParams =
+ TunnelConnectionParamsUtilsTest.buildTestParams(ikeParams);
+ new VcnGatewayConnectionConfig.Builder(GATEWAY_CONNECTION_NAME_PREFIX, tunnelParams);
+ fail("Expected exception due to MOBIKE not enabled");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @Test
+ public void testBuilderRequiresNonEmptyExposedCaps() {
+ try {
+ newBuilder().build();
+
+ fail("Expected exception due to invalid exposed capabilities");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @Test
+ public void testBuilderRequiresNonNullRetryInterval() {
+ try {
+ newBuilder().setRetryIntervalsMillis(null);
+ fail("Expected exception due to invalid retryIntervalMs");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @Test
+ public void testBuilderRequiresNonEmptyRetryInterval() {
+ try {
+ newBuilder().setRetryIntervalsMillis(new long[0]);
+ fail("Expected exception due to invalid retryIntervalMs");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @Test
+ public void testBuilderRequiresValidMtu() {
+ try {
+ newBuilder().setMaxMtu(VcnGatewayConnectionConfig.MIN_MTU_V6 - 1);
+ fail("Expected exception due to invalid mtu");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @Test
+ public void testBuilderAndGetters() {
+ final VcnGatewayConnectionConfig config = buildTestConfig();
+
+ assertTrue(config.getGatewayConnectionName().startsWith(GATEWAY_CONNECTION_NAME_PREFIX));
+
+ int[] exposedCaps = config.getExposedCapabilities();
+ Arrays.sort(exposedCaps);
+ assertArrayEquals(EXPOSED_CAPS, exposedCaps);
+
+ assertEquals(TUNNEL_CONNECTION_PARAMS, config.getTunnelConnectionParams());
+
+ assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis());
+ assertEquals(MAX_MTU, config.getMaxMtu());
+ }
+
+ @Test
+ public void testPersistableBundle() {
+ final VcnGatewayConnectionConfig config = buildTestConfig();
+
+ assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle()));
+ }
+
+ private static IkeTunnelConnectionParams buildTunnelConnectionParams(String ikePsk) {
+ final IkeSessionParams ikeParams =
+ IkeSessionParamsUtilsTest.createBuilderMinimum()
+ .setAuthPsk(ikePsk.getBytes())
+ .build();
+ return TunnelConnectionParamsUtilsTest.buildTestParams(ikeParams);
+ }
+
+ @Test
+ public void testTunnelConnectionParamsEquals() throws Exception {
+ final String connectionName = "testTunnelConnectionParamsEquals.connectionName";
+ final String psk = "testTunnelConnectionParamsEquals.psk";
+
+ final IkeTunnelConnectionParams tunnelParams = buildTunnelConnectionParams(psk);
+ final VcnGatewayConnectionConfig config = buildTestConfig(connectionName, tunnelParams);
+
+ final IkeTunnelConnectionParams anotherTunnelParams = buildTunnelConnectionParams(psk);
+ final VcnGatewayConnectionConfig anotherConfig =
+ buildTestConfig(connectionName, anotherTunnelParams);
+
+ assertNotSame(tunnelParams, anotherTunnelParams);
+ assertEquals(tunnelParams, anotherTunnelParams);
+ assertEquals(config, anotherConfig);
+ }
+
+ @Test
+ public void testTunnelConnectionParamsNotEquals() throws Exception {
+ final String connectionName = "testTunnelConnectionParamsNotEquals.connectionName";
+
+ final IkeTunnelConnectionParams tunnelParams =
+ buildTunnelConnectionParams("testTunnelConnectionParamsNotEquals.pskA");
+ final VcnGatewayConnectionConfig config = buildTestConfig(connectionName, tunnelParams);
+
+ final IkeTunnelConnectionParams anotherTunnelParams =
+ buildTunnelConnectionParams("testTunnelConnectionParamsNotEquals.pskB");
+ final VcnGatewayConnectionConfig anotherConfig =
+ buildTestConfig(connectionName, anotherTunnelParams);
+
+ assertNotEquals(tunnelParams, anotherTunnelParams);
+ assertNotEquals(config, anotherConfig);
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
new file mode 100644
index 000000000000..8461de6d877b
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn;
+
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
+
+import static androidx.test.InstrumentationRegistry.getContext;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
+import android.net.vcn.VcnManager.VcnStatusCallback;
+import android.net.vcn.VcnManager.VcnStatusCallbackBinder;
+import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener;
+import android.os.ParcelUuid;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import java.net.UnknownHostException;
+import java.util.UUID;
+import java.util.concurrent.Executor;
+
+public class VcnManagerTest {
+ private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0));
+ private static final String GATEWAY_CONNECTION_NAME = "gatewayConnectionName";
+ private static final Executor INLINE_EXECUTOR = Runnable::run;
+
+ private IVcnManagementService mMockVcnManagementService;
+ private VcnUnderlyingNetworkPolicyListener mMockPolicyListener;
+ private VcnStatusCallback mMockStatusCallback;
+
+ private Context mContext;
+ private VcnManager mVcnManager;
+
+ @Before
+ public void setUp() {
+ mMockVcnManagementService = mock(IVcnManagementService.class);
+ mMockPolicyListener = mock(VcnUnderlyingNetworkPolicyListener.class);
+ mMockStatusCallback = mock(VcnStatusCallback.class);
+
+ mContext = getContext();
+ mVcnManager = new VcnManager(mContext, mMockVcnManagementService);
+ }
+
+ @Test
+ public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception {
+ mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, mMockPolicyListener);
+
+ ArgumentCaptor<IVcnUnderlyingNetworkPolicyListener> captor =
+ ArgumentCaptor.forClass(IVcnUnderlyingNetworkPolicyListener.class);
+ verify(mMockVcnManagementService).addVcnUnderlyingNetworkPolicyListener(captor.capture());
+
+ assertTrue(VcnManager.getAllPolicyListeners().containsKey(mMockPolicyListener));
+
+ IVcnUnderlyingNetworkPolicyListener listenerWrapper = captor.getValue();
+ listenerWrapper.onPolicyChanged();
+ verify(mMockPolicyListener).onPolicyChanged();
+ }
+
+ @Test
+ public void testRemoveVcnUnderlyingNetworkPolicyListener() throws Exception {
+ mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, mMockPolicyListener);
+
+ mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ assertFalse(VcnManager.getAllPolicyListeners().containsKey(mMockPolicyListener));
+ verify(mMockVcnManagementService)
+ .addVcnUnderlyingNetworkPolicyListener(
+ any(IVcnUnderlyingNetworkPolicyListener.class));
+ }
+
+ @Test
+ public void testRemoveVcnUnderlyingNetworkPolicyListenerUnknownListener() throws Exception {
+ mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ assertFalse(VcnManager.getAllPolicyListeners().containsKey(mMockPolicyListener));
+ verify(mMockVcnManagementService, never())
+ .addVcnUnderlyingNetworkPolicyListener(
+ any(IVcnUnderlyingNetworkPolicyListener.class));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testAddVcnUnderlyingNetworkPolicyListenerNullExecutor() throws Exception {
+ mVcnManager.addVcnUnderlyingNetworkPolicyListener(null, mMockPolicyListener);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testAddVcnUnderlyingNetworkPolicyListenerNullListener() throws Exception {
+ mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testRemoveVcnUnderlyingNetworkPolicyListenerNullListener() {
+ mVcnManager.removeVcnUnderlyingNetworkPolicyListener(null);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicy() throws Exception {
+ NetworkCapabilities nc = new NetworkCapabilities();
+ LinkProperties lp = new LinkProperties();
+ when(mMockVcnManagementService.getUnderlyingNetworkPolicy(eq(nc), eq(lp)))
+ .thenReturn(new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, nc));
+
+ VcnUnderlyingNetworkPolicy policy = mVcnManager.getUnderlyingNetworkPolicy(nc, lp);
+
+ assertFalse(policy.isTeardownRequested());
+ assertEquals(nc, policy.getMergedNetworkCapabilities());
+ verify(mMockVcnManagementService).getUnderlyingNetworkPolicy(eq(nc), eq(lp));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testGetUnderlyingNetworkPolicyNullNetworkCapabilities() throws Exception {
+ mVcnManager.getUnderlyingNetworkPolicy(null, new LinkProperties());
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testGetUnderlyingNetworkPolicyNullLinkProperties() throws Exception {
+ mVcnManager.getUnderlyingNetworkPolicy(new NetworkCapabilities(), null);
+ }
+
+ @Test
+ public void testRegisterVcnStatusCallback() throws Exception {
+ mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback);
+
+ verify(mMockVcnManagementService)
+ .registerVcnStatusCallback(eq(SUB_GROUP), notNull(), any());
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testRegisterVcnStatusCallbackAlreadyRegistered() throws Exception {
+ mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback);
+ mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testRegisterVcnStatusCallbackNullSubscriptionGroup() throws Exception {
+ mVcnManager.registerVcnStatusCallback(null, INLINE_EXECUTOR, mMockStatusCallback);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testRegisterVcnStatusCallbackNullExecutor() throws Exception {
+ mVcnManager.registerVcnStatusCallback(SUB_GROUP, null, mMockStatusCallback);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testRegisterVcnStatusCallbackNullCallback() throws Exception {
+ mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, null);
+ }
+
+ @Test
+ public void testUnregisterVcnStatusCallback() throws Exception {
+ mVcnManager.registerVcnStatusCallback(SUB_GROUP, INLINE_EXECUTOR, mMockStatusCallback);
+
+ mVcnManager.unregisterVcnStatusCallback(mMockStatusCallback);
+
+ verify(mMockVcnManagementService).unregisterVcnStatusCallback(any());
+ }
+
+ @Test
+ public void testUnregisterUnknownVcnStatusCallback() throws Exception {
+ mVcnManager.unregisterVcnStatusCallback(mMockStatusCallback);
+
+ verifyNoMoreInteractions(mMockVcnManagementService);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testUnregisterNullVcnStatusCallback() throws Exception {
+ mVcnManager.unregisterVcnStatusCallback(null);
+ }
+
+ @Test
+ public void testVcnStatusCallbackBinder() throws Exception {
+ IVcnStatusCallback cbBinder =
+ new VcnStatusCallbackBinder(INLINE_EXECUTOR, mMockStatusCallback);
+
+ cbBinder.onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE);
+ verify(mMockStatusCallback).onStatusChanged(VCN_STATUS_CODE_ACTIVE);
+
+ cbBinder.onGatewayConnectionError(
+ GATEWAY_CONNECTION_NAME,
+ VcnManager.VCN_ERROR_CODE_NETWORK_ERROR,
+ UnknownHostException.class.getName(),
+ "exception_message");
+ verify(mMockStatusCallback)
+ .onGatewayConnectionError(
+ eq(GATEWAY_CONNECTION_NAME),
+ eq(VcnManager.VCN_ERROR_CODE_NETWORK_ERROR),
+ any(UnknownHostException.class));
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java
new file mode 100644
index 000000000000..19df3c75266c
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
+import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
+import static android.net.NetworkCapabilities.REDACT_NONE;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+
+import android.net.NetworkCapabilities;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.os.Parcel;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+
+public class VcnTransportInfoTest {
+ private static final int SUB_ID = 1;
+ private static final int NETWORK_ID = 5;
+ private static final WifiInfo WIFI_INFO =
+ new WifiInfo.Builder().setNetworkId(NETWORK_ID).build();
+
+ private static final VcnTransportInfo CELL_UNDERLYING_INFO = new VcnTransportInfo(SUB_ID);
+ private static final VcnTransportInfo WIFI_UNDERLYING_INFO = new VcnTransportInfo(WIFI_INFO);
+
+ @Test
+ public void testGetWifiInfo() {
+ assertEquals(WIFI_INFO, WIFI_UNDERLYING_INFO.getWifiInfo());
+
+ assertNull(CELL_UNDERLYING_INFO.getWifiInfo());
+ }
+
+ @Test
+ public void testGetSubId() {
+ assertEquals(SUB_ID, CELL_UNDERLYING_INFO.getSubId());
+
+ assertEquals(INVALID_SUBSCRIPTION_ID, WIFI_UNDERLYING_INFO.getSubId());
+ }
+
+ @Test
+ public void testMakeCopyRedactForNetworkSettings() {
+ for (VcnTransportInfo info : Arrays.asList(CELL_UNDERLYING_INFO, WIFI_UNDERLYING_INFO)) {
+ assertEquals(
+ INVALID_SUBSCRIPTION_ID,
+ ((VcnTransportInfo) info.makeCopy(REDACT_FOR_NETWORK_SETTINGS))
+ .getSubId());
+ assertNull(
+ ((VcnTransportInfo) info.makeCopy(REDACT_FOR_NETWORK_SETTINGS))
+ .getWifiInfo());
+ }
+ }
+
+ @Test
+ public void testMakeCopyRedactForAccessFineLocation() {
+ assertEquals(
+ SUB_ID,
+ ((VcnTransportInfo) CELL_UNDERLYING_INFO.makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION))
+ .getSubId());
+ assertEquals(
+ WifiConfiguration.INVALID_NETWORK_ID,
+ ((VcnTransportInfo) WIFI_UNDERLYING_INFO.makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION))
+ .getWifiInfo().getNetworkId());
+ }
+
+ @Test
+ public void testEquals() {
+ assertEquals(CELL_UNDERLYING_INFO, CELL_UNDERLYING_INFO);
+ assertEquals(WIFI_UNDERLYING_INFO, WIFI_UNDERLYING_INFO);
+ assertNotEquals(CELL_UNDERLYING_INFO, WIFI_UNDERLYING_INFO);
+ }
+
+ @Test
+ public void testParcelUnparcel() {
+ verifyParcelingIsNull(CELL_UNDERLYING_INFO);
+ verifyParcelingIsNull(WIFI_UNDERLYING_INFO);
+ }
+
+ private void verifyParcelingIsNull(VcnTransportInfo vcnTransportInfo) {
+ VcnTransportInfo redacted = (VcnTransportInfo) vcnTransportInfo.makeCopy(
+ NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS);
+
+ Parcel parcel = Parcel.obtain();
+ redacted.writeToParcel(parcel, 0 /* flags */);
+ parcel.setDataPosition(0);
+
+ assertNull(VcnTransportInfo.CREATOR.createFromParcel(parcel));
+ }
+
+ @Test
+ public void testParcelNotRedactedForSysUi() {
+ VcnTransportInfo cellRedacted = parcelForSysUi(CELL_UNDERLYING_INFO);
+ assertEquals(SUB_ID, cellRedacted.getSubId());
+ VcnTransportInfo wifiRedacted = parcelForSysUi(WIFI_UNDERLYING_INFO);
+ assertEquals(NETWORK_ID, wifiRedacted.getWifiInfo().getNetworkId());
+ }
+
+ private VcnTransportInfo parcelForSysUi(VcnTransportInfo vcnTransportInfo) {
+ // Allow fully unredacted; SysUI will have all the relevant permissions.
+ final VcnTransportInfo unRedacted = (VcnTransportInfo) vcnTransportInfo.makeCopy(
+ REDACT_NONE);
+ final Parcel parcel = Parcel.obtain();
+ unRedacted.writeToParcel(parcel, 0 /* flags */);
+ parcel.setDataPosition(0);
+
+ final VcnTransportInfo unparceled = VcnTransportInfo.CREATOR.createFromParcel(parcel);
+ assertEquals(vcnTransportInfo, unparceled);
+ return unparceled;
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
new file mode 100644
index 000000000000..a674425efea3
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn;
+
+import static com.android.testutils.ParcelUtils.assertParcelSane;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.net.NetworkCapabilities;
+
+import org.junit.Test;
+
+public class VcnUnderlyingNetworkPolicyTest {
+ private static final VcnUnderlyingNetworkPolicy DEFAULT_NETWORK_POLICY =
+ new VcnUnderlyingNetworkPolicy(
+ false /* isTearDownRequested */, new NetworkCapabilities());
+ private static final VcnUnderlyingNetworkPolicy SAMPLE_NETWORK_POLICY =
+ new VcnUnderlyingNetworkPolicy(
+ true /* isTearDownRequested */,
+ new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .build());
+
+ @Test
+ public void testEquals() {
+ assertEquals(DEFAULT_NETWORK_POLICY, DEFAULT_NETWORK_POLICY);
+ assertEquals(SAMPLE_NETWORK_POLICY, SAMPLE_NETWORK_POLICY);
+
+ assertNotEquals(DEFAULT_NETWORK_POLICY, SAMPLE_NETWORK_POLICY);
+ }
+
+ @Test
+ public void testParcelUnparcel() {
+ assertParcelSane(SAMPLE_NETWORK_POLICY, 1);
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java
new file mode 100644
index 000000000000..2110d6ee7c86
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.testutils.ParcelUtils.assertParcelSane;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.net.TelephonyNetworkSpecifier;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnUnderlyingNetworkSpecifierTest {
+ private static final int[] TEST_SUB_IDS = new int[] {1, 2, 3, 5};
+
+ @Test
+ public void testGetSubIds() {
+ final VcnUnderlyingNetworkSpecifier specifier =
+ new VcnUnderlyingNetworkSpecifier(TEST_SUB_IDS);
+
+ assertEquals(TEST_SUB_IDS, specifier.getSubIds());
+ }
+
+ @Test
+ public void testParceling() {
+ final VcnUnderlyingNetworkSpecifier specifier =
+ new VcnUnderlyingNetworkSpecifier(TEST_SUB_IDS);
+ assertParcelSane(specifier, 1);
+ }
+
+ @Test
+ public void testCanBeSatisfiedByTelephonyNetworkSpecifier() {
+ final TelephonyNetworkSpecifier telSpecifier =
+ new TelephonyNetworkSpecifier(TEST_SUB_IDS[0]);
+
+ final VcnUnderlyingNetworkSpecifier specifier =
+ new VcnUnderlyingNetworkSpecifier(TEST_SUB_IDS);
+ assertTrue(specifier.canBeSatisfiedBy(telSpecifier));
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java
new file mode 100644
index 000000000000..bc8e9d3200b6
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn.persistablebundleutils;
+
+import static android.telephony.TelephonyManager.APPTYPE_USIM;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.eap.EapSessionConfig;
+import android.os.PersistableBundle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class EapSessionConfigUtilsTest {
+ private static final byte[] EAP_ID = "test@android.net".getBytes(StandardCharsets.US_ASCII);
+ private static final String USERNAME = "username";
+ private static final String PASSWORD = "password";
+ private static final int SUB_ID = 1;
+ private static final String NETWORK_NAME = "android.net";
+ private static final boolean ALLOW_MISMATCHED_NETWORK_NAMES = true;
+
+ private EapSessionConfig.Builder createBuilderWithId() {
+ return new EapSessionConfig.Builder().setEapIdentity(EAP_ID);
+ }
+
+ private static void verifyPersistableBundleEncodeDecodeIsLossless(EapSessionConfig config) {
+ final PersistableBundle bundle = EapSessionConfigUtils.toPersistableBundle(config);
+ final EapSessionConfig resultConfig = EapSessionConfigUtils.fromPersistableBundle(bundle);
+
+ assertEquals(config, resultConfig);
+ }
+
+ @Test
+ public void testSetEapMsChapV2EncodeDecodeIsLossless() throws Exception {
+ final EapSessionConfig config =
+ createBuilderWithId().setEapMsChapV2Config(USERNAME, PASSWORD).build();
+
+ verifyPersistableBundleEncodeDecodeIsLossless(config);
+ }
+
+ @Test
+ public void testSetEapSimEncodeDecodeIsLossless() throws Exception {
+ final EapSessionConfig config =
+ createBuilderWithId().setEapSimConfig(SUB_ID, APPTYPE_USIM).build();
+
+ verifyPersistableBundleEncodeDecodeIsLossless(config);
+ }
+
+ @Test
+ public void testSetEapAkaEncodeDecodeIsLossless() throws Exception {
+ final EapSessionConfig config =
+ createBuilderWithId().setEapAkaConfig(SUB_ID, APPTYPE_USIM).build();
+
+ verifyPersistableBundleEncodeDecodeIsLossless(config);
+ }
+
+ @Test
+ public void testSetEapAkaPrimeEncodeDecodeIsLossless() throws Exception {
+ final EapSessionConfig config =
+ createBuilderWithId()
+ .setEapAkaPrimeConfig(
+ SUB_ID, APPTYPE_USIM, NETWORK_NAME, ALLOW_MISMATCHED_NETWORK_NAMES)
+ .build();
+
+ verifyPersistableBundleEncodeDecodeIsLossless(config);
+ }
+
+ @Test
+ public void testSetEapTtlsEncodeDecodeIsLossless() throws Exception {
+ final InputStream inputStream =
+ InstrumentationRegistry.getContext()
+ .getResources()
+ .getAssets()
+ .open("self-signed-ca.pem");
+ final CertificateFactory factory = CertificateFactory.getInstance("X.509");
+ final X509Certificate trustedCa =
+ (X509Certificate) factory.generateCertificate(inputStream);
+
+ final EapSessionConfig innerConfig =
+ new EapSessionConfig.Builder().setEapMsChapV2Config(USERNAME, PASSWORD).build();
+
+ final EapSessionConfig config =
+ new EapSessionConfig.Builder().setEapTtlsConfig(trustedCa, innerConfig).build();
+
+ verifyPersistableBundleEncodeDecodeIsLossless(config);
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java
new file mode 100644
index 000000000000..4f3930f9b5af
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.persistablebundleutils;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.ipsec.ike.IkeDerAsn1DnIdentification;
+import android.net.ipsec.ike.IkeFqdnIdentification;
+import android.net.ipsec.ike.IkeIdentification;
+import android.net.ipsec.ike.IkeIpv4AddrIdentification;
+import android.net.ipsec.ike.IkeIpv6AddrIdentification;
+import android.net.ipsec.ike.IkeKeyIdIdentification;
+import android.net.ipsec.ike.IkeRfc822AddrIdentification;
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+
+import javax.security.auth.x500.X500Principal;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IkeIdentificationUtilsTest {
+ private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeIdentification id) {
+ final PersistableBundle bundle = IkeIdentificationUtils.toPersistableBundle(id);
+ final IkeIdentification result = IkeIdentificationUtils.fromPersistableBundle(bundle);
+
+ assertEquals(result, id);
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeIpv4AddressId() throws Exception {
+ final Inet4Address ipv4Address = (Inet4Address) InetAddress.getByName("192.0.2.100");
+ verifyPersistableBundleEncodeDecodeIsLossless(new IkeIpv4AddrIdentification(ipv4Address));
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeIpv6AddressId() throws Exception {
+ final Inet6Address ipv6Address = (Inet6Address) InetAddress.getByName("2001:db8:2::100");
+ verifyPersistableBundleEncodeDecodeIsLossless(new IkeIpv6AddrIdentification(ipv6Address));
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeRfc822AddrId() throws Exception {
+ verifyPersistableBundleEncodeDecodeIsLossless(new IkeFqdnIdentification("ike.android.net"));
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeFqdnId() throws Exception {
+ verifyPersistableBundleEncodeDecodeIsLossless(
+ new IkeRfc822AddrIdentification("androidike@example.com"));
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeKeyId() throws Exception {
+ verifyPersistableBundleEncodeDecodeIsLossless(
+ new IkeKeyIdIdentification("androidIkeKeyId".getBytes()));
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeDerAsn1DnId() throws Exception {
+ verifyPersistableBundleEncodeDecodeIsLossless(
+ new IkeDerAsn1DnIdentification(
+ new X500Principal("CN=small.server.test.android.net, O=Android, C=US")));
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java
new file mode 100644
index 000000000000..f3851130c68a
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.persistablebundleutils;
+
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.telephony.TelephonyManager.APPTYPE_USIM;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.net.eap.EapSessionConfig;
+import android.net.ipsec.ike.IkeFqdnIdentification;
+import android.net.ipsec.ike.IkeSessionParams;
+import android.os.PersistableBundle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.org.bouncycastle.util.io.pem.PemObject;
+import com.android.internal.org.bouncycastle.util.io.pem.PemReader;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPrivateKey;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IkeSessionParamsUtilsTest {
+ // Public for use in VcnGatewayConnectionConfigTest, EncryptedTunnelParamsUtilsTest
+ public static IkeSessionParams.Builder createBuilderMinimum() {
+ final InetAddress serverAddress = InetAddresses.parseNumericAddress("192.0.2.100");
+
+ // TODO: b/185941731 Make sure all valid IKE_OPTIONS are added and validated.
+ return new IkeSessionParams.Builder()
+ .setServerHostname(serverAddress.getHostAddress())
+ .addSaProposal(SaProposalUtilsTest.buildTestIkeSaProposal())
+ .setLocalIdentification(new IkeFqdnIdentification("client.test.android.net"))
+ .setRemoteIdentification(new IkeFqdnIdentification("server.test.android.net"))
+ .addIkeOption(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500)
+ .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE)
+ .setAuthPsk("psk".getBytes());
+ }
+
+ private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeSessionParams params) {
+ final PersistableBundle bundle = IkeSessionParamsUtils.toPersistableBundle(params);
+ final IkeSessionParams result = IkeSessionParamsUtils.fromPersistableBundle(bundle);
+
+ assertEquals(result, params);
+ }
+
+ @Test
+ public void testEncodeRecodeParamsWithLifetimes() throws Exception {
+ final int hardLifetime = (int) TimeUnit.HOURS.toSeconds(20L);
+ final int softLifetime = (int) TimeUnit.HOURS.toSeconds(10L);
+ final IkeSessionParams params =
+ createBuilderMinimum().setLifetimeSeconds(hardLifetime, softLifetime).build();
+ verifyPersistableBundleEncodeDecodeIsLossless(params);
+ }
+
+ @Test
+ public void testEncodeRecodeParamsWithDpdDelay() throws Exception {
+ final int dpdDelay = (int) TimeUnit.MINUTES.toSeconds(10L);
+ final IkeSessionParams params = createBuilderMinimum().setDpdDelaySeconds(dpdDelay).build();
+
+ verifyPersistableBundleEncodeDecodeIsLossless(params);
+ }
+
+ @Test
+ public void testEncodeRecodeParamsWithNattKeepalive() throws Exception {
+ final int nattKeepAliveDelay = (int) TimeUnit.MINUTES.toSeconds(5L);
+ final IkeSessionParams params =
+ createBuilderMinimum().setNattKeepAliveDelaySeconds(nattKeepAliveDelay).build();
+
+ verifyPersistableBundleEncodeDecodeIsLossless(params);
+ }
+
+ @Test
+ public void testEncodeRecodeParamsWithRetransmissionTimeouts() throws Exception {
+ final int[] retransmissionTimeout = new int[] {500, 500, 500, 500, 500, 500};
+ final IkeSessionParams params =
+ createBuilderMinimum()
+ .setRetransmissionTimeoutsMillis(retransmissionTimeout)
+ .build();
+
+ verifyPersistableBundleEncodeDecodeIsLossless(params);
+ }
+
+ @Test
+ public void testEncodeRecodeParamsWithConfigRequests() throws Exception {
+ final Inet4Address ipv4Address =
+ (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.100");
+ final Inet6Address ipv6Address =
+ (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::1");
+
+ final IkeSessionParams params =
+ createBuilderMinimum()
+ .addPcscfServerRequest(AF_INET)
+ .addPcscfServerRequest(AF_INET6)
+ .addPcscfServerRequest(ipv4Address)
+ .addPcscfServerRequest(ipv6Address)
+ .build();
+ verifyPersistableBundleEncodeDecodeIsLossless(params);
+ }
+
+ @Test
+ public void testEncodeRecodeParamsWithAuthPsk() throws Exception {
+ final IkeSessionParams params = createBuilderMinimum().setAuthPsk("psk".getBytes()).build();
+ verifyPersistableBundleEncodeDecodeIsLossless(params);
+ }
+
+ @Test
+ public void testEncodeRecodeParamsWithIkeOptions() throws Exception {
+ final IkeSessionParams params =
+ createBuilderMinimum()
+ .addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
+ .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE)
+ .build();
+ verifyPersistableBundleEncodeDecodeIsLossless(params);
+ }
+
+ private static InputStream openAssetsFile(String fileName) throws Exception {
+ return InstrumentationRegistry.getContext().getResources().getAssets().open(fileName);
+ }
+
+ private static X509Certificate createCertFromPemFile(String fileName) throws Exception {
+ final CertificateFactory factory = CertificateFactory.getInstance("X.509");
+ return (X509Certificate) factory.generateCertificate(openAssetsFile(fileName));
+ }
+
+ private static RSAPrivateKey createRsaPrivateKeyFromKeyFile(String fileName) throws Exception {
+ final PemObject pemObject =
+ new PemReader(new InputStreamReader(openAssetsFile(fileName))).readPemObject();
+ return (RSAPrivateKey) CertUtils.privateKeyFromByteArray(pemObject.getContent());
+ }
+
+ @Test
+ public void testEncodeRecodeParamsWithDigitalSignAuth() throws Exception {
+ final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem");
+ final X509Certificate clientEndCert = createCertFromPemFile("client-end-cert.pem");
+ final RSAPrivateKey clientPrivateKey =
+ createRsaPrivateKeyFromKeyFile("client-private-key.key");
+
+ final IkeSessionParams params =
+ createBuilderMinimum()
+ .setAuthDigitalSignature(serverCaCert, clientEndCert, clientPrivateKey)
+ .build();
+ verifyPersistableBundleEncodeDecodeIsLossless(params);
+ }
+
+ @Test
+ public void testEncodeRecodeParamsWithEapAuth() throws Exception {
+ final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem");
+
+ final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII);
+ final int subId = 1;
+ final EapSessionConfig eapConfig =
+ new EapSessionConfig.Builder()
+ .setEapIdentity(eapId)
+ .setEapSimConfig(subId, APPTYPE_USIM)
+ .setEapAkaConfig(subId, APPTYPE_USIM)
+ .build();
+
+ final IkeSessionParams params =
+ createBuilderMinimum().setAuthEap(serverCaCert, eapConfig).build();
+ verifyPersistableBundleEncodeDecodeIsLossless(params);
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java
new file mode 100644
index 000000000000..28cf38a2a583
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.persistablebundleutils;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.net.ipsec.ike.IkeTrafficSelector;
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.InetAddress;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IkeTrafficSelectorUtilsTest {
+ private static final int START_PORT = 16;
+ private static final int END_PORT = 65520;
+
+ private static final InetAddress IPV4_START_ADDRESS =
+ InetAddresses.parseNumericAddress("192.0.2.100");
+ private static final InetAddress IPV4_END_ADDRESS =
+ InetAddresses.parseNumericAddress("192.0.2.101");
+
+ private static final InetAddress IPV6_START_ADDRESS =
+ InetAddresses.parseNumericAddress("2001:db8:2::100");
+ private static final InetAddress IPV6_END_ADDRESS =
+ InetAddresses.parseNumericAddress("2001:db8:2::101");
+
+ private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeTrafficSelector ts) {
+ final PersistableBundle bundle = IkeTrafficSelectorUtils.toPersistableBundle(ts);
+ final IkeTrafficSelector resultTs = IkeTrafficSelectorUtils.fromPersistableBundle(bundle);
+ assertEquals(ts, resultTs);
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeIsLosslessIpv4Ts() throws Exception {
+ verifyPersistableBundleEncodeDecodeIsLossless(
+ new IkeTrafficSelector(START_PORT, END_PORT, IPV4_START_ADDRESS, IPV4_END_ADDRESS));
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeIsLosslessIpv6Ts() throws Exception {
+ verifyPersistableBundleEncodeDecodeIsLossless(
+ new IkeTrafficSelector(START_PORT, END_PORT, IPV6_START_ADDRESS, IPV6_END_ADDRESS));
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java
new file mode 100644
index 000000000000..664044a9e7d4
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.persistablebundleutils;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.ipsec.ike.ChildSaProposal;
+import android.net.ipsec.ike.IkeSaProposal;
+import android.net.ipsec.ike.SaProposal;
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SaProposalUtilsTest {
+ /** Package private so that IkeSessionParamsUtilsTest can use it */
+ static IkeSaProposal buildTestIkeSaProposal() {
+ return new IkeSaProposal.Builder()
+ .addEncryptionAlgorithm(
+ SaProposal.ENCRYPTION_ALGORITHM_3DES, SaProposal.KEY_LEN_UNUSED)
+ .addEncryptionAlgorithm(
+ SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128)
+ .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
+ .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128)
+ .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC)
+ .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256)
+ .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
+ .addDhGroup(SaProposal.DH_GROUP_3072_BIT_MODP)
+ .build();
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeIsLosslessIkeProposal() throws Exception {
+ final IkeSaProposal proposal = buildTestIkeSaProposal();
+
+ final PersistableBundle bundle = IkeSaProposalUtils.toPersistableBundle(proposal);
+ final SaProposal resultProposal = IkeSaProposalUtils.fromPersistableBundle(bundle);
+
+ assertEquals(proposal, resultProposal);
+ }
+
+ /** Package private so that TunnelModeChildSessionParamsUtilsTest can use it */
+ static ChildSaProposal buildTestChildSaProposal() {
+ return new ChildSaProposal.Builder()
+ .addEncryptionAlgorithm(
+ SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128)
+ .addEncryptionAlgorithm(
+ SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_192)
+ .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
+ .addDhGroup(SaProposal.DH_GROUP_4096_BIT_MODP)
+ .build();
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeIsLosslessChildProposal() throws Exception {
+ final ChildSaProposal proposal = buildTestChildSaProposal();
+
+ final PersistableBundle bundle = ChildSaProposalUtils.toPersistableBundle(proposal);
+ final SaProposal resultProposal = ChildSaProposalUtils.fromPersistableBundle(bundle);
+
+ assertEquals(proposal, resultProposal);
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java
new file mode 100644
index 000000000000..f9dc9eb4d5ae
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.persistablebundleutils;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.ipsec.ike.IkeSessionParams;
+import android.net.ipsec.ike.IkeTunnelConnectionParams;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TunnelConnectionParamsUtilsTest {
+ // Public for use in VcnGatewayConnectionConfigTest
+ public static IkeTunnelConnectionParams buildTestParams() {
+ return buildTestParams(IkeSessionParamsUtilsTest.createBuilderMinimum().build());
+ }
+
+ // Public for use in VcnGatewayConnectionConfigTest
+ public static IkeTunnelConnectionParams buildTestParams(IkeSessionParams params) {
+ return new IkeTunnelConnectionParams(
+ params, TunnelModeChildSessionParamsUtilsTest.createBuilderMinimum().build());
+ }
+
+ @Test
+ public void testIkeTunnelConnectionParamsToFromPersistableBundle() {
+ final IkeTunnelConnectionParams params = buildTestParams();
+
+ assertEquals(
+ params,
+ TunnelConnectionParamsUtils.fromPersistableBundle(
+ TunnelConnectionParamsUtils.toPersistableBundle(params)));
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java
new file mode 100644
index 000000000000..e0b5f0ef0381
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.persistablebundleutils;
+
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.net.ipsec.ike.ChildSaProposal;
+import android.net.ipsec.ike.IkeTrafficSelector;
+import android.net.ipsec.ike.TunnelModeChildSessionParams;
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TunnelModeChildSessionParamsUtilsTest {
+ // Package private for use in EncryptedTunnelParamsUtilsTest
+ static TunnelModeChildSessionParams.Builder createBuilderMinimum() {
+ final ChildSaProposal saProposal = SaProposalUtilsTest.buildTestChildSaProposal();
+ return new TunnelModeChildSessionParams.Builder().addSaProposal(saProposal);
+ }
+
+ private static void verifyPersistableBundleEncodeDecodeIsLossless(
+ TunnelModeChildSessionParams params) {
+ final PersistableBundle bundle =
+ TunnelModeChildSessionParamsUtils.toPersistableBundle(params);
+ final TunnelModeChildSessionParams result =
+ TunnelModeChildSessionParamsUtils.fromPersistableBundle(bundle);
+
+ assertEquals(params, result);
+ }
+
+ @Test
+ public void testMinimumParamsEncodeDecodeIsLossless() throws Exception {
+ final TunnelModeChildSessionParams sessionParams = createBuilderMinimum().build();
+ verifyPersistableBundleEncodeDecodeIsLossless(sessionParams);
+ }
+
+ @Test
+ public void testSetTsEncodeDecodeIsLossless() throws Exception {
+ final IkeTrafficSelector tsInbound =
+ new IkeTrafficSelector(
+ 16,
+ 65520,
+ InetAddresses.parseNumericAddress("192.0.2.100"),
+ InetAddresses.parseNumericAddress("192.0.2.101"));
+ final IkeTrafficSelector tsOutbound =
+ new IkeTrafficSelector(
+ 32,
+ 256,
+ InetAddresses.parseNumericAddress("192.0.2.200"),
+ InetAddresses.parseNumericAddress("192.0.2.255"));
+
+ final TunnelModeChildSessionParams sessionParams =
+ createBuilderMinimum()
+ .addInboundTrafficSelectors(tsInbound)
+ .addOutboundTrafficSelectors(tsOutbound)
+ .build();
+ verifyPersistableBundleEncodeDecodeIsLossless(sessionParams);
+ }
+
+ @Test
+ public void testSetLifetimesEncodeDecodeIsLossless() throws Exception {
+ final int hardLifetime = (int) TimeUnit.HOURS.toSeconds(3L);
+ final int softLifetime = (int) TimeUnit.HOURS.toSeconds(1L);
+
+ final TunnelModeChildSessionParams sessionParams =
+ createBuilderMinimum().setLifetimeSeconds(hardLifetime, softLifetime).build();
+ verifyPersistableBundleEncodeDecodeIsLossless(sessionParams);
+ }
+
+ @Test
+ public void testSetConfigRequestsEncodeDecodeIsLossless() throws Exception {
+ final int ipv6PrefixLen = 64;
+ final Inet4Address ipv4Address =
+ (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.100");
+ final Inet6Address ipv6Address =
+ (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::1");
+
+ final TunnelModeChildSessionParams sessionParams =
+ createBuilderMinimum()
+ .addInternalAddressRequest(AF_INET)
+ .addInternalAddressRequest(AF_INET6)
+ .addInternalAddressRequest(ipv4Address)
+ .addInternalAddressRequest(ipv6Address, ipv6PrefixLen)
+ .addInternalDnsServerRequest(AF_INET)
+ .addInternalDnsServerRequest(AF_INET6)
+ .addInternalDhcpServerRequest(AF_INET)
+ .build();
+ verifyPersistableBundleEncodeDecodeIsLossless(sessionParams);
+ }
+}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
new file mode 100644
index 000000000000..7c7dc4d79e9a
--- /dev/null
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -0,0 +1,1349 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static android.net.ConnectivityManager.NetworkCallback;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+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 android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
+
+import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
+import static com.android.server.vcn.VcnTestUtils.setupSystemService;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.CALLS_REAL_METHODS;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.argThat;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.annotation.NonNull;
+import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.net.TelephonyNetworkSpecifier;
+import android.net.vcn.IVcnStatusCallback;
+import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
+import android.net.vcn.VcnConfig;
+import android.net.vcn.VcnConfigTest;
+import android.net.vcn.VcnGatewayConnectionConfigTest;
+import android.net.vcn.VcnManager;
+import android.net.vcn.VcnUnderlyingNetworkPolicy;
+import android.os.IBinder;
+import android.os.ParcelUuid;
+import android.os.PersistableBundle;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.test.TestLooper;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.ArraySet;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.VcnManagementService.VcnCallback;
+import com.android.server.VcnManagementService.VcnStatusCallbackInfo;
+import com.android.server.vcn.TelephonySubscriptionTracker;
+import com.android.server.vcn.Vcn;
+import com.android.server.vcn.VcnContext;
+import com.android.server.vcn.VcnNetworkProvider;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.UUID;
+
+/** Tests for {@link VcnManagementService}. */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnManagementServiceTest {
+ private static final String TEST_PACKAGE_NAME =
+ VcnManagementServiceTest.class.getPackage().getName();
+ private static final String TEST_CB_PACKAGE_NAME =
+ VcnManagementServiceTest.class.getPackage().getName() + ".callback";
+ private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0));
+ private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1));
+ private static final VcnConfig TEST_VCN_CONFIG;
+ private static final int TEST_UID = Process.FIRST_APPLICATION_UID;
+
+ static {
+ final Context mockConfigContext = mock(Context.class);
+ doReturn(TEST_PACKAGE_NAME).when(mockConfigContext).getOpPackageName();
+
+ TEST_VCN_CONFIG = VcnConfigTest.buildTestConfig(mockConfigContext);
+ }
+
+ private static final Map<ParcelUuid, VcnConfig> TEST_VCN_CONFIG_MAP =
+ Collections.unmodifiableMap(Collections.singletonMap(TEST_UUID_1, TEST_VCN_CONFIG));
+
+ private static final int TEST_SUBSCRIPTION_ID = 1;
+ private static final int TEST_SUBSCRIPTION_ID_2 = 2;
+ private static final SubscriptionInfo TEST_SUBSCRIPTION_INFO =
+ new SubscriptionInfo(
+ TEST_SUBSCRIPTION_ID /* id */,
+ "" /* iccId */,
+ 0 /* simSlotIndex */,
+ "Carrier" /* displayName */,
+ "Carrier" /* carrierName */,
+ 0 /* nameSource */,
+ 255 /* iconTint */,
+ "12345" /* number */,
+ 0 /* roaming */,
+ null /* icon */,
+ "0" /* mcc */,
+ "0" /* mnc */,
+ "0" /* countryIso */,
+ false /* isEmbedded */,
+ null /* nativeAccessRules */,
+ null /* cardString */,
+ false /* isOpportunistic */,
+ TEST_UUID_1.toString() /* groupUUID */,
+ 0 /* carrierId */,
+ 0 /* profileClass */);
+
+ private final Context mMockContext = mock(Context.class);
+ private final VcnManagementService.Dependencies mMockDeps =
+ mock(VcnManagementService.Dependencies.class);
+ private final TestLooper mTestLooper = new TestLooper();
+ private final ConnectivityManager mConnMgr = mock(ConnectivityManager.class);
+ private final TelephonyManager mTelMgr = mock(TelephonyManager.class);
+ private final SubscriptionManager mSubMgr = mock(SubscriptionManager.class);
+ private final AppOpsManager mAppOpsMgr = mock(AppOpsManager.class);
+ private final VcnContext mVcnContext = mock(VcnContext.class);
+ private final PersistableBundleUtils.LockingReadWriteHelper mConfigReadWriteHelper =
+ mock(PersistableBundleUtils.LockingReadWriteHelper.class);
+ private final TelephonySubscriptionTracker mSubscriptionTracker =
+ mock(TelephonySubscriptionTracker.class);
+
+ private final ArgumentCaptor<VcnCallback> mVcnCallbackCaptor =
+ ArgumentCaptor.forClass(VcnCallback.class);
+
+ private final VcnManagementService mVcnMgmtSvc;
+
+ private final IVcnUnderlyingNetworkPolicyListener mMockPolicyListener =
+ mock(IVcnUnderlyingNetworkPolicyListener.class);
+ private final IVcnStatusCallback mMockStatusCallback = mock(IVcnStatusCallback.class);
+ private final IBinder mMockIBinder = mock(IBinder.class);
+
+ public VcnManagementServiceTest() throws Exception {
+ setupSystemService(
+ mMockContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+ setupSystemService(
+ mMockContext, mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
+ setupSystemService(
+ mMockContext,
+ mSubMgr,
+ Context.TELEPHONY_SUBSCRIPTION_SERVICE,
+ SubscriptionManager.class);
+ setupSystemService(mMockContext, mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class);
+
+ doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName();
+
+ doReturn(mMockContext).when(mVcnContext).getContext();
+ doReturn(mTestLooper.getLooper()).when(mMockDeps).getLooper();
+ doReturn(TEST_UID).when(mMockDeps).getBinderCallingUid();
+ doReturn(mVcnContext)
+ .when(mMockDeps)
+ .newVcnContext(
+ eq(mMockContext),
+ eq(mTestLooper.getLooper()),
+ any(VcnNetworkProvider.class),
+ anyBoolean());
+ doReturn(mSubscriptionTracker)
+ .when(mMockDeps)
+ .newTelephonySubscriptionTracker(
+ eq(mMockContext),
+ eq(mTestLooper.getLooper()),
+ any(TelephonySubscriptionTrackerCallback.class));
+ doReturn(mConfigReadWriteHelper)
+ .when(mMockDeps)
+ .newPersistableBundleLockingReadWriteHelper(any());
+
+ // Setup VCN instance generation
+ doAnswer((invocation) -> {
+ // Mock-within a doAnswer is safe, because it doesn't actually run nested.
+ return mock(Vcn.class);
+ }).when(mMockDeps).newVcn(any(), any(), any(), any(), any());
+
+ final PersistableBundle bundle =
+ PersistableBundleUtils.fromMap(
+ TEST_VCN_CONFIG_MAP,
+ PersistableBundleUtils::fromParcelUuid,
+ VcnConfig::toPersistableBundle);
+ doReturn(bundle).when(mConfigReadWriteHelper).readFromDisk();
+
+ setupMockedCarrierPrivilege(true);
+ mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps);
+ setupActiveSubscription(TEST_UUID_1);
+
+ doReturn(mMockIBinder).when(mMockPolicyListener).asBinder();
+ doReturn(mMockIBinder).when(mMockStatusCallback).asBinder();
+
+ // Make sure the profiles are loaded.
+ mTestLooper.dispatchAll();
+ }
+
+ @Before
+ public void setUp() {
+ doNothing()
+ .when(mMockContext)
+ .enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.NETWORK_FACTORY), any());
+ }
+
+ private void setupMockedCarrierPrivilege(boolean isPrivileged) {
+ doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO))
+ .when(mSubMgr)
+ .getSubscriptionsInGroup(any());
+ doReturn(mTelMgr)
+ .when(mTelMgr)
+ .createForSubscriptionId(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId()));
+ doReturn(isPrivileged
+ ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
+ : CARRIER_PRIVILEGE_STATUS_NO_ACCESS)
+ .when(mTelMgr)
+ .checkCarrierPrivilegesForPackage(eq(TEST_PACKAGE_NAME));
+ }
+
+ @Test
+ public void testSystemReady() throws Exception {
+ mVcnMgmtSvc.systemReady();
+
+ verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class));
+ verify(mSubscriptionTracker).register();
+ verify(mConnMgr)
+ .registerNetworkCallback(
+ eq(new NetworkRequest.Builder().clearCapabilities().build()),
+ any(NetworkCallback.class));
+ }
+
+ @Test
+ public void testNonSystemServerRealConfigFileAccessPermission() throws Exception {
+ // Attempt to build a real instance of the dependencies, and verify we cannot write to the
+ // file.
+ VcnManagementService.Dependencies deps = new VcnManagementService.Dependencies();
+ PersistableBundleUtils.LockingReadWriteHelper configReadWriteHelper =
+ deps.newPersistableBundleLockingReadWriteHelper(
+ VcnManagementService.VCN_CONFIG_FILE);
+
+ // Even tests should not be able to read/write configs from disk; SELinux policies restrict
+ // it to only the system server.
+ // Reading config should always return null since the file "does not exist", and writing
+ // should throw an IOException.
+ assertNull(configReadWriteHelper.readFromDisk());
+
+ try {
+ configReadWriteHelper.writeToDisk(new PersistableBundle());
+ fail("Expected IOException due to SELinux policy");
+ } catch (FileNotFoundException expected) {
+ }
+ }
+
+ @Test
+ public void testLoadVcnConfigsOnStartup() throws Exception {
+ mTestLooper.dispatchAll();
+
+ assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs());
+ verify(mConfigReadWriteHelper).readFromDisk();
+ }
+
+ private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
+ ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups) {
+ return triggerSubscriptionTrackerCbAndGetSnapshot(
+ activeDataSubGrp, activeSubscriptionGroups, Collections.emptyMap());
+ }
+
+ private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
+ ParcelUuid activeDataSubGrp,
+ Set<ParcelUuid> activeSubscriptionGroups,
+ Map<Integer, ParcelUuid> subIdToGroupMap) {
+ return triggerSubscriptionTrackerCbAndGetSnapshot(
+ activeDataSubGrp,
+ activeSubscriptionGroups,
+ subIdToGroupMap,
+ true /* hasCarrierPrivileges */);
+ }
+
+ private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
+ ParcelUuid activeDataSubGrp,
+ Set<ParcelUuid> activeSubscriptionGroups,
+ Map<Integer, ParcelUuid> subIdToGroupMap,
+ boolean hasCarrierPrivileges) {
+ return triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_SUBSCRIPTION_ID,
+ activeDataSubGrp,
+ activeSubscriptionGroups,
+ subIdToGroupMap,
+ hasCarrierPrivileges);
+ }
+
+ private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
+ int activeDataSubId,
+ ParcelUuid activeDataSubGrp,
+ Set<ParcelUuid> activeSubscriptionGroups,
+ Map<Integer, ParcelUuid> subIdToGroupMap,
+ boolean hasCarrierPrivileges) {
+ final TelephonySubscriptionSnapshot snapshot =
+ buildSubscriptionSnapshot(
+ activeDataSubId,
+ activeDataSubGrp,
+ activeSubscriptionGroups,
+ subIdToGroupMap,
+ hasCarrierPrivileges);
+
+ final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+ cb.onNewSnapshot(snapshot);
+
+ return snapshot;
+ }
+
+ private TelephonySubscriptionSnapshot buildSubscriptionSnapshot(
+ int activeDataSubId,
+ ParcelUuid activeDataSubGrp,
+ Set<ParcelUuid> activeSubscriptionGroups,
+ Map<Integer, ParcelUuid> subIdToGroupMap,
+ boolean hasCarrierPrivileges) {
+ final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class);
+ doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups();
+ doReturn(activeDataSubGrp).when(snapshot).getActiveDataSubscriptionGroup();
+ doReturn(activeDataSubId).when(snapshot).getActiveDataSubscriptionId();
+
+ final Set<String> privilegedPackages =
+ (activeSubscriptionGroups == null || activeSubscriptionGroups.isEmpty())
+ ? Collections.emptySet()
+ : Collections.singleton(TEST_PACKAGE_NAME);
+ doReturn(hasCarrierPrivileges)
+ .when(snapshot)
+ .packageHasPermissionsForSubscriptionGroup(
+ argThat(val -> activeSubscriptionGroups.contains(val)),
+ eq(TEST_PACKAGE_NAME));
+
+ doAnswer(invocation -> {
+ return subIdToGroupMap.get(invocation.getArgument(0));
+ }).when(snapshot).getGroupForSubId(anyInt());
+
+ doAnswer(invocation -> {
+ final ParcelUuid subGrp = invocation.getArgument(0);
+ final Set<Integer> subIds = new ArraySet<>();
+ for (Entry<Integer, ParcelUuid> entry : subIdToGroupMap.entrySet()) {
+ if (entry.getValue().equals(subGrp)) {
+ subIds.add(entry.getKey());
+ }
+ }
+ return subIds;
+ }).when(snapshot).getAllSubIdsInGroup(any());
+
+ return snapshot;
+ }
+
+ private void setupActiveSubscription(ParcelUuid activeDataSubGrp) {
+ mVcnMgmtSvc.setLastSnapshot(
+ buildSubscriptionSnapshot(
+ TEST_SUBSCRIPTION_ID,
+ activeDataSubGrp,
+ Collections.emptySet(),
+ Collections.emptyMap(),
+ true /* hasCarrierPrivileges */));
+ }
+
+ private TelephonySubscriptionTrackerCallback getTelephonySubscriptionTrackerCallback() {
+ final ArgumentCaptor<TelephonySubscriptionTrackerCallback> captor =
+ ArgumentCaptor.forClass(TelephonySubscriptionTrackerCallback.class);
+ verify(mMockDeps)
+ .newTelephonySubscriptionTracker(
+ eq(mMockContext), eq(mTestLooper.getLooper()), captor.capture());
+ return captor.getValue();
+ }
+
+ private BroadcastReceiver getPackageChangeReceiver() {
+ final ArgumentCaptor<BroadcastReceiver> captor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mMockContext).registerReceiver(captor.capture(), any(), any(), any());
+ return captor.getValue();
+ }
+
+ private Vcn startAndGetVcnInstance(ParcelUuid uuid) {
+ mVcnMgmtSvc.setVcnConfig(uuid, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ return mVcnMgmtSvc.getAllVcns().get(uuid);
+ }
+
+ @Test
+ public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception {
+ // Add a record for a non-active SIM
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+
+ TelephonySubscriptionSnapshot snapshot =
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_UUID_1, new ArraySet<>(Arrays.asList(TEST_UUID_1, TEST_UUID_2)));
+ verify(mMockDeps)
+ .newVcnContext(
+ eq(mMockContext),
+ eq(mTestLooper.getLooper()),
+ any(VcnNetworkProvider.class),
+ anyBoolean());
+
+ // Verify that only the VCN for the active data SIM was started.
+ verify(mMockDeps)
+ .newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot), any());
+ verify(mMockDeps, never())
+ .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), eq(snapshot), any());
+ }
+
+ @Test
+ public void testTelephonyNetworkTrackerCallbackSwitchingActiveDataStartsAndStopsInstances()
+ throws Exception {
+ // Add a record for a non-active SIM
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ final Vcn vcn = startAndGetVcnInstance(TEST_UUID_1);
+
+ TelephonySubscriptionSnapshot snapshot =
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_UUID_2, new ArraySet<>(Arrays.asList(TEST_UUID_1, TEST_UUID_2)));
+
+ // Verify that a new VCN for UUID_2 was started, and the old instance was torn down
+ // immediately
+ verify(mMockDeps)
+ .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), eq(snapshot), any());
+ verify(vcn).teardownAsynchronously();
+ assertEquals(1, mVcnMgmtSvc.getAllVcns().size());
+ assertFalse(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_1));
+ assertTrue(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_2));
+ }
+
+ @Test
+ public void testTelephonyNetworkTrackerCallbackStopsInstances() throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
+ final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+ final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet());
+
+ // Verify teardown after delay
+ mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
+ mTestLooper.dispatchAll();
+ verify(vcn).teardownAsynchronously();
+ verify(mMockPolicyListener).onPolicyChanged();
+ }
+
+ @Test
+ public void testTelephonyNetworkTrackerCallbackSwitchToNewSubscriptionImmediatelyTearsDown()
+ throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
+ final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+ final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
+
+ // Simulate switch to different default data subscription that does not have a VCN.
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_SUBSCRIPTION_ID,
+ null /* activeDataSubscriptionGroup */,
+ Collections.emptySet(),
+ Collections.emptyMap(),
+ false /* hasCarrierPrivileges */);
+ mTestLooper.dispatchAll();
+
+ verify(vcn).teardownAsynchronously();
+ assertEquals(0, mVcnMgmtSvc.getAllVcns().size());
+ }
+
+ /**
+ * Tests an intermediate state where carrier privileges are marked as lost before active data
+ * subId changes during a SIM ejection.
+ *
+ * <p>The expected outcome is that the VCN is torn down after a delay, as opposed to
+ * immediately.
+ */
+ @Test
+ public void testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges()
+ throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
+ final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+ final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
+
+ // Simulate privileges lost
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_SUBSCRIPTION_ID,
+ TEST_UUID_2,
+ Collections.emptySet(),
+ Collections.emptyMap(),
+ false /* hasCarrierPrivileges */);
+
+ // Verify teardown after delay
+ mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
+ mTestLooper.dispatchAll();
+ verify(vcn).teardownAsynchronously();
+ }
+
+ @Test
+ public void testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances()
+ throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
+ final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+ final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
+
+ // Simulate SIM unloaded
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ INVALID_SUBSCRIPTION_ID,
+ null /* activeDataSubscriptionGroup */,
+ Collections.emptySet(),
+ Collections.emptyMap(),
+ false /* hasCarrierPrivileges */);
+
+ // Simulate new SIM loaded right during teardown delay.
+ mTestLooper.moveTimeForward(
+ VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
+ mTestLooper.dispatchAll();
+ triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
+
+ // Verify that even after the full timeout duration, the VCN instance is not torn down
+ mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
+ mTestLooper.dispatchAll();
+ verify(vcn, never()).teardownAsynchronously();
+ }
+
+ @Test
+ public void testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances() throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
+ final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+ final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2);
+
+ // Simulate SIM unloaded
+ triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet());
+
+ // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new
+ // vcnInstance.
+ mTestLooper.moveTimeForward(
+ VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
+ mTestLooper.dispatchAll();
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
+ triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
+ final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2);
+
+ // Verify that new instance was different, and the old one was torn down
+ assertTrue(oldInstance != newInstance);
+ verify(oldInstance).teardownAsynchronously();
+
+ // Verify that even after the full timeout duration, the new VCN instance is not torn down
+ mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
+ mTestLooper.dispatchAll();
+ verify(newInstance, never()).teardownAsynchronously();
+ }
+
+ @Test
+ public void testPackageChangeListenerRegistered() throws Exception {
+ verify(mMockContext).registerReceiver(any(BroadcastReceiver.class), argThat(filter -> {
+ return filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED);
+ }), any(), any());
+ }
+
+ @Test
+ public void testPackageChangeListener_packageAdded() throws Exception {
+ final BroadcastReceiver receiver = getPackageChangeReceiver();
+
+ verify(mMockContext).registerReceiver(any(), argThat(filter -> {
+ return filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED);
+ }), any(), any());
+
+ receiver.onReceive(mMockContext, new Intent(Intent.ACTION_PACKAGE_ADDED));
+ verify(mSubscriptionTracker).handleSubscriptionsChanged();
+ }
+
+ @Test
+ public void testPackageChangeListener_packageRemoved() throws Exception {
+ final BroadcastReceiver receiver = getPackageChangeReceiver();
+
+ verify(mMockContext).registerReceiver(any(), argThat(filter -> {
+ return filter.hasAction(Intent.ACTION_PACKAGE_REMOVED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED);
+ }), any(), any());
+
+ receiver.onReceive(mMockContext, new Intent(Intent.ACTION_PACKAGE_REMOVED));
+ verify(mSubscriptionTracker).handleSubscriptionsChanged();
+ }
+
+ @Test
+ public void testSetVcnConfigRequiresNonSystemServer() throws Exception {
+ doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
+
+ try {
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ fail("Expected IllegalStateException exception for system server");
+ } catch (IllegalStateException expected) {
+ }
+ }
+
+ @Test
+ public void testSetVcnConfigRequiresSystemUser() throws Exception {
+ doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID))
+ .when(mMockDeps)
+ .getBinderCallingUid();
+
+ try {
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ fail("Expected security exception for non system user");
+ } catch (SecurityException expected) {
+ verify(mMockPolicyListener, never()).onPolicyChanged();
+ }
+ }
+
+ @Test
+ public void testSetVcnConfigRequiresCarrierPrivileges() throws Exception {
+ setupMockedCarrierPrivilege(false);
+
+ try {
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ fail("Expected security exception for missing carrier privileges");
+ } catch (SecurityException expected) {
+ verify(mMockPolicyListener, never()).onPolicyChanged();
+ }
+ }
+
+ @Test
+ public void testSetVcnConfigMismatchedPackages() throws Exception {
+ try {
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, "IncorrectPackage");
+ fail("Expected exception due to mismatched packages in config and method call");
+ } catch (IllegalArgumentException expected) {
+ verify(mMockPolicyListener, never()).onPolicyChanged();
+ }
+ }
+
+ @Test
+ public void testSetVcnConfig() throws Exception {
+ // Use a different UUID to simulate a new VCN config.
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2));
+ verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
+ }
+
+ @Test
+ public void testSetVcnConfigNonActiveSimDoesNotStartVcn() throws Exception {
+ // Use a different UUID to simulate a new VCN config.
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2));
+ verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
+
+ verify(mMockDeps, never()).newVcn(any(), any(), any(), any(), any());
+ }
+
+ @Test
+ public void testSetVcnConfigActiveSimTearsDownExistingVcnsImmediately() throws Exception {
+ final Vcn vcn = startAndGetVcnInstance(TEST_UUID_1);
+
+ // Use a different UUID to simulate a new VCN config.
+ setupActiveSubscription(TEST_UUID_2);
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+
+ verify(mMockDeps, times(2)).newVcn(any(), any(), any(), any(), any());
+ verify(vcn).teardownAsynchronously();
+ assertEquals(1, mVcnMgmtSvc.getAllVcns().size());
+ assertFalse(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_1));
+ assertTrue(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_2));
+ }
+
+ @Test
+ public void testSetVcnConfigTestModeRequiresPermission() throws Exception {
+ doThrow(new SecurityException("Requires MANAGE_TEST_NETWORKS"))
+ .when(mMockContext)
+ .enforceCallingPermission(
+ eq(android.Manifest.permission.MANAGE_TEST_NETWORKS), any());
+
+ final VcnConfig vcnConfig =
+ new VcnConfig.Builder(mMockContext)
+ .addGatewayConnectionConfig(
+ VcnGatewayConnectionConfigTest.buildTestConfig())
+ .setIsTestModeProfile()
+ .build();
+
+ try {
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, vcnConfig, TEST_PACKAGE_NAME);
+ fail("Expected exception due to using test-mode without permission");
+ } catch (SecurityException e) {
+ verify(mMockPolicyListener, never()).onPolicyChanged();
+ }
+ }
+
+ @Test
+ public void testSetVcnConfigNotifiesStatusCallback() throws Exception {
+ triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
+
+ mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
+ verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
+
+ // Use a different UUID to simulate a new VCN config.
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+
+ verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
+ }
+
+ @Test
+ public void testClearVcnConfigRequiresNonSystemServer() throws Exception {
+ doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
+
+ try {
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
+ fail("Expected IllegalStateException exception for system server");
+ } catch (IllegalStateException expected) {
+ }
+ }
+
+ @Test
+ public void testClearVcnConfigRequiresSystemUser() throws Exception {
+ doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID))
+ .when(mMockDeps)
+ .getBinderCallingUid();
+
+ try {
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
+ fail("Expected security exception for non system user");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @Test
+ public void testClearVcnConfigRequiresCarrierPrivileges() throws Exception {
+ setupMockedCarrierPrivilege(false);
+
+ try {
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
+ fail("Expected security exception for missing carrier privileges");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @Test
+ public void testClearVcnConfigMismatchedPackages() throws Exception {
+ try {
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, "IncorrectPackage");
+ fail("Expected security exception due to mismatched packages");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @Test
+ public void testClearVcnConfig() throws Exception {
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
+ assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
+ verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
+ }
+
+ @Test
+ public void testClearVcnConfigNotifiesStatusCallback() throws Exception {
+ setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */);
+ mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
+ verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
+
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
+
+ verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
+ }
+
+ @Test
+ public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTearsDownVcns() throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
+ // Use a different UUID to simulate a new VCN config.
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ final Map<ParcelUuid, Vcn> vcnInstances = mVcnMgmtSvc.getAllVcns();
+ final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2);
+ assertEquals(1, vcnInstances.size());
+ assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2));
+ verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
+
+ // Verify Vcn is started
+ verify(mMockDeps)
+ .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), any(), any());
+
+ // Verify Vcn is updated if it was previously started
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ verify(vcnInstance).updateConfig(TEST_VCN_CONFIG);
+
+ // Verify Vcn is stopped if it was already started
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
+ verify(vcnInstance).teardownAsynchronously();
+ }
+
+ @Test
+ public void testGetConfiguredSubscriptionGroupsRequiresSystemUser() throws Exception {
+ doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, TEST_UID))
+ .when(mMockDeps)
+ .getBinderCallingUid();
+
+ try {
+ mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME);
+ fail("Expected security exception for non system user");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @Test
+ public void testGetConfiguredSubscriptionGroupsMismatchedPackages() throws Exception {
+ final String badPackage = "IncorrectPackage";
+ doThrow(new SecurityException()).when(mAppOpsMgr).checkPackage(TEST_UID, badPackage);
+
+ try {
+ mVcnMgmtSvc.getConfiguredSubscriptionGroups(badPackage);
+ fail("Expected security exception due to mismatched packages");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @Test
+ public void testGetConfiguredSubscriptionGroups() throws Exception {
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+
+ // Assert that if both UUID 1 and 2 are provisioned, the caller only gets ones that they are
+ // privileged for.
+ triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1));
+ final List<ParcelUuid> subGrps =
+ mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME);
+ assertEquals(Collections.singletonList(TEST_UUID_1), subGrps);
+ }
+
+ @Test
+ public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception {
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ verify(mMockIBinder).linkToDeath(any(), anyInt());
+ }
+
+ @Test(expected = SecurityException.class)
+ public void testAddVcnUnderlyingNetworkPolicyListenerInvalidPermission() {
+ doReturn(PackageManager.PERMISSION_DENIED)
+ .when(mMockContext)
+ .checkCallingOrSelfPermission(any());
+
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+ }
+
+ @Test
+ public void testRemoveVcnUnderlyingNetworkPolicyListener() {
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+ }
+
+ @Test(expected = SecurityException.class)
+ public void testRemoveVcnUnderlyingNetworkPolicyListenerInvalidPermission() {
+ doReturn(PackageManager.PERMISSION_DENIED)
+ .when(mMockContext)
+ .checkCallingOrSelfPermission(any());
+
+ mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+ }
+
+ @Test
+ public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() {
+ mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+ }
+
+ private void verifyMergedNetworkCapabilities(
+ NetworkCapabilities mergedCapabilities,
+ int transportType,
+ boolean isVcnManaged,
+ boolean isRestricted) {
+ assertTrue(mergedCapabilities.hasTransport(transportType));
+ assertEquals(
+ !isVcnManaged,
+ mergedCapabilities.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED));
+ assertEquals(
+ !isRestricted,
+ mergedCapabilities.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED));
+ }
+
+ private void setupSubscriptionAndStartVcn(int subId, ParcelUuid subGrp, boolean isVcnActive) {
+ setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive, true /* hasCarrierPrivileges */);
+ }
+
+ private void setupSubscriptionAndStartVcn(
+ int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) {
+ mVcnMgmtSvc.systemReady();
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ subGrp,
+ Collections.singleton(subGrp),
+ Collections.singletonMap(subId, subGrp),
+ hasCarrierPrivileges);
+
+ final Vcn vcn = startAndGetVcnInstance(subGrp);
+ doReturn(isVcnActive ? VCN_STATUS_CODE_ACTIVE : VCN_STATUS_CODE_SAFE_MODE)
+ .when(vcn)
+ .getStatus();
+ }
+
+ private NetworkCapabilities.Builder getNetworkCapabilitiesBuilderForTransport(
+ int subId, int transport) {
+ final NetworkCapabilities.Builder ncBuilder =
+ new NetworkCapabilities.Builder()
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .addTransportType(transport);
+ if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ ncBuilder.setSubscriptionIds(Collections.singleton(subId));
+ }
+
+ return ncBuilder;
+ }
+
+ private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport(
+ int subId, ParcelUuid subGrp, boolean isVcnActive, int transport) {
+ setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive);
+
+ return mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+ getNetworkCapabilitiesBuilderForTransport(subId, transport).build(),
+ new LinkProperties());
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicyCellular() throws Exception {
+ final VcnUnderlyingNetworkPolicy policy =
+ startVcnAndGetPolicyForTransport(
+ TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_CELLULAR);
+
+ assertFalse(policy.isTeardownRequested());
+ verifyMergedNetworkCapabilities(
+ policy.getMergedNetworkCapabilities(),
+ TRANSPORT_CELLULAR,
+ true /* isVcnManaged */,
+ false /* isRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicyCellular_safeMode() throws Exception {
+ final VcnUnderlyingNetworkPolicy policy =
+ startVcnAndGetPolicyForTransport(
+ TEST_SUBSCRIPTION_ID,
+ TEST_UUID_2,
+ false /* isActive */,
+ TRANSPORT_CELLULAR);
+
+ assertFalse(policy.isTeardownRequested());
+ verifyMergedNetworkCapabilities(
+ policy.getMergedNetworkCapabilities(),
+ NetworkCapabilities.TRANSPORT_CELLULAR,
+ false /* isVcnManaged */,
+ false /* isRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicyWifi() throws Exception {
+ final VcnUnderlyingNetworkPolicy policy =
+ startVcnAndGetPolicyForTransport(
+ TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_WIFI);
+
+ assertFalse(policy.isTeardownRequested());
+ verifyMergedNetworkCapabilities(
+ policy.getMergedNetworkCapabilities(),
+ NetworkCapabilities.TRANSPORT_WIFI,
+ true /* isVcnManaged */,
+ true /* isRestricted */);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicyVcnWifi_safeMode() throws Exception {
+ final VcnUnderlyingNetworkPolicy policy =
+ startVcnAndGetPolicyForTransport(
+ TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI);
+
+ assertFalse(policy.isTeardownRequested());
+ verifyMergedNetworkCapabilities(
+ policy.getMergedNetworkCapabilities(),
+ NetworkCapabilities.TRANSPORT_WIFI,
+ false /* isVcnManaged */,
+ true /* isRestricted */);
+ }
+
+ private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) {
+ mVcnMgmtSvc.systemReady();
+
+ final ArgumentCaptor<NetworkCallback> captor =
+ ArgumentCaptor.forClass(NetworkCallback.class);
+ verify(mConnMgr)
+ .registerNetworkCallback(
+ eq(new NetworkRequest.Builder().clearCapabilities().build()),
+ captor.capture());
+ captor.getValue().onCapabilitiesChanged(mock(Network.class, CALLS_REAL_METHODS), caps);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicyVcnWifi_unrestrictingExistingNetworkRequiresRestart()
+ throws Exception {
+ final NetworkCapabilities existingNetworkCaps =
+ getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
+ .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ .build();
+ setupTrackedCarrierWifiNetwork(existingNetworkCaps);
+
+ // Trigger test without VCN instance alive; expect restart due to change of NOT_RESTRICTED
+ // immutable capability
+ final VcnUnderlyingNetworkPolicy policy =
+ mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+ getNetworkCapabilitiesBuilderForTransport(
+ TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
+ .build(),
+ new LinkProperties());
+ assertTrue(policy.isTeardownRequested());
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicyVcnWifi_restrictingExistingNetworkRequiresRestart()
+ throws Exception {
+ final NetworkCapabilities existingNetworkCaps =
+ getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
+ .build();
+ setupTrackedCarrierWifiNetwork(existingNetworkCaps);
+
+ final VcnUnderlyingNetworkPolicy policy =
+ startVcnAndGetPolicyForTransport(
+ TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI);
+
+ assertTrue(policy.isTeardownRequested());
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception {
+ setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_1, true /* isActive */);
+
+ NetworkCapabilities nc =
+ new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_2))
+ .build();
+
+ VcnUnderlyingNetworkPolicy policy =
+ mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties());
+
+ assertFalse(policy.isTeardownRequested());
+ assertEquals(nc, policy.getMergedNetworkCapabilities());
+ }
+
+ @Test(expected = SecurityException.class)
+ public void testGetUnderlyingNetworkPolicyInvalidPermission() {
+ doReturn(PackageManager.PERMISSION_DENIED)
+ .when(mMockContext)
+ .checkCallingOrSelfPermission(any());
+
+ mVcnMgmtSvc.getUnderlyingNetworkPolicy(new NetworkCapabilities(), new LinkProperties());
+ }
+
+ @Test
+ public void testSubscriptionSnapshotUpdateNotifiesVcn() {
+ setupActiveSubscription(TEST_UUID_2);
+
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ final Map<ParcelUuid, Vcn> vcnInstances = mVcnMgmtSvc.getAllVcns();
+ final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2);
+
+ TelephonySubscriptionSnapshot snapshot =
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_UUID_2, Collections.singleton(TEST_UUID_2));
+
+ verify(vcnInstance).updateSubscriptionSnapshot(eq(snapshot));
+ }
+
+ @Test
+ public void testAddNewVcnUpdatesPolicyListener() throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+
+ verify(mMockPolicyListener).onPolicyChanged();
+ }
+
+ @Test
+ public void testRemoveVcnUpdatesPolicyListener() throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
+
+ verify(mMockPolicyListener).onPolicyChanged();
+ }
+
+ @Test
+ public void testVcnSubIdChangeUpdatesPolicyListener() throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
+ startAndGetVcnInstance(TEST_UUID_2);
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_UUID_2,
+ Collections.singleton(TEST_UUID_2),
+ Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_2));
+
+ verify(mMockPolicyListener).onPolicyChanged();
+ }
+
+ private void triggerVcnSafeMode(
+ @NonNull ParcelUuid subGroup,
+ @NonNull TelephonySubscriptionSnapshot snapshot,
+ boolean isInSafeMode)
+ throws Exception {
+ verify(mMockDeps)
+ .newVcn(
+ eq(mVcnContext),
+ eq(subGroup),
+ eq(TEST_VCN_CONFIG),
+ eq(snapshot),
+ mVcnCallbackCaptor.capture());
+
+ VcnCallback vcnCallback = mVcnCallbackCaptor.getValue();
+ vcnCallback.onSafeModeStatusChanged(isInSafeMode);
+ }
+
+ private void verifyVcnSafeModeChangesNotifiesPolicyListeners(boolean enterSafeMode)
+ throws Exception {
+ TelephonySubscriptionSnapshot snapshot =
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_UUID_1, Collections.singleton(TEST_UUID_1));
+
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ triggerVcnSafeMode(TEST_UUID_1, snapshot, enterSafeMode);
+
+ verify(mMockPolicyListener).onPolicyChanged();
+ }
+
+ @Test
+ public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception {
+ verifyVcnSafeModeChangesNotifiesPolicyListeners(true /* enterSafeMode */);
+ }
+
+ @Test
+ public void testVcnExitingSafeModeNotifiesPolicyListeners() throws Exception {
+ verifyVcnSafeModeChangesNotifiesPolicyListeners(false /* enterSafeMode */);
+ }
+
+ private void triggerVcnStatusCallbackOnSafeModeStatusChanged(
+ @NonNull ParcelUuid subGroup,
+ @NonNull String pkgName,
+ int uid,
+ boolean hasPermissionsforSubGroup)
+ throws Exception {
+ TelephonySubscriptionSnapshot snapshot =
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ subGroup, Collections.singleton(subGroup));
+
+ setupSubscriptionAndStartVcn(
+ TEST_SUBSCRIPTION_ID, subGroup, true /* isActive */, hasPermissionsforSubGroup);
+
+ doReturn(hasPermissionsforSubGroup)
+ .when(snapshot)
+ .packageHasPermissionsForSubscriptionGroup(eq(subGroup), eq(pkgName));
+
+ mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName);
+
+ triggerVcnSafeMode(subGroup, snapshot, true /* enterSafeMode */);
+ }
+
+ @Test
+ public void testVcnStatusCallbackOnSafeModeStatusChangedWithCarrierPrivileges()
+ throws Exception {
+ triggerVcnStatusCallbackOnSafeModeStatusChanged(
+ TEST_UUID_1, TEST_PACKAGE_NAME, TEST_UID, true /* hasPermissionsforSubGroup */);
+
+ verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
+ }
+
+ @Test
+ public void testVcnStatusCallbackOnSafeModeStatusChangedWithoutCarrierPrivileges()
+ throws Exception {
+ triggerVcnStatusCallbackOnSafeModeStatusChanged(
+ TEST_UUID_1, TEST_PACKAGE_NAME, TEST_UID, false /* hasPermissionsforSubGroup */);
+
+ verify(mMockStatusCallback, never())
+ .onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
+ }
+
+ @Test
+ public void testRegisterVcnStatusCallback() throws Exception {
+ mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+
+ Map<IBinder, VcnStatusCallbackInfo> callbacks = mVcnMgmtSvc.getAllStatusCallbacks();
+ VcnStatusCallbackInfo cbInfo = callbacks.get(mMockIBinder);
+
+ assertNotNull(cbInfo);
+ assertEquals(TEST_UUID_1, cbInfo.mSubGroup);
+ assertEquals(mMockStatusCallback, cbInfo.mCallback);
+ assertEquals(TEST_PACKAGE_NAME, cbInfo.mPkgName);
+ assertEquals(TEST_UID, cbInfo.mUid);
+ verify(mMockIBinder).linkToDeath(eq(cbInfo), anyInt());
+
+ verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
+ }
+
+ @Test
+ public void testRegisterVcnStatusCallback_MissingPermission() throws Exception {
+ setupSubscriptionAndStartVcn(
+ TEST_SUBSCRIPTION_ID,
+ TEST_UUID_1,
+ true /* isActive */,
+ false /* hasCarrierPrivileges */);
+
+ mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+
+ verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
+ }
+
+ @Test
+ public void testRegisterVcnStatusCallback_VcnInactive() throws Exception {
+ setupSubscriptionAndStartVcn(
+ TEST_SUBSCRIPTION_ID,
+ TEST_UUID_1,
+ true /* isActive */,
+ true /* hasCarrierPrivileges */);
+
+ // VCN is currently active. Lose carrier privileges for TEST_PACKAGE and hit teardown
+ // timeout so the VCN goes inactive.
+ final TelephonySubscriptionSnapshot snapshot =
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_UUID_1,
+ Collections.singleton(TEST_UUID_1),
+ Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1),
+ false /* hasCarrierPrivileges */);
+ mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
+ mTestLooper.dispatchAll();
+
+ // Giving TEST_PACKAGE privileges again will restart the VCN (which will indicate ACTIVE
+ // when the status callback is registered). Instead, setup permissions for TEST_CB_PACKAGE
+ // so that it's permissioned to receive INACTIVE (instead of NOT_CONFIGURED) without
+ // reactivating the VCN.
+ doReturn(true)
+ .when(snapshot)
+ .packageHasPermissionsForSubscriptionGroup(
+ eq(TEST_UUID_1), eq(TEST_CB_PACKAGE_NAME));
+
+ mVcnMgmtSvc.registerVcnStatusCallback(
+ TEST_UUID_1, mMockStatusCallback, TEST_CB_PACKAGE_NAME);
+
+ verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_INACTIVE);
+ }
+
+ @Test
+ public void testRegisterVcnStatusCallback_VcnActive() throws Exception {
+ setupSubscriptionAndStartVcn(
+ TEST_SUBSCRIPTION_ID,
+ TEST_UUID_1,
+ true /* isActive */,
+ true /* hasCarrierPrivileges */);
+
+ mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+
+ verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
+ }
+
+ @Test
+ public void testRegisterVcnStatusCallback_VcnSafeMode() throws Exception {
+ setupSubscriptionAndStartVcn(
+ TEST_SUBSCRIPTION_ID,
+ TEST_UUID_1,
+ false /* isActive */,
+ true /* hasCarrierPrivileges */);
+
+ mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+
+ verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testRegisterVcnStatusCallbackDuplicate() {
+ mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+ mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testUnregisterVcnStatusCallback() {
+ mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+ Map<IBinder, VcnStatusCallbackInfo> callbacks = mVcnMgmtSvc.getAllStatusCallbacks();
+ VcnStatusCallbackInfo cbInfo = callbacks.get(mMockIBinder);
+
+ mVcnMgmtSvc.unregisterVcnStatusCallback(mMockStatusCallback);
+ assertTrue(mVcnMgmtSvc.getAllStatusCallbacks().isEmpty());
+ verify(mMockIBinder).unlinkToDeath(eq(cbInfo), anyInt());
+ }
+
+ @Test(expected = SecurityException.class)
+ public void testRegisterVcnStatusCallbackInvalidPackage() {
+ doThrow(new SecurityException()).when(mAppOpsMgr).checkPackage(TEST_UID, TEST_PACKAGE_NAME);
+
+ mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testUnregisterVcnStatusCallbackNeverRegistered() {
+ mVcnMgmtSvc.unregisterVcnStatusCallback(mMockStatusCallback);
+
+ assertTrue(mVcnMgmtSvc.getAllStatusCallbacks().isEmpty());
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
new file mode 100644
index 000000000000..1f0df62fe72c
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
+import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX;
+import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
+import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
+
+import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import static java.util.Collections.emptyMap;
+import static java.util.Collections.emptySet;
+import static java.util.Collections.singletonMap;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.ParcelUuid;
+import android.os.test.TestLooper;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.telephony.TelephonyCallback;
+import android.telephony.TelephonyManager;
+import android.util.ArraySet;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+/** Tests for TelephonySubscriptionTracker */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TelephonySubscriptionTrackerTest {
+ private static final String PACKAGE_NAME =
+ TelephonySubscriptionTrackerTest.class.getPackage().getName();
+ 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;
+ private static final SubscriptionInfo TEST_SUBINFO_1 = mock(SubscriptionInfo.class);
+ private static final int TEST_SUBSCRIPTION_ID_2 = 3;
+ private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class);
+ private static final Map<ParcelUuid, Set<String>> TEST_PRIVILEGED_PACKAGES =
+ Collections.singletonMap(TEST_PARCEL_UUID, Collections.singleton(PACKAGE_NAME));
+ private static final Map<Integer, SubscriptionInfo> TEST_SUBID_TO_INFO_MAP;
+
+ static {
+ final Map<Integer, SubscriptionInfo> subIdToGroupMap = new HashMap<>();
+ subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_SUBINFO_1);
+ subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_SUBINFO_2);
+ TEST_SUBID_TO_INFO_MAP = Collections.unmodifiableMap(subIdToGroupMap);
+ }
+
+ @NonNull private final Context mContext;
+ @NonNull private final TestLooper mTestLooper;
+ @NonNull private final Handler mHandler;
+ @NonNull private final TelephonySubscriptionTracker.Dependencies mDeps;
+
+ @NonNull private final TelephonyManager mTelephonyManager;
+ @NonNull private final SubscriptionManager mSubscriptionManager;
+ @NonNull private final CarrierConfigManager mCarrierConfigManager;
+
+ @NonNull private TelephonySubscriptionTrackerCallback mCallback;
+ @NonNull private TelephonySubscriptionTracker mTelephonySubscriptionTracker;
+
+ public TelephonySubscriptionTrackerTest() {
+ mContext = mock(Context.class);
+ mTestLooper = new TestLooper();
+ mHandler = new Handler(mTestLooper.getLooper());
+ mDeps = mock(TelephonySubscriptionTracker.Dependencies.class);
+
+ mTelephonyManager = mock(TelephonyManager.class);
+ mSubscriptionManager = mock(SubscriptionManager.class);
+ mCarrierConfigManager = mock(CarrierConfigManager.class);
+
+ doReturn(Context.TELEPHONY_SERVICE)
+ .when(mContext)
+ .getSystemServiceName(TelephonyManager.class);
+ doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE);
+
+ doReturn(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
+ .when(mContext)
+ .getSystemServiceName(SubscriptionManager.class);
+ doReturn(mSubscriptionManager)
+ .when(mContext)
+ .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+
+ doReturn(Context.CARRIER_CONFIG_SERVICE)
+ .when(mContext)
+ .getSystemServiceName(CarrierConfigManager.class);
+ doReturn(mCarrierConfigManager)
+ .when(mContext)
+ .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+
+ // subId 1, 2 are in same subGrp, only subId 1 is active
+ doReturn(TEST_PARCEL_UUID).when(TEST_SUBINFO_1).getGroupUuid();
+ doReturn(TEST_PARCEL_UUID).when(TEST_SUBINFO_2).getGroupUuid();
+ doReturn(TEST_SIM_SLOT_INDEX).when(TEST_SUBINFO_1).getSimSlotIndex();
+ doReturn(INVALID_SIM_SLOT_INDEX).when(TEST_SUBINFO_2).getSimSlotIndex();
+ doReturn(TEST_SUBSCRIPTION_ID_1).when(TEST_SUBINFO_1).getSubscriptionId();
+ doReturn(TEST_SUBSCRIPTION_ID_2).when(TEST_SUBINFO_2).getSubscriptionId();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mCallback = mock(TelephonySubscriptionTrackerCallback.class);
+ mTelephonySubscriptionTracker =
+ new TelephonySubscriptionTracker(mContext, mHandler, mCallback, mDeps);
+ mTelephonySubscriptionTracker.register();
+
+ doReturn(true).when(mDeps).isConfigForIdentifiedCarrier(any());
+ doReturn(Arrays.asList(TEST_SUBINFO_1, TEST_SUBINFO_2))
+ .when(mSubscriptionManager)
+ .getAllSubscriptionInfoList();
+
+ doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
+ setPrivilegedPackagesForMock(Collections.singletonList(PACKAGE_NAME));
+ }
+
+ private IntentFilter getIntentFilter() {
+ final ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
+ verify(mContext).registerReceiver(any(), captor.capture(), any(), any());
+
+ return captor.getValue();
+ }
+
+ private OnSubscriptionsChangedListener getOnSubscriptionsChangedListener() {
+ final ArgumentCaptor<OnSubscriptionsChangedListener> captor =
+ ArgumentCaptor.forClass(OnSubscriptionsChangedListener.class);
+ verify(mSubscriptionManager).addOnSubscriptionsChangedListener(any(), captor.capture());
+
+ return captor.getValue();
+ }
+
+ private ActiveDataSubscriptionIdListener getActiveDataSubscriptionIdListener() {
+ final ArgumentCaptor<TelephonyCallback> captor =
+ ArgumentCaptor.forClass(TelephonyCallback.class);
+ verify(mTelephonyManager).registerTelephonyCallback(any(), captor.capture());
+
+ return (ActiveDataSubscriptionIdListener) captor.getValue();
+ }
+
+ private Intent buildTestBroadcastIntent(boolean hasValidSubscription) {
+ Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED);
+ intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX);
+ intent.putExtra(
+ EXTRA_SUBSCRIPTION_INDEX,
+ hasValidSubscription ? TEST_SUBSCRIPTION_ID_1 : INVALID_SUBSCRIPTION_ID);
+
+ return intent;
+ }
+
+ private TelephonySubscriptionSnapshot buildExpectedSnapshot(
+ Map<ParcelUuid, Set<String>> privilegedPackages) {
+ return buildExpectedSnapshot(TEST_SUBID_TO_INFO_MAP, privilegedPackages);
+ }
+
+ private TelephonySubscriptionSnapshot buildExpectedSnapshot(
+ Map<Integer, SubscriptionInfo> subIdToInfoMap,
+ Map<ParcelUuid, Set<String>> privilegedPackages) {
+ return new TelephonySubscriptionSnapshot(0, subIdToInfoMap, privilegedPackages);
+ }
+
+ private TelephonySubscriptionSnapshot buildExpectedSnapshot(
+ int activeSubId,
+ Map<Integer, SubscriptionInfo> subIdToInfoMap,
+ Map<ParcelUuid, Set<String>> privilegedPackages) {
+ return new TelephonySubscriptionSnapshot(activeSubId, subIdToInfoMap, privilegedPackages);
+ }
+
+ private void verifyNoActiveSubscriptions() {
+ verify(mCallback).onNewSnapshot(
+ argThat(snapshot -> snapshot.getActiveSubscriptionGroups().isEmpty()));
+ }
+
+ private void setupReadySubIds() {
+ mTelephonySubscriptionTracker.setReadySubIdsBySlotId(
+ Collections.singletonMap(TEST_SIM_SLOT_INDEX, TEST_SUBSCRIPTION_ID_1));
+ }
+
+ private void setPrivilegedPackagesForMock(@NonNull List<String> privilegedPackages) {
+ doReturn(privilegedPackages).when(mTelephonyManager).getPackagesWithCarrierPrivileges();
+ }
+
+ @Test
+ public void testRegister() throws Exception {
+ verify(mContext)
+ .registerReceiver(
+ eq(mTelephonySubscriptionTracker),
+ any(IntentFilter.class),
+ any(),
+ eq(mHandler));
+ final IntentFilter filter = getIntentFilter();
+ assertEquals(1, filter.countActions());
+ assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED));
+
+ verify(mSubscriptionManager)
+ .addOnSubscriptionsChangedListener(any(HandlerExecutor.class), any());
+ assertNotNull(getOnSubscriptionsChangedListener());
+ }
+
+ @Test
+ public void testUnregister() throws Exception {
+ mTelephonySubscriptionTracker.unregister();
+
+ verify(mContext).unregisterReceiver(eq(mTelephonySubscriptionTracker));
+
+ final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
+ verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(eq(listener));
+ }
+
+ @Test
+ public void testOnSubscriptionsChangedFired_NoReadySubIds() throws Exception {
+ final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
+ listener.onSubscriptionsChanged();
+ mTestLooper.dispatchAll();
+
+ verifyNoActiveSubscriptions();
+ }
+
+ @Test
+ public void testOnSubscriptionsChangedFired_onActiveSubIdsChanged() throws Exception {
+ setupReadySubIds();
+ setPrivilegedPackagesForMock(Collections.emptyList());
+
+ doReturn(TEST_SUBSCRIPTION_ID_2).when(mDeps).getActiveDataSubscriptionId();
+ final ActiveDataSubscriptionIdListener listener = getActiveDataSubscriptionIdListener();
+ listener.onActiveDataSubscriptionIdChanged(TEST_SUBSCRIPTION_ID_2);
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor<TelephonySubscriptionSnapshot> snapshotCaptor =
+ ArgumentCaptor.forClass(TelephonySubscriptionSnapshot.class);
+ verify(mCallback).onNewSnapshot(snapshotCaptor.capture());
+
+ TelephonySubscriptionSnapshot snapshot = snapshotCaptor.getValue();
+ assertNotNull(snapshot);
+ assertEquals(TEST_SUBSCRIPTION_ID_2, snapshot.getActiveDataSubscriptionId());
+ assertEquals(TEST_PARCEL_UUID, snapshot.getActiveDataSubscriptionGroup());
+ }
+
+ @Test
+ public void testOnSubscriptionsChangedFired_WithReadySubidsNoPrivilegedPackages()
+ throws Exception {
+ setupReadySubIds();
+ setPrivilegedPackagesForMock(Collections.emptyList());
+
+ final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
+ listener.onSubscriptionsChanged();
+ mTestLooper.dispatchAll();
+
+ final Map<ParcelUuid, Set<String>> privilegedPackages =
+ Collections.singletonMap(TEST_PARCEL_UUID, new ArraySet<>());
+ verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(privilegedPackages)));
+ }
+
+ @Test
+ public void testOnSubscriptionsChangedFired_WithReadySubidsAndPrivilegedPackages()
+ throws Exception {
+ setupReadySubIds();
+
+ final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
+ listener.onSubscriptionsChanged();
+ mTestLooper.dispatchAll();
+
+ verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
+ }
+
+ @Test
+ public void testReceiveBroadcast_ConfigReadyWithSubscriptions() throws Exception {
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ mTestLooper.dispatchAll();
+
+ verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
+ }
+
+ @Test
+ public void testReceiveBroadcast_ConfigReadyNoSubscriptions() throws Exception {
+ doReturn(new ArrayList<SubscriptionInfo>())
+ .when(mSubscriptionManager)
+ .getAllSubscriptionInfoList();
+
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ mTestLooper.dispatchAll();
+
+ // Expect an empty snapshot
+ verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(emptyMap(), emptyMap())));
+ }
+
+ @Test
+ public void testReceiveBroadcast_SlotCleared() throws Exception {
+ setupReadySubIds();
+
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false));
+ mTestLooper.dispatchAll();
+
+ verifyNoActiveSubscriptions();
+ assertTrue(mTelephonySubscriptionTracker.getReadySubIdsBySlotId().isEmpty());
+ }
+
+ @Test
+ public void testReceiveBroadcast_ConfigNotReady() throws Exception {
+ doReturn(false).when(mDeps).isConfigForIdentifiedCarrier(any());
+
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ mTestLooper.dispatchAll();
+
+ // No interactions expected; config was not loaded
+ verifyNoMoreInteractions(mCallback);
+ }
+
+ @Test
+ public void testSubscriptionsClearedAfterValidTriggersCallbacks() throws Exception {
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ mTestLooper.dispatchAll();
+ verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
+ assertNotNull(
+ mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX));
+
+ doReturn(Collections.emptyList()).when(mSubscriptionManager).getAllSubscriptionInfoList();
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ mTestLooper.dispatchAll();
+ verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(emptyMap(), emptyMap())));
+ }
+
+ @Test
+ public void testSlotClearedAfterValidTriggersCallbacks() throws Exception {
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+ mTestLooper.dispatchAll();
+ verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
+ assertNotNull(
+ mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX));
+
+ mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false));
+ mTestLooper.dispatchAll();
+ verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(emptyMap())));
+ assertNull(mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX));
+ }
+
+ @Test
+ public void testChangingPrivilegedPackagesAfterValidTriggersCallbacks() throws Exception {
+ setupReadySubIds();
+
+ // Setup initial "valid" state
+ final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
+ listener.onSubscriptionsChanged();
+ mTestLooper.dispatchAll();
+
+ verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES)));
+
+ // Simulate a loss of carrier privileges
+ setPrivilegedPackagesForMock(Collections.emptyList());
+ listener.onSubscriptionsChanged();
+ mTestLooper.dispatchAll();
+
+ verify(mCallback)
+ .onNewSnapshot(
+ eq(buildExpectedSnapshot(singletonMap(TEST_PARCEL_UUID, emptySet()))));
+ }
+
+ @Test
+ public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception {
+ final TelephonySubscriptionSnapshot snapshot =
+ new TelephonySubscriptionSnapshot(
+ TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap());
+
+ assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1));
+ assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2));
+ }
+
+ @Test
+ public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception {
+ final TelephonySubscriptionSnapshot snapshot =
+ new TelephonySubscriptionSnapshot(
+ TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap());
+
+ assertEquals(
+ new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)),
+ snapshot.getAllSubIdsInGroup(TEST_PARCEL_UUID));
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
new file mode 100644
index 000000000000..5af69b5d1bf2
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
@@ -0,0 +1,491 @@
+/*
+ * 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;
+
+import static com.android.server.vcn.VcnTestUtils.setupSystemService;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.net.TelephonyNetworkSpecifier;
+import android.os.ParcelUuid;
+import android.os.test.TestLooper;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
+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 org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.UUID;
+
+public class UnderlyingNetworkTrackerTest {
+ 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;
+ private static final int UPDATED_SUB_ID = 3;
+
+ private static final Set<Integer> INITIAL_SUB_IDS =
+ new ArraySet<>(Arrays.asList(INITIAL_SUB_ID_1, INITIAL_SUB_ID_2));
+ private static final Set<Integer> UPDATED_SUB_IDS =
+ new ArraySet<>(Arrays.asList(UPDATED_SUB_ID));
+
+ private static final NetworkCapabilities INITIAL_NETWORK_CAPABILITIES =
+ new NetworkCapabilities.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+ .build();
+ private static final NetworkCapabilities SUSPENDED_NETWORK_CAPABILITIES =
+ new NetworkCapabilities.Builder(INITIAL_NETWORK_CAPABILITIES)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
+ .build();
+ private static final NetworkCapabilities UPDATED_NETWORK_CAPABILITIES =
+ new NetworkCapabilities.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .build();
+
+ private static final LinkProperties INITIAL_LINK_PROPERTIES =
+ getLinkPropertiesWithName("initial_iface");
+ private static final LinkProperties UPDATED_LINK_PROPERTIES =
+ getLinkPropertiesWithName("updated_iface");
+
+ @Mock private Context mContext;
+ @Mock private VcnNetworkProvider mVcnNetworkProvider;
+ @Mock private ConnectivityManager mConnectivityManager;
+ @Mock private TelephonyManager mTelephonyManager;
+ @Mock private CarrierConfigManager mCarrierConfigManager;
+ @Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
+ @Mock private UnderlyingNetworkTrackerCallback mNetworkTrackerCb;
+ @Mock private Network mNetwork;
+
+ @Captor private ArgumentCaptor<UnderlyingNetworkListener> mUnderlyingNetworkListenerCaptor;
+
+ private TestLooper mTestLooper;
+ private VcnContext mVcnContext;
+ private UnderlyingNetworkTracker mUnderlyingNetworkTracker;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mTestLooper = new TestLooper();
+ mVcnContext =
+ spy(
+ new VcnContext(
+ mContext,
+ mTestLooper.getLooper(),
+ mVcnNetworkProvider,
+ false /* isInTestMode */));
+ resetVcnContext();
+
+ setupSystemService(
+ mContext,
+ mConnectivityManager,
+ Context.CONNECTIVITY_SERVICE,
+ ConnectivityManager.class);
+ setupSystemService(
+ mContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class);
+ setupSystemService(
+ mContext,
+ mCarrierConfigManager,
+ Context.CARRIER_CONFIG_SERVICE,
+ CarrierConfigManager.class);
+
+ when(mSubscriptionSnapshot.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(INITIAL_SUB_IDS);
+
+ mUnderlyingNetworkTracker =
+ new UnderlyingNetworkTracker(
+ mVcnContext,
+ SUB_GROUP,
+ mSubscriptionSnapshot,
+ mNetworkTrackerCb);
+ }
+
+ private void resetVcnContext() {
+ reset(mVcnContext);
+ doNothing().when(mVcnContext).ensureRunningOnLooperThread();
+ }
+
+ private static LinkProperties getLinkPropertiesWithName(String iface) {
+ LinkProperties linkProperties = new LinkProperties();
+ linkProperties.setInterfaceName(iface);
+ return linkProperties;
+ }
+
+ private SubscriptionInfo getSubscriptionInfoForSubId(int subId) {
+ SubscriptionInfo subInfo = mock(SubscriptionInfo.class);
+ when(subInfo.getSubscriptionId()).thenReturn(subId);
+ return subInfo;
+ }
+
+ @Test
+ public void testNetworkCallbacksRegisteredOnStartup() {
+ verifyNetworkRequestsRegistered(INITIAL_SUB_IDS);
+ }
+
+ @Test
+ public void testNetworkCallbacksRegisteredOnStartupForTestMode() {
+ final ConnectivityManager cm = mock(ConnectivityManager.class);
+ setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+ final VcnContext vcnContext =
+ new VcnContext(
+ mContext,
+ mTestLooper.getLooper(),
+ mVcnNetworkProvider,
+ true /* isInTestMode */);
+
+ new UnderlyingNetworkTracker(
+ vcnContext,
+ SUB_GROUP,
+ mSubscriptionSnapshot,
+ mNetworkTrackerCb);
+
+ verify(cm)
+ .registerNetworkCallback(
+ eq(getTestNetworkRequest(INITIAL_SUB_IDS)),
+ any(UnderlyingNetworkListener.class),
+ any());
+ }
+
+ private void verifyNetworkRequestsRegistered(Set<Integer> expectedSubIds) {
+ verify(mConnectivityManager)
+ .requestBackgroundNetwork(
+ eq(getWifiRequest(expectedSubIds)),
+ any(NetworkBringupCallback.class),
+ any());
+ for (final int subId : expectedSubIds) {
+ verify(mConnectivityManager)
+ .requestBackgroundNetwork(
+ eq(getCellRequestForSubId(subId)),
+ any(NetworkBringupCallback.class), any());
+ }
+
+ verify(mConnectivityManager)
+ .registerNetworkCallback(
+ eq(getRouteSelectionRequest(expectedSubIds)),
+ any(UnderlyingNetworkListener.class),
+ any());
+ verify(mConnectivityManager)
+ .registerNetworkCallback(
+ eq(getWifiEntryRssiThresholdRequest(expectedSubIds)),
+ any(NetworkBringupCallback.class),
+ any());
+ verify(mConnectivityManager)
+ .registerNetworkCallback(
+ eq(getWifiExitRssiThresholdRequest(expectedSubIds)),
+ any(NetworkBringupCallback.class),
+ any());
+ }
+
+ @Test
+ public void testUpdateSubscriptionSnapshot() {
+ // Verify initial cell background requests filed
+ verifyNetworkRequestsRegistered(INITIAL_SUB_IDS);
+
+ TelephonySubscriptionSnapshot subscriptionUpdate =
+ mock(TelephonySubscriptionSnapshot.class);
+ when(subscriptionUpdate.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(UPDATED_SUB_IDS);
+
+ mUnderlyingNetworkTracker.updateSubscriptionSnapshot(subscriptionUpdate);
+
+ // verify that initially-filed bringup requests are unregistered (cell + wifi)
+ verify(mConnectivityManager, times(INITIAL_SUB_IDS.size() + 3))
+ .unregisterNetworkCallback(any(NetworkBringupCallback.class));
+ verify(mConnectivityManager)
+ .unregisterNetworkCallback(any(UnderlyingNetworkListener.class));
+ verifyNetworkRequestsRegistered(UPDATED_SUB_IDS);
+ }
+
+ private NetworkRequest getWifiRequest(Set<Integer> netCapsSubIds) {
+ return getExpectedRequestBase()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .setSubscriptionIds(netCapsSubIds)
+ .build();
+ }
+
+ private NetworkRequest getWifiEntryRssiThresholdRequest(Set<Integer> netCapsSubIds) {
+ // TODO (b/187991063): Add tests for carrier-config based thresholds
+ return getExpectedRequestBase()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .setSubscriptionIds(netCapsSubIds)
+ .setSignalStrength(UnderlyingNetworkTracker.WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT)
+ .build();
+ }
+
+ private NetworkRequest getWifiExitRssiThresholdRequest(Set<Integer> netCapsSubIds) {
+ // TODO (b/187991063): Add tests for carrier-config based thresholds
+ return getExpectedRequestBase()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .setSubscriptionIds(netCapsSubIds)
+ .setSignalStrength(UnderlyingNetworkTracker.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT)
+ .build();
+ }
+
+ private NetworkRequest getCellRequestForSubId(int subId) {
+ return getExpectedRequestBase()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId))
+ .build();
+ }
+
+ private NetworkRequest getRouteSelectionRequest(Set<Integer> netCapsSubIds) {
+ return getExpectedRequestBase()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
+ .setSubscriptionIds(netCapsSubIds)
+ .build();
+ }
+
+ private NetworkRequest getTestNetworkRequest(Set<Integer> netCapsSubIds) {
+ return new NetworkRequest.Builder()
+ .clearCapabilities()
+ .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
+ .setSubscriptionIds(netCapsSubIds)
+ .build();
+ }
+
+ private NetworkRequest.Builder getExpectedRequestBase() {
+ final NetworkRequest.Builder builder =
+ new NetworkRequest.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+
+ return builder;
+ }
+
+ @Test
+ public void testTeardown() {
+ mUnderlyingNetworkTracker.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
+ verify(mConnectivityManager, times(5))
+ .unregisterNetworkCallback(any(NetworkBringupCallback.class));
+ verify(mConnectivityManager)
+ .unregisterNetworkCallback(any(UnderlyingNetworkListener.class));
+ }
+
+ @Test
+ public void testUnderlyingNetworkRecordEquals() {
+ UnderlyingNetworkRecord recordA =
+ new UnderlyingNetworkRecord(
+ mNetwork,
+ INITIAL_NETWORK_CAPABILITIES,
+ INITIAL_LINK_PROPERTIES,
+ false /* isBlocked */);
+ UnderlyingNetworkRecord recordB =
+ new UnderlyingNetworkRecord(
+ mNetwork,
+ INITIAL_NETWORK_CAPABILITIES,
+ INITIAL_LINK_PROPERTIES,
+ false /* isBlocked */);
+ UnderlyingNetworkRecord recordC =
+ new UnderlyingNetworkRecord(
+ mNetwork,
+ UPDATED_NETWORK_CAPABILITIES,
+ UPDATED_LINK_PROPERTIES,
+ false /* isBlocked */);
+
+ assertEquals(recordA, recordB);
+ assertNotEquals(recordA, recordC);
+ }
+
+ @Test
+ public void testRecordTrackerCallbackNotifiedForNetworkChange() {
+ verifyRegistrationOnAvailableAndGetCallback();
+ }
+
+ private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback() {
+ return verifyRegistrationOnAvailableAndGetCallback(INITIAL_NETWORK_CAPABILITIES);
+ }
+
+ private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback(
+ NetworkCapabilities networkCapabilities) {
+ verify(mConnectivityManager)
+ .registerNetworkCallback(
+ eq(getRouteSelectionRequest(INITIAL_SUB_IDS)),
+ mUnderlyingNetworkListenerCaptor.capture(),
+ any());
+
+ UnderlyingNetworkListener cb = mUnderlyingNetworkListenerCaptor.getValue();
+ cb.onAvailable(mNetwork);
+ cb.onCapabilitiesChanged(mNetwork, networkCapabilities);
+ cb.onLinkPropertiesChanged(mNetwork, INITIAL_LINK_PROPERTIES);
+ cb.onBlockedStatusChanged(mNetwork, false /* isFalse */);
+
+ UnderlyingNetworkRecord expectedRecord =
+ new UnderlyingNetworkRecord(
+ mNetwork,
+ networkCapabilities,
+ INITIAL_LINK_PROPERTIES,
+ false /* isBlocked */);
+ verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ return cb;
+ }
+
+ @Test
+ public void testRecordTrackerCallbackNotifiedForNetworkCapabilitiesChange() {
+ UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
+
+ cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES);
+
+ UnderlyingNetworkRecord expectedRecord =
+ new UnderlyingNetworkRecord(
+ mNetwork,
+ UPDATED_NETWORK_CAPABILITIES,
+ INITIAL_LINK_PROPERTIES,
+ false /* isBlocked */);
+ verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ }
+
+ @Test
+ public void testRecordTrackerCallbackNotifiedForLinkPropertiesChange() {
+ UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
+
+ cb.onLinkPropertiesChanged(mNetwork, UPDATED_LINK_PROPERTIES);
+
+ UnderlyingNetworkRecord expectedRecord =
+ new UnderlyingNetworkRecord(
+ mNetwork,
+ INITIAL_NETWORK_CAPABILITIES,
+ UPDATED_LINK_PROPERTIES,
+ false /* isBlocked */);
+ verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ }
+
+ @Test
+ public void testRecordTrackerCallbackNotifiedForNetworkSuspended() {
+ UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
+
+ cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES);
+
+ UnderlyingNetworkRecord expectedRecord =
+ new UnderlyingNetworkRecord(
+ mNetwork,
+ SUSPENDED_NETWORK_CAPABILITIES,
+ INITIAL_LINK_PROPERTIES,
+ false /* isBlocked */);
+ verify(mNetworkTrackerCb, 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));
+ }
+
+ @Test
+ public void testRecordTrackerCallbackNotifiedForNetworkResumed() {
+ UnderlyingNetworkListener cb =
+ verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES);
+
+ cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
+
+ UnderlyingNetworkRecord expectedRecord =
+ new UnderlyingNetworkRecord(
+ mNetwork,
+ INITIAL_NETWORK_CAPABILITIES,
+ INITIAL_LINK_PROPERTIES,
+ false /* isBlocked */);
+ verify(mNetworkTrackerCb, 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));
+ }
+
+ @Test
+ public void testRecordTrackerCallbackNotifiedForBlocked() {
+ UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
+
+ cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */);
+
+ UnderlyingNetworkRecord expectedRecord =
+ new UnderlyingNetworkRecord(
+ mNetwork,
+ INITIAL_NETWORK_CAPABILITIES,
+ INITIAL_LINK_PROPERTIES,
+ true /* isBlocked */);
+ verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ }
+
+ @Test
+ public void testRecordTrackerCallbackNotifiedForNetworkLoss() {
+ UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
+
+ cb.onLost(mNetwork);
+
+ verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(null);
+ }
+
+ @Test
+ public void testRecordTrackerCallbackIgnoresDuplicateRecord() {
+ UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
+
+ cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
+
+ // Verify no more calls to the UnderlyingNetworkTrackerCallback when the
+ // UnderlyingNetworkRecord does not actually change
+ verifyNoMoreInteractions(mNetworkTrackerCb);
+ }
+
+ @Test
+ public void testRecordTrackerCallbackNotifiedAfterTeardown() {
+ UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
+ mUnderlyingNetworkTracker.teardown();
+
+ cb.onCapabilitiesChanged(mNetwork, UPDATED_NETWORK_CAPABILITIES);
+
+ // Verify that the only call was during onAvailable()
+ verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(any());
+ }
+
+ // TODO (b/187991063): Add tests for network prioritization
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
new file mode 100644
index 000000000000..0f84f6ebe522
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static android.net.IpSecManager.DIRECTION_FWD;
+import static android.net.IpSecManager.DIRECTION_IN;
+import static android.net.IpSecManager.DIRECTION_OUT;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED;
+import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE;
+import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR;
+import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR;
+import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR;
+
+import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration;
+import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
+import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import static java.util.Collections.singletonList;
+
+import android.net.ConnectivityManager;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.NetworkAgent;
+import android.net.NetworkCapabilities;
+import android.net.ipsec.ike.ChildSaProposal;
+import android.net.ipsec.ike.exceptions.IkeException;
+import android.net.ipsec.ike.exceptions.IkeInternalException;
+import android.net.ipsec.ike.exceptions.IkeProtocolException;
+import android.net.vcn.VcnGatewayConnectionConfig;
+import android.net.vcn.VcnGatewayConnectionConfigTest;
+import android.net.vcn.VcnManager.VcnErrorCode;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.vcn.util.MtuUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+
+/** Tests for VcnGatewayConnection.ConnectedState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase {
+ private VcnIkeSession mIkeSession;
+ private VcnNetworkAgent mNetworkAgent;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mNetworkAgent = mock(VcnNetworkAgent.class);
+ doReturn(mNetworkAgent)
+ .when(mDeps)
+ .newNetworkAgent(any(), any(), any(), any(), any(), any(), any(), any(), any());
+
+ mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
+
+ mIkeSession = mGatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_1.network);
+ mGatewayConnection.setIkeSession(mIkeSession);
+
+ mGatewayConnection.transitionTo(mGatewayConnection.mConnectedState);
+ mTestLooper.dispatchAll();
+ }
+
+ @Test
+ public void testEnterStateCreatesNewIkeSession() throws Exception {
+ verify(mDeps).newIkeSession(any(), any(), any(), any(), any());
+ }
+
+ @Test
+ public void testEnterStateDoesNotCancelSafeModeAlarm() {
+ verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+ }
+
+ @Test
+ public void testNullNetworkDoesNotTriggerDisconnect() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(null);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession, never()).close();
+ verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */);
+ }
+
+ @Test
+ public void testNewNetworkTriggersMigration() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession, never()).close();
+ verify(mIkeSession).setNetwork(TEST_UNDERLYING_NETWORK_RECORD_2.network);
+ }
+
+ @Test
+ public void testSameNetworkDoesNotTriggerMigration() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+ }
+
+ private void verifyVcnTransformsApplied(
+ VcnGatewayConnection vcnGatewayConnection, boolean expectForwardTransform)
+ throws Exception {
+ for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) {
+ getChildSessionCallback().onIpSecTransformCreated(makeDummyIpSecTransform(), direction);
+ mTestLooper.dispatchAll();
+
+ verify(mIpSecSvc)
+ .applyTunnelModeTransform(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any());
+ }
+
+ verify(mIpSecSvc, expectForwardTransform ? times(1) : never())
+ .applyTunnelModeTransform(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(DIRECTION_FWD), anyInt(), any());
+
+ assertEquals(vcnGatewayConnection.mConnectedState, vcnGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testCreatedTransformsAreApplied() throws Exception {
+ verifyVcnTransformsApplied(mGatewayConnection, false /* expectForwardTransform */);
+ }
+
+ @Test
+ public void testCreatedTransformsAreAppliedWithDun() throws Exception {
+ VcnGatewayConnectionConfig gatewayConfig =
+ VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(
+ NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN);
+ VcnGatewayConnection gatewayConnection =
+ new VcnGatewayConnection(
+ mVcnContext,
+ TEST_SUB_GRP,
+ TEST_SUBSCRIPTION_SNAPSHOT,
+ gatewayConfig,
+ mGatewayStatusCallback,
+ true /* isMobileDataEnabled */,
+ mDeps);
+ gatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
+ final VcnIkeSession session =
+ gatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_1.network);
+ gatewayConnection.setIkeSession(session);
+ gatewayConnection.transitionTo(gatewayConnection.mConnectedState);
+ mTestLooper.dispatchAll();
+
+ verifyVcnTransformsApplied(gatewayConnection, true /* expectForwardTransform */);
+ }
+
+ @Test
+ public void testMigration() throws Exception {
+ triggerChildOpened();
+
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
+ getChildSessionCallback()
+ .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform());
+ mTestLooper.dispatchAll();
+
+ verify(mIpSecSvc, times(2))
+ .setNetworkForTunnelInterface(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID),
+ eq(TEST_UNDERLYING_NETWORK_RECORD_2.network),
+ any());
+
+ for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) {
+ verify(mIpSecSvc)
+ .applyTunnelModeTransform(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any());
+ }
+
+ assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+
+ final List<ChildSaProposal> saProposals =
+ mConfig.getTunnelConnectionParams()
+ .getTunnelModeChildSessionParams()
+ .getSaProposals();
+ final int expectedMtu =
+ MtuUtils.getMtu(
+ saProposals,
+ mConfig.getMaxMtu(),
+ TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.getMtu());
+ verify(mNetworkAgent).sendLinkProperties(
+ argThat(lp -> expectedMtu == lp.getMtu()
+ && TEST_TCP_BUFFER_SIZES_2.equals(lp.getTcpBufferSizes())));
+ verify(mNetworkAgent)
+ .setUnderlyingNetworks(eq(singletonList(TEST_UNDERLYING_NETWORK_RECORD_2.network)));
+ }
+
+ private void triggerChildOpened() {
+ triggerChildOpened(Collections.singletonList(TEST_INTERNAL_ADDR), TEST_DNS_ADDR);
+ }
+
+ private void triggerChildOpened(List<LinkAddress> internalAddresses, InetAddress dnsAddress) {
+ final VcnChildSessionConfiguration mMockChildSessionConfig =
+ mock(VcnChildSessionConfiguration.class);
+ doReturn(internalAddresses).when(mMockChildSessionConfig).getInternalAddresses();
+ doReturn(Collections.singletonList(dnsAddress))
+ .when(mMockChildSessionConfig)
+ .getInternalDnsServers();
+
+ getChildSessionCallback().onOpened(mMockChildSessionConfig);
+ }
+
+ private void triggerValidation(int status) {
+ final ArgumentCaptor<Consumer<Integer>> validationCallbackCaptor =
+ ArgumentCaptor.forClass(Consumer.class);
+ verify(mDeps)
+ .newNetworkAgent(
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ validationCallbackCaptor.capture());
+
+ validationCallbackCaptor.getValue().accept(status);
+ }
+
+ @Test
+ public void testChildOpenedRegistersNetwork() throws Exception {
+ // Verify scheduled but not canceled when entering ConnectedState
+ verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+ triggerChildOpened();
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+
+ final ArgumentCaptor<LinkProperties> lpCaptor =
+ ArgumentCaptor.forClass(LinkProperties.class);
+ final ArgumentCaptor<NetworkCapabilities> ncCaptor =
+ ArgumentCaptor.forClass(NetworkCapabilities.class);
+ verify(mDeps)
+ .newNetworkAgent(
+ eq(mVcnContext),
+ any(String.class),
+ ncCaptor.capture(),
+ lpCaptor.capture(),
+ any(),
+ argThat(nac -> nac.getLegacyType() == ConnectivityManager.TYPE_MOBILE),
+ any(),
+ any(),
+ any());
+ verify(mNetworkAgent).register();
+ verify(mNetworkAgent)
+ .setUnderlyingNetworks(eq(singletonList(TEST_UNDERLYING_NETWORK_RECORD_1.network)));
+ verify(mNetworkAgent).markConnected();
+
+ verify(mIpSecSvc)
+ .addAddressToTunnelInterface(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
+
+ final LinkProperties lp = lpCaptor.getValue();
+ assertEquals(Collections.singletonList(TEST_INTERNAL_ADDR), lp.getLinkAddresses());
+ assertEquals(Collections.singletonList(TEST_DNS_ADDR), lp.getDnsServers());
+ assertEquals(TEST_TCP_BUFFER_SIZES_1, lp.getTcpBufferSizes());
+
+ final NetworkCapabilities nc = ncCaptor.getValue();
+ assertTrue(nc.hasTransport(TRANSPORT_CELLULAR));
+ assertFalse(nc.hasTransport(TRANSPORT_WIFI));
+ for (int cap : mConfig.getAllExposedCapabilities()) {
+ assertTrue(nc.hasCapability(cap));
+ }
+
+ // Now that Vcn Network is up, notify it as validated and verify the SafeMode alarm is
+ // canceled
+ triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
+ verify(mSafeModeTimeoutAlarm).cancel();
+ assertFalse(mGatewayConnection.isInSafeMode());
+ }
+
+ @Test
+ public void testInternalAndDnsAddressesChanged() throws Exception {
+ final List<LinkAddress> startingInternalAddrs =
+ Arrays.asList(new LinkAddress[] {TEST_INTERNAL_ADDR, TEST_INTERNAL_ADDR_2});
+ triggerChildOpened(startingInternalAddrs, TEST_DNS_ADDR);
+ mTestLooper.dispatchAll();
+
+ for (LinkAddress addr : startingInternalAddrs) {
+ verify(mIpSecSvc)
+ .addAddressToTunnelInterface(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(addr), any());
+ }
+
+ verify(mDeps)
+ .newNetworkAgent(
+ any(),
+ any(),
+ any(),
+ argThat(
+ lp ->
+ startingInternalAddrs.equals(lp.getLinkAddresses())
+ && Collections.singletonList(TEST_DNS_ADDR)
+ .equals(lp.getDnsServers())),
+ any(),
+ any(),
+ any(),
+ any(),
+ any());
+
+ // Trigger another connection event, and verify that the addresses change
+ final List<LinkAddress> newInternalAddrs =
+ Arrays.asList(new LinkAddress[] {TEST_INTERNAL_ADDR_2, TEST_INTERNAL_ADDR_3});
+ triggerChildOpened(newInternalAddrs, TEST_DNS_ADDR_2);
+ mTestLooper.dispatchAll();
+
+ // Verify addresses on tunnel network added/removed
+ for (LinkAddress addr : newInternalAddrs) {
+ verify(mIpSecSvc)
+ .addAddressToTunnelInterface(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(addr), any());
+ }
+ verify(mIpSecSvc)
+ .removeAddressFromTunnelInterface(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
+
+ verify(mNetworkAgent).sendLinkProperties(argThat(
+ lp -> newInternalAddrs.equals(lp.getLinkAddresses())
+ && Collections.singletonList(TEST_DNS_ADDR_2).equals(lp.getDnsServers())));
+
+ // Verify that IpSecTunnelInterface only created once
+ verify(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any());
+ verifyNoMoreInteractions(mIpSecSvc);
+ }
+
+ @Test
+ public void testSuccessfulConnectionExitsSafeMode() throws Exception {
+ verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+ mGatewayConnection.mConnectedState);
+
+ assertTrue(mGatewayConnection.isInSafeMode());
+ assertFalse(mGatewayConnection.isQuitting());
+
+ triggerChildOpened();
+ mTestLooper.dispatchAll();
+
+ triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
+
+ assertFalse(mGatewayConnection.isInSafeMode());
+ }
+
+ @Test
+ public void testSubsequentFailedValidationTriggersSafeMode() throws Exception {
+ triggerChildOpened();
+ mTestLooper.dispatchAll();
+
+ triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
+ assertFalse(mGatewayConnection.isInSafeMode());
+
+ // Trigger a failed validation, and the subsequent safemode timeout.
+ triggerValidation(NetworkAgent.VALIDATION_STATUS_NOT_VALID);
+ mTestLooper.dispatchAll();
+
+ final ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+ verify(mDeps, times(2))
+ .newWakeupMessage(
+ eq(mVcnContext),
+ any(),
+ eq(VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM),
+ runnableCaptor.capture());
+ runnableCaptor.getValue().run();
+ mTestLooper.dispatchAll();
+
+ assertTrue(mGatewayConnection.isInSafeMode());
+ }
+
+ private Consumer<VcnNetworkAgent> setupNetworkAndGetUnwantedCallback() {
+ triggerChildOpened();
+ mTestLooper.dispatchAll();
+
+ final ArgumentCaptor<Consumer<VcnNetworkAgent>> unwantedCallbackCaptor =
+ ArgumentCaptor.forClass(Consumer.class);
+ verify(mDeps)
+ .newNetworkAgent(
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ unwantedCallbackCaptor.capture(),
+ any());
+
+ return unwantedCallbackCaptor.getValue();
+ }
+
+ @Test
+ public void testUnwantedNetworkAgentTriggersTeardown() throws Exception {
+ final Consumer<VcnNetworkAgent> unwantedCallback = setupNetworkAndGetUnwantedCallback();
+
+ unwantedCallback.accept(mNetworkAgent);
+ mTestLooper.dispatchAll();
+
+ assertTrue(mGatewayConnection.isQuitting());
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testUnwantedNetworkAgentWithDisconnectedNetworkAgent() throws Exception {
+ final Consumer<VcnNetworkAgent> unwantedCallback = setupNetworkAndGetUnwantedCallback();
+
+ mGatewayConnection.setNetworkAgent(null);
+ unwantedCallback.accept(mNetworkAgent);
+ mTestLooper.dispatchAll();
+
+ // Verify that the call was ignored; the state machine is still running, and the state has
+ // not changed.
+ assertFalse(mGatewayConnection.isQuitting());
+ assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testUnwantedNetworkAgentWithNewNetworkAgent() throws Exception {
+ final Consumer<VcnNetworkAgent> unwantedCallback = setupNetworkAndGetUnwantedCallback();
+ final VcnNetworkAgent testAgent = mock(VcnNetworkAgent.class);
+
+ mGatewayConnection.setNetworkAgent(testAgent);
+ unwantedCallback.accept(mNetworkAgent);
+ mTestLooper.dispatchAll();
+
+ assertFalse(mGatewayConnection.isQuitting());
+ assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+ assertEquals(testAgent, mGatewayConnection.getNetworkAgent());
+ }
+
+ @Test
+ public void testChildSessionClosedTriggersDisconnect() throws Exception {
+ // Verify scheduled but not canceled when entering ConnectedState
+ verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+
+ getChildSessionCallback().onClosed();
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+
+ // Since network never validated, verify mSafeModeTimeoutAlarm not canceled
+ verifyNoMoreInteractions(mSafeModeTimeoutAlarm);
+
+ // The child session was closed without exception, so verify that the GatewayStatusCallback
+ // was not notified
+ verifyNoMoreInteractions(mGatewayStatusCallback);
+ }
+
+ @Test
+ public void testChildSessionClosedExceptionallyNotifiesGatewayStatusCallback()
+ throws Exception {
+ final IkeInternalException exception = new IkeInternalException(mock(IOException.class));
+ getChildSessionCallback().onClosedExceptionally(exception);
+ mTestLooper.dispatchAll();
+
+ verify(mGatewayStatusCallback)
+ .onGatewayConnectionError(
+ eq(mConfig.getGatewayConnectionName()),
+ eq(VCN_ERROR_CODE_INTERNAL_ERROR),
+ any(),
+ any());
+ }
+
+ @Test
+ public void testIkeSessionClosedTriggersDisconnect() throws Exception {
+ // Verify scheduled but not canceled when entering ConnectedState
+ verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+
+ getIkeSessionCallback().onClosed();
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).close();
+
+ // Since network never validated, verify mSafeModeTimeoutAlarm not canceled
+ verifyNoMoreInteractions(mSafeModeTimeoutAlarm);
+
+ // IkeSession closed with no error, so verify that the GatewayStatusCallback was not
+ // notified
+ verifyNoMoreInteractions(mGatewayStatusCallback);
+ }
+
+ private void verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback(
+ IkeException cause, @VcnErrorCode int expectedErrorType) {
+ getIkeSessionCallback().onClosedExceptionally(cause);
+ mTestLooper.dispatchAll();
+
+ verify(mIkeSession).close();
+
+ verify(mGatewayStatusCallback)
+ .onGatewayConnectionError(
+ eq(mConfig.getGatewayConnectionName()),
+ eq(expectedErrorType),
+ any(),
+ any());
+ }
+
+ private static IkeProtocolException buildMockIkeProtocolException(int errorCode) {
+ final IkeProtocolException exception = mock(IkeProtocolException.class);
+ when(exception.getErrorType()).thenReturn(errorCode);
+ return exception;
+ }
+
+ @Test
+ public void testIkeSessionClosedExceptionallyAuthenticationFailure() throws Exception {
+ verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback(
+ buildMockIkeProtocolException(ERROR_TYPE_AUTHENTICATION_FAILED),
+ VCN_ERROR_CODE_CONFIG_ERROR);
+ }
+
+ @Test
+ public void testIkeSessionClosedExceptionallyDnsFailure() throws Exception {
+ verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback(
+ new IkeInternalException(new UnknownHostException()), VCN_ERROR_CODE_NETWORK_ERROR);
+ }
+
+ @Test
+ public void testIkeSessionClosedExceptionallyInternalFailure() throws Exception {
+ verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback(
+ buildMockIkeProtocolException(ERROR_TYPE_TEMPORARY_FAILURE),
+ VCN_ERROR_CODE_INTERNAL_ERROR);
+ }
+
+ @Test
+ public void testTeardown() throws Exception {
+ mGatewayConnection.teardownAsynchronously();
+ mTestLooper.dispatchAll();
+
+ // Verify that sending a non-quitting disconnect request does not unset the isQuitting flag
+ mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ assertTrue(mGatewayConnection.isQuitting());
+ }
+
+ @Test
+ public void testNonTeardownDisconnectRequest() throws Exception {
+ mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ assertFalse(mGatewayConnection.isQuitting());
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
new file mode 100644
index 000000000000..d1f3a210d870
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.net.ipsec.ike.IkeSessionParams;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+/** Tests for VcnGatewayConnection.ConnectingState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectionTestBase {
+ private VcnIkeSession mIkeSession;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
+ mGatewayConnection.transitionTo(mGatewayConnection.mConnectingState);
+ mTestLooper.dispatchAll();
+
+ mIkeSession = mGatewayConnection.getIkeSession();
+ }
+
+ @Test
+ public void testEnterStateCreatesNewIkeSession() throws Exception {
+ final ArgumentCaptor<IkeSessionParams> paramsCaptor =
+ ArgumentCaptor.forClass(IkeSessionParams.class);
+ verify(mDeps).newIkeSession(any(), paramsCaptor.capture(), any(), any(), any());
+ assertEquals(
+ TEST_UNDERLYING_NETWORK_RECORD_1.network, paramsCaptor.getValue().getNetwork());
+ }
+
+ @Test
+ public void testNullNetworkTriggersDisconnect() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(null);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).kill();
+ verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */);
+ }
+
+ @Test
+ public void testNewNetworkTriggersReconnect() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).close();
+ verify(mIkeSession, never()).kill();
+ verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+ }
+
+ @Test
+ public void testSameNetworkDoesNotTriggerReconnect() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testChildSessionClosedTriggersDisconnect() throws Exception {
+ getChildSessionCallback().onClosed();
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).close();
+ verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+ }
+
+ @Test
+ public void testIkeSessionClosedTriggersDisconnect() throws Exception {
+ getIkeSessionCallback().onClosed();
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).close();
+ verifyTeardownTimeoutAlarmAndGetCallback(true /* expectCanceled */);
+ }
+
+ @Test
+ public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() {
+ verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+ mGatewayConnection.mConnectingState);
+ }
+
+ @Test
+ public void testTeardown() throws Exception {
+ mGatewayConnection.teardownAsynchronously();
+ mTestLooper.dispatchAll();
+
+ // Verify that sending a non-quitting disconnect request does not unset the isQuitting flag
+ mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ assertTrue(mGatewayConnection.isQuitting());
+ }
+
+ @Test
+ public void testNonTeardownDisconnectRequest() throws Exception {
+ mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ assertFalse(mGatewayConnection.isQuitting());
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
new file mode 100644
index 000000000000..2056eea42ce6
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static android.net.IpSecManager.IpSecTunnelInterface;
+
+import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.net.IpSecManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for VcnGatewayConnection.DisconnectedState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnectionTestBase {
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ final IpSecTunnelInterface tunnelIface =
+ mContext.getSystemService(IpSecManager.class)
+ .createIpSecTunnelInterface(
+ DUMMY_ADDR, DUMMY_ADDR, TEST_UNDERLYING_NETWORK_RECORD_1.network);
+ mGatewayConnection.setTunnelInterface(tunnelIface);
+
+ // Don't need to transition to DisconnectedState because it is the starting state
+ mTestLooper.dispatchAll();
+ }
+
+ @Test
+ public void testEnterWhileQuittingTriggersQuit() throws Exception {
+ final VcnGatewayConnection vgc =
+ new VcnGatewayConnection(
+ mVcnContext,
+ TEST_SUB_GRP,
+ TEST_SUBSCRIPTION_SNAPSHOT,
+ mConfig,
+ mGatewayStatusCallback,
+ true /* isMobileDataEnabled */,
+ mDeps);
+
+ vgc.setQuitting();
+ vgc.transitionTo(vgc.mDisconnectedState);
+ mTestLooper.dispatchAll();
+
+ assertNull(vgc.getCurrentState());
+ }
+
+ @Test
+ public void testNetworkChangesTriggerStateTransitions() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+ verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+ }
+
+ @Test
+ public void testNullNetworkDoesNotTriggerStateTransition() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(null);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+ verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */);
+ }
+
+ @Test
+ public void testTeardown() throws Exception {
+ mGatewayConnection.teardownAsynchronously();
+ mTestLooper.dispatchAll();
+
+ // Verify that sending a non-quitting disconnect request does not unset the isQuitting flag
+ mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+ mTestLooper.dispatchAll();
+
+ assertNull(mGatewayConnection.getCurrentState());
+ verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any());
+ verifySafeModeTimeoutAlarmAndGetCallback(true /* expectCanceled */);
+ assertTrue(mGatewayConnection.isQuitting());
+ verify(mGatewayStatusCallback).onQuit();
+ }
+
+ @Test
+ public void testNonTeardownDisconnectRequest() throws Exception {
+ mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+ assertFalse(mGatewayConnection.isQuitting());
+ verify(mGatewayStatusCallback, never()).onQuit();
+ // No safe mode timer changes expected.
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
new file mode 100644
index 000000000000..78aefad9f8ff
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for VcnGatewayConnection.DisconnectedState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnectionTestBase {
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mGatewayConnection.setIkeSession(
+ mGatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_2.network));
+
+ // ensure that mGatewayConnection has an underlying Network before entering
+ // DisconnectingState
+ mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_2);
+ mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectingState);
+ mTestLooper.dispatchAll();
+ }
+
+ @Test
+ public void testIkeSessionClosed() throws Exception {
+ getIkeSessionCallback().onClosed();
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
+ verify(mMockIkeSession).close();
+ verify(mMockIkeSession, never()).kill();
+ verifyTeardownTimeoutAlarmAndGetCallback(true /* expectCanceled */);
+ }
+
+ @Test
+ public void testTimeoutExpired() throws Exception {
+ Runnable delayedEvent =
+ verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+
+ // Can't use mTestLooper to advance the time since VcnGatewayConnection uses WakeupMessages
+ // (which are mocked here). Directly invoke the runnable instead. This is still sufficient,
+ // since verifyTeardownTimeoutAlarmAndGetCallback() verifies the WakeupMessage was scheduled
+ // with the correct delay.
+ delayedEvent.run();
+ mTestLooper.dispatchAll();
+
+ verify(mMockIkeSession).kill();
+ }
+
+ @Test
+ public void testTeardown() throws Exception {
+ mGatewayConnection.teardownAsynchronously();
+ mTestLooper.dispatchAll();
+
+ // Verify that sending a non-quitting disconnect request does not unset the isQuitting flag
+ mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+ mTestLooper.dispatchAll();
+
+ // Should do nothing; already tearing down.
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+ assertTrue(mGatewayConnection.isQuitting());
+ }
+
+ @Test
+ public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() {
+ verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+ mGatewayConnection.mDisconnectingState);
+ }
+
+ @Test
+ public void testNonTeardownDisconnectRequest() throws Exception {
+ mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ assertFalse(mGatewayConnection.isQuitting());
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
new file mode 100644
index 000000000000..1c859790a2fe
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for VcnGatewayConnection.RetryTimeoutState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnectionTestBase {
+ private long mFirstRetryInterval;
+ private VcnNetworkAgent mNetworkAgent;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mFirstRetryInterval = mConfig.getRetryIntervalsMillis()[0];
+ mNetworkAgent = mock(VcnNetworkAgent.class);
+
+ mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
+ mGatewayConnection.transitionTo(mGatewayConnection.mRetryTimeoutState);
+ mTestLooper.dispatchAll();
+
+ mGatewayConnection.setNetworkAgent(mNetworkAgent);
+ }
+
+ @Test
+ public void testNewNetworkTriggerRetry() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+ verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */);
+
+ assertNotNull(mGatewayConnection.getNetworkAgent());
+ verify(mNetworkAgent, never()).unregister();
+ }
+
+ @Test
+ public void testSameNetworkDoesNotTriggerRetry() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
+ verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, false /* expectCanceled */);
+
+ assertNotNull(mGatewayConnection.getNetworkAgent());
+ verify(mNetworkAgent, never()).unregister();
+ }
+
+ @Test
+ public void testNullNetworkTriggersDisconnect() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(null);
+ mTestLooper.dispatchAll();
+
+ // Verify that sending a non-quitting disconnect request does not unset the isQuitting flag
+ mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+ verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */);
+
+ assertNull(mGatewayConnection.getNetworkAgent());
+ verify(mNetworkAgent).unregister();
+ }
+
+ @Test
+ public void testTimeoutElapsingTriggersRetry() throws Exception {
+ final Runnable delayedEvent =
+ verifyRetryTimeoutAlarmAndGetCallback(
+ mFirstRetryInterval, false /* expectCanceled */);
+
+ // Can't use mTestLooper to advance the time since VcnGatewayConnection uses WakeupMessages
+ // (which are mocked here). Directly invoke the runnable instead. This is still sufficient,
+ // since verifyRetryTimeoutAlarmAndGetCallback() verifies the WakeupMessage was scheduled
+ // with the correct delay.
+ delayedEvent.run();
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+ verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */);
+
+ assertNotNull(mGatewayConnection.getNetworkAgent());
+ verify(mNetworkAgent, never()).unregister();
+ }
+
+ @Test
+ public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() {
+ verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+ mGatewayConnection.mRetryTimeoutState);
+ }
+
+ @Test
+ public void testTeardownDisconnectRequest() throws Exception {
+ mGatewayConnection.teardownAsynchronously();
+ mTestLooper.dispatchAll();
+
+ assertNull(mGatewayConnection.getCurrentState());
+ assertTrue(mGatewayConnection.isQuitting());
+
+ assertNull(mGatewayConnection.getNetworkAgent());
+ verify(mNetworkAgent).unregister();
+ }
+
+ @Test
+ public void testNonTeardownDisconnectRequest() throws Exception {
+ mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+ assertFalse(mGatewayConnection.isQuitting());
+
+ assertNull(mGatewayConnection.getNetworkAgent());
+ verify(mNetworkAgent).unregister();
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
new file mode 100644
index 000000000000..a7001713533c
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+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.VcnIkeSession;
+import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyLong;
+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.verify;
+
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.TelephonyNetworkSpecifier;
+import android.net.vcn.VcnGatewayConnectionConfigTest;
+import android.net.vcn.VcnTransportInfo;
+import android.net.wifi.WifiInfo;
+import android.os.ParcelUuid;
+import android.os.Process;
+import android.telephony.SubscriptionInfo;
+
+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 org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/** Tests for TelephonySubscriptionTracker */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
+ private static final int TEST_UID = Process.myUid() + 1;
+
+ 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;
+ private static final SubscriptionInfo TEST_SUBINFO_1 = mock(SubscriptionInfo.class);
+ 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 int TEST_UPSTREAM_BANDWIDTH = 1234;
+ private static final int TEST_DOWNSTREAM_BANDWIDTH = 2345;
+
+ static {
+ final Map<Integer, ParcelUuid> subIdToGroupMap = new HashMap<>();
+ subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID);
+ subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_PARCEL_UUID);
+ TEST_SUBID_TO_GROUP_MAP = Collections.unmodifiableMap(subIdToGroupMap);
+ }
+
+ private WifiInfo mWifiInfo;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mWifiInfo = mock(WifiInfo.class);
+ doReturn(mWifiInfo).when(mWifiInfo).makeCopy(anyLong());
+ }
+
+ private void verifyBuildNetworkCapabilitiesCommon(
+ int transportType, boolean isMobileDataEnabled) {
+ final NetworkCapabilities.Builder capBuilder = new NetworkCapabilities.Builder();
+ capBuilder.addTransportType(transportType);
+ capBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+ capBuilder.addCapability(NET_CAPABILITY_NOT_METERED);
+ capBuilder.addCapability(NET_CAPABILITY_NOT_ROAMING);
+
+ if (transportType == TRANSPORT_WIFI) {
+ capBuilder.setTransportInfo(mWifiInfo);
+ capBuilder.setOwnerUid(TEST_UID);
+ } else if (transportType == TRANSPORT_CELLULAR) {
+ capBuilder.setNetworkSpecifier(
+ new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_1));
+ }
+ capBuilder.setLinkUpstreamBandwidthKbps(TEST_UPSTREAM_BANDWIDTH);
+ capBuilder.setLinkDownstreamBandwidthKbps(TEST_DOWNSTREAM_BANDWIDTH);
+ capBuilder.setAdministratorUids(new int[] {TEST_UID});
+ UnderlyingNetworkRecord record = new UnderlyingNetworkRecord(
+ mock(Network.class, CALLS_REAL_METHODS),
+ capBuilder.build(), new LinkProperties(), false);
+ final NetworkCapabilities vcnCaps =
+ VcnGatewayConnection.buildNetworkCapabilities(
+ VcnGatewayConnectionConfigTest.buildTestConfig(),
+ record,
+ isMobileDataEnabled);
+
+ assertTrue(vcnCaps.hasTransport(TRANSPORT_CELLULAR));
+ assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+
+ for (int cap : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
+ if (cap == NET_CAPABILITY_INTERNET || cap == NET_CAPABILITY_DUN) {
+ assertEquals(isMobileDataEnabled, vcnCaps.hasCapability(cap));
+ } else {
+ assertTrue(vcnCaps.hasCapability(cap));
+ }
+ }
+
+ assertArrayEquals(new int[] {Process.myUid(), TEST_UID}, vcnCaps.getAdministratorUids());
+ assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo);
+ assertEquals(TEST_UPSTREAM_BANDWIDTH, vcnCaps.getLinkUpstreamBandwidthKbps());
+ assertEquals(TEST_DOWNSTREAM_BANDWIDTH, vcnCaps.getLinkDownstreamBandwidthKbps());
+
+ final VcnTransportInfo info = (VcnTransportInfo) vcnCaps.getTransportInfo();
+ if (transportType == TRANSPORT_WIFI) {
+ assertEquals(mWifiInfo, info.getWifiInfo());
+ } else if (transportType == TRANSPORT_CELLULAR) {
+ assertEquals(TEST_SUBSCRIPTION_ID_1, info.getSubId());
+ }
+ }
+
+ @Test
+ public void testBuildNetworkCapabilitiesUnderlyingWifi() throws Exception {
+ verifyBuildNetworkCapabilitiesCommon(TRANSPORT_WIFI, true /* isMobileDataEnabled */);
+ }
+
+ @Test
+ public void testBuildNetworkCapabilitiesUnderlyingCell() throws Exception {
+ verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR, true /* isMobileDataEnabled */);
+ }
+
+ @Test
+ public void testBuildNetworkCapabilitiesMobileDataDisabled() throws Exception {
+ verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR, false /* isMobileDataEnabled */);
+ }
+
+ @Test
+ public void testSubscriptionSnapshotUpdateNotifiesUnderlyingNetworkTracker() {
+ verifyWakeLockSetUp();
+
+ final TelephonySubscriptionSnapshot updatedSnapshot =
+ mock(TelephonySubscriptionSnapshot.class);
+ mGatewayConnection.updateSubscriptionSnapshot(updatedSnapshot);
+
+ verify(mUnderlyingNetworkTracker).updateSubscriptionSnapshot(eq(updatedSnapshot));
+ verifyWakeLockAcquired();
+
+ mTestLooper.dispatchAll();
+
+ verifyWakeLockReleased();
+ }
+
+ @Test
+ public void testNonNullUnderlyingNetworkRecordUpdateCancelsAlarm() {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(null);
+
+ verifyDisconnectRequestAlarmAndGetCallback(false /* expectCanceled */);
+
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+
+ verify(mDisconnectRequestAlarm).cancel();
+ }
+
+ @Test
+ public void testQuittingCleansUpPersistentState() {
+ final VcnIkeSession vcnIkeSession = mock(VcnIkeSession.class);
+ final VcnNetworkAgent vcnNetworkAgent = mock(VcnNetworkAgent.class);
+
+ mGatewayConnection.setIkeSession(vcnIkeSession);
+ mGatewayConnection.setNetworkAgent(vcnNetworkAgent);
+
+ mGatewayConnection.quitNow();
+ mTestLooper.dispatchAll();
+
+ assertNull(mGatewayConnection.getIkeSession());
+ verify(vcnIkeSession).kill();
+ assertNull(mGatewayConnection.getNetworkAgent());
+ verify(vcnNetworkAgent).unregister();
+
+ verifyWakeLockReleased();
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
new file mode 100644
index 000000000000..a696b3ae28f7
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
+import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
+import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
+import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.CALLS_REAL_METHODS;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.InetAddresses;
+import android.net.IpSecConfig;
+import android.net.IpSecManager;
+import android.net.IpSecTransform;
+import android.net.IpSecTunnelInterfaceResponse;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.ipsec.ike.ChildSessionCallback;
+import android.net.ipsec.ike.IkeSessionCallback;
+import android.net.vcn.VcnGatewayConnectionConfig;
+import android.net.vcn.VcnGatewayConnectionConfigTest;
+import android.os.ParcelUuid;
+import android.os.PowerManager;
+import android.os.test.TestLooper;
+import android.telephony.SubscriptionInfo;
+
+import com.android.internal.util.State;
+import com.android.internal.util.WakeupMessage;
+import com.android.server.IpSecService;
+import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
+import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback;
+import com.android.server.vcn.VcnGatewayConnection.VcnWakeLock;
+
+import org.junit.Before;
+import org.mockito.ArgumentCaptor;
+
+import java.net.InetAddress;
+import java.util.Collections;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+public class VcnGatewayConnectionTestBase {
+ protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID());
+ protected static final SubscriptionInfo TEST_SUB_INFO = mock(SubscriptionInfo.class);
+
+ static {
+ doReturn(TEST_SUB_GRP).when(TEST_SUB_INFO).getGroupUuid();
+ }
+
+ protected static final InetAddress TEST_DNS_ADDR =
+ InetAddresses.parseNumericAddress("2001:DB8:0:1::");
+ protected static final InetAddress TEST_DNS_ADDR_2 =
+ InetAddresses.parseNumericAddress("2001:DB8:0:2::");
+ protected static final LinkAddress TEST_INTERNAL_ADDR =
+ new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:1::"), 64);
+ protected static final LinkAddress TEST_INTERNAL_ADDR_2 =
+ new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:2::"), 64);
+ protected static final LinkAddress TEST_INTERNAL_ADDR_3 =
+ new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:3::"), 64);
+
+ protected static final int TEST_IPSEC_SPI_VALUE = 0x1234;
+ protected static final int TEST_IPSEC_SPI_RESOURCE_ID = 1;
+ protected static final int TEST_IPSEC_TRANSFORM_RESOURCE_ID = 2;
+ protected static final int TEST_IPSEC_TUNNEL_RESOURCE_ID = 3;
+ protected static final int TEST_SUB_ID = 5;
+ protected static final long ELAPSED_REAL_TIME = 123456789L;
+ protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
+
+ protected static final String TEST_TCP_BUFFER_SIZES_1 = "1,2,3,4";
+ protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
+ new UnderlyingNetworkRecord(
+ mock(Network.class, CALLS_REAL_METHODS),
+ new NetworkCapabilities(),
+ new LinkProperties(),
+ false /* blocked */);
+
+ static {
+ TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setMtu(1500);
+ TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES_1);
+ }
+
+ protected static final String TEST_TCP_BUFFER_SIZES_2 = "2,3,4,5";
+ protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 =
+ new UnderlyingNetworkRecord(
+ mock(Network.class, CALLS_REAL_METHODS),
+ new NetworkCapabilities(),
+ new LinkProperties(),
+ false /* blocked */);
+
+ static {
+ TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setMtu(1460);
+ TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES_2);
+ }
+
+ protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT =
+ new TelephonySubscriptionSnapshot(
+ TEST_SUB_ID,
+ Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO),
+ Collections.EMPTY_MAP);
+
+ @NonNull protected final Context mContext;
+ @NonNull protected final TestLooper mTestLooper;
+ @NonNull protected final VcnNetworkProvider mVcnNetworkProvider;
+ @NonNull protected final VcnContext mVcnContext;
+ @NonNull protected final VcnGatewayConnectionConfig mConfig;
+ @NonNull protected final VcnGatewayStatusCallback mGatewayStatusCallback;
+ @NonNull protected final VcnGatewayConnection.Dependencies mDeps;
+ @NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker;
+ @NonNull protected final VcnWakeLock mWakeLock;
+ @NonNull protected final WakeupMessage mTeardownTimeoutAlarm;
+ @NonNull protected final WakeupMessage mDisconnectRequestAlarm;
+ @NonNull protected final WakeupMessage mRetryTimeoutAlarm;
+ @NonNull protected final WakeupMessage mSafeModeTimeoutAlarm;
+
+ @NonNull protected final IpSecService mIpSecSvc;
+ @NonNull protected final ConnectivityManager mConnMgr;
+
+ protected VcnIkeSession mMockIkeSession;
+ protected VcnGatewayConnection mGatewayConnection;
+
+ public VcnGatewayConnectionTestBase() {
+ mContext = mock(Context.class);
+ mTestLooper = new TestLooper();
+ mVcnNetworkProvider = mock(VcnNetworkProvider.class);
+ mVcnContext = mock(VcnContext.class);
+ mConfig = VcnGatewayConnectionConfigTest.buildTestConfig();
+ mGatewayStatusCallback = mock(VcnGatewayStatusCallback.class);
+ mDeps = mock(VcnGatewayConnection.Dependencies.class);
+ mUnderlyingNetworkTracker = mock(UnderlyingNetworkTracker.class);
+ mWakeLock = mock(VcnWakeLock.class);
+ mTeardownTimeoutAlarm = mock(WakeupMessage.class);
+ mDisconnectRequestAlarm = mock(WakeupMessage.class);
+ mRetryTimeoutAlarm = mock(WakeupMessage.class);
+ mSafeModeTimeoutAlarm = mock(WakeupMessage.class);
+
+ mIpSecSvc = mock(IpSecService.class);
+ setupIpSecManager(mContext, mIpSecSvc);
+
+ mConnMgr = mock(ConnectivityManager.class);
+ VcnTestUtils.setupSystemService(
+ mContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+
+ doReturn(mContext).when(mVcnContext).getContext();
+ doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
+ doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
+
+ doReturn(mUnderlyingNetworkTracker)
+ .when(mDeps)
+ .newUnderlyingNetworkTracker(any(), any(), any(), any());
+ doReturn(mWakeLock)
+ .when(mDeps)
+ .newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any());
+
+ setUpWakeupMessage(mTeardownTimeoutAlarm, VcnGatewayConnection.TEARDOWN_TIMEOUT_ALARM);
+ setUpWakeupMessage(mDisconnectRequestAlarm, VcnGatewayConnection.DISCONNECT_REQUEST_ALARM);
+ setUpWakeupMessage(mRetryTimeoutAlarm, VcnGatewayConnection.RETRY_TIMEOUT_ALARM);
+ setUpWakeupMessage(mSafeModeTimeoutAlarm, VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM);
+
+ doReturn(ELAPSED_REAL_TIME).when(mDeps).getElapsedRealTime();
+ }
+
+ private void setUpWakeupMessage(@NonNull WakeupMessage msg, @NonNull String cmdName) {
+ doReturn(msg).when(mDeps).newWakeupMessage(eq(mVcnContext), any(), eq(cmdName), any());
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ IpSecTunnelInterfaceResponse resp =
+ new IpSecTunnelInterfaceResponse(
+ IpSecManager.Status.OK,
+ TEST_IPSEC_TUNNEL_RESOURCE_ID,
+ TEST_IPSEC_TUNNEL_IFACE);
+ doReturn(resp).when(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any());
+
+ mMockIkeSession = mock(VcnIkeSession.class);
+ doReturn(mMockIkeSession).when(mDeps).newIkeSession(any(), any(), any(), any(), any());
+
+ mGatewayConnection =
+ new VcnGatewayConnection(
+ mVcnContext,
+ TEST_SUB_GRP,
+ TEST_SUBSCRIPTION_SNAPSHOT,
+ mConfig,
+ mGatewayStatusCallback,
+ true /* isMobileDataEnabled */,
+ mDeps);
+ }
+
+ protected IpSecTransform makeDummyIpSecTransform() throws Exception {
+ return new IpSecTransform(mContext, new IpSecConfig());
+ }
+
+ protected IkeSessionCallback getIkeSessionCallback() {
+ ArgumentCaptor<IkeSessionCallback> captor =
+ ArgumentCaptor.forClass(IkeSessionCallback.class);
+ verify(mDeps).newIkeSession(any(), any(), any(), captor.capture(), any());
+ return captor.getValue();
+ }
+
+ protected VcnChildSessionCallback getChildSessionCallback() {
+ ArgumentCaptor<ChildSessionCallback> captor =
+ ArgumentCaptor.forClass(ChildSessionCallback.class);
+ verify(mDeps, atLeastOnce()).newIkeSession(any(), any(), any(), any(), captor.capture());
+ return (VcnChildSessionCallback) captor.getValue();
+ }
+
+ protected void verifyWakeLockSetUp() {
+ verify(mDeps).newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any());
+ verifyNoMoreInteractions(mWakeLock);
+ }
+
+ protected void verifyWakeLockAcquired() {
+ verify(mWakeLock).acquire();
+ verifyNoMoreInteractions(mWakeLock);
+ }
+
+ protected void verifyWakeLockReleased() {
+ verify(mWakeLock).release();
+ verifyNoMoreInteractions(mWakeLock);
+ }
+
+ private Runnable verifyWakeupMessageSetUpAndGetCallback(
+ @NonNull String tag,
+ @NonNull WakeupMessage msg,
+ long delayInMillis,
+ boolean expectCanceled) {
+ ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+ verify(mDeps).newWakeupMessage(eq(mVcnContext), any(), eq(tag), runnableCaptor.capture());
+
+ verify(mDeps, atLeastOnce()).getElapsedRealTime();
+ verify(msg).schedule(ELAPSED_REAL_TIME + delayInMillis);
+ verify(msg, expectCanceled ? times(1) : never()).cancel();
+
+ return runnableCaptor.getValue();
+ }
+
+ protected Runnable verifyTeardownTimeoutAlarmAndGetCallback(boolean expectCanceled) {
+ return verifyWakeupMessageSetUpAndGetCallback(
+ VcnGatewayConnection.TEARDOWN_TIMEOUT_ALARM,
+ mTeardownTimeoutAlarm,
+ TimeUnit.SECONDS.toMillis(VcnGatewayConnection.TEARDOWN_TIMEOUT_SECONDS),
+ expectCanceled);
+ }
+
+ protected Runnable verifyDisconnectRequestAlarmAndGetCallback(boolean expectCanceled) {
+ return verifyWakeupMessageSetUpAndGetCallback(
+ VcnGatewayConnection.DISCONNECT_REQUEST_ALARM,
+ mDisconnectRequestAlarm,
+ TimeUnit.SECONDS.toMillis(
+ VcnGatewayConnection.NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS),
+ expectCanceled);
+ }
+
+ protected Runnable verifyRetryTimeoutAlarmAndGetCallback(
+ long delayInMillis, boolean expectCanceled) {
+ return verifyWakeupMessageSetUpAndGetCallback(
+ VcnGatewayConnection.RETRY_TIMEOUT_ALARM,
+ mRetryTimeoutAlarm,
+ delayInMillis,
+ expectCanceled);
+ }
+
+ protected Runnable verifySafeModeTimeoutAlarmAndGetCallback(boolean expectCanceled) {
+ return verifyWakeupMessageSetUpAndGetCallback(
+ VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM,
+ mSafeModeTimeoutAlarm,
+ TimeUnit.SECONDS.toMillis(VcnGatewayConnection.SAFEMODE_TIMEOUT_SECONDS),
+ expectCanceled);
+ }
+
+ protected void verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+ @NonNull State expectedState) {
+ // Set a VcnNetworkAgent, and expect it to be unregistered and cleared
+ final VcnNetworkAgent mockNetworkAgent = mock(VcnNetworkAgent.class);
+ mGatewayConnection.setNetworkAgent(mockNetworkAgent);
+
+ // SafeMode timer starts when VcnGatewayConnection exits DisconnectedState (the initial
+ // state)
+ final Runnable delayedEvent =
+ verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+ delayedEvent.run();
+ mTestLooper.dispatchAll();
+
+ verify(mGatewayStatusCallback).onSafeModeStatusChanged();
+ assertEquals(expectedState, mGatewayConnection.getCurrentState());
+ assertTrue(mGatewayConnection.isInSafeMode());
+
+ verify(mockNetworkAgent).unregister();
+ assertNull(mGatewayConnection.getNetworkAgent());
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java b/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
new file mode 100644
index 000000000000..e9026e22b6b2
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static android.net.NetworkProvider.NetworkOfferCallback;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkRequest;
+import android.os.test.TestLooper;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Tests for TelephonySubscriptionTracker */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnNetworkProviderTest {
+ private static final int TEST_SCORE_UNSATISFIED = 0;
+ private static final int TEST_PROVIDER_ID = 1;
+
+ @NonNull private final Context mContext;
+ @NonNull private final TestLooper mTestLooper;
+
+ @NonNull private VcnNetworkProvider.Dependencies mDeps;
+ @NonNull private ConnectivityManager mConnMgr;
+ @NonNull private VcnNetworkProvider mVcnNetworkProvider;
+ @NonNull private NetworkRequestListener mListener;
+
+ public VcnNetworkProviderTest() {
+ mContext = mock(Context.class);
+ mTestLooper = new TestLooper();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mDeps = mock(VcnNetworkProvider.Dependencies.class);
+ mConnMgr = mock(ConnectivityManager.class);
+ VcnTestUtils.setupSystemService(
+ mContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+
+ mVcnNetworkProvider = new VcnNetworkProvider(mContext, mTestLooper.getLooper(), mDeps);
+ mListener = mock(NetworkRequestListener.class);
+ }
+
+ private NetworkOfferCallback verifyRegisterAndGetOfferCallback() throws Exception {
+ mVcnNetworkProvider.register();
+
+ final ArgumentCaptor<NetworkOfferCallback> cbCaptor =
+ ArgumentCaptor.forClass(NetworkOfferCallback.class);
+
+ verify(mConnMgr).registerNetworkProvider(eq(mVcnNetworkProvider));
+ verify(mDeps)
+ .registerNetworkOffer(
+ eq(mVcnNetworkProvider),
+ argThat(
+ score ->
+ score.getLegacyInt() == Vcn.getNetworkScore().getLegacyInt()
+ && score.isTransportPrimary()),
+ any(),
+ any(),
+ cbCaptor.capture());
+
+ return cbCaptor.getValue();
+ }
+
+ @Test
+ public void testRegister() throws Exception {
+ verifyRegisterAndGetOfferCallback();
+ }
+
+ @Test
+ public void testRequestsPassedToRegisteredListeners() throws Exception {
+ mVcnNetworkProvider.registerListener(mListener);
+
+ final NetworkRequest request = mock(NetworkRequest.class);
+ verifyRegisterAndGetOfferCallback().onNetworkNeeded(request);
+ verify(mListener).onNetworkRequested(request);
+ }
+
+ @Test
+ public void testUnregisterListener() throws Exception {
+ mVcnNetworkProvider.registerListener(mListener);
+ mVcnNetworkProvider.unregisterListener(mListener);
+
+ final NetworkRequest request = mock(NetworkRequest.class);
+ verifyRegisterAndGetOfferCallback().onNetworkNeeded(request);
+ verifyNoMoreInteractions(mListener);
+ }
+
+ @Test
+ public void testCachedRequestsPassedOnRegister() throws Exception {
+ final List<NetworkRequest> requests = new ArrayList<>();
+ final NetworkOfferCallback offerCb = verifyRegisterAndGetOfferCallback();
+
+ for (int i = 0; i < 10; i++) {
+ // Build unique network requests; in this case, iterate down the capabilities as a way
+ // to unique-ify requests.
+ final NetworkRequest request =
+ new NetworkRequest.Builder().clearCapabilities().addCapability(i).build();
+
+ requests.add(request);
+ offerCb.onNetworkNeeded(request);
+ }
+
+ // Remove one, and verify that it is never sent to the listeners.
+ final NetworkRequest removed = requests.remove(0);
+ offerCb.onNetworkUnneeded(removed);
+
+ mVcnNetworkProvider.registerListener(mListener);
+ for (NetworkRequest request : requests) {
+ verify(mListener).onNetworkRequested(request);
+ }
+ verifyNoMoreInteractions(mListener);
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java
new file mode 100644
index 000000000000..5d2f9d748581
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java
@@ -0,0 +1,461 @@
+/*
+ * 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;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+
+import static com.android.server.vcn.Vcn.VcnContentResolver;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.NetworkRequest;
+import android.net.Uri;
+import android.net.vcn.VcnConfig;
+import android.net.vcn.VcnGatewayConnectionConfig;
+import android.net.vcn.VcnGatewayConnectionConfigTest;
+import android.os.ParcelUuid;
+import android.os.test.TestLooper;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+import android.util.ArraySet;
+
+import com.android.server.VcnManagementService.VcnCallback;
+import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
+import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.UUID;
+
+public class VcnTest {
+ private static final String PKG_NAME = VcnTest.class.getPackage().getName();
+ private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0));
+ private static final boolean MOBILE_DATA_ENABLED = true;
+ private static final Set<Integer> TEST_SUB_IDS_IN_GROUP =
+ new ArraySet<>(Arrays.asList(1, 2, 3));
+ private static final int[][] TEST_CAPS =
+ new int[][] {
+ new int[] {NET_CAPABILITY_IMS, NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN},
+ new int[] {NET_CAPABILITY_CBS, NET_CAPABILITY_INTERNET},
+ new int[] {NET_CAPABILITY_FOTA, NET_CAPABILITY_DUN},
+ new int[] {NET_CAPABILITY_MMS}
+ };
+
+ private Context mContext;
+ private VcnContext mVcnContext;
+ private TelephonyManager mTelephonyManager;
+ private VcnContentResolver mContentResolver;
+ private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
+ private VcnNetworkProvider mVcnNetworkProvider;
+ private VcnCallback mVcnCallback;
+ private Vcn.Dependencies mDeps;
+
+ private ArgumentCaptor<VcnGatewayStatusCallback> mGatewayStatusCallbackCaptor;
+
+ private TestLooper mTestLooper;
+ private VcnGatewayConnectionConfig mGatewayConnectionConfig;
+ private VcnConfig mConfig;
+ private Vcn mVcn;
+
+ @Before
+ public void setUp() {
+ mContext = mock(Context.class);
+ mVcnContext = mock(VcnContext.class);
+ mTelephonyManager =
+ setupAndGetTelephonyManager(MOBILE_DATA_ENABLED /* isMobileDataEnabled */);
+ mContentResolver = mock(VcnContentResolver.class);
+ mSubscriptionSnapshot = mock(TelephonySubscriptionSnapshot.class);
+ mVcnNetworkProvider = mock(VcnNetworkProvider.class);
+ mVcnCallback = mock(VcnCallback.class);
+ mDeps = mock(Vcn.Dependencies.class);
+
+ mTestLooper = new TestLooper();
+
+ doReturn(PKG_NAME).when(mContext).getOpPackageName();
+ doReturn(mContext).when(mVcnContext).getContext();
+ doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
+ doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
+ doReturn(mContentResolver).when(mDeps).newVcnContentResolver(eq(mVcnContext));
+
+ // Setup VcnGatewayConnection instance generation
+ doAnswer((invocation) -> {
+ // Mock-within a doAnswer is safe, because it doesn't actually run nested.
+ return mock(VcnGatewayConnection.class);
+ }).when(mDeps).newVcnGatewayConnection(any(), any(), any(), any(), any(), anyBoolean());
+
+ doReturn(TEST_SUB_IDS_IN_GROUP).when(mSubscriptionSnapshot).getAllSubIdsInGroup(any());
+
+ mGatewayStatusCallbackCaptor = ArgumentCaptor.forClass(VcnGatewayStatusCallback.class);
+
+ final VcnConfig.Builder configBuilder = new VcnConfig.Builder(mContext);
+ for (final int[] caps : TEST_CAPS) {
+ configBuilder.addGatewayConnectionConfig(
+ VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(caps));
+ }
+
+ mConfig = configBuilder.build();
+ mVcn =
+ new Vcn(
+ mVcnContext,
+ TEST_SUB_GROUP,
+ mConfig,
+ mSubscriptionSnapshot,
+ mVcnCallback,
+ mDeps);
+ }
+
+ private TelephonyManager setupAndGetTelephonyManager(boolean isMobileDataEnabled) {
+ final TelephonyManager telephonyManager = mock(TelephonyManager.class);
+ VcnTestUtils.setupSystemService(
+ mContext, telephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class);
+ doReturn(telephonyManager).when(telephonyManager).createForSubscriptionId(anyInt());
+ doReturn(isMobileDataEnabled).when(telephonyManager).isDataEnabled();
+
+ return telephonyManager;
+ }
+
+ private NetworkRequestListener verifyAndGetRequestListener() {
+ ArgumentCaptor<NetworkRequestListener> mNetworkRequestListenerCaptor =
+ ArgumentCaptor.forClass(NetworkRequestListener.class);
+ verify(mVcnNetworkProvider).registerListener(mNetworkRequestListenerCaptor.capture());
+
+ return mNetworkRequestListenerCaptor.getValue();
+ }
+
+ private void startVcnGatewayWithCapabilities(
+ NetworkRequestListener requestListener, int... netCapabilities) {
+ final NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
+ requestBuilder.addTransportType(TRANSPORT_CELLULAR);
+ for (final int netCapability : netCapabilities) {
+ requestBuilder.addCapability(netCapability);
+ }
+
+ requestListener.onNetworkRequested(requestBuilder.build());
+ mTestLooper.dispatchAll();
+ }
+
+ private void verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(int status) {
+ final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+ startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]);
+
+ final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections();
+ assertFalse(gatewayConnections.isEmpty());
+
+ final TelephonySubscriptionSnapshot updatedSnapshot =
+ mock(TelephonySubscriptionSnapshot.class);
+
+ mVcn.setStatus(status);
+
+ mVcn.updateSubscriptionSnapshot(updatedSnapshot);
+ mTestLooper.dispatchAll();
+
+ for (final VcnGatewayConnection gateway : gatewayConnections) {
+ verify(gateway).updateSubscriptionSnapshot(eq(updatedSnapshot));
+ }
+ }
+
+ @Test
+ public void testContentObserverRegistered() {
+ // Validate state from setUp()
+ final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA);
+ verify(mContentResolver)
+ .registerContentObserver(eq(uri), eq(true), any(ContentObserver.class));
+ }
+
+ @Test
+ public void testMobileDataStateCheckedOnInitialization_enabled() {
+ // Validate state from setUp()
+ assertTrue(mVcn.isMobileDataEnabled());
+ verify(mTelephonyManager).isDataEnabled();
+ }
+
+ @Test
+ public void testMobileDataStateCheckedOnInitialization_disabled() {
+ // Build and setup new telephonyManager to ensure method call count is reset.
+ final TelephonyManager telephonyManager =
+ setupAndGetTelephonyManager(false /* isMobileDataEnabled */);
+ final Vcn vcn =
+ new Vcn(
+ mVcnContext,
+ TEST_SUB_GROUP,
+ mConfig,
+ mSubscriptionSnapshot,
+ mVcnCallback,
+ mDeps);
+
+ assertFalse(vcn.isMobileDataEnabled());
+ verify(mTelephonyManager).isDataEnabled();
+ }
+
+ @Test
+ public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
+ verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_ACTIVE);
+ }
+
+ @Test
+ public void testSubscriptionSnapshotUpdatesVcnGatewayConnectionsInSafeMode() {
+ verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_SAFE_MODE);
+ }
+
+ @Test
+ public void testSubscriptionSnapshotUpdatesMobileDataState() {
+ final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+ startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]);
+
+ // Expect mobile data enabled from setUp()
+ assertTrue(mVcn.isMobileDataEnabled());
+
+ final TelephonySubscriptionSnapshot updatedSnapshot =
+ mock(TelephonySubscriptionSnapshot.class);
+ doReturn(TEST_SUB_IDS_IN_GROUP)
+ .when(updatedSnapshot)
+ .getAllSubIdsInGroup(eq(TEST_SUB_GROUP));
+ doReturn(false).when(mTelephonyManager).isDataEnabled();
+
+ mVcn.updateSubscriptionSnapshot(updatedSnapshot);
+ mTestLooper.dispatchAll();
+
+ assertFalse(mVcn.isMobileDataEnabled());
+ }
+
+ private void triggerVcnRequestListeners(NetworkRequestListener requestListener) {
+ for (final int[] caps : TEST_CAPS) {
+ startVcnGatewayWithCapabilities(requestListener, caps);
+ }
+ }
+
+ public Set<VcnGatewayConnection> startGatewaysAndGetGatewayConnections(
+ NetworkRequestListener requestListener) {
+ triggerVcnRequestListeners(requestListener);
+
+ final int numExpectedGateways = TEST_CAPS.length;
+
+ final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections();
+ assertEquals(numExpectedGateways, gatewayConnections.size());
+ verify(mDeps, times(numExpectedGateways))
+ .newVcnGatewayConnection(
+ eq(mVcnContext),
+ eq(TEST_SUB_GROUP),
+ eq(mSubscriptionSnapshot),
+ any(),
+ mGatewayStatusCallbackCaptor.capture(),
+ eq(MOBILE_DATA_ENABLED));
+
+ return gatewayConnections;
+ }
+
+ private void verifySafeMode(
+ NetworkRequestListener requestListener,
+ Set<VcnGatewayConnection> activeGateways,
+ boolean expectInSafeMode) {
+ for (VcnGatewayConnection gatewayConnection : activeGateways) {
+ verify(gatewayConnection, never()).teardownAsynchronously();
+ }
+
+ assertEquals(
+ expectInSafeMode ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE,
+ mVcn.getStatus());
+ verify(mVcnCallback).onSafeModeStatusChanged(expectInSafeMode);
+ }
+
+ @Test
+ public void testGatewayEnteringAndExitingSafeModeNotifiesVcn() {
+ final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+ final Set<VcnGatewayConnection> gatewayConnections =
+ startGatewaysAndGetGatewayConnections(requestListener);
+
+ // Doesn't matter which callback this gets, or which VCN is in safe mode - any Gateway
+ // entering Safemode should trigger safe mode
+ final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
+ final VcnGatewayConnection gatewayConnection = gatewayConnections.iterator().next();
+
+ doReturn(true).when(gatewayConnection).isInSafeMode();
+ statusCallback.onSafeModeStatusChanged();
+ mTestLooper.dispatchAll();
+
+ verifySafeMode(requestListener, gatewayConnections, true /* expectInSafeMode */);
+
+ // Verify that when all GatewayConnections exit safe mode, the VCN also exits safe mode
+ doReturn(false).when(gatewayConnection).isInSafeMode();
+ statusCallback.onSafeModeStatusChanged();
+ mTestLooper.dispatchAll();
+
+ verifySafeMode(requestListener, gatewayConnections, false /* expectInSafeMode */);
+
+ // Re-trigger, verify safe mode callback does not get fired again for identical state
+ statusCallback.onSafeModeStatusChanged();
+ mTestLooper.dispatchAll();
+
+ // Expect only once still; from above.
+ verify(mVcnCallback).onSafeModeStatusChanged(false);
+ }
+
+ private void verifyGatewayQuit(int status) {
+ mVcn.setStatus(status);
+
+ final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+ final Set<VcnGatewayConnection> gatewayConnections =
+ new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
+
+ final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
+ statusCallback.onQuit();
+ mTestLooper.dispatchAll();
+
+ // Verify that the VCN requests the networkRequests be resent
+ assertEquals(gatewayConnections.size() - 1, mVcn.getVcnGatewayConnections().size());
+ verify(mVcnNetworkProvider).resendAllRequests(requestListener);
+
+ // Verify that the VcnGatewayConnection is restarted if a request exists for it
+ triggerVcnRequestListeners(requestListener);
+ mTestLooper.dispatchAll();
+ assertEquals(gatewayConnections.size(), mVcn.getVcnGatewayConnections().size());
+ verify(mDeps, times(gatewayConnections.size() + 1))
+ .newVcnGatewayConnection(
+ eq(mVcnContext),
+ eq(TEST_SUB_GROUP),
+ eq(mSubscriptionSnapshot),
+ any(),
+ mGatewayStatusCallbackCaptor.capture(),
+ anyBoolean());
+ }
+
+ @Test
+ public void testGatewayQuitReevaluatesRequests() {
+ verifyGatewayQuit(VCN_STATUS_CODE_ACTIVE);
+ }
+
+ @Test
+ public void testGatewayQuitReevaluatesRequestsInSafeMode() {
+ verifyGatewayQuit(VCN_STATUS_CODE_SAFE_MODE);
+ }
+
+ @Test
+ public void testUpdateConfigReevaluatesGatewayConnections() {
+ final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+ startGatewaysAndGetGatewayConnections(requestListener);
+ assertEquals(TEST_CAPS.length, mVcn.getVcnGatewayConnectionConfigMap().size());
+
+ // Create VcnConfig with only one VcnGatewayConnectionConfig so a gateway connection is torn
+ // down. Reuse existing VcnGatewayConnectionConfig so that the gateway connection name
+ // matches.
+ final List<VcnGatewayConnectionConfig> currentConfigs =
+ new ArrayList<>(mVcn.getVcnGatewayConnectionConfigMap().keySet());
+ final VcnGatewayConnectionConfig activeConfig = currentConfigs.get(0);
+ final VcnGatewayConnectionConfig removedConfig = currentConfigs.get(1);
+ final VcnConfig updatedConfig =
+ new VcnConfig.Builder(mContext).addGatewayConnectionConfig(activeConfig).build();
+
+ mVcn.updateConfig(updatedConfig);
+ mTestLooper.dispatchAll();
+
+ final VcnGatewayConnection activeGatewayConnection =
+ mVcn.getVcnGatewayConnectionConfigMap().get(activeConfig);
+ final VcnGatewayConnection removedGatewayConnection =
+ mVcn.getVcnGatewayConnectionConfigMap().get(removedConfig);
+ verify(activeGatewayConnection, never()).teardownAsynchronously();
+ verify(removedGatewayConnection).teardownAsynchronously();
+ verify(mVcnNetworkProvider).resendAllRequests(requestListener);
+ }
+
+ private void verifyMobileDataToggled(boolean startingToggleState, boolean endingToggleState) {
+ final ArgumentCaptor<ContentObserver> captor =
+ ArgumentCaptor.forClass(ContentObserver.class);
+ verify(mContentResolver).registerContentObserver(any(), anyBoolean(), captor.capture());
+ final ContentObserver contentObserver = captor.getValue();
+
+ // Start VcnGatewayConnections
+ final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+ mVcn.setMobileDataEnabled(startingToggleState);
+ triggerVcnRequestListeners(requestListener);
+ final Map<VcnGatewayConnectionConfig, VcnGatewayConnection> gateways =
+ mVcn.getVcnGatewayConnectionConfigMap();
+
+ // Trigger data toggle change.
+ doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled();
+ contentObserver.onChange(false /* selfChange, ignored */);
+ mTestLooper.dispatchAll();
+
+ // Verify that data toggle changes restart ONLY INTERNET or DUN networks, and only if the
+ // toggle state changed.
+ for (Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry : gateways.entrySet()) {
+ final Set<Integer> exposedCaps = entry.getKey().getAllExposedCapabilities();
+ if (startingToggleState != endingToggleState
+ && (exposedCaps.contains(NET_CAPABILITY_INTERNET)
+ || exposedCaps.contains(NET_CAPABILITY_DUN))) {
+ verify(entry.getValue()).teardownAsynchronously();
+ } else {
+ verify(entry.getValue(), never()).teardownAsynchronously();
+ }
+ }
+
+ if (startingToggleState != endingToggleState) {
+ verify(mVcnNetworkProvider).resendAllRequests(requestListener);
+ }
+ assertEquals(endingToggleState, mVcn.isMobileDataEnabled());
+ }
+
+ @Test
+ public void testMobileDataEnabled() {
+ verifyMobileDataToggled(false /* startingToggleState */, true /* endingToggleState */);
+ }
+
+ @Test
+ public void testMobileDataDisabled() {
+ verifyMobileDataToggled(true /* startingToggleState */, false /* endingToggleState */);
+ }
+
+ @Test
+ public void testMobileDataObserverFiredWithoutChanges_dataEnabled() {
+ verifyMobileDataToggled(false /* startingToggleState */, false /* endingToggleState */);
+ }
+
+ @Test
+ public void testMobileDataObserverFiredWithoutChanges_dataDisabled() {
+ verifyMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */);
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java b/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java
new file mode 100644
index 000000000000..2b1080650d6d
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static org.mockito.Mockito.doReturn;
+
+import android.content.Context;
+import android.net.IpSecManager;
+
+import com.android.server.IpSecService;
+
+public class VcnTestUtils {
+ /** Mock system services by directly mocking the *Manager interface. */
+ public static void setupSystemService(
+ Context mockContext, Object service, String name, Class<?> serviceClass) {
+ doReturn(name).when(mockContext).getSystemServiceName(serviceClass);
+ doReturn(service).when(mockContext).getSystemService(name);
+ }
+
+ /** Mock IpSecService by mocking the underlying service binder. */
+ public static IpSecManager setupIpSecManager(Context mockContext, IpSecService service) {
+ doReturn(Context.IPSEC_SERVICE).when(mockContext).getSystemServiceName(IpSecManager.class);
+
+ final IpSecManager ipSecMgr = new IpSecManager(mockContext, service);
+ doReturn(ipSecMgr).when(mockContext).getSystemService(Context.IPSEC_SERVICE);
+
+ // Return to ensure this doesn't get reaped.
+ return ipSecMgr;
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java b/tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java
new file mode 100644
index 000000000000..29511f780bf6
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn.util;
+
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128;
+import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_256;
+
+import static com.android.net.module.util.NetworkStackConstants.ETHER_MTU;
+import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
+import static com.android.server.vcn.util.MtuUtils.getMtu;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import static java.util.Collections.emptyList;
+
+import android.net.ipsec.ike.ChildSaProposal;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class MtuUtilsTest {
+ @Test
+ public void testUnderlyingMtuZero() {
+ assertEquals(
+ IPV6_MIN_MTU, getMtu(emptyList(), ETHER_MTU /* maxMtu */, 0 /* underlyingMtu */));
+ }
+
+ @Test
+ public void testClampsToMaxMtu() {
+ assertEquals(0, getMtu(emptyList(), 0 /* maxMtu */, IPV6_MIN_MTU /* underlyingMtu */));
+ }
+
+ @Test
+ public void testNormalModeAlgorithmLessThanUnderlyingMtu() {
+ final List<ChildSaProposal> saProposals =
+ Arrays.asList(
+ new ChildSaProposal.Builder()
+ .addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256)
+ .addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128)
+ .build());
+
+ final int actualMtu =
+ getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */);
+ assertTrue(ETHER_MTU > actualMtu);
+ }
+
+ @Test
+ public void testCombinedModeAlgorithmLessThanUnderlyingMtu() {
+ final List<ChildSaProposal> saProposals =
+ Arrays.asList(
+ new ChildSaProposal.Builder()
+ .addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256)
+ .addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_256)
+ .addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_256)
+ .build());
+
+ final int actualMtu =
+ getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */);
+ assertTrue(ETHER_MTU > actualMtu);
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java b/tests/vcn/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java
new file mode 100644
index 000000000000..a44a734a2dce
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/util/PersistableBundleUtilsTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn.util;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Objects;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class PersistableBundleUtilsTest {
+ private static final String TEST_KEY = "testKey";
+ private static final String TEST_STRING_PREFIX = "testString";
+ private static final int[] TEST_INT_ARRAY = new int[] {0, 1, 2, 3, 4};
+
+ private static final int NUM_COLLECTION_ENTRIES = 10;
+
+ private static class TestKey {
+ private static final String TEST_INTEGER_KEY =
+ "mTestInteger"; // Purposely colliding with keys of test class to ensure namespacing
+ private final int mTestInteger;
+
+ TestKey(int testInteger) {
+ mTestInteger = testInteger;
+ }
+
+ TestKey(PersistableBundle in) {
+ mTestInteger = in.getInt(TEST_INTEGER_KEY);
+ }
+
+ public PersistableBundle toPersistableBundle() {
+ final PersistableBundle result = new PersistableBundle();
+
+ result.putInt(TEST_INTEGER_KEY, mTestInteger);
+
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTestInteger);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof TestKey)) {
+ return false;
+ }
+
+ final TestKey other = (TestKey) o;
+ return mTestInteger == other.mTestInteger;
+ }
+ }
+
+ private static class TestClass {
+ private static final String TEST_INTEGER_KEY = "mTestInteger";
+ private final int mTestInteger;
+
+ private static final String TEST_INT_ARRAY_KEY = "mTestIntArray";
+ private final int[] mTestIntArray;
+
+ private static final String TEST_STRING_KEY = "mTestString";
+ private final String mTestString;
+
+ private static final String TEST_PERSISTABLE_BUNDLE_KEY = "mTestPersistableBundle";
+ private final PersistableBundle mTestPersistableBundle;
+
+ TestClass(
+ int testInteger,
+ int[] testIntArray,
+ String testString,
+ PersistableBundle testPersistableBundle) {
+ mTestInteger = testInteger;
+ mTestIntArray = testIntArray;
+ mTestString = testString;
+ mTestPersistableBundle = testPersistableBundle;
+ }
+
+ TestClass(PersistableBundle in) {
+ mTestInteger = in.getInt(TEST_INTEGER_KEY);
+ mTestIntArray = in.getIntArray(TEST_INT_ARRAY_KEY);
+ mTestString = in.getString(TEST_STRING_KEY);
+ mTestPersistableBundle = in.getPersistableBundle(TEST_PERSISTABLE_BUNDLE_KEY);
+ }
+
+ public PersistableBundle toPersistableBundle() {
+ final PersistableBundle result = new PersistableBundle();
+
+ result.putInt(TEST_INTEGER_KEY, mTestInteger);
+ result.putIntArray(TEST_INT_ARRAY_KEY, mTestIntArray);
+ result.putString(TEST_STRING_KEY, mTestString);
+ result.putPersistableBundle(TEST_PERSISTABLE_BUNDLE_KEY, mTestPersistableBundle);
+
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mTestInteger,
+ Arrays.hashCode(mTestIntArray),
+ mTestString,
+ mTestPersistableBundle);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof TestClass)) {
+ return false;
+ }
+
+ final TestClass other = (TestClass) o;
+
+ // TODO: Add a proper equals() to PersistableBundle. But in the meantime, force
+ // TODO: unparcelling in order to allow test comparison.
+ if (mTestPersistableBundle.size() != other.mTestPersistableBundle.size()) {
+ return false;
+ }
+
+ return mTestInteger == other.mTestInteger
+ && Arrays.equals(mTestIntArray, other.mTestIntArray)
+ && mTestString.equals(other.mTestString)
+ && mTestPersistableBundle.kindofEquals(other.mTestPersistableBundle);
+ }
+ }
+
+ @Test
+ public void testListConversionLossless() throws Exception {
+ final List<TestClass> sourceList = new ArrayList<>();
+ for (int i = 0; i < NUM_COLLECTION_ENTRIES; i++) {
+ final PersistableBundle innerBundle = new PersistableBundle();
+ innerBundle.putInt(TEST_KEY, i);
+
+ sourceList.add(new TestClass(i, TEST_INT_ARRAY, TEST_STRING_PREFIX + i, innerBundle));
+ }
+
+ final PersistableBundle bundled =
+ PersistableBundleUtils.fromList(sourceList, TestClass::toPersistableBundle);
+ final List<TestClass> resultList = PersistableBundleUtils.toList(bundled, TestClass::new);
+
+ assertEquals(sourceList, resultList);
+ }
+
+ @Test
+ public void testMapConversionLossless() throws Exception {
+ final LinkedHashMap<TestKey, TestClass> sourceMap = new LinkedHashMap<>();
+ for (int i = 0; i < NUM_COLLECTION_ENTRIES; i++) {
+ final TestKey key = new TestKey(i * i);
+
+ final PersistableBundle innerBundle = new PersistableBundle();
+ innerBundle.putInt(TEST_KEY, i);
+ final TestClass value =
+ new TestClass(i, TEST_INT_ARRAY, TEST_STRING_PREFIX + i, innerBundle);
+
+ sourceMap.put(key, value);
+ }
+
+ final PersistableBundle bundled =
+ PersistableBundleUtils.fromMap(
+ sourceMap, TestKey::toPersistableBundle, TestClass::toPersistableBundle);
+ final LinkedHashMap<TestKey, TestClass> resultList =
+ PersistableBundleUtils.toMap(bundled, TestKey::new, TestClass::new);
+
+ assertEquals(sourceMap, resultList);
+ }
+
+ @Test
+ public void testByteArrayConversionLossless() {
+ final byte[] byteArray = "testByteArrayConversionLossless".getBytes();
+
+ PersistableBundle bundle = PersistableBundleUtils.fromByteArray(byteArray);
+ byte[] result = PersistableBundleUtils.toByteArray(bundle);
+
+ assertArrayEquals(byteArray, result);
+ }
+
+ @Test
+ public void testIntegerConversionLossless() throws Exception {
+ final int testInt = 1;
+ final PersistableBundle integerBundle =
+ PersistableBundleUtils.INTEGER_SERIALIZER.toPersistableBundle(testInt);
+ final int result =
+ PersistableBundleUtils.INTEGER_DESERIALIZER.fromPersistableBundle(integerBundle);
+
+ assertEquals(testInt, result);
+ }
+}