Merge "Verify apps cannot receive ACTION_SNOOZE_WARNING broadcast." into sc-dev

This commit is contained in:
Sudheer Shanka
2021-07-27 05:13:23 +00:00
committed by Android (Google) Code Review
11 changed files with 165 additions and 4 deletions

View File

@@ -29,5 +29,6 @@ java_test_host {
test_suites: [ test_suites: [
"cts", "cts",
"general-tests", "general-tests",
"sts"
], ],
} }

View File

@@ -26,14 +26,15 @@ android_test_helper_app {
], ],
platform_apis: true, platform_apis: true,
static_libs: [ static_libs: [
"androidx.test.rules", "CtsHostsideNetworkTestsAidl",
"androidx.test.ext.junit", "androidx.test.ext.junit",
"androidx.test.rules",
"androidx.test.uiautomator_uiautomator",
"compatibility-device-util-axt", "compatibility-device-util-axt",
"cts-net-utils", "cts-net-utils",
"ctstestrunner-axt", "ctstestrunner-axt",
"ub-uiautomator",
"CtsHostsideNetworkTestsAidl",
"modules-utils-build", "modules-utils-build",
"ub-uiautomator",
], ],
libs: [ libs: [
"android.test.runner", "android.test.runner",

View File

@@ -99,6 +99,9 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase {
"com.android.cts.net.hostside.app2.action.FINISH_ACTIVITY"; "com.android.cts.net.hostside.app2.action.FINISH_ACTIVITY";
private static final String ACTION_FINISH_JOB = private static final String ACTION_FINISH_JOB =
"com.android.cts.net.hostside.app2.action.FINISH_JOB"; "com.android.cts.net.hostside.app2.action.FINISH_JOB";
// Copied from com.android.server.net.NetworkPolicyManagerService class
private static final String ACTION_SNOOZE_WARNING =
"com.android.server.net.action.SNOOZE_WARNING";
private static final String ACTION_RECEIVER_READY = private static final String ACTION_RECEIVER_READY =
"com.android.cts.net.hostside.app2.action.RECEIVER_READY"; "com.android.cts.net.hostside.app2.action.RECEIVER_READY";
@@ -148,6 +151,8 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase {
protected static final long TEMP_POWERSAVE_WHITELIST_DURATION_MS = 5_000; // 5 sec protected static final long TEMP_POWERSAVE_WHITELIST_DURATION_MS = 5_000; // 5 sec
private static final long BROADCAST_TIMEOUT_MS = 15_000;
protected Context mContext; protected Context mContext;
protected Instrumentation mInstrumentation; protected Instrumentation mInstrumentation;
protected ConnectivityManager mCm; protected ConnectivityManager mCm;
@@ -217,6 +222,12 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase {
+ maxAttempts * SLEEP_TIME_SEC + " seconds", expectedCount, count); + maxAttempts * SLEEP_TIME_SEC + " seconds", expectedCount, count);
} }
protected void assertSnoozeWarningNotReceived() throws Exception {
// Wait for a while to take broadcast queue delays into account
SystemClock.sleep(BROADCAST_TIMEOUT_MS);
assertEquals(0, getNumberBroadcastsReceived(DYNAMIC_RECEIVER, ACTION_SNOOZE_WARNING));
}
protected String sendOrderedBroadcast(Intent intent) throws Exception { protected String sendOrderedBroadcast(Intent intent) throws Exception {
return sendOrderedBroadcast(intent, ORDERED_BROADCAST_TIMEOUT_MS); return sendOrderedBroadcast(intent, ORDERED_BROADCAST_TIMEOUT_MS);
} }

View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.cts.net.hostside;
import static com.android.cts.net.hostside.NetworkPolicyTestUtils.clearSnoozeTimestamps;
import android.content.pm.PackageManager;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionPlan;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.uiautomator.UiDevice;
import com.android.compatibility.common.util.SystemUtil;
import com.android.compatibility.common.util.UiAutomatorUtils;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import java.time.Period;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.List;
public class DataWarningReceiverTest extends AbstractRestrictBackgroundNetworkTestCase {
@Before
public void setUp() throws Exception {
super.setUp();
clearSnoozeTimestamps();
registerBroadcastReceiver();
turnScreenOn();
}
@After
public void tearDown() throws Exception {
super.tearDown();
}
@Test
public void testSnoozeWarningNotReceived() throws Exception {
Assume.assumeTrue("Feature not supported: " + PackageManager.FEATURE_TELEPHONY,
mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY));
final SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class);
final int subId = SubscriptionManager.getDefaultDataSubscriptionId();
Assume.assumeTrue("Valid subId not found",
subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID);
setSubPlanOwner(subId, TEST_PKG);
final List<SubscriptionPlan> originalPlans = sm.getSubscriptionPlans(subId);
try {
// In NetworkPolicyManagerService class, we set the data warning bytes to 90% of
// data limit bytes. So, create the subscription plan in such a way this data warning
// threshold is already reached.
final SubscriptionPlan plan = SubscriptionPlan.Builder
.createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"),
Period.ofMonths(1))
.setTitle("CTS")
.setDataLimit(1_000_000_000, SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
.setDataUsage(999_000_000, System.currentTimeMillis())
.build();
sm.setSubscriptionPlans(subId, Arrays.asList(plan));
final UiDevice uiDevice = UiDevice.getInstance(mInstrumentation);
uiDevice.openNotification();
try {
final UiObject2 uiObject = UiAutomatorUtils.waitFindObject(
By.text("Data warning"));
Assume.assumeNotNull(uiObject);
uiObject.wait(Until.clickable(true), 10_000L);
uiObject.getParent().swipe(Direction.RIGHT, 1.0f);
} catch (Throwable t) {
Assume.assumeNoException(
"Error occurred while finding and swiping the notification", t);
}
assertSnoozeWarningNotReceived();
uiDevice.pressHome();
} finally {
sm.setSubscriptionPlans(subId, originalPlans);
setSubPlanOwner(subId, "");
}
}
private static void setSubPlanOwner(int subId, String packageName) throws Exception {
SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
"cmd netpolicy set sub-plan-owner " + subId + " " + packageName);
}
}

View File

@@ -25,6 +25,7 @@ import android.os.ParcelFileDescriptor;
import android.util.Log; import android.util.Log;
import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.uiautomator.UiDevice;
import com.android.compatibility.common.util.OnFailureRule; import com.android.compatibility.common.util.OnFailureRule;
@@ -52,7 +53,8 @@ public class DumpOnFailureRule extends OnFailureRule {
} }
prepareDumpRootDir(); prepareDumpRootDir();
final File dumpFile = new File(mDumpDir, "dump-" + getShortenedTestName(description)); final String shortenedTestName = getShortenedTestName(description);
final File dumpFile = new File(mDumpDir, "dump-" + shortenedTestName);
Log.i(TAG, "Dumping debug info for " + description + ": " + dumpFile.getPath()); Log.i(TAG, "Dumping debug info for " + description + ": " + dumpFile.getPath());
try (FileOutputStream out = new FileOutputStream(dumpFile)) { try (FileOutputStream out = new FileOutputStream(dumpFile)) {
for (String cmd : new String[] { for (String cmd : new String[] {
@@ -68,6 +70,16 @@ public class DumpOnFailureRule extends OnFailureRule {
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "Error closing file: " + dumpFile, e); Log.e(TAG, "Error closing file: " + dumpFile, e);
} }
final UiDevice uiDevice = UiDevice.getInstance(
InstrumentationRegistry.getInstrumentation());
final File screenshotFile = new File(mDumpDir, "sc-" + shortenedTestName + ".png");
uiDevice.takeScreenshot(screenshotFile);
final File windowHierarchyFile = new File(mDumpDir, "wh-" + shortenedTestName + ".xml");
try {
uiDevice.dumpWindowHierarchy(windowHierarchyFile);
} catch (IOException e) {
Log.e(TAG, "Error dumping window hierarchy", e);
}
} }
private String getShortenedTestName(Description description) { private String getShortenedTestName(Description description) {

View File

@@ -377,6 +377,10 @@ public class NetworkPolicyTestUtils {
} }
} }
public static void clearSnoozeTimestamps() {
executeShellCommand("dumpsys netpolicy --unsnooze");
}
public static String executeShellCommand(String command) { public static String executeShellCommand(String command) {
final String result = runShellCommand(command).trim(); final String result = runShellCommand(command).trim();
Log.d(TAG, "Output of '" + command + "': '" + result + "'"); Log.d(TAG, "Output of '" + command + "': '" + result + "'");

View File

@@ -63,4 +63,12 @@
android:permission="android.permission.BIND_JOB_SERVICE" /> android:permission="android.permission.BIND_JOB_SERVICE" />
</application> </application>
<!--
Adding this to make sure that receiving the broadcast is not restricted by
package visibility restrictions.
-->
<queries>
<package android:name="android" />
</queries>
</manifest> </manifest>

View File

@@ -44,6 +44,9 @@ public final class Common {
"com.android.cts.net.hostside.app2.action.FINISH_JOB"; "com.android.cts.net.hostside.app2.action.FINISH_JOB";
static final String ACTION_SHOW_TOAST = static final String ACTION_SHOW_TOAST =
"com.android.cts.net.hostside.app2.action.SHOW_TOAST"; "com.android.cts.net.hostside.app2.action.SHOW_TOAST";
// Copied from com.android.server.net.NetworkPolicyManagerService class
static final String ACTION_SNOOZE_WARNING =
"com.android.server.net.action.SNOOZE_WARNING";
static final String NOTIFICATION_TYPE_CONTENT = "CONTENT"; static final String NOTIFICATION_TYPE_CONTENT = "CONTENT";
static final String NOTIFICATION_TYPE_DELETE = "DELETE"; static final String NOTIFICATION_TYPE_DELETE = "DELETE";

View File

@@ -20,6 +20,7 @@ import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED
import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY; import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY;
import static com.android.cts.net.hostside.app2.Common.ACTION_SHOW_TOAST; import static com.android.cts.net.hostside.app2.Common.ACTION_SHOW_TOAST;
import static com.android.cts.net.hostside.app2.Common.ACTION_SNOOZE_WARNING;
import static com.android.cts.net.hostside.app2.Common.MANIFEST_RECEIVER; import static com.android.cts.net.hostside.app2.Common.MANIFEST_RECEIVER;
import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION; import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION;
import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION_BUNDLE; import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_ACTION_BUNDLE;
@@ -76,6 +77,9 @@ public class MyBroadcastReceiver extends BroadcastReceiver {
Log.d(TAG, "onReceive() for " + mName + ": " + intent); Log.d(TAG, "onReceive() for " + mName + ": " + intent);
final String action = intent.getAction(); final String action = intent.getAction();
switch (action) { switch (action) {
case ACTION_SNOOZE_WARNING:
increaseCounter(context, action);
break;
case ACTION_RESTRICT_BACKGROUND_CHANGED: case ACTION_RESTRICT_BACKGROUND_CHANGED:
increaseCounter(context, action); increaseCounter(context, action);
break; break;

View File

@@ -18,6 +18,7 @@ package com.android.cts.net.hostside.app2;
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY; import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY;
import static com.android.cts.net.hostside.app2.Common.ACTION_SNOOZE_WARNING;
import static com.android.cts.net.hostside.app2.Common.DYNAMIC_RECEIVER; import static com.android.cts.net.hostside.app2.Common.DYNAMIC_RECEIVER;
import static com.android.cts.net.hostside.app2.Common.TAG; import static com.android.cts.net.hostside.app2.Common.TAG;
@@ -67,6 +68,7 @@ public class MyService extends Service {
context.registerReceiver(mReceiver, new IntentFilter(ACTION_RECEIVER_READY)); context.registerReceiver(mReceiver, new IntentFilter(ACTION_RECEIVER_READY));
context.registerReceiver(mReceiver, context.registerReceiver(mReceiver,
new IntentFilter(ACTION_RESTRICT_BACKGROUND_CHANGED)); new IntentFilter(ACTION_RESTRICT_BACKGROUND_CHANGED));
context.registerReceiver(mReceiver, new IntentFilter(ACTION_SNOOZE_WARNING));
Log.d(TAG, "receiver registered"); Log.d(TAG, "receiver registered");
} }

View File

@@ -17,6 +17,7 @@
package com.android.cts.net; package com.android.cts.net;
import android.platform.test.annotations.FlakyTest; import android.platform.test.annotations.FlakyTest;
import android.platform.test.annotations.SecurityTest;
import com.android.ddmlib.Log; import com.android.ddmlib.Log;
import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.device.DeviceNotAvailableException;
@@ -38,6 +39,12 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC
uninstallPackage(TEST_APP2_PKG, true); uninstallPackage(TEST_APP2_PKG, true);
} }
@SecurityTest
public void testDataWarningReceiver() throws Exception {
runDeviceTests(TEST_PKG, TEST_PKG + ".DataWarningReceiverTest",
"testSnoozeWarningNotReceived");
}
/************************** /**************************
* Data Saver Mode tests. * * Data Saver Mode tests. *
**************************/ **************************/