diff options
Diffstat (limited to 'tests')
43 files changed, 1027 insertions, 427 deletions
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/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp index a23ac38785f6..125deb521ddc 100644 --- a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp +++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp @@ -33,5 +33,6 @@ cc_test_library { "-Werror", "-Wno-unused-parameter", ], + header_libs: ["jni_headers"], stl: "c++_static", } diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.mk b/tests/DynamicCodeLoggerIntegrationTests/Android.mk index 62c1ba89653c..2d58ce8baddc 100644 --- a/tests/DynamicCodeLoggerIntegrationTests/Android.mk +++ b/tests/DynamicCodeLoggerIntegrationTests/Android.mk @@ -36,8 +36,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_MODULE := DynamicCodeLoggerNativeTestLibrary 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 diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml index d1da47f0f9d8..a331ec5b52bd 100644 --- a/tests/FlickerTests/AndroidTest.xml +++ b/tests/FlickerTests/AndroidTest.xml @@ -9,6 +9,14 @@ <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="adb shell cmd window tracing level all" /> + <!-- inform WM to log all transactions --> + <option name="run-command" value="adb shell cmd window tracing transaction" /> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.DeviceCleaner"> + <!-- keeps the screen on during tests --> + <option name="cleanup-action" value="REBOOT" /> </target_preparer> <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true"/> diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java index 5a66e805c575..ad64840aaee2 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java @@ -144,6 +144,19 @@ public class ChangeAppRotationTest extends FlickerTestBase { ); } + @Test + public void checkVisibility_screenshotLayerBecomesInvisible() { + checkResults(result -> LayersTraceSubject.assertThat(result) + .showsLayer(mTestApp.getPackage()) + .then() + .replaceVisibleLayer(mTestApp.getPackage(), "Screenshot") + .then() + .showsLayer(mTestApp.getPackage()).and().showsLayer("Screenshot") + .then() + .replaceVisibleLayer("Screenshot", mTestApp.getPackage()) + .forAllEntries()); + } + @FlakyTest(bugId = 140855415) @Ignore("Waiting bug feedback") @Test diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java index e033d0ab9578..0201a95b18bb 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java @@ -20,7 +20,6 @@ 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; @@ -176,11 +175,15 @@ class CommonTransitions { .repeat(ITERATIONS); } - static TransitionBuilder appToSplitScreen(IAppHelper testApp, UiDevice device) { + static TransitionBuilder appToSplitScreen(IAppHelper testApp, UiDevice device, + int beginRotation) { + final String testTag = "appToSplitScreen_" + testApp.getLauncherName() + "_" + + rotationToString(beginRotation); return TransitionRunner.newBuilder() - .withTag("appToSplitScreen_" + testApp.getLauncherName()) + .withTag(testTag) .recordAllRuns() .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) + .runBeforeAll(() -> setRotation(device, beginRotation)) .runBefore(testApp::open) .runBefore(device::waitForIdle) .runBefore(() -> sleep(500)) @@ -285,41 +288,52 @@ class CommonTransitions { .repeat(ITERATIONS); } - static TransitionBuilder enterPipMode(PipAppHelper testApp, UiDevice device) { + static TransitionBuilder enterPipMode(PipAppHelper testApp, UiDevice device, + int beginRotation) { return TransitionRunner.newBuilder() - .withTag("enterPipMode_" + testApp.getLauncherName()) + .withTag("enterPipMode_" + testApp.getLauncherName() + + rotationToString(beginRotation)) .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) .runBefore(device::pressHome) + .runBefore(() -> setRotation(device, beginRotation)) .runBefore(testApp::open) .run(() -> testApp.clickEnterPipButton(device)) - .runAfter(() -> closePipWindow(device)) + .runAfter(() -> testApp.closePipWindow(device)) .runAfterAll(testApp::exit) .repeat(ITERATIONS); } - static TransitionBuilder exitPipModeToHome(PipAppHelper testApp, UiDevice device) { + static TransitionBuilder exitPipModeToHome(PipAppHelper testApp, UiDevice device, + int beginRotation) { return TransitionRunner.newBuilder() - .withTag("exitPipModeToHome_" + testApp.getLauncherName()) + .withTag("exitPipModeToHome_" + testApp.getLauncherName() + + rotationToString(beginRotation)) + .recordAllRuns() .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) .runBefore(device::pressHome) + .runBefore(() -> setRotation(device, beginRotation)) .runBefore(testApp::open) - .runBefore(() -> testApp.clickEnterPipButton(device)) - .run(() -> closePipWindow(device)) + .run(() -> testApp.clickEnterPipButton(device)) + .run(() -> testApp.closePipWindow(device)) .run(device::waitForIdle) - .runAfterAll(testApp::exit) + .run(testApp::exit) .repeat(ITERATIONS); } - static TransitionBuilder exitPipModeToApp(PipAppHelper testApp, UiDevice device) { + static TransitionBuilder exitPipModeToApp(PipAppHelper testApp, UiDevice device, + int beginRotation) { return TransitionRunner.newBuilder() - .withTag("exitPipModeToApp_" + testApp.getLauncherName()) + .withTag("exitPipModeToApp_" + testApp.getLauncherName() + + rotationToString(beginRotation)) + .recordAllRuns() .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) - .runBefore(device::pressHome) - .runBefore(testApp::open) - .runBefore(() -> testApp.clickEnterPipButton(device)) + .run(device::pressHome) + .run(() -> setRotation(device, beginRotation)) + .run(testApp::open) + .run(() -> testApp.clickEnterPipButton(device)) .run(() -> expandPipWindow(device)) .run(device::waitForIdle) - .runAfterAll(testApp::exit) + .run(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 index 8f0177c7afc5..666a0b9be779 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java @@ -94,7 +94,8 @@ public class DebugTest { */ @Test public void openAppToSplitScreen() { - CommonTransitions.appToSplitScreen(testApp, uiDevice).includeJankyRuns().recordAllRuns() + CommonTransitions.appToSplitScreen(testApp, uiDevice, + Surface.ROTATION_0).includeJankyRuns().recordAllRuns() .build().run(); } @@ -116,7 +117,7 @@ public class DebugTest { 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(); + .includeJankyRuns().build().run(); } // IME tests @@ -128,7 +129,7 @@ public class DebugTest { public void editTextSetFocus() { ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation()); CommonTransitions.editTextSetFocus(testApp, uiDevice, Surface.ROTATION_0) - .includeJankyRuns().recordEachRun() + .includeJankyRuns() .build().run(); } @@ -139,7 +140,7 @@ public class DebugTest { public void editTextLoseFocusToHome() { ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation()); CommonTransitions.editTextLoseFocusToHome(testApp, uiDevice, Surface.ROTATION_0) - .includeJankyRuns().recordEachRun() + .includeJankyRuns() .build().run(); } @@ -150,7 +151,7 @@ public class DebugTest { public void editTextLoseFocusToApp() { ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation()); CommonTransitions.editTextLoseFocusToHome(testApp, uiDevice, Surface.ROTATION_0) - .includeJankyRuns().recordEachRun() + .includeJankyRuns() .build().run(); } @@ -162,7 +163,7 @@ public class DebugTest { @Test public void enterPipMode() { PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation()); - CommonTransitions.enterPipMode(testApp, uiDevice).includeJankyRuns().recordEachRun() + CommonTransitions.enterPipMode(testApp, uiDevice, Surface.ROTATION_0).includeJankyRuns() .build().run(); } @@ -172,7 +173,8 @@ public class DebugTest { @Test public void exitPipModeToHome() { PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation()); - CommonTransitions.exitPipModeToHome(testApp, uiDevice).includeJankyRuns().recordEachRun() + CommonTransitions.exitPipModeToHome(testApp, uiDevice, Surface.ROTATION_0) + .includeJankyRuns() .build().run(); } @@ -182,7 +184,7 @@ public class DebugTest { @Test public void exitPipModeToApp() { PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation()); - CommonTransitions.exitPipModeToApp(testApp, uiDevice).includeJankyRuns().recordEachRun() + CommonTransitions.exitPipModeToApp(testApp, uiDevice, Surface.ROTATION_0).includeJankyRuns() .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 index 883d59ea8a92..4578fa3f0b9a 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java @@ -89,7 +89,7 @@ public class FlickerTestBase { } if (result.screenCaptureVideoExists()) { Log.e(TAG, "Screen capture video saved to " + result - .screenCaptureVideo.toString()); + .screenCaptureVideoPath().toString()); } } }); diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java index efdfaee60e64..2981ff9aefe6 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java @@ -19,6 +19,8 @@ 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 android.view.Surface; + import androidx.test.InstrumentationRegistry; import androidx.test.filters.FlakyTest; import androidx.test.filters.LargeTest; @@ -76,10 +78,20 @@ public class OpenAppColdTest extends NonRotationTestBase { @Test public void checkVisibility_wallpaperLayerBecomesInvisible() { - checkResults(result -> LayersTraceSubject.assertThat(result) - .showsLayer("Wallpaper") - .then() - .hidesLayer("Wallpaper") - .forAllEntries()); + if (mBeginRotation == Surface.ROTATION_0) { + checkResults(result -> LayersTraceSubject.assertThat(result) + .showsLayer("Wallpaper") + .then() + .replaceVisibleLayer("Wallpaper", mTestApp.getPackage()) + .forAllEntries()); + } else { + checkResults(result -> LayersTraceSubject.assertThat(result) + .showsLayer("Wallpaper") + .then() + .replaceVisibleLayer("Wallpaper", "Screenshot") + .then() + .showsLayer(mTestApp.getPackage()) + .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 index f8b7938901a8..ddead6d321a0 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java @@ -17,35 +17,38 @@ 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; +import org.junit.runners.Parameterized; /** * Test open app to split screen. * To run this test: {@code atest FlickerTests:OpenAppToSplitScreenTest} */ @LargeTest -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class OpenAppToSplitScreenTest extends FlickerTestBase { +public class OpenAppToSplitScreenTest extends NonRotationTestBase { + + public OpenAppToSplitScreenTest(String beginRotationName, int beginRotation) { + super(beginRotationName, beginRotation); - 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()); + super.runTransition(appToSplitScreen(mTestApp, mUiDevice, mBeginRotation) + .includeJankyRuns() + .build()); } @Test @@ -70,25 +73,6 @@ public class OpenAppToSplitScreenTest extends FlickerTestBase { } @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) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java index 7ce6315f529a..bb684d19d645 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java @@ -19,6 +19,8 @@ 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 android.view.Surface; + import androidx.test.InstrumentationRegistry; import androidx.test.filters.FlakyTest; import androidx.test.filters.LargeTest; @@ -76,10 +78,20 @@ public class OpenAppWarmTest extends NonRotationTestBase { @Test public void checkVisibility_wallpaperLayerBecomesInvisible() { - checkResults(result -> LayersTraceSubject.assertThat(result) - .showsLayer("Wallpaper") - .then() - .hidesLayer("Wallpaper") - .forAllEntries()); + if (mBeginRotation == Surface.ROTATION_0) { + checkResults(result -> LayersTraceSubject.assertThat(result) + .showsLayer("Wallpaper") + .then() + .replaceVisibleLayer("Wallpaper", mTestApp.getPackage()) + .forAllEntries()); + } else { + checkResults(result -> LayersTraceSubject.assertThat(result) + .showsLayer("Wallpaper") + .then() + .replaceVisibleLayer("Wallpaper", "Screenshot") + .then() + .showsLayer(mTestApp.getPackage()) + .forAllEntries()); + } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/PipToAppTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/PipToAppTest.java new file mode 100644 index 000000000000..85706bd14c5e --- /dev/null +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/PipToAppTest.java @@ -0,0 +1,89 @@ +/* + * 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.exitPipModeToApp; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; + +import com.android.server.wm.flicker.helpers.PipAppHelper; + +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 Pip launch. + * To run this test: {@code atest FlickerTests:PipToAppTest} + */ +@LargeTest +@RunWith(Parameterized.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class PipToAppTest extends NonRotationTestBase { + + static final String sPipWindowTitle = "PipMenuActivity"; + + public PipToAppTest(String beginRotationName, int beginRotation) { + super(beginRotationName, beginRotation); + + this.mTestApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation()); + } + + @Before + public void runTransition() { + run(exitPipModeToApp((PipAppHelper) mTestApp, mUiDevice, mBeginRotation) + .includeJankyRuns().build()); + } + + @Test + public void checkVisibility_pipWindowBecomesVisible() { + checkResults(result -> WmTraceSubject.assertThat(result) + .skipUntilFirstAssertion() + .showsAppWindowOnTop(sPipWindowTitle) + .then() + .hidesAppWindow(sPipWindowTitle) + .forAllEntries()); + } + + @Test + public void checkVisibility_pipLayerBecomesVisible() { + checkResults(result -> LayersTraceSubject.assertThat(result) + .skipUntilFirstAssertion() + .showsLayer(sPipWindowTitle) + .then() + .hidesLayer(sPipWindowTitle) + .forAllEntries()); + } + + @Test + public void checkVisibility_backgroundWindowVisibleBehindPipLayer() { + checkResults(result -> WmTraceSubject.assertThat(result) + .skipUntilFirstAssertion() + .showsAppWindowOnTop(sPipWindowTitle) + .then() + .showsBelowAppWindow("Wallpaper") + .then() + .showsAppWindowOnTop(mTestApp.getPackage()) + .then() + .hidesAppWindowOnTop(mTestApp.getPackage()) + .forAllEntries()); + } +} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/PipToHomeTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/PipToHomeTest.java new file mode 100644 index 000000000000..ef856dc52167 --- /dev/null +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/PipToHomeTest.java @@ -0,0 +1,93 @@ +/* + * 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.exitPipModeToHome; + +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.PipAppHelper; + +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 Pip launch. + * To run this test: {@code atest FlickerTests:PipToHomeTest} + */ +@LargeTest +@RunWith(AndroidJUnit4.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class PipToHomeTest extends FlickerTestBase { + + static final String sPipWindowTitle = "PipActivity"; + + // public PipToHomeTest(String beginRotationName, int beginRotation) { + public PipToHomeTest() { + // super(beginRotationName, beginRotation); + + this.mTestApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation()); + } + + @Before + public void runTransition() { + // run(exitPipModeToHome((PipAppHelper) mTestApp, mUiDevice, mBeginRotation) + run(exitPipModeToHome((PipAppHelper) mTestApp, mUiDevice, Surface.ROTATION_0) + .includeJankyRuns().build()); + } + + @Ignore + @Test + public void checkVisibility_pipWindowBecomesVisible() { + checkResults(result -> WmTraceSubject.assertThat(result) + .skipUntilFirstAssertion() + .showsAppWindowOnTop(sPipWindowTitle) + .then() + .hidesAppWindow(sPipWindowTitle) + .forAllEntries()); + } + + @Test + public void checkVisibility_pipLayerBecomesVisible() { + checkResults(result -> LayersTraceSubject.assertThat(result) + .skipUntilFirstAssertion() + .showsLayer(sPipWindowTitle) + .then() + .hidesLayer(sPipWindowTitle) + .forAllEntries()); + } + + @Ignore + @Test + public void checkVisibility_backgroundWindowVisibleBehindPipLayer() { + checkResults(result -> WmTraceSubject.assertThat(result) + .showsAppWindowOnTop(sPipWindowTitle) + .then() + .showsBelowAppWindow("Wallpaper") + .then() + .showsAppWindowOnTop("Wallpaper") + .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 index 29b624005495..e36701be0cad 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java @@ -95,7 +95,7 @@ public class ResizeSplitScreenTest extends NonRotationTestBase { Rect displayBounds = getDisplayBounds(); checkResults(result -> { LayersTrace entries = LayersTrace.parseFrom(result.getLayersTrace(), - result.getLayersTracePath()); + result.getLayersTracePath(), result.getLayersTraceChecksum()); assertThat(entries.getEntries()).isNotEmpty(); Rect startingDividerBounds = entries.getEntries().get(0).getVisibleBounds @@ -124,7 +124,7 @@ public class ResizeSplitScreenTest extends NonRotationTestBase { Rect displayBounds = getDisplayBounds(); checkResults(result -> { LayersTrace entries = LayersTrace.parseFrom(result.getLayersTrace(), - result.getLayersTracePath()); + result.getLayersTracePath(), result.getLayersTraceChecksum()); assertThat(entries.getEntries()).isNotEmpty(); Rect endingDividerBounds = entries.getEntries().get( 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 index d00e11b2994d..d5f9a2062a17 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java @@ -40,4 +40,8 @@ public class PipAppHelper extends FlickerAppHelper { } } + public void closePipWindow(UiDevice device) { + AutomationUtils.closePipWindow(device); + } + } diff --git a/tests/GamePerformance/Android.bp b/tests/GamePerformance/Android.bp new file mode 100644 index 000000000000..648fd8151b4e --- /dev/null +++ b/tests/GamePerformance/Android.bp @@ -0,0 +1,32 @@ +// 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. + +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: ["android-support-test"], + 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/LocalizationTest/Android.bp b/tests/LocalizationTest/Android.bp new file mode 100644 index 000000000000..c4bfcb1d2261 --- /dev/null +++ b/tests/LocalizationTest/Android.bp @@ -0,0 +1,41 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the 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/ProtoInputStreamTests/Android.bp b/tests/ProtoInputStreamTests/Android.bp new file mode 100644 index 000000000000..ecc405664128 --- /dev/null +++ b/tests/ProtoInputStreamTests/Android.bp @@ -0,0 +1,33 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +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.test.rules", + "frameworks-base-testutils", + "mockito-target-minus-junit4", + ], +} 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/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt index ef15b668e24c..a50f0461fae6 100644 --- a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt +++ b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt @@ -39,12 +39,12 @@ class MatchAllNetworkSpecifierTest { } @Test(expected = IllegalStateException::class) - fun testSatisfiedBy() { + fun testCanBeSatisfiedBy() { 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) + specifier.canBeSatisfiedBy(wifiAwareNetworkSpecifier) } } diff --git a/tests/net/common/java/android/net/NetworkProviderTest.kt b/tests/net/common/java/android/net/NetworkProviderTest.kt index b7c47c2bc223..dd3f5bebdb8e 100644 --- a/tests/net/common/java/android/net/NetworkProviderTest.kt +++ b/tests/net/common/java/android/net/NetworkProviderTest.kt @@ -19,23 +19,23 @@ package android.net import android.app.Instrumentation import android.content.Context import android.net.NetworkCapabilities.TRANSPORT_TEST +import android.net.NetworkProviderTest.TestNetworkCallback.CallbackEntry.OnUnavailable +import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequestWithdrawn +import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequested 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.net.module.util.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 +import java.util.UUID +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals private const val DEFAULT_TIMEOUT_MS = 5000L private val instrumentation: Instrumentation diff --git a/tests/net/integration/AndroidManifest.xml b/tests/net/integration/AndroidManifest.xml index 09c0e4826075..f5a4234ede9e 100644 --- a/tests/net/integration/AndroidManifest.xml +++ b/tests/net/integration/AndroidManifest.xml @@ -16,50 +16,55 @@ * limitations under the License. */ --> + <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.server.net.integrationtests"> + package="com.android.server.net.integrationtests"> <!-- For ConnectivityService registerReceiverAsUser (receiving broadcasts) --> - <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> + <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" /> + <uses-permission android:name="android.permission.MANAGE_USERS"/> <!-- ConnectivityService sends notifications to BatteryStats --> - <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" /> + <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" /> + <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"/> + <!-- Obtain LinkProperties callbacks with sensitive fields --> + <uses-permission android:name="android.permission.NETWORK_SETTINGS" /> + <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" /> + <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/> <application android:debuggable="true"> - <uses-library android:name="android.test.runner" /> + <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 --> + 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"> + android:process="com.android.server.net.integrationtests.testnetworkstack" + android:exported="true"> <intent-filter> <action android:name="android.net.INetworkStackConnector.Test"/> </intent-filter> </service> <service android:name=".NetworkStackInstrumentationService" - android:process="com.android.server.net.integrationtests.testnetworkstack"> + android:process="com.android.server.net.integrationtests.testnetworkstack" + android:exported="true"> <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"/> + 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" /> + android:targetPackage="com.android.server.net.integrationtests" + android:label="Frameworks Net Integration Tests"/> </manifest> diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt index c4801aab5c32..bc069e148b99 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt @@ -28,10 +28,13 @@ import android.net.INetd import android.net.INetworkPolicyManager import android.net.INetworkStatsService import android.net.LinkProperties +import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET +import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED import android.net.NetworkCapabilities.TRANSPORT_CELLULAR import android.net.NetworkRequest import android.net.TestNetworkStackClient +import android.net.Uri import android.net.metrics.IpConnectivityLog import android.os.ConditionVariable import android.os.IBinder @@ -64,6 +67,8 @@ import org.mockito.Mockito.spy import org.mockito.MockitoAnnotations import org.mockito.Spy import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotNull import kotlin.test.assertTrue import kotlin.test.fail @@ -110,6 +115,10 @@ class ConnectivityServiceIntegrationTest { private val bindingCondition = ConditionVariable(false) private val realContext get() = InstrumentationRegistry.getInstrumentation().context + private val httpProbeUrl get() = + realContext.getResources().getString(R.string.config_captive_portal_http_url) + private val httpsProbeUrl get() = + realContext.getResources().getString(R.string.config_captive_portal_https_url) private class InstrumentationServiceConnection : ServiceConnection { override fun onServiceConnected(name: ComponentName?, service: IBinder?) { @@ -188,12 +197,8 @@ class ConnectivityServiceIntegrationTest { 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)) + nsInstrumentation.addHttpResponse(HttpResponse(httpProbeUrl, responseCode = 204)) + nsInstrumentation.addHttpResponse(HttpResponse(httpsProbeUrl, responseCode = 204)) val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, LinkProperties(), context) networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS) @@ -204,4 +209,52 @@ class ConnectivityServiceIntegrationTest { testCallback.expectAvailableThenValidatedCallbacks(na.network, TEST_TIMEOUT_MS) assertEquals(2, nsInstrumentation.getRequestUrls().size) } + + @Test + fun testCapportApi() { + val request = NetworkRequest.Builder() + .clearCapabilities() + .addCapability(NET_CAPABILITY_INTERNET) + .build() + val testCb = TestableNetworkCallback() + val apiUrl = "https://capport.android.com" + + cm.registerNetworkCallback(request, testCb) + nsInstrumentation.addHttpResponse(HttpResponse( + apiUrl, + """ + |{ + | "captive": true, + | "user-portal-url": "https://login.capport.android.com", + | "venue-info-url": "https://venueinfo.capport.android.com" + |} + """.trimMargin())) + + // Tests will fail if a non-mocked query is received: mock the HTTPS probe, but not the + // HTTP probe as it should not be sent. + // Even if the HTTPS probe succeeds, a portal should be detected as the API takes precedence + // in that case. + nsInstrumentation.addHttpResponse(HttpResponse(httpsProbeUrl, responseCode = 204)) + + val lp = LinkProperties() + lp.captivePortalApiUrl = Uri.parse(apiUrl) + val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, lp, context) + networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS) + + na.addCapability(NET_CAPABILITY_INTERNET) + na.connect() + + testCb.expectAvailableCallbacks(na.network, validated = false, tmt = TEST_TIMEOUT_MS) + + val capportData = testCb.expectLinkPropertiesThat(na, TEST_TIMEOUT_MS) { + it.captivePortalData != null + }.lp.captivePortalData + assertNotNull(capportData) + assertTrue(capportData.isCaptive) + assertEquals(Uri.parse("https://login.capport.android.com"), capportData.userPortalUrl) + assertEquals(Uri.parse("https://venueinfo.capport.android.com"), capportData.venueInfoUrl) + + val nc = testCb.expectCapabilitiesWith(NET_CAPABILITY_CAPTIVE_PORTAL, na, TEST_TIMEOUT_MS) + assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED)) + } }
\ 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 index 45073d8df3f7..e2063138fef1 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt @@ -22,16 +22,21 @@ import android.os.Parcelable data class HttpResponse( val requestUrl: String, val responseCode: Int, - val contentLength: Long, - val redirectUrl: String? + val content: String = "", + val redirectUrl: String? = null ) : Parcelable { - constructor(p: Parcel): this(p.readString(), p.readInt(), p.readLong(), p.readString()) + constructor(p: Parcel): this(p.readString(), p.readInt(), p.readString(), p.readString()) + constructor(requestUrl: String, contentBody: String): this( + requestUrl, + responseCode = 200, + content = contentBody, + redirectUrl = null) override fun writeToParcel(dest: Parcel, flags: Int) { with(dest) { writeString(requestUrl) writeInt(responseCode) - writeLong(contentLength) + writeString(content) writeString(redirectUrl) } } 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 index 4827d2997d93..e807952cec11 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt @@ -65,6 +65,9 @@ class NetworkStackInstrumentationService : Service() { * * <p>For any subsequent HTTP/HTTPS query, the first response with a matching URL will be * used to mock the query response. + * + * <p>All requests that are expected to be sent must have a mock response: if an unexpected + * request is seen, the test will fail. */ override fun addHttpResponse(response: HttpResponse) { httpResponses.getValue(response.requestUrl).add(response) 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 index 8c2de4035d0b..a44ad1e05259 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt @@ -33,9 +33,11 @@ import com.android.server.net.integrationtests.NetworkStackInstrumentationServic import org.mockito.Mockito.doReturn import org.mockito.Mockito.mock import org.mockito.Mockito.spy +import java.io.ByteArrayInputStream import java.net.HttpURLConnection import java.net.URL import java.net.URLConnection +import java.nio.charset.StandardCharsets private const val TEST_NETID = 42 @@ -71,11 +73,13 @@ class TestNetworkStackService : Service() { private inner class TestNetwork(netId: Int) : Network(netId) { override fun openConnection(url: URL): URLConnection { val response = InstrumentationConnector.processRequest(url) + val responseBytes = response.content.toByteArray(StandardCharsets.UTF_8) val connection = mock(HttpURLConnection::class.java) doReturn(response.responseCode).`when`(connection).responseCode - doReturn(response.contentLength).`when`(connection).contentLengthLong + doReturn(responseBytes.size.toLong()).`when`(connection).contentLengthLong doReturn(response.redirectUrl).`when`(connection).getHeaderField("location") + doReturn(ByteArrayInputStream(responseBytes)).`when`(connection).inputStream return connection } } diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java index d6bf334ee56a..d74a621842f9 100644 --- a/tests/net/java/android/net/ConnectivityManagerTest.java +++ b/tests/net/java/android/net/ConnectivityManagerTest.java @@ -36,6 +36,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; @@ -213,7 +214,7 @@ public class ConnectivityManagerTest { // register callback when(mService.requestNetwork( - any(), captor.capture(), anyInt(), any(), anyInt(), any())) + any(), captor.capture(), anyInt(), any(), anyInt(), any(), nullable(String.class))) .thenReturn(request); manager.requestNetwork(request, callback, handler); @@ -242,7 +243,7 @@ public class ConnectivityManagerTest { // register callback when(mService.requestNetwork( - any(), captor.capture(), anyInt(), any(), anyInt(), any())) + any(), captor.capture(), anyInt(), any(), anyInt(), any(), nullable(String.class))) .thenReturn(req1); manager.requestNetwork(req1, callback, handler); @@ -261,7 +262,7 @@ public class ConnectivityManagerTest { // callback can be registered again when(mService.requestNetwork( - any(), captor.capture(), anyInt(), any(), anyInt(), any())) + any(), captor.capture(), anyInt(), any(), anyInt(), any(), nullable(String.class))) .thenReturn(req2); manager.requestNetwork(req2, callback, handler); @@ -285,8 +286,8 @@ public class ConnectivityManagerTest { info.targetSdkVersion = VERSION_CODES.N_MR1 + 1; when(mCtx.getApplicationInfo()).thenReturn(info); - when(mService.requestNetwork(any(), any(), anyInt(), any(), anyInt(), any())) - .thenReturn(request); + when(mService.requestNetwork(any(), any(), anyInt(), any(), anyInt(), any(), + nullable(String.class))).thenReturn(request); Handler handler = new Handler(Looper.getMainLooper()); manager.requestNetwork(request, callback, handler); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 385005f90c3b..e6346ea52548 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -3054,6 +3054,13 @@ public class ConnectivityServiceTest { assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar); } + /** + * @return the context's attribution tag + */ + private String getAttributionTag() { + return null; + } + @Test public void testInvalidNetworkSpecifier() { assertThrows(IllegalArgumentException.class, () -> { @@ -3066,7 +3073,8 @@ public class ConnectivityServiceTest { networkCapabilities.addTransportType(TRANSPORT_WIFI) .setNetworkSpecifier(new MatchAllNetworkSpecifier()); mService.requestNetwork(networkCapabilities, null, 0, null, - ConnectivityManager.TYPE_WIFI, mContext.getPackageName()); + ConnectivityManager.TYPE_WIFI, mContext.getPackageName(), + getAttributionTag()); }); class NonParcelableSpecifier extends NetworkSpecifier { @@ -4218,7 +4226,7 @@ public class ConnectivityServiceTest { callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS); } - // Sanity check before testing started keepalive. + // Basic check before testing started keepalive. try (SocketKeepalive ka = mCm.createSocketKeepalive( myNet, testSocket, myIPv4, dstIPv4, executor, callback)) { ka.start(validKaInterval); diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt index 42d4cf3c382b..a10a3c81bc86 100644 --- a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt +++ b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt @@ -14,6 +14,11 @@ * limitations under the License. */ +// Don't warn about deprecated types anywhere in this test, because LegacyTypeTracker's very reason +// for existence is to power deprecated APIs. The annotation has to apply to the whole file because +// otherwise warnings will be generated by the imports of deprecated constants like TYPE_xxx. +@file:Suppress("DEPRECATION") + package com.android.server import android.net.ConnectivityManager.TYPE_ETHERNET diff --git a/tests/net/java/com/android/server/NetIdManagerTest.kt b/tests/net/java/com/android/server/NetIdManagerTest.kt index 045f89f85e3b..6f5e740d344c 100644 --- a/tests/net/java/com/android/server/NetIdManagerTest.kt +++ b/tests/net/java/com/android/server/NetIdManagerTest.kt @@ -19,8 +19,8 @@ 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 com.android.testutils.ExceptionUtils.ThrowingRunnable import org.junit.Test import org.junit.runner.RunWith import kotlin.test.assertEquals diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java index 39f849c340f7..a384687e06f6 100644 --- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -26,10 +26,9 @@ 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.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.os.Process.SYSTEM_UID; import static com.android.server.connectivity.PermissionMonitor.NETWORK; @@ -76,7 +75,6 @@ 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; @@ -88,7 +86,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Set; - @RunWith(AndroidJUnit4.class) @SmallTest public class PermissionMonitorTest { @@ -99,7 +96,6 @@ public class PermissionMonitorTest { 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"; @@ -116,8 +112,8 @@ public class PermissionMonitorTest { @Mock private INetd mNetdService; @Mock private PackageManagerInternal mMockPmi; @Mock private UserManager mUserManager; + @Mock private PermissionMonitor.Dependencies mDeps; - private PackageManagerInternal.PackageListObserver mObserver; private PermissionMonitor mPermissionMonitor; @Before @@ -130,8 +126,9 @@ public class PermissionMonitorTest { new UserInfo(MOCK_USER1, "", 0), new UserInfo(MOCK_USER2, "", 0), })); + doReturn(PackageManager.PERMISSION_DENIED).when(mDeps).uidPermission(anyString(), anyInt()); - mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService)); + mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps)); LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.addService(PackageManagerInternal.class, mMockPmi); @@ -139,42 +136,18 @@ public class PermissionMonitorTest { /* 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(); + verify(mMockPmi).getPackageList(mPermissionMonitor); } - private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid, - String... permissions) { - final PackageInfo packageInfo = - packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, permissions, partition); + private boolean wouldBeCarryoverPackage(String partition, int targetSdkVersion, int uid) { + final PackageInfo packageInfo = buildPackageInfo(partition, uid, MOCK_USER1); 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); + return mPermissionMonitor.isCarryoverPackage(packageInfo.applicationInfo); } - 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; - } + private static PackageInfo packageInfoWithPartition(String partition) { final PackageInfo packageInfo = new PackageInfo(); - packageInfo.requestedPermissions = permissions; packageInfo.applicationInfo = new ApplicationInfo(); - packageInfo.requestedPermissionsFlags = requestedPermissionsFlags; int privateFlags = 0; switch (partition) { case PARTITION_OEM: @@ -191,168 +164,145 @@ public class PermissionMonitorTest { 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[] {}, ""); - } + private static PackageInfo buildPackageInfo(String partition, int uid, int userId) { + final PackageInfo pkgInfo = packageInfoWithPartition(partition); pkgInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(uid)); return pkgInfo; } + /** This will REMOVE all previously set permissions from given uid. */ + private void removeAllPermissions(int uid) { + doReturn(PackageManager.PERMISSION_DENIED).when(mDeps).uidPermission(anyString(), eq(uid)); + } + + /** Set up mocks so that given UID has the requested permissions. */ + private void addPermissions(int uid, String... permissions) { + for (String permission : permissions) { + doReturn(PackageManager.PERMISSION_GRANTED) + .when(mDeps).uidPermission(eq(permission), eq(uid)); + } + } + @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)); + addPermissions(MOCK_UID1); + assertFalse(mPermissionMonitor.hasPermission(CHANGE_NETWORK_STATE, MOCK_UID1)); + assertFalse(mPermissionMonitor.hasPermission(NETWORK_STACK, MOCK_UID1)); + assertFalse(mPermissionMonitor.hasPermission( + CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID1)); + assertFalse(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID1)); + + addPermissions(MOCK_UID1, CHANGE_NETWORK_STATE, NETWORK_STACK); + assertTrue(mPermissionMonitor.hasPermission(CHANGE_NETWORK_STATE, MOCK_UID1)); + assertTrue(mPermissionMonitor.hasPermission(NETWORK_STACK, MOCK_UID1)); + assertFalse(mPermissionMonitor.hasPermission( + CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID1)); + assertFalse(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID1)); + assertFalse(mPermissionMonitor.hasPermission(CHANGE_NETWORK_STATE, MOCK_UID2)); + assertFalse(mPermissionMonitor.hasPermission(NETWORK_STACK, MOCK_UID2)); + + addPermissions(MOCK_UID2, CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL); + assertFalse(mPermissionMonitor.hasPermission( + CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID1)); + assertFalse(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID1)); + assertTrue(mPermissionMonitor.hasPermission( + CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID2)); + assertTrue(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID2)); } @Test public void testIsVendorApp() { - PackageInfo app = systemPackageInfoWithPermissions(); + PackageInfo app = packageInfoWithPartition(PARTITION_SYSTEM); assertFalse(mPermissionMonitor.isVendorApp(app.applicationInfo)); - app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, - new String[] {}, PARTITION_OEM); + app = packageInfoWithPartition(PARTITION_OEM); assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo)); - app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, - new String[] {}, PARTITION_PRODUCT); + app = packageInfoWithPartition(PARTITION_PRODUCT); assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo)); - app = vendorPackageInfoWithPermissions(); + app = packageInfoWithPartition(PARTITION_VENDOR); 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)); + /** + * Remove all permissions from the uid then setup permissions to uid for checking restricted + * network permission. + */ + private void assertRestrictedNetworkPermission(boolean hasPermission, int uid, + String... permissions) { + removeAllPermissions(uid); + addPermissions(uid, permissions); + assertEquals(hasPermission, mPermissionMonitor.hasRestrictedNetworkPermission(uid)); } @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)); + assertRestrictedNetworkPermission(false, MOCK_UID1); + assertRestrictedNetworkPermission(false, MOCK_UID1, CHANGE_NETWORK_STATE); + assertRestrictedNetworkPermission(true, MOCK_UID1, NETWORK_STACK); + assertRestrictedNetworkPermission(false, MOCK_UID1, CONNECTIVITY_INTERNAL); + assertRestrictedNetworkPermission(true, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS); + assertRestrictedNetworkPermission(false, MOCK_UID1, CHANGE_WIFI_STATE); + assertRestrictedNetworkPermission(true, MOCK_UID1, PERMISSION_MAINLINE_NETWORK_STACK); + + assertFalse(mPermissionMonitor.hasRestrictedNetworkPermission(MOCK_UID2)); + assertFalse(mPermissionMonitor.hasRestrictedNetworkPermission(SYSTEM_UID)); } @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)); + public void testIsCarryoverPackage() { + doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt(); + assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID)); + assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID)); + assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1)); + assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1)); + assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID)); + assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID)); + assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1)); + assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1)); + + doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt(); + assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID)); + assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID)); + assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1)); + assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1)); + assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID)); + assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID)); + assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1)); + assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1)); + + assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, SYSTEM_UID)); + assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, SYSTEM_UID)); + assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, MOCK_UID1)); + assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, MOCK_UID1)); } 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)); + .thenReturn(buildPackageInfo(PARTITION_SYSTEM, uid, MOCK_USER1)); + addPermissions(uid, permissions); 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); + assertBackgroundPermission(false, "mock1", MOCK_UID1); + assertBackgroundPermission(false, "mock2", MOCK_UID1, CONNECTIVITY_INTERNAL); + assertBackgroundPermission(true, "mock3", MOCK_UID1, NETWORK_STACK); 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); + assertBackgroundPermission(false, "mock4", MOCK_UID2); + assertBackgroundPermission(true, "mock5", MOCK_UID2, + CONNECTIVITY_USE_RESTRICTED_NETWORKS); + + doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt(); + assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(SYSTEM_UID)); + assertBackgroundPermission(false, "system1", SYSTEM_UID); + assertBackgroundPermission(true, "system2", SYSTEM_UID, CHANGE_NETWORK_STATE); + doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt(); + removeAllPermissions(SYSTEM_UID); + assertBackgroundPermission(true, "system3", SYSTEM_UID); } private class NetdMonitor { @@ -422,13 +372,14 @@ public class PermissionMonitorTest { // 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(eq(SYSTEM), + anyString(), anyInt()); doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(any(), - eq(SYSTEM_PACKAGE1)); + eq(SYSTEM_PACKAGE1), anyInt()); doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(), - eq(SYSTEM_PACKAGE2)); + eq(SYSTEM_PACKAGE2), anyInt()); doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(), - eq(MOCK_PACKAGE1)); + eq(MOCK_PACKAGE1), anyInt()); // Add SYSTEM_PACKAGE2, expect only have network permission. mPermissionMonitor.onUserAdded(MOCK_USER1); @@ -450,13 +401,13 @@ public class PermissionMonitorTest { 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); + mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); + removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, 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); + removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, SYSTEM_PACKAGE1, SYSTEM_UID); mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2}, new int[]{SYSTEM_UID}); @@ -465,7 +416,7 @@ public class PermissionMonitorTest { // Remove all packages, expect no permission left. when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{}); - removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_UID); + removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_PACKAGE2, SYSTEM_UID); mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{SYSTEM_UID, MOCK_UID1}); @@ -479,13 +430,15 @@ public class PermissionMonitorTest { 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) + buildPackageInfo(PARTITION_SYSTEM, SYSTEM_UID1, MOCK_USER1), + buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1), + buildPackageInfo(PARTITION_SYSTEM, MOCK_UID2, MOCK_USER1), + buildPackageInfo(PARTITION_SYSTEM, VPN_UID, MOCK_USER1) })); when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn( - buildPackageInfo(false, MOCK_UID1, MOCK_USER1)); + buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1)); + addPermissions(SYSTEM_UID, + CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS); mPermissionMonitor.startMonitoring(); // Every app on user 0 except MOCK_UID2 are under VPN. final Set<UidRange> vpnRange1 = new HashSet<>(Arrays.asList(new UidRange[] { @@ -501,7 +454,8 @@ public class PermissionMonitorTest { reset(mNetdService); // When MOCK_UID1 package is uninstalled and reinstalled, expect Netd to be updated - mPermissionMonitor.onPackageRemoved(UserHandle.getUid(MOCK_USER1, MOCK_UID1)); + mPermissionMonitor.onPackageRemoved( + MOCK_PACKAGE1, 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"), @@ -529,11 +483,11 @@ public class PermissionMonitorTest { 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) + buildPackageInfo(PARTITION_SYSTEM, SYSTEM_UID1, MOCK_USER1), + buildPackageInfo(PARTITION_SYSTEM, VPN_UID, MOCK_USER1) })); when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn( - buildPackageInfo(false, MOCK_UID1, MOCK_USER1)); + buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1)); mPermissionMonitor.startMonitoring(); final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(MOCK_USER1)); @@ -545,7 +499,8 @@ public class PermissionMonitorTest { aryEq(new int[] {MOCK_UID1})); // Removed package should have its uid rules removed - mPermissionMonitor.onPackageRemoved(UserHandle.getUid(MOCK_USER1, MOCK_UID1)); + mPermissionMonitor.onPackageRemoved( + MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1)); verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1})); } @@ -559,9 +514,9 @@ public class PermissionMonitorTest { } } - private void removePackageForUsers(int[] users, int uid) { + private void removePackageForUsers(int[] users, String packageName, int uid) { for (final int user : users) { - mPermissionMonitor.onPackageRemoved(UserHandle.getUid(user, uid)); + mPermissionMonitor.onPackageRemoved(packageName, UserHandle.getUid(user, uid)); } } @@ -637,17 +592,17 @@ public class PermissionMonitorTest { private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions) throws Exception { - PackageInfo packageInfo = packageInfoWithPermissions( - REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM); + final PackageInfo packageInfo = buildPackageInfo(PARTITION_SYSTEM, uid, MOCK_USER1); when(mPackageManager.getPackageInfo(eq(packageName), anyInt())).thenReturn(packageInfo); when(mPackageManager.getPackagesForUid(eq(uid))).thenReturn(new String[]{packageName}); + addPermissions(uid, permissions); return packageInfo; } private PackageInfo addPackage(String packageName, int uid, String[] permissions) throws Exception { PackageInfo packageInfo = setPackagePermissions(packageName, uid, permissions); - mObserver.onPackageAdded(packageName, uid); + mPermissionMonitor.onPackageAdded(packageName, uid); return packageInfo; } @@ -667,18 +622,17 @@ public class PermissionMonitorTest { public void testPackageInstallSharedUid() throws Exception { final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); - PackageInfo packageInfo1 = addPackage(MOCK_PACKAGE1, MOCK_UID1, - new String[] {INTERNET, UPDATE_DEVICE_STATS}); + 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(); + final PackageInfo packageInfo2 = buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1); 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); + mPermissionMonitor.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1); mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); } @@ -692,7 +646,7 @@ public class PermissionMonitorTest { | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{}); - mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); + mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1}); } @@ -705,7 +659,8 @@ public class PermissionMonitorTest { | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{}); - mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); + removeAllPermissions(MOCK_UID1); + mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1}); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET}); @@ -719,10 +674,7 @@ public class PermissionMonitorTest { 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); + addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET}); mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1}); } @@ -735,12 +687,14 @@ public class PermissionMonitorTest { | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); // Mock another package with the same uid but different permissions. - PackageInfo packageInfo2 = systemPackageInfoWithPermissions(INTERNET); + final PackageInfo packageInfo2 = buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1); when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2); when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{ MOCK_PACKAGE2}); + removeAllPermissions(MOCK_UID1); + addPermissions(MOCK_UID1, INTERNET); - mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); + mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1}); } @@ -750,9 +704,6 @@ public class PermissionMonitorTest { // 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)); + assertTrue(monitor.hasPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, SYSTEM_UID)); } } diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java index 551498f2c0cc..e83d2a90bffa 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java @@ -23,11 +23,12 @@ 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.NetworkUtils.multiplySafeByRational; 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 com.android.testutils.MiscAssertsKt.assertThrows; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -505,23 +506,25 @@ public class NetworkStatsCollectionTest { } @Test - public void testMultiplySafe() { - assertEquals(25, multiplySafe(50, 1, 2)); - assertEquals(100, multiplySafe(50, 2, 1)); + public void testMultiplySafeRational() { + assertEquals(25, multiplySafeByRational(50, 1, 2)); + assertEquals(100, multiplySafeByRational(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(-10, multiplySafeByRational(30, -1, 3)); + assertEquals(0, multiplySafeByRational(30, 0, 3)); + assertEquals(10, multiplySafeByRational(30, 1, 3)); + assertEquals(20, multiplySafeByRational(30, 2, 3)); + assertEquals(30, multiplySafeByRational(30, 3, 3)); + assertEquals(40, multiplySafeByRational(30, 4, 3)); assertEquals(100_000_000_000L, - multiplySafe(300_000_000_000L, 10_000_000_000L, 30_000_000_000L)); + multiplySafeByRational(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)); + multiplySafeByRational(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)); + multiplySafeByRational(4_939_212_288L, 2_121_815_528L, 12_730_893_165L)); + + assertThrows(ArithmeticException.class, () -> multiplySafeByRational(30, 3, 0)); } /** diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index a1bb0d586916..1307a849f1eb 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -41,6 +41,7 @@ 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.NETWORK_TYPE_ALL; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateMobileWithRatType; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; @@ -62,6 +63,7 @@ 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.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -71,6 +73,7 @@ import android.app.AlarmManager; import android.app.usage.NetworkStatsManager; import android.content.Context; import android.content.Intent; +import android.database.ContentObserver; import android.net.DataUsageRequest; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsSession; @@ -94,6 +97,7 @@ import android.os.Message; import android.os.Messenger; import android.os.PowerManager; import android.os.SimpleClock; +import android.provider.Settings; import android.telephony.TelephonyManager; import androidx.test.InstrumentationRegistry; @@ -173,6 +177,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { private NetworkStatsService mService; private INetworkStatsSession mSession; private INetworkManagementEventObserver mNetworkObserver; + private ContentObserver mContentObserver; + private Handler mHandler; private final Clock mClock = new SimpleClock(ZoneOffset.UTC) { @Override @@ -212,6 +218,12 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { mService.systemReady(); // Verify that system ready fetches realtime stats verify(mStatsFactory).readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL); + // Wait for posting onChange() event to handler thread and verify that when system ready, + // start monitoring data usage per RAT type because the settings value is mock as false + // by default in expectSettings(). + waitForIdle(); + verify(mNetworkStatsSubscriptionsMonitor).start(); + reset(mNetworkStatsSubscriptionsMonitor); mSession = mService.openSession(); assertNotNull("openSession() failed", mSession); @@ -233,11 +245,19 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { @Override public NetworkStatsSubscriptionsMonitor makeSubscriptionsMonitor( - @NonNull Context context, @NonNull Executor executor, + @NonNull Context context, @NonNull Looper looper, @NonNull Executor executor, @NonNull NetworkStatsService service) { return mNetworkStatsSubscriptionsMonitor; } + + @Override + public ContentObserver makeContentObserver(Handler handler, + NetworkStatsSettings settings, NetworkStatsSubscriptionsMonitor monitor) { + mHandler = handler; + return mContentObserver = super.makeContentObserver(handler, settings, monitor); + } + }; } @@ -1191,6 +1211,99 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { provider.expectOnSetAlert(MB_IN_BYTES); } + private void setCombineSubtypeEnabled(boolean enable) { + when(mSettings.getCombineSubtypeEnabled()).thenReturn(enable); + mHandler.post(() -> mContentObserver.onChange(false, Settings.Global + .getUriFor(Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED))); + waitForIdle(); + if (enable) { + verify(mNetworkStatsSubscriptionsMonitor).stop(); + } else { + verify(mNetworkStatsSubscriptionsMonitor).start(); + } + } + + @Test + public void testDynamicWatchForNetworkRatTypeChanges() throws Exception { + // Build 3G template, type unknown template to get stats while network type is unknown + // and type all template to get the sum of all network type stats. + final NetworkTemplate template3g = + buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS); + final NetworkTemplate templateUnknown = + buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UNKNOWN); + final NetworkTemplate templateAll = + buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL); + final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)}; + + expectNetworkStatsSummary(buildEmptyStats()); + expectNetworkStatsUidDetail(buildEmptyStats()); + + // 3G network comes online. + 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(); + + // Since CombineSubtypeEnabled is false by default in unit test, the generated traffic + // will be split by RAT type. Verify 3G templates gets stats, while template with unknown + // RAT type gets nothing, and template with NETWORK_TYPE_ALL gets all stats. + assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0); + assertUidTotal(templateUnknown, UID_RED, 0L, 0L, 0L, 0L, 0); + assertUidTotal(templateAll, UID_RED, 12L, 18L, 14L, 1L, 0); + + // Stop monitoring data usage per RAT type changes NetworkStatsService records data + // to {@link TelephonyManager#NETWORK_TYPE_UNKNOWN}. + setCombineSubtypeEnabled(true); + + // Call handleOnCollapsedRatTypeChanged manually to simulate the callback fired + // when stopping monitor, this is needed by NetworkStatsService to trigger updateIfaces. + mService.handleOnCollapsedRatTypeChanged(); + HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT); + // Create some traffic. + incrementCurrentTime(MINUTE_IN_MILLIS); + // Append more traffic on existing snapshot. + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) + .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, + 12L + 4L, 18L + 4L, 14L + 3L, 1L + 1L, 0L)) + .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, + 35L, 29L, 7L, 11L, 1L))); + forcePollAndWaitForIdle(); + + // Verify 3G counters do not increase, while template with unknown RAT type gets new + // traffic and template with NETWORK_TYPE_ALL gets all stats. + assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0); + assertUidTotal(templateUnknown, UID_RED, 4L + 35L, 4L + 29L, 3L + 7L, 1L + 11L, 1); + assertUidTotal(templateAll, UID_RED, 16L + 35L, 22L + 29L, 17L + 7L, 2L + 11L, 1); + + // Start monitoring data usage per RAT type changes and NetworkStatsService records data + // by a granular subtype representative of the actual subtype + setCombineSubtypeEnabled(false); + + mService.handleOnCollapsedRatTypeChanged(); + HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT); + // Create some traffic. + incrementCurrentTime(MINUTE_IN_MILLIS); + // Append more traffic on existing snapshot. + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) + .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, + 22L, 26L, 19L, 5L, 0L)) + .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, + 35L, 29L, 7L, 11L, 1L))); + forcePollAndWaitForIdle(); + + // Verify traffic is split by RAT type, no increase on template with unknown RAT type + // and template with NETWORK_TYPE_ALL gets all stats. + assertUidTotal(template3g, UID_RED, 6L + 12L , 4L + 18L, 2L + 14L, 3L + 1L, 0); + assertUidTotal(templateUnknown, UID_RED, 4L + 35L, 4L + 29L, 3L + 7L, 1L + 11L, 1); + assertUidTotal(templateAll, UID_RED, 22L + 35L, 26L + 29L, 19L + 7L, 5L + 11L, 1); + } + private static File getBaseDir(File statsDir) { File baseDir = new File(statsDir, "netstats"); baseDir.mkdirs(); @@ -1403,6 +1516,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { private void forcePollAndWaitForIdle() { mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); + waitForIdle(); + } + + private void waitForIdle() { HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT); } diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java index c91dfecf041b..6dc4fced19a2 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java @@ -18,6 +18,7 @@ package com.android.server.net; 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.anyInt; import static org.mockito.Mockito.eq; @@ -31,7 +32,7 @@ import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.content.Context; import android.net.NetworkTemplate; -import android.os.Looper; +import android.os.test.TestLooper; import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; @@ -39,7 +40,6 @@ 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; @@ -66,20 +66,17 @@ public final class NetworkStatsSubscriptionsMonitorTest { @Mock private Context mContext; @Mock private SubscriptionManager mSubscriptionManager; @Mock private TelephonyManager mTelephonyManager; - @Mock private Delegate mDelegate; + @Mock private NetworkStatsSubscriptionsMonitor.Delegate mDelegate; private final List<Integer> mTestSubList = new ArrayList<>(); private final Executor mExecutor = Executors.newSingleThreadExecutor(); private NetworkStatsSubscriptionsMonitor mMonitor; + private TestLooper mTestLooper = new TestLooper(); @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))) @@ -87,7 +84,8 @@ public final class NetworkStatsSubscriptionsMonitorTest { when(mContext.getSystemService(eq(Context.TELEPHONY_SERVICE))) .thenReturn(mTelephonyManager); - mMonitor = new NetworkStatsSubscriptionsMonitor(mContext, mExecutor, mDelegate); + mMonitor = new NetworkStatsSubscriptionsMonitor(mContext, mTestLooper.getLooper(), + mExecutor, mDelegate); } @Test @@ -119,16 +117,18 @@ public final class NetworkStatsSubscriptionsMonitorTest { when(serviceState.getDataNetworkType()).thenReturn(type); final RatTypeListener match = CollectionUtils .find(listeners, it -> it.getSubId() == subId); - if (match != null) { - match.onServiceStateChanged(serviceState); + if (match == null) { + fail("Could not find listener with subId: " + subId); } + match.onServiceStateChanged(serviceState); } private void addTestSub(int subId, String subscriberId) { // add SubId to TestSubList. - if (!mTestSubList.contains(subId)) { - mTestSubList.add(subId); - } + if (mTestSubList.contains(subId)) fail("The subscriber list already contains this ID"); + + mTestSubList.add(subId); + final int[] subList = convertArrayListToIntArray(mTestSubList); when(mSubscriptionManager.getCompleteActiveSubscriptionIdList()).thenReturn(subList); when(mTelephonyManager.getSubscriberId(subId)).thenReturn(subscriberId); diff --git a/tests/utils/DummyIME/Android.bp b/tests/utils/StubIME/Android.bp index 4a44b3b27992..668c92c86c51 100644 --- a/tests/utils/DummyIME/Android.bp +++ b/tests/utils/StubIME/Android.bp @@ -15,7 +15,7 @@ // 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..04502d331d6a 100644 --- a/tests/utils/DummyIME/AndroidManifest.xml +++ b/tests/utils/StubIME/AndroidManifest.xml @@ -17,16 +17,16 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.testing.dummyime"> - <application android:label="Dummy IME"> - <service android:name="DummyIme" + package="com.android.testing.stubime"> + <application android:label="Stub IME"> + <service android:name="StubIme" android:permission="android.permission.BIND_INPUT_METHOD"> <intent-filter> <action android:name="android.view.InputMethod" /> </intent-filter> <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"> <intent-filter> <action android:name="android.intent.action.MAIN"/> </intent-filter> 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() { |