diff options
16 files changed, 527 insertions, 592 deletions
diff --git a/core/java/android/net/IIpConnectivityMetrics.aidl b/core/java/android/net/IIpConnectivityMetrics.aidl index d36b7661aaa3..8f634bbf0cc9 100644 --- a/core/java/android/net/IIpConnectivityMetrics.aidl +++ b/core/java/android/net/IIpConnectivityMetrics.aidl @@ -23,8 +23,7 @@ import android.net.ConnectivityMetricsEvent; interface IIpConnectivityMetrics { /** - * @return the number of remaining available slots in buffer, - * or -1 if the event was dropped due to rate limiting. + * @return number of remaining available slots in buffer. */ int logEvent(in ConnectivityMetricsEvent event); } diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index bdac134f20cb..21df50ef3ead 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2725,6 +2725,7 @@ <java-symbol type="bool" name="config_permissionReviewRequired" /> + <java-symbol type="drawable" name="ic_restart" /> <java-symbol type="drawable" name="emergency_icon" /> diff --git a/core/tests/coretests/src/android/util/TokenBucketTest.java b/core/tests/coretests/src/android/util/TokenBucketTest.java index f7ac20c7287f..a053ad33f589 100644 --- a/core/tests/coretests/src/android/util/TokenBucketTest.java +++ b/core/tests/coretests/src/android/util/TokenBucketTest.java @@ -177,3 +177,4 @@ public class TokenBucketTest extends TestCase { interface Fn { void call(); } } + diff --git a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp deleted file mode 100644 index a438afd5c889..000000000000 --- a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "TestSceneBase.h" - -class ShadowShaderAnimation; - -static TestScene::Registrar _ShadowShader(TestScene::Info{ - "shadowshader", - "A set of overlapping shadowed areas with simple tessellation useful for" - " benchmarking shadow shader performance.", - TestScene::simpleCreateScene<ShadowShaderAnimation> -}); - -class ShadowShaderAnimation : public TestScene { -public: - std::vector< sp<RenderNode> > cards; - void createContent(int width, int height, TestCanvas& canvas) override { - canvas.drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode); - canvas.insertReorderBarrier(true); - - int outset = 50; - for (int i = 0; i < 10; i++) { - sp<RenderNode> card = createCard(outset, outset, - width - (outset * 2), height - (outset * 2)); - canvas.drawRenderNode(card.get()); - cards.push_back(card); - } - - canvas.insertReorderBarrier(false); - } - void doFrame(int frameNr) override { - int curFrame = frameNr % 10; - for (size_t ci = 0; ci < cards.size(); ci++) { - cards[ci]->mutateStagingProperties().setTranslationX(curFrame); - cards[ci]->mutateStagingProperties().setTranslationY(curFrame); - cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); - } - } -private: - sp<RenderNode> createCard(int x, int y, int width, int height) { - return TestUtils::createNode(x, y, x + width, y + height, - [width, height](RenderProperties& props, TestCanvas& canvas) { - props.setElevation(1000); - - // Set 0 radius, no clipping, so shadow is easy to compute. Slightly transparent outline - // to signal contents aren't opaque (not necessary though, as elevation is so high, no - // inner content to cut out) - props.mutableOutline().setRoundRect(0, 0, width, height, 0, 0.99f); - props.mutableOutline().setShouldClip(false); - - // don't draw anything to card's canvas - we just want the shadow - }); - } -}; diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index 3b3ce073e099..78b33e5cd80f 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -760,8 +760,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); - if (!isEnabled() && mPermissionReviewRequired) { - startConsentUi(packageName, callingUid, BluetoothAdapter.ACTION_REQUEST_ENABLE); + if (!isEnabled() && mPermissionReviewRequired + && startConsentUiIfNeeded(packageName, callingUid, + BluetoothAdapter.ACTION_REQUEST_ENABLE)) { return false; } } @@ -795,8 +796,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); - if (isEnabled() && mPermissionReviewRequired) { - startConsentUi(packageName, callingUid, BluetoothAdapter.ACTION_REQUEST_DISABLE); + if (isEnabled() && mPermissionReviewRequired + && startConsentUiIfNeeded(packageName, callingUid, + BluetoothAdapter.ACTION_REQUEST_DISABLE)) { return false; } } @@ -816,8 +818,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return true; } - private void startConsentUi(String packageName, int callingUid, String intentAction) - throws RemoteException { + private boolean startConsentUiIfNeeded(String packageName, + int callingUid, String intentAction) throws RemoteException { try { // Validate the package only if we are going to use it ApplicationInfo applicationInfo = mContext.getPackageManager() @@ -829,12 +831,16 @@ class BluetoothManagerService extends IBluetoothManager.Stub { + " not in uid " + callingUid); } - // Permission review mode, trigger a user prompt - Intent intent = new Intent(intentAction); - mContext.startActivity(intent); + // Legacy apps in permission review mode trigger a user prompt + if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { + Intent intent = new Intent(intentAction); + mContext.startActivity(intent); + return true; + } } catch (PackageManager.NameNotFoundException e) { throw new RemoteException(e.getMessage()); } + return false; } public void unbindAndFinish() { diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 97f913e69d95..4405c1b6135a 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -49,6 +49,7 @@ import android.os.Bundle; import android.os.Environment; import android.os.FileUtils; import android.os.Handler; +import android.os.IBinder; import android.os.IDeviceIdleController; import android.os.IMaintenanceActivityListener; import android.os.Looper; @@ -1237,7 +1238,7 @@ public class DeviceIdleController extends SystemService } } - public class LocalService { + public final class LocalService { public void addPowerSaveTempWhitelistAppDirect(int appId, long duration, boolean sync, String reason) { addPowerSaveTempWhitelistAppDirectInternal(0, appId, duration, sync, reason); diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index ae1aef650ba4..10a538863c25 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -369,7 +369,7 @@ public final class ActiveServices { // we do not start the service and launch a review activity if the calling app // is in the foreground passing it a pending intent to start the service when // review is completed. - if (mAm.mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) { + if (Build.PERMISSIONS_REVIEW_REQUIRED) { if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage, callingUid, service, callerFg, userId)) { return null; @@ -913,7 +913,7 @@ public final class ActiveServices { // we schedule binding to the service but do not start its process, then // we launch a review activity to which is passed a callback to invoke // when done to start the bound service's process to completing the binding. - if (mAm.mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) { + if (Build.PERMISSIONS_REVIEW_REQUIRED) { if (mAm.getPackageManagerInternalLocked().isPermissionsReviewRequired( s.packageName, s.userId)) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 1feaa72867d1..063591eff604 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1576,8 +1576,6 @@ public final class ActivityManagerService extends ActivityManagerNative // being called for multiwindow assist in a single session. private int mViSessionId = 1000; - final boolean mPermissionReviewRequired; - final class KillHandler extends Handler { static final int KILL_PROCESS_GROUP_MSG = 4000; @@ -2625,9 +2623,6 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass()); - mPermissionReviewRequired = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_permissionReviewRequired); - mHandlerThread = new ServiceThread(TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/); mHandlerThread.start(); @@ -10845,7 +10840,7 @@ public final class ActivityManagerService extends ActivityManagerNative // If permissions need a review before any of the app components can run, // we return no provider and launch a review activity if the calling app // is in the foreground. - if (mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) { + if (Build.PERMISSIONS_REVIEW_REQUIRED) { if (!requestTargetProviderPermissionsReviewIfNeededLocked(cpi, r, userId)) { return null; } diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 907394e39b14..115971f6fffc 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -416,8 +416,7 @@ class ActivityStarter { // If permissions need a review before any of the app components can run, we // launch the review activity and pass a pending intent to start the activity // we are to launching now after the review is completed. - if ((mService.mPermissionReviewRequired - || Build.PERMISSIONS_REVIEW_REQUIRED) && aInfo != null) { + if (Build.PERMISSIONS_REVIEW_REQUIRED && aInfo != null) { if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired( aInfo.packageName, userId)) { IIntentSender target = mService.getIntentSenderLocked( diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index ea901ce28953..362a3479a6bf 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -626,7 +626,7 @@ public final class BroadcastQueue { // the broadcast and if the calling app is in the foreground and the broadcast is // explicit we launch the review UI passing it a pending intent to send the skipped // broadcast. - if (mService.mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) { + if (Build.PERMISSIONS_REVIEW_REQUIRED) { if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName, filter.owningUserId)) { r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED; @@ -1132,8 +1132,7 @@ public final class BroadcastQueue { // the broadcast and if the calling app is in the foreground and the broadcast is // explicit we launch the review UI passing it a pending intent to send the skipped // broadcast. - if ((mService.mPermissionReviewRequired - || Build.PERMISSIONS_REVIEW_REQUIRED) && !skip) { + if (Build.PERMISSIONS_REVIEW_REQUIRED && !skip) { if (!requestStartTargetPermissionsReviewIfNeededLocked(r, info.activityInfo.packageName, UserHandle.getUserId( info.activityInfo.applicationInfo.uid))) { diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java index be681739d2ee..642f2e01987b 100644 --- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java +++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java @@ -19,19 +19,15 @@ package com.android.server.connectivity; import android.content.Context; import android.net.ConnectivityMetricsEvent; import android.net.IIpConnectivityMetrics; -import android.net.metrics.ApfProgramEvent; import android.net.metrics.IpConnectivityLog; import android.os.IBinder; import android.os.Parcelable; import android.provider.Settings; import android.text.TextUtils; -import android.text.format.DateUtils; -import android.util.ArrayMap; import android.util.Base64; import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.TokenBucket; import com.android.server.SystemService; import java.io.FileDescriptor; import java.io.IOException; @@ -60,8 +56,6 @@ final public class IpConnectivityMetrics extends SystemService { // Maximum size of the event buffer. private static final int MAXIMUM_BUFFER_SIZE = DEFAULT_BUFFER_SIZE * 10; - private static final int ERROR_RATE_LIMITED = -1; - // Lock ensuring that concurrent manipulations of the event buffer are correct. // There are three concurrent operations to synchronize: // - appending events to the buffer. @@ -79,8 +73,6 @@ final public class IpConnectivityMetrics extends SystemService { private int mDropped; @GuardedBy("mLock") private int mCapacity; - @GuardedBy("mLock") - private final ArrayMap<Class<?>, TokenBucket> mBuckets = makeRateLimitingBuckets(); private final ToIntFunction<Context> mCapacityGetter; @@ -130,10 +122,6 @@ final public class IpConnectivityMetrics extends SystemService { if (event == null) { return left; } - if (isRateLimited(event)) { - // Do not count as a dropped event. TODO: consider adding separate counter - return ERROR_RATE_LIMITED; - } if (left == 0) { mDropped++; return 0; @@ -143,11 +131,6 @@ final public class IpConnectivityMetrics extends SystemService { } } - private boolean isRateLimited(ConnectivityMetricsEvent event) { - TokenBucket tb = mBuckets.get(event.data.getClass()); - return (tb != null) && !tb.get(); - } - private String flushEncodedOutput() { final ArrayList<ConnectivityMetricsEvent> events; final int dropped; @@ -273,11 +256,4 @@ final public class IpConnectivityMetrics extends SystemService { } return Math.min(size, MAXIMUM_BUFFER_SIZE); }; - - private static ArrayMap<Class<?>, TokenBucket> makeRateLimitingBuckets() { - ArrayMap<Class<?>, TokenBucket> map = new ArrayMap<>(); - // one token every minute, 50 tokens max: burst of ~50 events every hour. - map.put(ApfProgramEvent.class, new TokenBucket((int)DateUtils.MINUTE_IN_MILLIS, 50)); - return map; - } } diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java index 9ffa40b7522f..c6bf4c5fcd6a 100644 --- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java +++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java @@ -27,7 +27,7 @@ import android.net.NetworkCapabilities; import android.os.UserHandle; import android.telephony.TelephonyManager; import android.util.Slog; -import com.android.internal.annotations.VisibleForTesting; + import com.android.internal.R; import static android.net.NetworkCapabilities.*; @@ -37,8 +37,7 @@ public class NetworkNotificationManager { public static enum NotificationType { SIGN_IN, NO_INTERNET, LOST_INTERNET, NETWORK_SWITCH }; - @VisibleForTesting - static final String NOTIFICATION_ID = "Connectivity.Notification"; + private static final String NOTIFICATION_ID = "Connectivity.Notification"; private static final String TAG = NetworkNotificationManager.class.getSimpleName(); private static final boolean DBG = true; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ca0f85d51f3e..0b3bea844b93 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1148,8 +1148,6 @@ public class PackageManagerService extends IPackageManager.Stub { final @NonNull String mServicesSystemSharedLibraryPackageName; final @NonNull String mSharedSystemSharedLibraryPackageName; - final boolean mPermissionReviewRequired; - private final PackageUsage mPackageUsage = new PackageUsage(); private final CompilerStats mCompilerStats = new CompilerStats(); @@ -2080,10 +2078,6 @@ public class PackageManagerService extends IPackageManager.Stub { } mContext = context; - - mPermissionReviewRequired = context.getResources().getBoolean( - R.bool.config_permissionReviewRequired); - mFactoryTest = factoryTest; mOnlyCore = onlyCore; mMetrics = new DisplayMetrics(); @@ -4057,7 +4051,7 @@ public class PackageManagerService extends IPackageManager.Stub { // their permissions as always granted runtime ones since we need // to keep the review required permission flag per user while an // install permission's state is shared across all users. - if ((mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) + if (Build.PERMISSIONS_REVIEW_REQUIRED && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M && bp.isRuntime()) { return; @@ -4168,7 +4162,7 @@ public class PackageManagerService extends IPackageManager.Stub { // their permissions as always granted runtime ones since we need // to keep the review required permission flag per user while an // install permission's state is shared across all users. - if ((mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) + if (Build.PERMISSIONS_REVIEW_REQUIRED && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M && bp.isRuntime()) { return; @@ -10061,8 +10055,7 @@ public class PackageManagerService extends IPackageManager.Stub { // their permissions as always granted runtime ones since we need // to keep the review required permission flag per user while an // install permission's state is shared across all users. - if (!appSupportsRuntimePermissions && !mPermissionReviewRequired - && !Build.PERMISSIONS_REVIEW_REQUIRED) { + if (!appSupportsRuntimePermissions && !Build.PERMISSIONS_REVIEW_REQUIRED) { // For legacy apps dangerous permissions are install time ones. grant = GRANT_INSTALL; } else if (origPermissions.hasInstallPermission(bp.name)) { @@ -10148,7 +10141,7 @@ public class PackageManagerService extends IPackageManager.Stub { changedRuntimePermissionUserIds, userId); } // If the app supports runtime permissions no need for a review. - if ((mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) + if (Build.PERMISSIONS_REVIEW_REQUIRED && appSupportsRuntimePermissions && (flags & PackageManager .FLAG_PERMISSION_REVIEW_REQUIRED) != 0) { @@ -10157,8 +10150,7 @@ public class PackageManagerService extends IPackageManager.Stub { changedRuntimePermissionUserIds = ArrayUtils.appendInt( changedRuntimePermissionUserIds, userId); } - } else if ((mPermissionReviewRequired - || Build.PERMISSIONS_REVIEW_REQUIRED) + } else if (Build.PERMISSIONS_REVIEW_REQUIRED && !appSupportsRuntimePermissions) { // For legacy apps that need a permission review, every new // runtime permission is granted but it is pending a review. @@ -16753,7 +16745,7 @@ public class PackageManagerService extends IPackageManager.Stub { // If permission review is enabled and this is a legacy app, mark the // permission as requiring a review as this is the initial state. int flags = 0; - if ((mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) + if (Build.PERMISSIONS_REVIEW_REQUIRED && ps.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { flags |= FLAG_PERMISSION_REVIEW_REQUIRED; } @@ -20623,7 +20615,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); // permissions to keep per user flag state whether review is needed. // Hence, if a new user is added we have to propagate dangerous // permission grants for these legacy apps. - if (mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) { + if (Build.PERMISSIONS_REVIEW_REQUIRED) { updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_ALL); } @@ -21077,7 +21069,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); public boolean isPermissionsReviewRequired(String packageName, int userId) { synchronized (mPackages) { // If we do not support permission review, done. - if (!mPermissionReviewRequired && !Build.PERMISSIONS_REVIEW_REQUIRED) { + if (!Build.PERMISSIONS_REVIEW_REQUIRED) { return false; } diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index a545af96da70..aeeca79a8473 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -16,12 +16,17 @@ package com.android.server; +import static android.content.Intent.ACTION_UID_REMOVED; +import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.NetworkPolicy.CYCLE_NONE; import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.WARNING_DISABLED; import static android.net.NetworkPolicyManager.POLICY_NONE; import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; +import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; +import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import static android.net.NetworkPolicyManager.computeLastCycleBoundary; import static android.net.NetworkPolicyManager.computeNextCycleBoundary; import static android.net.TrafficStats.KB_IN_BYTES; @@ -29,42 +34,28 @@ import static android.net.TrafficStats.MB_IN_BYTES; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.Time.TIMEZONE_UTC; - import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT; import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED; import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING; +import static org.easymock.EasyMock.anyInt; +import static org.easymock.EasyMock.anyLong; +import static org.easymock.EasyMock.aryEq; +import static org.easymock.EasyMock.capture; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.eq; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.isA; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.ActivityManager; import android.app.IActivityManager; import android.app.INotificationManager; -import android.app.IUidObserver; +import android.app.IProcessObserver; import android.app.Notification; -import android.app.usage.UsageStatsManagerInternal; -import android.content.Context; import android.content.Intent; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.Signature; +import android.net.ConnectivityManager; import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkPolicyListener; @@ -78,48 +69,40 @@ import android.net.NetworkStats; import android.net.NetworkTemplate; import android.os.Binder; import android.os.INetworkManagementService; -import android.os.PowerManagerInternal; +import android.os.MessageQueue.IdleHandler; import android.os.UserHandle; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; +import android.test.AndroidTestCase; +import android.test.mock.MockPackageManager; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.Suppress; import android.text.format.Time; -import android.util.Log; import android.util.TrustedTime; import com.android.internal.util.test.BroadcastInterceptingContext; -import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.net.NetworkPolicyManagerService; - -import libcore.io.IoUtils; - import com.google.common.util.concurrent.AbstractFuture; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; +import org.easymock.Capture; +import org.easymock.EasyMock; +import org.easymock.IAnswer; import java.io.File; -import java.util.ArrayList; +import java.util.Calendar; import java.util.LinkedHashSet; -import java.util.List; -import java.util.concurrent.CountDownLatch; +import java.util.TimeZone; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.logging.Handler; + +import libcore.io.IoUtils; /** * Tests for {@link NetworkPolicyManagerService}. */ -@RunWith(AndroidJUnit4.class) -public class NetworkPolicyManagerServiceTest { +@LargeTest +public class NetworkPolicyManagerServiceTest extends AndroidTestCase { private static final String TAG = "NetworkPolicyManagerServiceTest"; private static final long TEST_START = 1194220800000L; @@ -131,19 +114,19 @@ public class NetworkPolicyManagerServiceTest { private BroadcastInterceptingContext mServiceContext; private File mPolicyDir; - private @Mock IActivityManager mActivityManager; - private @Mock INetworkStatsService mStatsService; - private @Mock INetworkManagementService mNetworkManager; - private @Mock TrustedTime mTime; - private @Mock IConnectivityManager mConnManager; - private @Mock INotificationManager mNotifManager; - private @Mock PackageManager mPackageManager; + private IActivityManager mActivityManager; + private INetworkStatsService mStatsService; + private INetworkManagementService mNetworkManager; + private INetworkPolicyListener mPolicyListener; + private TrustedTime mTime; + private IConnectivityManager mConnManager; + private INotificationManager mNotifManager; - private IUidObserver mUidObserver; + private NetworkPolicyManagerService mService; + private IProcessObserver mProcessObserver; private INetworkManagementEventObserver mNetworkObserver; - private NetworkPolicyListenerAnswer mPolicyListener; - private NetworkPolicyManagerService mService; + private Binder mStubBinder = new Binder(); private long mStartTime; private long mElapsedRealtime; @@ -156,30 +139,39 @@ public class NetworkPolicyManagerServiceTest { private static final int UID_A = UserHandle.getUid(USER_ID, APP_ID_A); private static final int UID_B = UserHandle.getUid(USER_ID, APP_ID_B); - private static final String PKG_NAME_A = "name.is.A,pkg.A"; - - @BeforeClass - public static void registerLocalServices() { - addLocalServiceMock(PowerManagerInternal.class); - addLocalServiceMock(DeviceIdleController.LocalService.class); - final UsageStatsManagerInternal usageStats = - addLocalServiceMock(UsageStatsManagerInternal.class); - when(usageStats.getIdleUidsForUser(anyInt())).thenReturn(new int[]{}); - } + private static final int PID_1 = 400; + private static final int PID_2 = 401; + private static final int PID_3 = 402; - @Before - public void callSystemReady() throws Exception { - MockitoAnnotations.initMocks(this); - - final Context context = InstrumentationRegistry.getContext(); + public void _setUp() throws Exception { + super.setUp(); setCurrentTimeMillis(TEST_START); // intercept various broadcasts, and pretend that uids have packages - mServiceContext = new BroadcastInterceptingContext(context) { + mServiceContext = new BroadcastInterceptingContext(getContext()) { @Override public PackageManager getPackageManager() { - return mPackageManager; + return new MockPackageManager() { + @Override + public String[] getPackagesForUid(int uid) { + return new String[] { "com.example" }; + } + + @Override + public PackageInfo getPackageInfo(String packageName, int flags) { + final PackageInfo info = new PackageInfo(); + final Signature signature; + if ("android".equals(packageName)) { + signature = new Signature("F00D"); + } else { + signature = new Signature("DEAD"); + } + info.signatures = new Signature[] { signature }; + return info; + } + + }; } @Override @@ -188,112 +180,229 @@ public class NetworkPolicyManagerServiceTest { } }; - mPolicyDir = context.getFilesDir(); + mPolicyDir = getContext().getFilesDir(); if (mPolicyDir.exists()) { IoUtils.deleteContents(mPolicyDir); } - doAnswer(new Answer<Void>() { - - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - mUidObserver = (IUidObserver) invocation.getArguments()[0]; - Log.d(TAG, "set mUidObserver to " + mUidObserver); - return null; - } - }).when(mActivityManager).registerUidObserver(any(), anyInt()); + mActivityManager = createMock(IActivityManager.class); + mStatsService = createMock(INetworkStatsService.class); + mNetworkManager = createMock(INetworkManagementService.class); + mPolicyListener = createMock(INetworkPolicyListener.class); + mTime = createMock(TrustedTime.class); + mConnManager = createMock(IConnectivityManager.class); + mNotifManager = createMock(INotificationManager.class); - mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mStatsService, - mNetworkManager, mTime, mPolicyDir, true); + mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, + mStatsService, mNetworkManager, mTime, mPolicyDir, true); mService.bindConnectivityManager(mConnManager); mService.bindNotificationManager(mNotifManager); - mPolicyListener = new NetworkPolicyListenerAnswer(mService); - // Sets some common expectations. - when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenAnswer( - new Answer<PackageInfo>() { + // RemoteCallbackList needs a binder to use as key + expect(mPolicyListener.asBinder()).andReturn(mStubBinder).atLeastOnce(); + replay(); + mService.registerListener(mPolicyListener); + verifyAndReset(); - @Override - public PackageInfo answer(InvocationOnMock invocation) throws Throwable { - final String packageName = (String) invocation.getArguments()[0]; - final PackageInfo info = new PackageInfo(); - final Signature signature; - if ("android".equals(packageName)) { - signature = new Signature("F00D"); - } else { - signature = new Signature("DEAD"); - } - info.signatures = new Signature[] { - signature - }; - return info; - } - }); - when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) - .thenReturn(new ApplicationInfo()); - when(mPackageManager.getPackagesForUid(UID_A)).thenReturn(new String[] {PKG_NAME_A}); - when(mNetworkManager.isBandwidthControlEnabled()).thenReturn(true); + // catch IProcessObserver during systemReady() + final Capture<IProcessObserver> processObserver = new Capture<IProcessObserver>(); + mActivityManager.registerProcessObserver(capture(processObserver)); + expectLastCall().atLeastOnce(); + + // catch INetworkManagementEventObserver during systemReady() + final Capture<INetworkManagementEventObserver> networkObserver = new Capture< + INetworkManagementEventObserver>(); + mNetworkManager.registerObserver(capture(networkObserver)); + expectLastCall().atLeastOnce(); + + expect(mNetworkManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce(); expectCurrentTime(); - // Prepare NPMS. + replay(); mService.systemReady(); + verifyAndReset(); - // catch INetworkManagementEventObserver during systemReady() - ArgumentCaptor<INetworkManagementEventObserver> networkObserver = - ArgumentCaptor.forClass(INetworkManagementEventObserver.class); - verify(mNetworkManager).registerObserver(networkObserver.capture()); + mProcessObserver = processObserver.getValue(); mNetworkObserver = networkObserver.getValue(); + } - @After - public void removeFiles() throws Exception { + public void _tearDown() throws Exception { for (File file : mPolicyDir.listFiles()) { file.delete(); } - } - @After - public void unregisterLocalServices() throws Exception { - // Registered by NetworkPolicyManagerService's constructor. - LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class); - } + mServiceContext = null; + mPolicyDir = null; - // NOTE: testPolicyChangeTriggersListener() and testUidForeground() are too superficial, they - // don't check for side-effects (like calls to NetworkManagementService) neither cover all - // different modes (Data Saver, Battery Saver, Doze, App idle, etc...). - // These scenarios are extensively tested on CTS' HostsideRestrictBackgroundNetworkTests. + mActivityManager = null; + mStatsService = null; + mPolicyListener = null; + mTime = null; - @Test - public void testPolicyChangeTriggersListener() throws Exception { - mPolicyListener.expect().onRestrictBackgroundBlacklistChanged(anyInt(), anyBoolean()); + mService = null; + mProcessObserver = null; + + super.tearDown(); + } + @Suppress + public void testPolicyChangeTriggersBroadcast() throws Exception { mService.setUidPolicy(APP_ID_A, POLICY_NONE); + + // change background policy and expect broadcast + final Future<Intent> backgroundChanged = mServiceContext.nextBroadcastIntent( + ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED); + mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND); - mPolicyListener.waitAndVerify().onRestrictBackgroundBlacklistChanged(APP_ID_A, true); + backgroundChanged.get(); } - @Test - public void testUidForeground() throws Exception { - // push all uids into background - mUidObserver.onUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE); - mUidObserver.onUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_SERVICE); + @Suppress + public void testPidForegroundCombined() throws Exception { + IdleFuture idle; + + // push all uid into background + idle = expectIdle(); + mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false); + mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false); + mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, false); + idle.get(); assertFalse(mService.isUidForeground(UID_A)); assertFalse(mService.isUidForeground(UID_B)); - // push one of the uids into foreground - mUidObserver.onUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP); + // push one of the shared pids into foreground + idle = expectIdle(); + mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true); + idle.get(); assertTrue(mService.isUidForeground(UID_A)); assertFalse(mService.isUidForeground(UID_B)); // and swap another uid into foreground - mUidObserver.onUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE); - mUidObserver.onUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_TOP); + idle = expectIdle(); + mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false); + mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, true); + idle.get(); assertFalse(mService.isUidForeground(UID_A)); assertTrue(mService.isUidForeground(UID_B)); + + // push both pid into foreground + idle = expectIdle(); + mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true); + mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true); + idle.get(); + assertTrue(mService.isUidForeground(UID_A)); + + // pull one out, should still be foreground + idle = expectIdle(); + mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false); + idle.get(); + assertTrue(mService.isUidForeground(UID_A)); + + // pull final pid out, should now be background + idle = expectIdle(); + mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false); + idle.get(); + assertFalse(mService.isUidForeground(UID_A)); + } + + @Suppress + public void testPolicyNone() throws Exception { + Future<Void> future; + + expectSetUidMeteredNetworkBlacklist(UID_A, false); + expectSetUidForeground(UID_A, true); + future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); + replay(); + mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true); + future.get(); + verifyAndReset(); + + // POLICY_NONE should RULE_ALLOW in foreground + expectSetUidMeteredNetworkBlacklist(UID_A, false); + expectSetUidForeground(UID_A, true); + future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); + replay(); + mService.setUidPolicy(APP_ID_A, POLICY_NONE); + future.get(); + verifyAndReset(); + + // POLICY_NONE should RULE_ALLOW in background + expectSetUidMeteredNetworkBlacklist(UID_A, false); + expectSetUidForeground(UID_A, false); + future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); + replay(); + mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false); + future.get(); + verifyAndReset(); + } + + @Suppress + public void testPolicyReject() throws Exception { + Future<Void> future; + + // POLICY_REJECT should RULE_ALLOW in background + expectSetUidMeteredNetworkBlacklist(UID_A, true); + expectSetUidForeground(UID_A, false); + future = expectRulesChanged(UID_A, RULE_REJECT_METERED); + replay(); + mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND); + future.get(); + verifyAndReset(); + + // POLICY_REJECT should RULE_ALLOW in foreground + expectSetUidMeteredNetworkBlacklist(UID_A, false); + expectSetUidForeground(UID_A, true); + future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); + replay(); + mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true); + future.get(); + verifyAndReset(); + + // POLICY_REJECT should RULE_REJECT in background + expectSetUidMeteredNetworkBlacklist(UID_A, true); + expectSetUidForeground(UID_A, false); + future = expectRulesChanged(UID_A, RULE_REJECT_METERED); + replay(); + mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false); + future.get(); + verifyAndReset(); + } + + @Suppress + public void testPolicyRejectAddRemove() throws Exception { + Future<Void> future; + + // POLICY_NONE should have RULE_ALLOW in background + expectSetUidMeteredNetworkBlacklist(UID_A, false); + expectSetUidForeground(UID_A, false); + future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); + replay(); + mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false); + mService.setUidPolicy(APP_ID_A, POLICY_NONE); + future.get(); + verifyAndReset(); + + // adding POLICY_REJECT should cause RULE_REJECT + expectSetUidMeteredNetworkBlacklist(UID_A, true); + expectSetUidForeground(UID_A, false); + future = expectRulesChanged(UID_A, RULE_REJECT_METERED); + replay(); + mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND); + future.get(); + verifyAndReset(); + + // removing POLICY_REJECT should return us to RULE_ALLOW + expectSetUidMeteredNetworkBlacklist(UID_A, false); + expectSetUidForeground(UID_A, false); + future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); + replay(); + mService.setUidPolicy(APP_ID_A, POLICY_NONE); + future.get(); + verifyAndReset(); } - @Test public void testLastCycleBoundaryThisMonth() throws Exception { // assume cycle day of "5th", which should be in same month final long currentTime = parseTime("2007-11-14T00:00:00.000Z"); @@ -305,7 +414,6 @@ public class NetworkPolicyManagerServiceTest { assertTimeEquals(expectedCycle, actualCycle); } - @Test public void testLastCycleBoundaryLastMonth() throws Exception { // assume cycle day of "20th", which should be in last month final long currentTime = parseTime("2007-11-14T00:00:00.000Z"); @@ -317,7 +425,6 @@ public class NetworkPolicyManagerServiceTest { assertTimeEquals(expectedCycle, actualCycle); } - @Test public void testLastCycleBoundaryThisMonthFebruary() throws Exception { // assume cycle day of "30th" in february; should go to january final long currentTime = parseTime("2007-02-14T00:00:00.000Z"); @@ -329,7 +436,6 @@ public class NetworkPolicyManagerServiceTest { assertTimeEquals(expectedCycle, actualCycle); } - @Test public void testLastCycleBoundaryLastMonthFebruary() throws Exception { // assume cycle day of "30th" in february, which should clamp final long currentTime = parseTime("2007-03-14T00:00:00.000Z"); @@ -341,7 +447,6 @@ public class NetworkPolicyManagerServiceTest { assertTimeEquals(expectedCycle, actualCycle); } - @Test public void testCycleBoundaryLeapYear() throws Exception { final NetworkPolicy policy = new NetworkPolicy( sTemplateWifi, 29, TIMEZONE_UTC, 1024L, 1024L, false); @@ -365,7 +470,6 @@ public class NetworkPolicyManagerServiceTest { computeNextCycleBoundary(parseTime("2007-03-14T00:00:00.000Z"), policy)); } - @Test public void testNextCycleTimezoneAfterUtc() throws Exception { // US/Central is UTC-6 final NetworkPolicy policy = new NetworkPolicy( @@ -374,7 +478,6 @@ public class NetworkPolicyManagerServiceTest { computeNextCycleBoundary(parseTime("2012-01-05T00:00:00.000Z"), policy)); } - @Test public void testNextCycleTimezoneBeforeUtc() throws Exception { // Israel is UTC+2 final NetworkPolicy policy = new NetworkPolicy( @@ -383,7 +486,6 @@ public class NetworkPolicyManagerServiceTest { computeNextCycleBoundary(parseTime("2012-01-05T00:00:00.000Z"), policy)); } - @Test public void testNextCycleSane() throws Exception { final NetworkPolicy policy = new NetworkPolicy( sTemplateWifi, 31, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, false); @@ -399,7 +501,6 @@ public class NetworkPolicyManagerServiceTest { } } - @Test public void testLastCycleSane() throws Exception { final NetworkPolicy policy = new NetworkPolicy( sTemplateWifi, 31, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, false); @@ -415,7 +516,6 @@ public class NetworkPolicyManagerServiceTest { } } - @Test public void testCycleTodayJanuary() throws Exception { final NetworkPolicy policy = new NetworkPolicy( sTemplateWifi, 14, "US/Pacific", 1024L, 1024L, false); @@ -435,7 +535,6 @@ public class NetworkPolicyManagerServiceTest { computeLastCycleBoundary(parseTime("2013-01-14T15:11:00.000-08:00"), policy)); } - @Test public void testLastCycleBoundaryDST() throws Exception { final long currentTime = parseTime("1989-01-02T07:30:00.000"); final long expectedCycle = parseTime("1988-12-03T02:00:00.000Z"); @@ -446,7 +545,6 @@ public class NetworkPolicyManagerServiceTest { assertTimeEquals(expectedCycle, actualCycle); } - @Test public void testLastCycleBoundaryJanuaryDST() throws Exception { final long currentTime = parseTime("1989-01-26T21:00:00.000Z"); final long expectedCycle = parseTime("1989-01-01T01:59:59.000Z"); @@ -457,10 +555,11 @@ public class NetworkPolicyManagerServiceTest { assertTimeEquals(expectedCycle, actualCycle); } - @Test + @Suppress public void testNetworkPolicyAppliedCycleLastMonth() throws Exception { NetworkState[] state = null; NetworkStats stats = null; + Future<Void> future; final long TIME_FEB_15 = 1171497600000L; final long TIME_MAR_10 = 1173484800000L; @@ -471,40 +570,75 @@ public class NetworkPolicyManagerServiceTest { // first, pretend that wifi network comes online. no policy active, // which means we shouldn't push limit to interface. state = new NetworkState[] { buildWifi() }; - when(mConnManager.getAllNetworkState()).thenReturn(state); + expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); expectCurrentTime(); + expectClearNotifications(); + expectAdvisePersistThreshold(); + future = expectMeteredIfacesChanged(); - mPolicyListener.expect().onMeteredIfacesChanged(any()); + replay(); mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); - mPolicyListener.waitAndVerify().onMeteredIfacesChanged(any()); + future.get(); + verifyAndReset(); // now change cycle to be on 15th, and test in early march, to verify we // pick cycle day in previous month. - when(mConnManager.getAllNetworkState()).thenReturn(state); + expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); expectCurrentTime(); // pretend that 512 bytes total have happened stats = new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 256L, 2L, 256L, 2L); - when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, TIME_MAR_10)) - .thenReturn(stats.getTotalBytes()); + expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, TIME_MAR_10)) + .andReturn(stats.getTotalBytes()).atLeastOnce(); + expectPolicyDataEnable(TYPE_WIFI, true); - mPolicyListener.expect().onMeteredIfacesChanged(any()); + // TODO: consider making strongly ordered mock + expectRemoveInterfaceQuota(TEST_IFACE); + expectSetInterfaceQuota(TEST_IFACE, (2 * MB_IN_BYTES) - 512); + + expectClearNotifications(); + expectAdvisePersistThreshold(); + future = expectMeteredIfacesChanged(TEST_IFACE); + + replay(); setNetworkPolicies(new NetworkPolicy( sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, false)); - mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE})); + future.get(); + verifyAndReset(); + } - // TODO: consider making strongly ordered mock - verifyPolicyDataEnable(TYPE_WIFI, true); - verifyRemoveInterfaceQuota(TEST_IFACE); - verifySetInterfaceQuota(TEST_IFACE, (2 * MB_IN_BYTES) - 512); + @Suppress + public void testUidRemovedPolicyCleared() throws Exception { + Future<Void> future; + + // POLICY_REJECT should RULE_REJECT in background + expectSetUidMeteredNetworkBlacklist(UID_A, true); + expectSetUidForeground(UID_A, false); + future = expectRulesChanged(UID_A, RULE_REJECT_METERED); + replay(); + mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND); + future.get(); + verifyAndReset(); + + // uninstall should clear RULE_REJECT + expectSetUidMeteredNetworkBlacklist(UID_A, false); + expectSetUidForeground(UID_A, false); + future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); + replay(); + final Intent intent = new Intent(ACTION_UID_REMOVED); + intent.putExtra(EXTRA_UID, UID_A); + mServiceContext.sendBroadcast(intent); + future.get(); + verifyAndReset(); } - @Test + @Suppress public void testOverWarningLimitNotification() throws Exception { NetworkState[] state = null; NetworkStats stats = null; - Future<String> tagFuture = null; + Future<Void> future; + Future<String> tagFuture; final long TIME_FEB_15 = 1171497600000L; final long TIME_MAR_10 = 1173484800000L; @@ -519,15 +653,20 @@ public class NetworkPolicyManagerServiceTest { { expectCurrentTime(); - when(mConnManager.getAllNetworkState()).thenReturn(state); - when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, - currentTimeMillis())).thenReturn(stats.getTotalBytes()); + expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); + expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) + .andReturn(stats.getTotalBytes()).atLeastOnce(); + expectPolicyDataEnable(TYPE_WIFI, true); + + expectClearNotifications(); + expectAdvisePersistThreshold(); + future = expectMeteredIfacesChanged(); - mPolicyListener.expect().onMeteredIfacesChanged(any()); + replay(); setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, false)); - mPolicyListener.waitAndVerify().onMeteredIfacesChanged(any()); - verifyPolicyDataEnable(TYPE_WIFI, true); + future.get(); + verifyAndReset(); } // bring up wifi network @@ -538,17 +677,22 @@ public class NetworkPolicyManagerServiceTest { { expectCurrentTime(); - when(mConnManager.getAllNetworkState()).thenReturn(state); - when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, - currentTimeMillis())).thenReturn(stats.getTotalBytes()); + expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); + expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) + .andReturn(stats.getTotalBytes()).atLeastOnce(); + expectPolicyDataEnable(TYPE_WIFI, true); - mPolicyListener.expect().onMeteredIfacesChanged(any()); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); - mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE})); + expectRemoveInterfaceQuota(TEST_IFACE); + expectSetInterfaceQuota(TEST_IFACE, 2 * MB_IN_BYTES); + + expectClearNotifications(); + expectAdvisePersistThreshold(); + future = expectMeteredIfacesChanged(TEST_IFACE); - verifyPolicyDataEnable(TYPE_WIFI, true); - verifyRemoveInterfaceQuota(TEST_IFACE); - verifySetInterfaceQuota(TEST_IFACE, 2 * MB_IN_BYTES); + replay(); + mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); + future.get(); + verifyAndReset(); } // go over warning, which should kick notification @@ -558,15 +702,18 @@ public class NetworkPolicyManagerServiceTest { { expectCurrentTime(); - when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, - currentTimeMillis())).thenReturn(stats.getTotalBytes()); + expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) + .andReturn(stats.getTotalBytes()).atLeastOnce(); + expectPolicyDataEnable(TYPE_WIFI, true); + + expectForceUpdate(); + expectClearNotifications(); tagFuture = expectEnqueueNotification(); + replay(); mNetworkObserver.limitReached(null, TEST_IFACE); - assertNotificationType(TYPE_WARNING, tagFuture.get()); - verifyPolicyDataEnable(TYPE_WIFI, true); - + verifyAndReset(); } // go over limit, which should kick notification and dialog @@ -576,14 +723,18 @@ public class NetworkPolicyManagerServiceTest { { expectCurrentTime(); - when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, - currentTimeMillis())).thenReturn(stats.getTotalBytes()); + expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) + .andReturn(stats.getTotalBytes()).atLeastOnce(); + expectPolicyDataEnable(TYPE_WIFI, false); + + expectForceUpdate(); + expectClearNotifications(); tagFuture = expectEnqueueNotification(); + replay(); mNetworkObserver.limitReached(null, TEST_IFACE); - assertNotificationType(TYPE_LIMIT, tagFuture.get()); - verifyPolicyDataEnable(TYPE_WIFI, false); + verifyAndReset(); } // now snooze policy, which should remove quota @@ -591,28 +742,35 @@ public class NetworkPolicyManagerServiceTest { { expectCurrentTime(); - when(mConnManager.getAllNetworkState()).thenReturn(state); - when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, - currentTimeMillis())).thenReturn(stats.getTotalBytes()); + expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); + expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) + .andReturn(stats.getTotalBytes()).atLeastOnce(); + expectPolicyDataEnable(TYPE_WIFI, true); + + // snoozed interface still has high quota so background data is + // still restricted. + expectRemoveInterfaceQuota(TEST_IFACE); + expectSetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE); + expectAdvisePersistThreshold(); + expectMeteredIfacesChanged(TEST_IFACE); + + future = expectClearNotifications(); tagFuture = expectEnqueueNotification(); - mPolicyListener.expect().onMeteredIfacesChanged(any()); + replay(); mService.snoozeLimit(sTemplateWifi); - mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE})); - assertNotificationType(TYPE_LIMIT_SNOOZED, tagFuture.get()); - // snoozed interface still has high quota so background data is - // still restricted. - verifyRemoveInterfaceQuota(TEST_IFACE); - verifySetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE); - verifyPolicyDataEnable(TYPE_WIFI, true); + future.get(); + verifyAndReset(); } } - @Test + @Suppress public void testMeteredNetworkWithoutLimit() throws Exception { NetworkState[] state = null; NetworkStats stats = null; + Future<Void> future; + Future<String> tagFuture; final long TIME_FEB_15 = 1171497600000L; final long TIME_MAR_10 = 1173484800000L; @@ -627,19 +785,24 @@ public class NetworkPolicyManagerServiceTest { { expectCurrentTime(); - when(mConnManager.getAllNetworkState()).thenReturn(state); - when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, - currentTimeMillis())).thenReturn(stats.getTotalBytes()); + expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); + expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) + .andReturn(stats.getTotalBytes()).atLeastOnce(); + expectPolicyDataEnable(TYPE_WIFI, true); + + expectRemoveInterfaceQuota(TEST_IFACE); + expectSetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE); - mPolicyListener.expect().onMeteredIfacesChanged(any()); + expectClearNotifications(); + expectAdvisePersistThreshold(); + future = expectMeteredIfacesChanged(TEST_IFACE); + + replay(); setNetworkPolicies(new NetworkPolicy( sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, true)); - mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE})); - - verifyPolicyDataEnable(TYPE_WIFI, true); - verifyRemoveInterfaceQuota(TEST_IFACE); - verifySetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE); + future.get(); + verifyAndReset(); } } @@ -662,36 +825,87 @@ public class NetworkPolicyManagerServiceTest { } private void expectCurrentTime() throws Exception { - when(mTime.forceRefresh()).thenReturn(false); - when(mTime.hasCache()).thenReturn(true); - when(mTime.currentTimeMillis()).thenReturn(currentTimeMillis()); - when(mTime.getCacheAge()).thenReturn(0L); - when(mTime.getCacheCertainty()).thenReturn(0L); + expect(mTime.forceRefresh()).andReturn(false).anyTimes(); + expect(mTime.hasCache()).andReturn(true).anyTimes(); + expect(mTime.currentTimeMillis()).andReturn(currentTimeMillis()).anyTimes(); + expect(mTime.getCacheAge()).andReturn(0L).anyTimes(); + expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes(); + } + + private void expectForceUpdate() throws Exception { + mStatsService.forceUpdate(); + expectLastCall().atLeastOnce(); + } + + private Future<Void> expectClearNotifications() throws Exception { + final FutureAnswer future = new FutureAnswer(); + mNotifManager.cancelNotificationWithTag( + isA(String.class), isA(String.class), anyInt(), anyInt()); + expectLastCall().andAnswer(future).anyTimes(); + return future; } private Future<String> expectEnqueueNotification() throws Exception { - final FutureAnswer<String> futureAnswer = new FutureAnswer<String>(2); - doAnswer(futureAnswer).when(mNotifManager).enqueueNotificationWithTag( - anyString(), anyString(), anyString() /* capture here (index 2)*/, - anyInt(), isA(Notification.class), isA(int[].class), anyInt()); - return futureAnswer; + final FutureCapture<String> tag = new FutureCapture<String>(); + mNotifManager.enqueueNotificationWithTag(isA(String.class), isA(String.class), + capture(tag.capture), anyInt(), + isA(Notification.class), isA(int[].class), UserHandle.myUserId()); + return tag; + } + + private void expectSetInterfaceQuota(String iface, long quotaBytes) throws Exception { + mNetworkManager.setInterfaceQuota(iface, quotaBytes); + expectLastCall().atLeastOnce(); + } + + private void expectRemoveInterfaceQuota(String iface) throws Exception { + mNetworkManager.removeInterfaceQuota(iface); + expectLastCall().atLeastOnce(); + } + + private void expectSetInterfaceAlert(String iface, long alertBytes) throws Exception { + mNetworkManager.setInterfaceAlert(iface, alertBytes); + expectLastCall().atLeastOnce(); + } + + private void expectRemoveInterfaceAlert(String iface) throws Exception { + mNetworkManager.removeInterfaceAlert(iface); + expectLastCall().atLeastOnce(); + } + + private void expectSetUidMeteredNetworkBlacklist(int uid, boolean rejectOnQuotaInterfaces) + throws Exception { + mNetworkManager.setUidMeteredNetworkBlacklist(uid, rejectOnQuotaInterfaces); + expectLastCall().atLeastOnce(); + } + + private void expectSetUidForeground(int uid, boolean uidForeground) throws Exception { + mStatsService.setUidForeground(uid, uidForeground); + expectLastCall().atLeastOnce(); } - private void verifySetInterfaceQuota(String iface, long quotaBytes) throws Exception { - verify(mNetworkManager, atLeastOnce()).setInterfaceQuota(iface, quotaBytes); + private Future<Void> expectRulesChanged(int uid, int policy) throws Exception { + final FutureAnswer future = new FutureAnswer(); + mPolicyListener.onUidRulesChanged(eq(uid), eq(policy)); + expectLastCall().andAnswer(future); + return future; } - private void verifyRemoveInterfaceQuota(String iface) throws Exception { - verify(mNetworkManager, atLeastOnce()).removeInterfaceQuota(iface); + private Future<Void> expectMeteredIfacesChanged(String... ifaces) throws Exception { + final FutureAnswer future = new FutureAnswer(); + mPolicyListener.onMeteredIfacesChanged(aryEq(ifaces)); + expectLastCall().andAnswer(future); + return future; } - private Future<Void> verifyPolicyDataEnable(int type, boolean enabled) throws Exception { + private Future<Void> expectPolicyDataEnable(int type, boolean enabled) throws Exception { // TODO: bring back this test return null; } - private void verifyAdvisePersistThreshold() throws Exception { - verify(mStatsService).advisePersistThreshold(anyLong()); + private void expectAdvisePersistThreshold() throws Exception { + mStatsService.advisePersistThreshold(anyLong()); + expectLastCall().anyTimes(); } private static class TestAbstractFuture<T> extends AbstractFuture<T> { @@ -705,21 +919,50 @@ public class NetworkPolicyManagerServiceTest { } } - private static class FutureAnswer<T> extends TestAbstractFuture<T> implements Answer<Void> { - private final int index; + private static class FutureAnswer extends TestAbstractFuture<Void> implements IAnswer<Void> { + @Override + public Void answer() { + set(null); + return null; + } + } + + private static class FutureCapture<T> extends TestAbstractFuture<T> { + public Capture<T> capture = new Capture<T>() { + @Override + public void setValue(T value) { + super.setValue(value); + set(value); + } + }; + } - FutureAnswer(int index) { - this.index = index; + private static class IdleFuture extends AbstractFuture<Void> implements IdleHandler { + @Override + public Void get() throws InterruptedException, ExecutionException { + try { + return get(5, TimeUnit.SECONDS); + } catch (TimeoutException e) { + throw new RuntimeException(e); + } } + @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - @SuppressWarnings("unchecked") - T captured = (T) invocation.getArguments()[index]; - set(captured); - return null; + public boolean queueIdle() { + set(null); + return false; } } + /** + * Wait until {@link #mService} internal {@link Handler} is idle. + */ + private IdleFuture expectIdle() { + final IdleFuture future = new IdleFuture(); + mService.addIdleHandler(future); + return future; + } + private static void assertTimeEquals(long expected, long actual) { if (expected != actual) { fail("expected " + formatTime(expected) + " but was actually " + formatTime(actual)); @@ -747,7 +990,7 @@ public class NetworkPolicyManagerServiceTest { } private static void assertNotificationType(int expected, String actualTag) { - assertEquals("notification type mismatch for '" + actualTag +"'", + assertEquals( Integer.toString(expected), actualTag.substring(actualTag.lastIndexOf(':') + 1)); } @@ -768,59 +1011,15 @@ public class NetworkPolicyManagerServiceTest { mElapsedRealtime += duration; } - /** - * Creates a mock and registers it to {@link LocalServices}. - */ - private static <T> T addLocalServiceMock(Class<T> clazz) { - final T mock = mock(clazz); - LocalServices.addService(clazz, mock); - return mock; + private void replay() { + EasyMock.replay(mActivityManager, mStatsService, mPolicyListener, mNetworkManager, mTime, + mConnManager, mNotifManager); } - /** - * Custom Mockito answer used to verify async {@link INetworkPolicyListener} calls. - * - * <p>Typical usage: - * <pre><code> - * mPolicyListener.expect().someCallback(any()); - * // do something on objects under test - * mPolicyListener.waitAndVerify().someCallback(eq(expectedValue)); - * </code></pre> - */ - final class NetworkPolicyListenerAnswer implements Answer<Void> { - private CountDownLatch latch; - private final INetworkPolicyListener listener; - - NetworkPolicyListenerAnswer(NetworkPolicyManagerService service) { - this.listener = mock(INetworkPolicyListener.class); - // RemoteCallbackList needs a binder to use as key - when(listener.asBinder()).thenReturn(new Binder()); - service.registerListener(listener); - } - - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - Log.d(TAG,"counting down on answer: " + invocation); - latch.countDown(); - return null; - } - - INetworkPolicyListener expect() { - assertNull("expect() called before waitAndVerify()", latch); - latch = new CountDownLatch(1); - return doAnswer(this).when(listener); - } - - INetworkPolicyListener waitAndVerify() { - assertNotNull("waitAndVerify() called before expect()", latch); - try { - assertTrue("callback not called in 5 seconds", latch.await(5, TimeUnit.SECONDS)); - } catch (InterruptedException e) { - fail("Thread interrupted before callback called"); - } finally { - latch = null; - } - return verify(listener, atLeastOnce()); - } + private void verifyAndReset() { + EasyMock.verify(mActivityManager, mStatsService, mPolicyListener, mNetworkManager, mTime, + mConnManager, mNotifManager); + EasyMock.reset(mActivityManager, mStatsService, mPolicyListener, mNetworkManager, mTime, + mConnManager, mNotifManager); } } diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java index aa491bbabd79..14b5cbeb9276 100644 --- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java +++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java @@ -19,7 +19,6 @@ package com.android.server.connectivity; import android.content.Context; import android.net.ConnectivityMetricsEvent; import android.net.IIpConnectivityMetrics; -import android.net.metrics.ApfProgramEvent; import android.net.metrics.ApfStats; import android.net.metrics.DefaultNetworkEvent; import android.net.metrics.DhcpClientEvent; @@ -113,27 +112,6 @@ public class IpConnectivityMetricsTest extends TestCase { assertEquals("", output3); } - public void testRateLimiting() { - final IpConnectivityLog logger = new IpConnectivityLog(mService.impl); - final ApfProgramEvent ev = new ApfProgramEvent(0, 0, 0, 0, 0); - final long fakeTimestamp = 1; - - int attempt = 100; // More than burst quota, but less than buffer size. - for (int i = 0; i < attempt; i++) { - logger.log(ev); - } - - String output1 = getdump("flush"); - assertFalse("".equals(output1)); - - for (int i = 0; i < attempt; i++) { - assertFalse("expected event to be dropped", logger.log(fakeTimestamp, ev)); - } - - String output2 = getdump("flush"); - assertEquals("", output2); - } - public void testEndToEndLogging() { IpConnectivityLog logger = new IpConnectivityLog(mService.impl); diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java deleted file mode 100644 index 813e92811881..000000000000 --- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.connectivity; - -import android.app.Notification; -import android.app.NotificationManager; -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.net.NetworkCapabilities; -import android.net.NetworkInfo; -import android.telephony.TelephonyManager; -import android.test.suitebuilder.annotation.SmallTest; -import com.android.server.connectivity.NetworkNotificationManager.NotificationType; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import junit.framework.TestCase; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.*; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class NetworkNotificationManagerTest extends TestCase { - - static final String NOTIFICATION_ID = NetworkNotificationManager.NOTIFICATION_ID; - - static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities(); - static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities(); - static { - CELL_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); - CELL_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - - WIFI_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); - WIFI_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - } - - @Mock Context mCtx; - @Mock Resources mResources; - @Mock PackageManager mPm; - @Mock TelephonyManager mTelephonyManager; - @Mock NotificationManager mNotificationManager; - @Mock NetworkAgentInfo mWifiNai; - @Mock NetworkAgentInfo mCellNai; - @Mock NetworkInfo mNetworkInfo; - ArgumentCaptor<Notification> mCaptor; - - NetworkNotificationManager mManager; - - public void setUp() { - MockitoAnnotations.initMocks(this); - mCaptor = ArgumentCaptor.forClass(Notification.class); - mWifiNai.networkCapabilities = WIFI_CAPABILITIES; - mWifiNai.networkInfo = mNetworkInfo; - mCellNai.networkCapabilities = CELL_CAPABILITIES; - mCellNai.networkInfo = mNetworkInfo; - when(mCtx.getResources()).thenReturn(mResources); - when(mCtx.getPackageManager()).thenReturn(mPm); - when(mCtx.getApplicationInfo()).thenReturn(new ApplicationInfo()); - when(mResources.getColor(anyInt(), any())).thenReturn(0xFF607D8B); - - mManager = new NetworkNotificationManager(mCtx, mTelephonyManager, mNotificationManager); - } - - @SmallTest - public void testNotificationsShownAndCleared() { - final int NETWORK_ID_BASE = 100; - List<NotificationType> types = Arrays.asList(NotificationType.values()); - List<Integer> ids = new ArrayList<>(types.size()); - for (int i = 0; i < ids.size(); i++) { - ids.add(NETWORK_ID_BASE + i); - } - Collections.shuffle(ids); - Collections.shuffle(types); - - for (int i = 0; i < ids.size(); i++) { - mManager.showNotification(ids.get(i), types.get(i), mWifiNai, mCellNai, null, false); - } - - Collections.shuffle(ids); - for (int i = 0; i < ids.size(); i++) { - mManager.clearNotification(ids.get(i)); - } - - for (int i = 0; i < ids.size(); i++) { - final int expectedId = NETWORK_ID_BASE + i; - verify(mNotificationManager, times(1)) - .notifyAsUser(eq(NOTIFICATION_ID), eq(expectedId), any(), any()); - verify(mNotificationManager, times(1)) - .cancelAsUser(eq(NOTIFICATION_ID), eq(expectedId), any()); - } - } - - @SmallTest - public void testNoInternetNotificationsNotShownForCellular() { - mManager.showNotification(100, NO_INTERNET, mCellNai, mWifiNai, null, false); - mManager.showNotification(101, LOST_INTERNET, mCellNai, mWifiNai, null, false); - - verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any()); - - mManager.showNotification(102, NO_INTERNET, mWifiNai, mCellNai, null, false); - - verify(mNotificationManager, times(1)) - .notifyAsUser(eq(NOTIFICATION_ID), eq(102), any(), any()); - } - - @SmallTest - public void testNotificationsNotShownIfNoInternetCapability() { - mWifiNai.networkCapabilities = new NetworkCapabilities(); - mWifiNai.networkCapabilities .addTransportType(NetworkCapabilities.TRANSPORT_WIFI); - mManager.showNotification(102, NO_INTERNET, mWifiNai, mCellNai, null, false); - mManager.showNotification(103, LOST_INTERNET, mWifiNai, mCellNai, null, false); - mManager.showNotification(104, NETWORK_SWITCH, mWifiNai, mCellNai, null, false); - - verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any()); - } -} |