Merge "Correct the calling method in removeDefaultNetworkActiveListener"
diff --git a/Tethering/bpf_progs/offload.c b/Tethering/bpf_progs/offload.c
index 336d27a..51fed76 100644
--- a/Tethering/bpf_progs/offload.c
+++ b/Tethering/bpf_progs/offload.c
@@ -80,7 +80,7 @@
} while(0)
#define TC_DROP(counter) COUNT_AND_RETURN(counter, TC_ACT_SHOT)
-#define TC_PUNT(counter) COUNT_AND_RETURN(counter, TC_ACT_OK)
+#define TC_PUNT(counter) COUNT_AND_RETURN(counter, TC_ACT_PIPE)
#define XDP_DROP(counter) COUNT_AND_RETURN(counter, XDP_DROP)
#define XDP_PUNT(counter) COUNT_AND_RETURN(counter, XDP_PASS)
@@ -108,10 +108,10 @@
static inline __always_inline int do_forward6(struct __sk_buff* skb, const bool is_ethernet,
const bool downstream) {
// Must be meta-ethernet IPv6 frame
- if (skb->protocol != htons(ETH_P_IPV6)) return TC_ACT_OK;
+ if (skb->protocol != htons(ETH_P_IPV6)) return TC_ACT_PIPE;
// Require ethernet dst mac address to be our unicast address.
- if (is_ethernet && (skb->pkt_type != PACKET_HOST)) return TC_ACT_OK;
+ if (is_ethernet && (skb->pkt_type != PACKET_HOST)) return TC_ACT_PIPE;
const int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0;
@@ -127,10 +127,10 @@
struct ipv6hdr* ip6 = is_ethernet ? (void*)(eth + 1) : data;
// Must have (ethernet and) ipv6 header
- if (data + l2_header_size + sizeof(*ip6) > data_end) return TC_ACT_OK;
+ if (data + l2_header_size + sizeof(*ip6) > data_end) return TC_ACT_PIPE;
// Ethertype - if present - must be IPv6
- if (is_ethernet && (eth->h_proto != htons(ETH_P_IPV6))) return TC_ACT_OK;
+ if (is_ethernet && (eth->h_proto != htons(ETH_P_IPV6))) return TC_ACT_PIPE;
// IP version must be 6
if (ip6->version != 6) TC_PUNT(INVALID_IP_VERSION);
@@ -182,7 +182,7 @@
: bpf_tether_upstream6_map_lookup_elem(&ku);
// If we don't find any offload information then simply let the core stack handle it...
- if (!v) return TC_ACT_OK;
+ if (!v) return TC_ACT_PIPE;
uint32_t stat_and_limit_k = downstream ? skb->ifindex : v->oif;
@@ -337,13 +337,13 @@
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_downstream6_rawip$stub", AID_ROOT, AID_NETWORK_STACK,
sched_cls_tether_downstream6_rawip_stub, KVER_NONE, KVER(5, 4, 0))
(struct __sk_buff* skb) {
- return TC_ACT_OK;
+ return TC_ACT_PIPE;
}
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_upstream6_rawip$stub", AID_ROOT, AID_NETWORK_STACK,
sched_cls_tether_upstream6_rawip_stub, KVER_NONE, KVER(5, 4, 0))
(struct __sk_buff* skb) {
- return TC_ACT_OK;
+ return TC_ACT_PIPE;
}
// ----- IPv4 Support -----
@@ -355,10 +355,10 @@
static inline __always_inline int do_forward4(struct __sk_buff* skb, const bool is_ethernet,
const bool downstream, const bool updatetime) {
// Require ethernet dst mac address to be our unicast address.
- if (is_ethernet && (skb->pkt_type != PACKET_HOST)) return TC_ACT_OK;
+ if (is_ethernet && (skb->pkt_type != PACKET_HOST)) return TC_ACT_PIPE;
// Must be meta-ethernet IPv4 frame
- if (skb->protocol != htons(ETH_P_IP)) return TC_ACT_OK;
+ if (skb->protocol != htons(ETH_P_IP)) return TC_ACT_PIPE;
const int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0;
@@ -374,10 +374,10 @@
struct iphdr* ip = is_ethernet ? (void*)(eth + 1) : data;
// Must have (ethernet and) ipv4 header
- if (data + l2_header_size + sizeof(*ip) > data_end) return TC_ACT_OK;
+ if (data + l2_header_size + sizeof(*ip) > data_end) return TC_ACT_PIPE;
// Ethertype - if present - must be IPv4
- if (is_ethernet && (eth->h_proto != htons(ETH_P_IP))) return TC_ACT_OK;
+ if (is_ethernet && (eth->h_proto != htons(ETH_P_IP))) return TC_ACT_PIPE;
// IP version must be 4
if (ip->version != 4) TC_PUNT(INVALID_IP_VERSION);
@@ -495,7 +495,7 @@
: bpf_tether_upstream4_map_lookup_elem(&k);
// If we don't find any offload information then simply let the core stack handle it...
- if (!v) return TC_ACT_OK;
+ if (!v) return TC_ACT_PIPE;
uint32_t stat_and_limit_k = downstream ? skb->ifindex : v->oif;
@@ -749,13 +749,13 @@
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_downstream4_rawip$stub", AID_ROOT, AID_NETWORK_STACK,
sched_cls_tether_downstream4_rawip_stub, KVER_NONE, KVER(5, 4, 0))
(struct __sk_buff* skb) {
- return TC_ACT_OK;
+ return TC_ACT_PIPE;
}
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_rawip$stub", AID_ROOT, AID_NETWORK_STACK,
sched_cls_tether_upstream4_rawip_stub, KVER_NONE, KVER(5, 4, 0))
(struct __sk_buff* skb) {
- return TC_ACT_OK;
+ return TC_ACT_PIPE;
}
// ETHER: 4.9-P/Q kernel
@@ -763,13 +763,13 @@
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_downstream4_ether$stub", AID_ROOT, AID_NETWORK_STACK,
sched_cls_tether_downstream4_ether_stub, KVER_NONE, KVER(4, 14, 0))
(struct __sk_buff* skb) {
- return TC_ACT_OK;
+ return TC_ACT_PIPE;
}
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_ether$stub", AID_ROOT, AID_NETWORK_STACK,
sched_cls_tether_upstream4_ether_stub, KVER_NONE, KVER(4, 14, 0))
(struct __sk_buff* skb) {
- return TC_ACT_OK;
+ return TC_ACT_PIPE;
}
// ----- XDP Support -----
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index 5b39a23..1df3e58 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -61,6 +61,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.modules.utils.build.SdkLevel;
+import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.NetworkStackConstants;
import com.android.net.module.util.Struct;
import com.android.net.module.util.netlink.ConntrackMessage;
@@ -131,6 +132,12 @@
@VisibleForTesting
static final int NF_CONNTRACK_UDP_TIMEOUT_STREAM = 180;
+ // List of TCP port numbers which aren't offloaded because the packets require the netfilter
+ // conntrack helper. See also TetherController::setForwardRules in netd.
+ @VisibleForTesting
+ static final short [] NON_OFFLOADED_UPSTREAM_IPV4_TCP_PORTS = new short [] {
+ 21 /* ftp */, 1723 /* pptp */};
+
@VisibleForTesting
enum StatsType {
STATS_PER_IFACE,
@@ -1556,7 +1563,15 @@
0 /* lastUsed, filled by bpf prog only */);
}
+ private boolean allowOffload(ConntrackEvent e) {
+ if (e.tupleOrig.protoNum != OsConstants.IPPROTO_TCP) return true;
+ return !CollectionUtils.contains(
+ NON_OFFLOADED_UPSTREAM_IPV4_TCP_PORTS, e.tupleOrig.dstPort);
+ }
+
public void accept(ConntrackEvent e) {
+ if (!allowOffload(e)) return;
+
final ClientInfo tetherClient = getClientInfo(e.tupleOrig.srcIp);
if (tetherClient == null) return;
diff --git a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
index 60fcfd0..4ca36df 100644
--- a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
+++ b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
@@ -70,7 +70,8 @@
@VisibleForTesting
protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
- private static final String ACTION_PROVISIONING_ALARM =
+ @VisibleForTesting
+ protected static final String ACTION_PROVISIONING_ALARM =
"com.android.networkstack.tethering.PROVISIONING_RECHECK_ALARM";
private final ComponentName mSilentProvisioningService;
@@ -410,20 +411,23 @@
return intent;
}
+ @VisibleForTesting
+ PendingIntent createRecheckAlarmIntent() {
+ final Intent intent = new Intent(ACTION_PROVISIONING_ALARM);
+ return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE);
+ }
+
// Not needed to check if this don't run on the handler thread because it's private.
- private void scheduleProvisioningRechecks(final TetheringConfiguration config) {
+ private void scheduleProvisioningRecheck(final TetheringConfiguration config) {
if (mProvisioningRecheckAlarm == null) {
final int period = config.provisioningCheckPeriod;
if (period <= 0) return;
- Intent intent = new Intent(ACTION_PROVISIONING_ALARM);
- mProvisioningRecheckAlarm = PendingIntent.getBroadcast(mContext, 0, intent,
- PendingIntent.FLAG_IMMUTABLE);
+ mProvisioningRecheckAlarm = createRecheckAlarmIntent();
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(
Context.ALARM_SERVICE);
- long periodMs = period * MS_PER_HOUR;
- long firstAlarmTime = SystemClock.elapsedRealtime() + periodMs;
- alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, firstAlarmTime, periodMs,
+ long triggerAtMillis = SystemClock.elapsedRealtime() + (period * MS_PER_HOUR);
+ alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtMillis,
mProvisioningRecheckAlarm);
}
}
@@ -437,6 +441,11 @@
}
}
+ private void rescheduleProvisioningRecheck(final TetheringConfiguration config) {
+ cancelTetherProvisioningRechecks();
+ scheduleProvisioningRecheck(config);
+ }
+
private void evaluateCellularPermission(final TetheringConfiguration config) {
final boolean permitted = isCellularUpstreamPermitted(config);
@@ -452,7 +461,7 @@
// Only schedule periodic re-check when tether is provisioned
// and the result is ok.
if (permitted && mCurrentEntitlementResults.size() > 0) {
- scheduleProvisioningRechecks(config);
+ scheduleProvisioningRecheck(config);
} else {
cancelTetherProvisioningRechecks();
}
@@ -493,6 +502,7 @@
if (ACTION_PROVISIONING_ALARM.equals(intent.getAction())) {
mLog.log("Received provisioning alarm");
final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
+ rescheduleProvisioningRecheck(config);
reevaluateSimCardProvisioning(config);
}
}
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index f1ddc6d..26297a2 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -17,6 +17,7 @@
package android.net;
import static android.Manifest.permission.ACCESS_NETWORK_STATE;
+import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.Manifest.permission.TETHER_PRIVILEGED;
@@ -121,9 +122,12 @@
@Before
public void setUp() throws Exception {
// Needed to create a TestNetworkInterface, to call requestTetheredInterface, and to receive
- // tethered client callbacks.
+ // tethered client callbacks. The restricted networks permission is needed to ensure that
+ // EthernetManager#isAvailable will correctly return true on devices where Ethernet is
+ // marked restricted, like cuttlefish.
mUiAutomation.adoptShellPermissionIdentity(
- MANAGE_TEST_NETWORKS, NETWORK_SETTINGS, TETHER_PRIVILEGED, ACCESS_NETWORK_STATE);
+ MANAGE_TEST_NETWORKS, NETWORK_SETTINGS, TETHER_PRIVILEGED, ACCESS_NETWORK_STATE,
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS);
mRunTests = mTm.isTetheringSupported() && mEm != null;
assumeTrue(mRunTests);
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
index 6e96085..acc042b 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
@@ -43,6 +43,7 @@
import static com.android.networkstack.tethering.BpfCoordinator.CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS;
import static com.android.networkstack.tethering.BpfCoordinator.NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED;
import static com.android.networkstack.tethering.BpfCoordinator.NF_CONNTRACK_UDP_TIMEOUT_STREAM;
+import static com.android.networkstack.tethering.BpfCoordinator.NON_OFFLOADED_UPSTREAM_IPV4_TCP_PORTS;
import static com.android.networkstack.tethering.BpfCoordinator.StatsType;
import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_IFACE;
import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_UID;
@@ -51,6 +52,7 @@
import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
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;
@@ -95,6 +97,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.NetworkStackConstants;
import com.android.net.module.util.Struct;
import com.android.net.module.util.netlink.ConntrackMessage;
@@ -1369,7 +1372,7 @@
}
@NonNull
- private ConntrackEvent makeTestConntrackEvent(short msgType, int proto) {
+ private ConntrackEvent makeTestConntrackEvent(short msgType, int proto, short remotePort) {
if (msgType != IPCTNL_MSG_CT_NEW && msgType != IPCTNL_MSG_CT_DELETE) {
fail("Not support message type " + msgType);
}
@@ -1383,13 +1386,18 @@
return new ConntrackEvent(
(short) (NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8 | msgType),
new Tuple(new TupleIpv4(PRIVATE_ADDR, REMOTE_ADDR),
- new TupleProto((byte) proto, PRIVATE_PORT, REMOTE_PORT)),
+ new TupleProto((byte) proto, PRIVATE_PORT, remotePort)),
new Tuple(new TupleIpv4(REMOTE_ADDR, PUBLIC_ADDR),
- new TupleProto((byte) proto, REMOTE_PORT, PUBLIC_PORT)),
+ new TupleProto((byte) proto, remotePort, PUBLIC_PORT)),
status,
timeoutSec);
}
+ @NonNull
+ private ConntrackEvent makeTestConntrackEvent(short msgType, int proto) {
+ return makeTestConntrackEvent(msgType, proto, REMOTE_PORT);
+ }
+
private void setUpstreamInformationTo(final BpfCoordinator coordinator) {
final LinkProperties lp = new LinkProperties();
lp.setInterfaceName(UPSTREAM_IFACE);
@@ -1563,14 +1571,14 @@
bpfMap.insertEntry(tcpKey, tcpValue);
bpfMap.insertEntry(udpKey, udpValue);
- // [1] Don't refresh contrack timeout.
+ // [1] Don't refresh conntrack timeout.
setElapsedRealtimeNanos(expiredTime);
mTestLooper.moveTimeForward(CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS);
waitForIdle();
ExtendedMockito.verifyNoMoreInteractions(staticMockMarker(NetlinkSocket.class));
ExtendedMockito.clearInvocations(staticMockMarker(NetlinkSocket.class));
- // [2] Refresh contrack timeout.
+ // [2] Refresh conntrack timeout.
setElapsedRealtimeNanos(validTime);
mTestLooper.moveTimeForward(CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS);
waitForIdle();
@@ -1587,7 +1595,7 @@
ExtendedMockito.verifyNoMoreInteractions(staticMockMarker(NetlinkSocket.class));
ExtendedMockito.clearInvocations(staticMockMarker(NetlinkSocket.class));
- // [3] Don't refresh contrack timeout if polling stopped.
+ // [3] Don't refresh conntrack timeout if polling stopped.
coordinator.stopPolling();
mTestLooper.moveTimeForward(CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS);
waitForIdle();
@@ -1629,4 +1637,39 @@
checkRefreshConntrackTimeout(bpfDownstream4Map, tcpKey, tcpValue, udpKey, udpValue);
}
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testNotAllowOffloadByConntrackMessageDestinationPort() throws Exception {
+ final BpfCoordinator coordinator = makeBpfCoordinator();
+ initBpfCoordinatorForRule4(coordinator);
+
+ final short offloadedPort = 42;
+ assertFalse(CollectionUtils.contains(NON_OFFLOADED_UPSTREAM_IPV4_TCP_PORTS,
+ offloadedPort));
+ mConsumer.accept(makeTestConntrackEvent(IPCTNL_MSG_CT_NEW, IPPROTO_TCP, offloadedPort));
+ verify(mBpfUpstream4Map).insertEntry(any(), any());
+ verify(mBpfDownstream4Map).insertEntry(any(), any());
+ clearInvocations(mBpfUpstream4Map, mBpfDownstream4Map);
+
+ for (final short port : NON_OFFLOADED_UPSTREAM_IPV4_TCP_PORTS) {
+ mConsumer.accept(makeTestConntrackEvent(IPCTNL_MSG_CT_NEW, IPPROTO_TCP, port));
+ verify(mBpfUpstream4Map, never()).insertEntry(any(), any());
+ verify(mBpfDownstream4Map, never()).insertEntry(any(), any());
+
+ mConsumer.accept(makeTestConntrackEvent(IPCTNL_MSG_CT_DELETE, IPPROTO_TCP, port));
+ verify(mBpfUpstream4Map, never()).deleteEntry(any());
+ verify(mBpfDownstream4Map, never()).deleteEntry(any());
+
+ mConsumer.accept(makeTestConntrackEvent(IPCTNL_MSG_CT_NEW, IPPROTO_UDP, port));
+ verify(mBpfUpstream4Map).insertEntry(any(), any());
+ verify(mBpfDownstream4Map).insertEntry(any(), any());
+ clearInvocations(mBpfUpstream4Map, mBpfDownstream4Map);
+
+ mConsumer.accept(makeTestConntrackEvent(IPCTNL_MSG_CT_DELETE, IPPROTO_UDP, port));
+ verify(mBpfUpstream4Map).deleteEntry(any());
+ verify(mBpfDownstream4Map).deleteEntry(any());
+ clearInvocations(mBpfUpstream4Map, mBpfDownstream4Map);
+ }
+ }
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
index 442be1e..46ce82c 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
@@ -43,14 +43,18 @@
import static org.junit.Assert.assertTrue;
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.Mockito.inOrder;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ModuleInfo;
@@ -63,6 +67,7 @@
import android.os.PersistableBundle;
import android.os.ResultReceiver;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.os.test.TestLooper;
import android.provider.DeviceConfig;
import android.provider.Settings;
@@ -91,6 +96,7 @@
private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app";
private static final String PROVISIONING_APP_RESPONSE = "app_response";
private static final String TEST_PACKAGE_NAME = "com.android.tethering.test";
+ private static final int RECHECK_TIMER_HOURS = 24;
@Mock private CarrierConfigManager mCarrierConfigManager;
@Mock private Context mContext;
@@ -98,12 +104,14 @@
@Mock private SharedLog mLog;
@Mock private PackageManager mPm;
@Mock private EntitlementManager.OnUiEntitlementFailedListener mEntitlementFailedListener;
+ @Mock private AlarmManager mAlarmManager;
+ @Mock private PendingIntent mAlarmIntent;
// Like so many Android system APIs, these cannot be mocked because it is marked final.
// We have to use the real versions.
private final PersistableBundle mCarrierConfig = new PersistableBundle();
private final TestLooper mLooper = new TestLooper();
- private Context mMockContext;
+ private MockContext mMockContext;
private Runnable mPermissionChangeCallback;
private WrappedEntitlementManager mEnMgr;
@@ -119,6 +127,13 @@
public Resources getResources() {
return mResources;
}
+
+ @Override
+ public Object getSystemService(String name) {
+ if (Context.ALARM_SERVICE.equals(name)) return mAlarmManager;
+
+ return super.getSystemService(name);
+ }
}
public class WrappedEntitlementManager extends EntitlementManager {
@@ -184,6 +199,11 @@
assertEquals(config.activeDataSubId,
intent.getIntExtra(EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID));
}
+
+ @Override
+ PendingIntent createRecheckAlarmIntent() {
+ return mAlarmIntent;
+ }
}
@Before
@@ -245,6 +265,8 @@
.thenReturn(PROVISIONING_NO_UI_APP_NAME);
when(mResources.getString(R.string.config_mobile_hotspot_provision_response)).thenReturn(
PROVISIONING_APP_RESPONSE);
+ when(mResources.getInteger(R.integer.config_mobile_hotspot_provision_check_period))
+ .thenReturn(RECHECK_TIMER_HOURS);
// Act like the CarrierConfigManager is present and ready unless told otherwise.
when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
.thenReturn(mCarrierConfigManager);
@@ -629,4 +651,31 @@
mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
assertFalse(mEnMgr.isCellularUpstreamPermitted());
}
+
+ private void sendProvisioningRecheckAlarm() {
+ final Intent intent = new Intent(EntitlementManager.ACTION_PROVISIONING_ALARM);
+ mMockContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ mLooper.dispatchAll();
+ }
+
+ @Test
+ public void testScheduleProvisioningReCheck() throws Exception {
+ setupForRequiredProvisioning();
+ assertFalse(mEnMgr.isCellularUpstreamPermitted());
+
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+ mEnMgr.notifyUpstream(true);
+ mLooper.dispatchAll();
+ mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
+ mLooper.dispatchAll();
+ assertTrue(mEnMgr.isCellularUpstreamPermitted());
+ verify(mAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), anyLong(),
+ eq(mAlarmIntent));
+ reset(mAlarmManager);
+
+ sendProvisioningRecheckAlarm();
+ verify(mAlarmManager).cancel(eq(mAlarmIntent));
+ verify(mAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), anyLong(),
+ eq(mAlarmIntent));
+ }
}
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 47bde72..9f63191 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -2311,9 +2311,7 @@
final ArrayList<NetworkStateSnapshot> result = new ArrayList<>();
for (Network network : getAllNetworks()) {
final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- // TODO: Consider include SUSPENDED networks, which should be considered as
- // temporary shortage of connectivity of a connected network.
- if (nai != null && nai.networkInfo.isConnected()) {
+ if (nai != null && nai.everConnected) {
// TODO (b/73321673) : NetworkStateSnapshot contains a copy of the
// NetworkCapabilities, which may contain UIDs of apps to which the
// network applies. Should the UIDs be cleared so as not to leak or
@@ -4622,9 +4620,16 @@
}
private void updateAvoidBadWifi() {
+ ensureRunningOnConnectivityServiceThread();
+ // Agent info scores and offer scores depend on whether cells yields to bad wifi.
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
nai.updateScoreForNetworkAgentUpdate();
}
+ // UpdateOfferScore will update mNetworkOffers inline, so make a copy first.
+ final ArrayList<NetworkOfferInfo> offersToUpdate = new ArrayList<>(mNetworkOffers);
+ for (final NetworkOfferInfo noi : offersToUpdate) {
+ updateOfferScore(noi.offer);
+ }
rematchAllNetworksAndRequests();
}
@@ -6413,11 +6418,23 @@
Objects.requireNonNull(score);
Objects.requireNonNull(caps);
Objects.requireNonNull(callback);
+ final boolean yieldToBadWiFi = caps.hasTransport(TRANSPORT_CELLULAR) && !avoidBadWifi();
final NetworkOffer offer = new NetworkOffer(
- FullScore.makeProspectiveScore(score, caps), caps, callback, providerId);
+ FullScore.makeProspectiveScore(score, caps, yieldToBadWiFi),
+ caps, callback, providerId);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_OFFER, offer));
}
+ private void updateOfferScore(final NetworkOffer offer) {
+ final boolean yieldToBadWiFi =
+ offer.caps.hasTransport(TRANSPORT_CELLULAR) && !avoidBadWifi();
+ final NetworkOffer newOffer = new NetworkOffer(
+ offer.score.withYieldToBadWiFi(yieldToBadWiFi),
+ offer.caps, offer.callback, offer.providerId);
+ if (offer.equals(newOffer)) return;
+ handleRegisterNetworkOffer(newOffer);
+ }
+
@Override
public void unofferNetwork(@NonNull final INetworkOfferCallback callback) {
mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_OFFER, callback));
@@ -6838,6 +6855,7 @@
* @param newOffer The new offer. If the callback member is the same as an existing
* offer, it is an update of that offer.
*/
+ // TODO : rename this to handleRegisterOrUpdateNetworkOffer
private void handleRegisterNetworkOffer(@NonNull final NetworkOffer newOffer) {
ensureRunningOnConnectivityServiceThread();
if (!isNetworkProviderWithIdRegistered(newOffer.providerId)) {
@@ -6852,6 +6870,14 @@
if (null != existingOffer) {
handleUnregisterNetworkOffer(existingOffer);
newOffer.migrateFrom(existingOffer.offer);
+ if (DBG) {
+ // handleUnregisterNetworkOffer has already logged the old offer
+ log("update offer from providerId " + newOffer.providerId + " new : " + newOffer);
+ }
+ } else {
+ if (DBG) {
+ log("register offer from providerId " + newOffer.providerId + " : " + newOffer);
+ }
}
final NetworkOfferInfo noi = new NetworkOfferInfo(newOffer);
try {
@@ -6866,6 +6892,9 @@
private void handleUnregisterNetworkOffer(@NonNull final NetworkOfferInfo noi) {
ensureRunningOnConnectivityServiceThread();
+ if (DBG) {
+ log("unregister offer from providerId " + noi.offer.providerId + " : " + noi.offer);
+ }
mNetworkOffers.remove(noi);
noi.offer.callback.asBinder().unlinkToDeath(noi, 0 /* flags */);
}
diff --git a/service/src/com/android/server/connectivity/FullScore.java b/service/src/com/android/server/connectivity/FullScore.java
index 14cec09..aebb80d 100644
--- a/service/src/com/android/server/connectivity/FullScore.java
+++ b/service/src/com/android/server/connectivity/FullScore.java
@@ -183,7 +183,7 @@
* @return a FullScore appropriate for comparing to actual network's scores.
*/
public static FullScore makeProspectiveScore(@NonNull final NetworkScore score,
- @NonNull final NetworkCapabilities caps) {
+ @NonNull final NetworkCapabilities caps, final boolean yieldToBadWiFi) {
// If the network offers Internet access, it may validate.
final boolean mayValidate = caps.hasCapability(NET_CAPABILITY_INTERNET);
// VPN transports are known in advance.
@@ -197,8 +197,6 @@
final boolean everUserSelected = false;
// Don't assume the user will accept unvalidated connectivity.
final boolean acceptUnvalidated = false;
- // Don't assume clinging to bad wifi
- final boolean yieldToBadWiFi = false;
// A prospective score is invincible if the legacy int in the filter is over the maximum
// score.
final boolean invincible = score.getLegacyInt() > NetworkRanker.LEGACY_INT_MAX;
@@ -259,6 +257,16 @@
}
/**
+ * Returns this score but with the specified yield to bad wifi policy.
+ */
+ public FullScore withYieldToBadWiFi(final boolean newYield) {
+ return new FullScore(mLegacyInt,
+ newYield ? mPolicies | (1L << POLICY_YIELD_TO_BAD_WIFI)
+ : mPolicies & ~(1L << POLICY_YIELD_TO_BAD_WIFI),
+ mKeepConnectedReason);
+ }
+
+ /**
* Returns this score but validated.
*/
public FullScore asValidated() {
diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
index bbf523a..6426f86 100644
--- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
@@ -1187,6 +1187,7 @@
? " underlying{" + Arrays.toString(declaredUnderlyingNetworks) + "}" : "")
+ " lp{" + linkProperties + "}"
+ " nc{" + networkCapabilities + "}"
+ + " factorySerialNumber=" + factorySerialNumber
+ "}";
}
diff --git a/service/src/com/android/server/connectivity/PermissionMonitor.java b/service/src/com/android/server/connectivity/PermissionMonitor.java
index 7c0fb91..f596c4a 100755
--- a/service/src/com/android/server/connectivity/PermissionMonitor.java
+++ b/service/src/com/android/server/connectivity/PermissionMonitor.java
@@ -74,11 +74,10 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Set;
/**
- * A utility class to inform Netd of UID permisisons.
+ * A utility class to inform Netd of UID permissions.
* Does a mass update at boot and then monitors for app install/remove.
*
* @hide
@@ -86,8 +85,6 @@
public class PermissionMonitor {
private static final String TAG = "PermissionMonitor";
private static final boolean DBG = true;
- protected static final Boolean SYSTEM = Boolean.TRUE;
- protected static final Boolean NETWORK = Boolean.FALSE;
private static final int VERSION_Q = Build.VERSION_CODES.Q;
private final PackageManager mPackageManager;
@@ -100,9 +97,9 @@
@GuardedBy("this")
private final Set<UserHandle> mUsers = new HashSet<>();
- // Keys are app uids. Values are true for SYSTEM permission and false for NETWORK permission.
+ // Keys are appIds. Values are true for SYSTEM permission and false for NETWORK permission.
@GuardedBy("this")
- private final Map<Integer, Boolean> mApps = new HashMap<>();
+ private final SparseIntArray mApps = new SparseIntArray();
// Keys are active non-bypassable and fully-routed VPN's interface name, Values are uid ranges
// for apps under the VPN
@@ -194,6 +191,23 @@
mContext = context;
}
+ private int getPackageNetdNetworkPermission(@NonNull final PackageInfo app) {
+ if (hasRestrictedNetworkPermission(app)) {
+ return PERMISSION_SYSTEM;
+ }
+ if (hasNetworkPermission(app)) {
+ return PERMISSION_NETWORK;
+ }
+ return PERMISSION_NONE;
+ }
+
+ static boolean isHigherNetworkPermission(final int targetPermission,
+ final int currentPermission) {
+ // This is relied on strict order of network permissions (SYSTEM > NETWORK > NONE), and it
+ // is enforced in tests.
+ return targetPermission > currentPermission;
+ }
+
// Intended to be called only once at startup, after the system is ready. Installs a broadcast
// receiver to monitor ongoing UID changes, so this shouldn't/needn't be called again.
public synchronized void startMonitoring() {
@@ -237,31 +251,25 @@
return;
}
- SparseIntArray netdPermsUids = new SparseIntArray();
+ final SparseIntArray netdPermsAppIds = new SparseIntArray();
for (PackageInfo app : apps) {
int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
if (uid < 0) {
continue;
}
- mAllApps.add(UserHandle.getAppId(uid));
+ final int appId = UserHandle.getAppId(uid);
+ mAllApps.add(appId);
- boolean isNetwork = hasNetworkPermission(app);
- boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
-
- if (isNetwork || hasRestrictedPermission) {
- Boolean permission = mApps.get(UserHandle.getAppId(uid));
- // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
- // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
- if (permission == null || permission == NETWORK) {
- mApps.put(UserHandle.getAppId(uid), hasRestrictedPermission);
- }
+ final int permission = getPackageNetdNetworkPermission(app);
+ if (isHigherNetworkPermission(permission, mApps.get(appId, PERMISSION_NONE))) {
+ mApps.put(appId, permission);
}
//TODO: unify the management of the permissions into one codepath.
int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions,
app.requestedPermissionsFlags);
- netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
+ netdPermsAppIds.put(appId, netdPermsAppIds.get(appId) | otherNetdPerms);
}
mUsers.addAll(mUserManager.getUserHandles(true /* excludeDying */));
@@ -275,13 +283,13 @@
final int[] hasPermissionUids =
mSystemConfigManager.getSystemPermissionUids(systemPermission);
for (int j = 0; j < hasPermissionUids.length; j++) {
- final int uid = hasPermissionUids[j];
- netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
+ final int appId = UserHandle.getAppId(hasPermissionUids[j]);
+ netdPermsAppIds.put(appId, netdPermsAppIds.get(appId) | netdPermission);
}
}
log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
update(mUsers, mApps, true);
- sendPackagePermissionsToNetd(netdPermsUids);
+ sendPackagePermissionsToNetd(netdPermsAppIds);
}
@VisibleForTesting
@@ -352,25 +360,29 @@
// networks. mApps contains the result of checks for both hasNetworkPermission and
// hasRestrictedNetworkPermission. If uid is in the mApps list that means uid has one of
// permissions at least.
- return mApps.containsKey(UserHandle.getAppId(uid));
+ return mApps.get(UserHandle.getAppId(uid), PERMISSION_NONE) != PERMISSION_NONE;
}
/**
* Returns whether the given uid has permission to use restricted networks.
*/
public synchronized boolean hasRestrictedNetworksPermission(int uid) {
- return Boolean.TRUE.equals(mApps.get(UserHandle.getAppId(uid)));
+ return PERMISSION_SYSTEM == mApps.get(UserHandle.getAppId(uid), PERMISSION_NONE);
}
- private void update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add) {
+ private void update(Set<UserHandle> users, SparseIntArray apps, boolean add) {
List<Integer> network = new ArrayList<>();
List<Integer> system = new ArrayList<>();
- for (Entry<Integer, Boolean> app : apps.entrySet()) {
- List<Integer> list = app.getValue() ? system : network;
+ for (int i = 0; i < apps.size(); i++) {
+ final int permission = apps.valueAt(i);
+ if (PERMISSION_NONE == permission) {
+ continue; // Normally NONE is not stored in this map, but just in case
+ }
+ List<Integer> list = (PERMISSION_SYSTEM == permission) ? system : network;
for (UserHandle user : users) {
if (user == null) continue;
- list.add(user.getUid(app.getKey()));
+ list.add(user.getUid(apps.keyAt(i)));
}
}
try {
@@ -395,10 +407,7 @@
*/
public synchronized void onUserAdded(@NonNull UserHandle user) {
mUsers.add(user);
-
- Set<UserHandle> users = new HashSet<>();
- users.add(user);
- update(users, mApps, true);
+ update(Set.of(user), mApps, true);
}
/**
@@ -410,10 +419,7 @@
*/
public synchronized void onUserRemoved(@NonNull UserHandle user) {
mUsers.remove(user);
-
- Set<UserHandle> users = new HashSet<>();
- users.add(user);
- update(users, mApps, false);
+ update(Set.of(user), mApps, false);
}
/**
@@ -425,17 +431,16 @@
* permission.
*/
@VisibleForTesting
- protected Boolean highestPermissionForUid(Boolean currentPermission, String name) {
- if (currentPermission == SYSTEM) {
+ protected int highestPermissionForUid(int currentPermission, String name) {
+ if (currentPermission == PERMISSION_SYSTEM) {
return currentPermission;
}
try {
final PackageInfo app = mPackageManager.getPackageInfo(name,
GET_PERMISSIONS | MATCH_ANY_USER);
- final boolean isNetwork = hasNetworkPermission(app);
- final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
- if (isNetwork || hasRestrictedPermission) {
- currentPermission = hasRestrictedPermission;
+ final int permission = getPackageNetdNetworkPermission(app);
+ if (isHigherNetworkPermission(permission, currentPermission)) {
+ return permission;
}
} catch (NameNotFoundException e) {
// App not found.
@@ -464,6 +469,17 @@
return permission;
}
+ private synchronized void updateVpnUid(int uid, boolean add) {
+ for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
+ if (UidRange.containsUid(vpn.getValue(), uid)) {
+ final Set<Integer> changedUids = new HashSet<>();
+ changedUids.add(uid);
+ removeBypassingUids(changedUids, -1 /* vpnAppUid */);
+ updateVpnUidsInterfaceRules(vpn.getKey(), changedUids, add);
+ }
+ }
+ }
+
/**
* Called when a package is added.
*
@@ -473,45 +489,37 @@
* @hide
*/
public synchronized void onPackageAdded(@NonNull final String packageName, final int uid) {
- // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
- // using appId instead of uid actually
- sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));
+ final int appId = UserHandle.getAppId(uid);
+ sendPackagePermissionsForAppId(appId, getPermissionForUid(uid));
// If multiple packages share a UID (cf: android:sharedUserId) and ask for different
// permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
- final int appId = UserHandle.getAppId(uid);
- final Boolean permission = highestPermissionForUid(mApps.get(appId), packageName);
- if (permission != mApps.get(appId)) {
+ final int currentPermission = mApps.get(appId, PERMISSION_NONE);
+ final int permission = highestPermissionForUid(currentPermission, packageName);
+ if (permission != currentPermission) {
mApps.put(appId, permission);
- Map<Integer, Boolean> apps = new HashMap<>();
+ SparseIntArray apps = new SparseIntArray();
apps.put(appId, permission);
update(mUsers, apps, true);
}
// If the newly-installed package falls within some VPN's uid range, update Netd with it.
- // This needs to happen after the mApps update above, since removeBypassingUids() depends
- // on mApps to check if the package can bypass VPN.
- for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
- if (UidRange.containsUid(vpn.getValue(), uid)) {
- final Set<Integer> changedUids = new HashSet<>();
- changedUids.add(uid);
- removeBypassingUids(changedUids, /* vpnAppUid */ -1);
- updateVpnUids(vpn.getKey(), changedUids, true);
- }
- }
+ // This needs to happen after the mApps update above, since removeBypassingUids() in
+ // updateVpnUid() depends on mApps to check if the package can bypass VPN.
+ updateVpnUid(uid, true /* add */);
mAllApps.add(appId);
}
- private Boolean highestUidNetworkPermission(int uid) {
- Boolean permission = null;
+ private int highestUidNetworkPermission(int uid) {
+ int permission = PERMISSION_NONE;
final String[] packages = mPackageManager.getPackagesForUid(uid);
if (!CollectionUtils.isEmpty(packages)) {
for (String name : packages) {
// If multiple packages have the same UID, give the UID all permissions that
// any package in that UID has.
permission = highestPermissionForUid(permission, name);
- if (permission == SYSTEM) {
+ if (permission == PERMISSION_SYSTEM) {
break;
}
}
@@ -528,46 +536,36 @@
* @hide
*/
public synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) {
- // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
- // using appId instead of uid actually
- sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));
+ final int appId = UserHandle.getAppId(uid);
+ sendPackagePermissionsForAppId(appId, getPermissionForUid(uid));
// If the newly-removed package falls within some VPN's uid range, update Netd with it.
- // This needs to happen before the mApps update below, since removeBypassingUids() depends
- // on mApps to check if the package can bypass VPN.
- for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
- if (UidRange.containsUid(vpn.getValue(), uid)) {
- final Set<Integer> changedUids = new HashSet<>();
- changedUids.add(uid);
- removeBypassingUids(changedUids, /* vpnAppUid */ -1);
- updateVpnUids(vpn.getKey(), changedUids, false);
- }
- }
+ // This needs to happen before the mApps update below, since removeBypassingUids() in
+ // updateVpnUid() depends on mApps to check if the package can bypass VPN.
+ updateVpnUid(uid, false /* add */);
// If the package has been removed from all users on the device, clear it form mAllApps.
if (mPackageManager.getNameForUid(uid) == null) {
- mAllApps.remove(UserHandle.getAppId(uid));
+ mAllApps.remove(appId);
}
- Map<Integer, Boolean> apps = new HashMap<>();
- final Boolean permission = highestUidNetworkPermission(uid);
- if (permission == SYSTEM) {
+ final int permission = highestUidNetworkPermission(uid);
+ if (permission == PERMISSION_SYSTEM) {
// An app with this UID still has the SYSTEM permission.
// Therefore, this UID must already have the SYSTEM permission.
// Nothing to do.
return;
}
+ // If the permissions of this UID have not changed, do nothing.
+ if (permission == mApps.get(appId, PERMISSION_NONE)) return;
- final int appId = UserHandle.getAppId(uid);
- if (permission == mApps.get(appId)) {
- // The permissions of this UID have not changed. Nothing to do.
- return;
- } else if (permission != null) {
+ final SparseIntArray apps = new SparseIntArray();
+ if (permission != PERMISSION_NONE) {
mApps.put(appId, permission);
apps.put(appId, permission);
update(mUsers, apps, true);
} else {
- mApps.remove(appId);
- apps.put(appId, NETWORK); // doesn't matter which permission we pick here
+ mApps.delete(appId);
+ apps.put(appId, PERMISSION_NETWORK); // doesn't matter which permission we pick here
update(mUsers, apps, false);
}
}
@@ -614,7 +612,7 @@
// but that's safe.
final Set<Integer> changedUids = intersectUids(rangesToAdd, mAllApps);
removeBypassingUids(changedUids, vpnAppUid);
- updateVpnUids(iface, changedUids, true);
+ updateVpnUidsInterfaceRules(iface, changedUids, true /* add */);
if (mVpnUidRanges.containsKey(iface)) {
mVpnUidRanges.get(iface).addAll(rangesToAdd);
} else {
@@ -635,7 +633,7 @@
// ranges and update Netd about them.
final Set<Integer> changedUids = intersectUids(rangesToRemove, mAllApps);
removeBypassingUids(changedUids, vpnAppUid);
- updateVpnUids(iface, changedUids, false);
+ updateVpnUidsInterfaceRules(iface, changedUids, false /* add */);
Set<UidRange> existingRanges = mVpnUidRanges.getOrDefault(iface, null);
if (existingRanges == null) {
loge("Attempt to remove unknown vpn uid Range iface = " + iface);
@@ -674,7 +672,7 @@
/**
* Remove all apps which can elect to bypass the VPN from the list of uids
*
- * An app can elect to bypass the VPN if it hold SYSTEM permission, or if its the active VPN
+ * An app can elect to bypass the VPN if it holds SYSTEM permission, or if it's the active VPN
* app itself.
*
* @param uids The list of uids to operate on
@@ -682,7 +680,8 @@
*/
private void removeBypassingUids(Set<Integer> uids, int vpnAppUid) {
uids.remove(vpnAppUid);
- uids.removeIf(uid -> mApps.getOrDefault(UserHandle.getAppId(uid), NETWORK) == SYSTEM);
+ uids.removeIf(uid ->
+ mApps.get(UserHandle.getAppId(uid), PERMISSION_NONE) == PERMISSION_SYSTEM);
}
/**
@@ -696,7 +695,7 @@
* @param add {@code true} if the uids are to be added to the interface, {@code false} if they
* are to be removed from the interface.
*/
- private void updateVpnUids(String iface, Set<Integer> uids, boolean add) {
+ private void updateVpnUidsInterfaceRules(String iface, Set<Integer> uids, boolean add) {
if (uids.size() == 0) {
return;
}
@@ -718,27 +717,25 @@
}
/**
- * Called by PackageListObserver when a package is installed/uninstalled. Send the updated
- * permission information to netd.
+ * Send the updated permission information to netd. Called upon package install/uninstall.
*
- * @param uid the app uid of the package installed
+ * @param appId the appId of the package installed
* @param permissions the permissions the app requested and netd cares about.
*
* @hide
*/
@VisibleForTesting
- void sendPackagePermissionsForUid(int uid, int permissions) {
+ void sendPackagePermissionsForAppId(int appId, int permissions) {
SparseIntArray netdPermissionsAppIds = new SparseIntArray();
- netdPermissionsAppIds.put(uid, permissions);
+ netdPermissionsAppIds.put(appId, permissions);
sendPackagePermissionsToNetd(netdPermissionsAppIds);
}
/**
- * Called by packageManagerService to send IPC to netd. Grant or revoke the INTERNET
- * and/or UPDATE_DEVICE_STATS permission of the uids in array.
+ * Grant or revoke the INTERNET and/or UPDATE_DEVICE_STATS permission of the appIds in array.
*
- * @param netdPermissionsAppIds integer pairs of uids and the permission granted to it. If the
- * permission is 0, revoke all permissions of that uid.
+ * @param netdPermissionsAppIds integer pairs of appIds and the permission granted to it. If the
+ * permission is 0, revoke all permissions of that appId.
*
* @hide
*/
@@ -816,17 +813,18 @@
updateUidsAllowedOnRestrictedNetworks(mDeps.getUidsAllowedOnRestrictedNetworks(mContext));
uidsToUpdate.addAll(mUidsAllowedOnRestrictedNetworks);
- final Map<Integer, Boolean> updatedUids = new HashMap<>();
- final Map<Integer, Boolean> removedUids = new HashMap<>();
+ final SparseIntArray updatedUids = new SparseIntArray();
+ final SparseIntArray removedUids = new SparseIntArray();
// Step2. For each uid to update, find out its new permission.
for (Integer uid : uidsToUpdate) {
- final Boolean permission = highestUidNetworkPermission(uid);
+ final int permission = highestUidNetworkPermission(uid);
final int appId = UserHandle.getAppId(uid);
- if (null == permission) {
- removedUids.put(appId, NETWORK); // Doesn't matter which permission is set here.
- mApps.remove(appId);
+ if (PERMISSION_NONE == permission) {
+ // Doesn't matter which permission is set here.
+ removedUids.put(appId, PERMISSION_NETWORK);
+ mApps.delete(appId);
} else {
updatedUids.put(appId, permission);
mApps.put(appId, permission);
diff --git a/tests/cts/net/src/android/net/cts/AirplaneModeTest.java b/tests/cts/net/src/android/net/cts/AirplaneModeTest.java
deleted file mode 100644
index 524e549..0000000
--- a/tests/cts/net/src/android/net/cts/AirplaneModeTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.cts;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.platform.test.annotations.AppModeFull;
-import android.provider.Settings;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import java.lang.Thread;
-
-@AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
-public class AirplaneModeTest extends AndroidTestCase {
- private static final String TAG = "AirplaneModeTest";
- private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
- private static final String FEATURE_WIFI = "android.hardware.wifi";
- private static final int TIMEOUT_MS = 10 * 1000;
- private boolean mHasFeature;
- private Context mContext;
- private ContentResolver resolver;
-
- public void setup() {
- mContext= getContext();
- resolver = mContext.getContentResolver();
- mHasFeature = (mContext.getPackageManager().hasSystemFeature(FEATURE_BLUETOOTH)
- || mContext.getPackageManager().hasSystemFeature(FEATURE_WIFI));
- }
-
- public void testAirplaneMode() {
- setup();
- if (!mHasFeature) {
- Log.i(TAG, "The device doesn't support network bluetooth or wifi feature");
- return;
- }
-
- for (int testCount = 0; testCount < 2; testCount++) {
- if (!doOneTest()) {
- fail("Airplane mode failed to change in " + TIMEOUT_MS + "msec");
- return;
- }
- }
- }
-
- private boolean doOneTest() {
- boolean airplaneModeOn = isAirplaneModeOn();
- setAirplaneModeOn(!airplaneModeOn);
-
- try {
- Thread.sleep(TIMEOUT_MS);
- } catch (InterruptedException e) {
- Log.e(TAG, "Sleep time interrupted.", e);
- }
-
- if (airplaneModeOn == isAirplaneModeOn()) {
- return false;
- }
- return true;
- }
-
- private void setAirplaneModeOn(boolean enabling) {
- // Change the system setting for airplane mode
- Settings.Global.putInt(resolver, Settings.Global.AIRPLANE_MODE_ON, enabling ? 1 : 0);
- }
-
- private boolean isAirplaneModeOn() {
- // Read the system setting for airplane mode
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
- }
-}
diff --git a/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java b/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
index 4d60279..80951ca 100644
--- a/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
@@ -17,6 +17,7 @@
package android.net.cts;
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
+import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
import static androidx.test.InstrumentationRegistry.getContext;
@@ -28,9 +29,11 @@
import static org.junit.Assert.fail;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.cts.util.CtsNetUtils;
+import android.net.wifi.WifiManager;
import android.os.BatteryStatsManager;
import android.os.Build;
import android.os.connectivity.CellularBatteryStats;
@@ -72,6 +75,8 @@
private Context mContext;
private BatteryStatsManager mBsm;
private ConnectivityManager mCm;
+ private WifiManager mWm;
+ private PackageManager mPm;
private CtsNetUtils mCtsNetUtils;
@Before
@@ -79,9 +84,14 @@
mContext = getContext();
mBsm = mContext.getSystemService(BatteryStatsManager.class);
mCm = mContext.getSystemService(ConnectivityManager.class);
+ mWm = mContext.getSystemService(WifiManager.class);
+ mPm = mContext.getPackageManager();
mCtsNetUtils = new CtsNetUtils(mContext);
}
+ // reportNetworkInterfaceForTransports classifies one network interface as wifi or mobile, so
+ // check that the interface is classified properly by checking the data usage is reported
+ // properly.
@Test
@AppModeFull(reason = "Cannot get CHANGE_NETWORK_STATE to request wifi/cell in instant mode")
@SkipPresubmit(reason = "Virtual hardware does not support wifi battery stats")
@@ -108,42 +118,9 @@
// Make sure wifi is disabled.
mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */);
- final Network cellNetwork = mCtsNetUtils.connectToCell();
- final URL url = new URL(TEST_URL);
+ verifyGetCellBatteryStats();
+ verifyGetWifiBatteryStats();
- // Get cellular battery stats
- CellularBatteryStats cellularStatsBefore = runAsShell(UPDATE_DEVICE_STATS,
- mBsm::getCellularBatteryStats);
-
- // Generate traffic on cellular network.
- Log.d(TAG, "Generate traffic on cellular network.");
- generateNetworkTraffic(cellNetwork, url);
-
- // The mobile battery stats are updated when a network stops being the default network.
- // ConnectivityService will call BatteryStatsManager.reportMobileRadioPowerState when
- // removing data activity tracking.
- final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
-
- // Check cellular battery stats are updated.
- runAsShell(UPDATE_DEVICE_STATS,
- () -> assertStatsEventually(mBsm::getCellularBatteryStats,
- cellularStatsAfter -> cellularBatteryStatsIncreased(
- cellularStatsBefore, cellularStatsAfter)));
-
- WifiBatteryStats wifiStatsBefore = runAsShell(UPDATE_DEVICE_STATS,
- mBsm::getWifiBatteryStats);
-
- // Generate traffic on wifi network.
- Log.d(TAG, "Generate traffic on wifi network.");
- generateNetworkTraffic(wifiNetwork, url);
- // Wifi battery stats are updated when wifi on.
- mCtsNetUtils.toggleWifi();
-
- // Check wifi battery stats are updated.
- runAsShell(UPDATE_DEVICE_STATS,
- () -> assertStatsEventually(mBsm::getWifiBatteryStats,
- wifiStatsAfter -> wifiBatteryStatsIncreased(wifiStatsBefore,
- wifiStatsAfter)));
} finally {
// Reset battery settings.
executeShellCommand("dumpsys batterystats disable no-auto-reset");
@@ -151,6 +128,62 @@
}
}
+ private void verifyGetCellBatteryStats() throws Exception {
+ final boolean isTelephonySupported = mPm.hasSystemFeature(FEATURE_TELEPHONY);
+
+ if (!isTelephonySupported) {
+ Log.d(TAG, "Skip cell battery stats test because device does not support telephony.");
+ return;
+ }
+
+ final Network cellNetwork = mCtsNetUtils.connectToCell();
+ final URL url = new URL(TEST_URL);
+
+ // Get cellular battery stats
+ CellularBatteryStats cellularStatsBefore = runAsShell(UPDATE_DEVICE_STATS,
+ mBsm::getCellularBatteryStats);
+
+ // Generate traffic on cellular network.
+ Log.d(TAG, "Generate traffic on cellular network.");
+ generateNetworkTraffic(cellNetwork, url);
+
+ // The mobile battery stats are updated when a network stops being the default network.
+ // ConnectivityService will call BatteryStatsManager.reportMobileRadioPowerState when
+ // removing data activity tracking.
+ mCtsNetUtils.ensureWifiConnected();
+
+ // Check cellular battery stats are updated.
+ runAsShell(UPDATE_DEVICE_STATS,
+ () -> assertStatsEventually(mBsm::getCellularBatteryStats,
+ cellularStatsAfter -> cellularBatteryStatsIncreased(
+ cellularStatsBefore, cellularStatsAfter)));
+ }
+
+ private void verifyGetWifiBatteryStats() throws Exception {
+ final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
+ final URL url = new URL(TEST_URL);
+
+ if (!mWm.isEnhancedPowerReportingSupported()) {
+ Log.d(TAG, "Skip wifi stats test because wifi does not support link layer stats.");
+ return;
+ }
+
+ WifiBatteryStats wifiStatsBefore = runAsShell(UPDATE_DEVICE_STATS,
+ mBsm::getWifiBatteryStats);
+
+ // Generate traffic on wifi network.
+ Log.d(TAG, "Generate traffic on wifi network.");
+ generateNetworkTraffic(wifiNetwork, url);
+ // Wifi battery stats are updated when wifi on.
+ mCtsNetUtils.toggleWifi();
+
+ // Check wifi battery stats are updated.
+ runAsShell(UPDATE_DEVICE_STATS,
+ () -> assertStatsEventually(mBsm::getWifiBatteryStats,
+ wifiStatsAfter -> wifiBatteryStatsIncreased(wifiStatsBefore,
+ wifiStatsAfter)));
+ }
+
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
index 9f079c4..9f98e3f 100644
--- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
+++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
@@ -46,6 +46,7 @@
import android.provider.DeviceConfig
import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY
import android.text.TextUtils
+import android.util.Log
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.RecorderCallback
@@ -79,6 +80,8 @@
private const val WIFI_CONNECT_TIMEOUT_MS = 120_000L
private const val TEST_TIMEOUT_MS = 10_000L
+private const val TAG = "CaptivePortalTest"
+
private fun <T> CompletableFuture<T>.assertGet(timeoutMs: Long, message: String): T {
try {
return get(timeoutMs, TimeUnit.MILLISECONDS)
@@ -155,6 +158,7 @@
server.addResponse(Request(TEST_HTTP_URL_PATH), Status.REDIRECT, headers)
setHttpsUrlDeviceConfig(makeUrl(TEST_HTTPS_URL_PATH))
setHttpUrlDeviceConfig(makeUrl(TEST_HTTP_URL_PATH))
+ Log.d(TAG, "Set portal URLs to $TEST_HTTPS_URL_PATH and $TEST_HTTP_URL_PATH")
// URL expiration needs to be in the next 10 minutes
assertTrue(WIFI_CONNECT_TIMEOUT_MS < TimeUnit.MINUTES.toMillis(10))
setUrlExpirationDeviceConfig(System.currentTimeMillis() + WIFI_CONNECT_TIMEOUT_MS)
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 65dffbd..f5c43d6 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -119,10 +119,8 @@
import android.net.NetworkInfo.State;
import android.net.NetworkProvider;
import android.net.NetworkRequest;
-import android.net.NetworkScore;
import android.net.NetworkSpecifier;
import android.net.NetworkStateSnapshot;
-import android.net.NetworkUtils;
import android.net.OemNetworkPreferences;
import android.net.ProxyInfo;
import android.net.SocketKeepalive;
@@ -260,6 +258,7 @@
"config_allowedUnprivilegedKeepalivePerUid";
private static final String KEEPALIVE_RESERVED_PER_SLOT_RES_NAME =
"config_reservedPrivilegedKeepaliveSlots";
+ private static final String TEST_RESTRICTED_NW_IFACE_NAME = "test-restricted-nw";
private static final LinkAddress TEST_LINKADDR = new LinkAddress(
InetAddresses.parseNumericAddress("2001:db8::8"), 64);
@@ -1082,7 +1081,8 @@
}
private Network waitForActiveNetworkMetered(final int targetTransportType,
- final boolean requestedMeteredness, final boolean useSystemDefault)
+ final boolean requestedMeteredness, final boolean waitForValidation,
+ final boolean useSystemDefault)
throws Exception {
final CompletableFuture<Network> networkFuture = new CompletableFuture<>();
final NetworkCallback networkCallback = new NetworkCallback() {
@@ -1091,7 +1091,8 @@
if (!nc.hasTransport(targetTransportType)) return;
final boolean metered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED);
- if (metered == requestedMeteredness) {
+ final boolean validated = nc.hasCapability(NET_CAPABILITY_VALIDATED);
+ if (metered == requestedMeteredness && (!waitForValidation || validated)) {
networkFuture.complete(network);
}
}
@@ -1120,11 +1121,13 @@
}
}
- private Network setWifiMeteredStatusAndWait(String ssid, boolean isMetered) throws Exception {
+ private Network setWifiMeteredStatusAndWait(String ssid, boolean isMetered,
+ boolean waitForValidation) throws Exception {
setWifiMeteredStatus(ssid, Boolean.toString(isMetered) /* metered */);
mCtsNetUtils.ensureWifiConnected();
return waitForActiveNetworkMetered(TRANSPORT_WIFI,
isMetered /* requestedMeteredness */,
+ waitForValidation,
true /* useSystemDefault */);
}
@@ -1187,9 +1190,10 @@
int newMeteredPreference = findNextPrefValue(resolver);
Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
Integer.toString(newMeteredPreference));
- // Wifi meterness changes from unmetered to metered will disconnect and reconnect since
- // R.
- final Network network = setWifiMeteredStatusAndWait(ssid, true);
+ // Wifi meteredness changes from unmetered to metered will disconnect and reconnect
+ // since R.
+ final Network network = setWifiMeteredStatusAndWait(ssid, true /* isMetered */,
+ false /* waitForValidation */);
assertEquals(ssid, unquoteSSID(mWifiManager.getConnectionInfo().getSSID()));
assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
NET_CAPABILITY_NOT_METERED), false);
@@ -1206,7 +1210,7 @@
oldMeteredPreference, newMeteredPreference);
// No disconnect from unmetered to metered.
- setWifiMeteredStatusAndWait(ssid, false);
+ setWifiMeteredStatusAndWait(ssid, false /* isMetered */, false /* waitForValidation */);
assertEquals(mCm.getNetworkCapabilities(network).hasCapability(
NET_CAPABILITY_NOT_METERED), true);
assertMultipathPreferenceIsEventually(network, newMeteredPreference,
@@ -1748,6 +1752,40 @@
greater >= lesser);
}
+ private void verifyBindSocketToRestrictedNetworkDisallowed() throws Exception {
+ final TestableNetworkCallback testNetworkCb = new TestableNetworkCallback();
+ final NetworkRequest testRequest = new NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(
+ TEST_RESTRICTED_NW_IFACE_NAME))
+ .build();
+ runWithShellPermissionIdentity(() -> requestNetwork(testRequest, testNetworkCb),
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS,
+ // CONNECTIVITY_INTERNAL is for requesting restricted network because shell does not
+ // have CONNECTIVITY_USE_RESTRICTED_NETWORKS on R.
+ CONNECTIVITY_INTERNAL);
+
+ // Create a restricted network and ensure this package cannot bind to that network either.
+ final NetworkAgent agent = createRestrictedNetworkAgent(mContext);
+ final Network network = agent.getNetwork();
+
+ try (Socket socket = new Socket()) {
+ // Verify that the network is restricted.
+ testNetworkCb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
+ NETWORK_CALLBACK_TIMEOUT_MS,
+ entry -> network.equals(entry.getNetwork())
+ && (!((CallbackEntry.CapabilitiesChanged) entry).getCaps()
+ .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)));
+ // CtsNetTestCases package doesn't hold CONNECTIVITY_USE_RESTRICTED_NETWORKS, so it
+ // does not allow to bind socket to restricted network.
+ assertThrows(IOException.class, () -> network.bindSocket(socket));
+ } finally {
+ agent.unregister();
+ }
+ }
+
/**
* Verifies that apps are not allowed to access restricted networks even if they declare the
* CONNECTIVITY_USE_RESTRICTED_NETWORKS permission in their manifests.
@@ -1764,23 +1802,33 @@
assertTrue(index >= 0);
assertTrue(app.requestedPermissionsFlags[index] != PERMISSION_GRANTED);
- // Ensure that NetworkUtils.queryUserAccess always returns false since this package should
- // not have netd system permission to call this function.
- final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
- assertFalse(NetworkUtils.queryUserAccess(Binder.getCallingUid(), wifiNetwork.netId));
+ if (mPackageManager.hasSystemFeature(FEATURE_WIFI)) {
+ // Expect binding to the wifi network to succeed.
+ final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected();
+ try (Socket socket = new Socket()) {
+ wifiNetwork.bindSocket(socket);
+ }
+ }
// Ensure that this package cannot bind to any restricted network that's currently
// connected.
Network[] networks = mCm.getAllNetworks();
for (Network network : networks) {
- NetworkCapabilities nc = mCm.getNetworkCapabilities(network);
- if (nc != null && !nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
- try {
- network.bindSocket(new Socket());
- fail("Bind to restricted network " + network + " unexpectedly succeeded");
- } catch (IOException expected) {}
+ final NetworkCapabilities nc = mCm.getNetworkCapabilities(network);
+ if (nc == null) {
+ continue;
+ }
+
+ try (Socket socket = new Socket()) {
+ if (nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
+ network.bindSocket(socket); // binding should succeed
+ } else {
+ assertThrows(IOException.class, () -> network.bindSocket(socket));
+ }
}
}
+
+ verifyBindSocketToRestrictedNetworkDisallowed();
}
/**
@@ -2322,8 +2370,10 @@
final boolean oldMeteredValue = wifiNetworkCapabilities.isMetered();
try {
- // This network will be used for unmetered.
- setWifiMeteredStatusAndWait(ssid, false /* isMetered */);
+ // This network will be used for unmetered. Wait for it to be validated because
+ // OEM_NETWORK_PREFERENCE_TEST only prefers NOT_METERED&VALIDATED to a network with
+ // TRANSPORT_TEST, like OEM_NETWORK_PREFERENCE_OEM_PAID.
+ setWifiMeteredStatusAndWait(ssid, false /* isMetered */, true /* waitForValidation */);
setOemNetworkPreferenceForMyPackage(OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST);
registerTestOemNetworkPreferenceCallbacks(defaultCallback, systemDefaultCallback);
@@ -2332,9 +2382,10 @@
waitForAvailable(defaultCallback, wifiNetwork);
waitForAvailable(systemDefaultCallback, wifiNetwork);
- // Validate when setting unmetered to metered, unmetered is lost and replaced by the
- // network with the TEST transport.
- setWifiMeteredStatusAndWait(ssid, true /* isMetered */);
+ // Validate that when setting unmetered to metered, unmetered is lost and replaced by
+ // the network with the TEST transport. Also wait for validation here, in case there
+ // is a bug that's only visible when the network is validated.
+ setWifiMeteredStatusAndWait(ssid, true /* isMetered */, true /* waitForValidation */);
defaultCallback.expectCallback(CallbackEntry.LOST, wifiNetwork,
NETWORK_CALLBACK_TIMEOUT_MS);
waitForAvailable(defaultCallback, tnt.getNetwork());
@@ -2350,7 +2401,7 @@
NETWORK_CALLBACK_TIMEOUT_MS);
waitForAvailable(defaultCallback);
- setWifiMeteredStatusAndWait(ssid, oldMeteredValue);
+ setWifiMeteredStatusAndWait(ssid, oldMeteredValue, false /* waitForValidation */);
// Cleanup any prior test state from setOemNetworkPreference
clearOemNetworkPreference();
@@ -2832,6 +2883,24 @@
}
}
+ private static NetworkAgent createRestrictedNetworkAgent(final Context context) {
+ // Create test network agent with restricted network.
+ final NetworkCapabilities nc = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(
+ TEST_RESTRICTED_NW_IFACE_NAME))
+ .build();
+ final NetworkAgent agent = new NetworkAgent(context, Looper.getMainLooper(), TAG, nc,
+ new LinkProperties(), 10 /* score */, new NetworkAgentConfig.Builder().build(),
+ new NetworkProvider(context, Looper.getMainLooper(), TAG)) {};
+ runWithShellPermissionIdentity(() -> agent.register(),
+ android.Manifest.permission.MANAGE_TEST_NETWORKS);
+ agent.markConnected();
+
+ return agent;
+ }
+
@AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
@Test
public void testUidsAllowedOnRestrictedNetworks() throws Exception {
@@ -2852,42 +2921,27 @@
ConnectivitySettingsManager.setUidsAllowedOnRestrictedNetworks(
mContext, originalUidsAllowedOnRestrictedNetworks), NETWORK_SETTINGS);
- final Handler h = new Handler(Looper.getMainLooper());
final TestableNetworkCallback testNetworkCb = new TestableNetworkCallback();
- registerBestMatchingNetworkCallback(new NetworkRequest.Builder().clearCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_TEST).build(), testNetworkCb, h);
-
- // Create test network agent with restricted network.
- final NetworkCapabilities nc = new NetworkCapabilities.Builder()
+ final NetworkRequest testRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_TEST)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .setNetworkSpecifier(CompatUtil.makeTestNetworkSpecifier(
+ TEST_RESTRICTED_NW_IFACE_NAME))
.build();
- final NetworkScore score = new NetworkScore.Builder()
- .setExiting(false)
- .setTransportPrimary(false)
- .setKeepConnectedReason(NetworkScore.KEEP_CONNECTED_FOR_HANDOVER)
- .build();
- final NetworkAgent agent = new NetworkAgent(mContext, Looper.getMainLooper(),
- TAG, nc, new LinkProperties(), score, new NetworkAgentConfig.Builder().build(),
- new NetworkProvider(mContext, Looper.getMainLooper(), TAG)) {};
- runWithShellPermissionIdentity(() -> agent.register(),
- android.Manifest.permission.MANAGE_TEST_NETWORKS);
- agent.markConnected();
+ runWithShellPermissionIdentity(() -> requestNetwork(testRequest, testNetworkCb),
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ final NetworkAgent agent = createRestrictedNetworkAgent(mContext);
final Network network = agent.getNetwork();
try (Socket socket = new Socket()) {
- testNetworkCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
- entry -> network.equals(entry.getNetwork()));
// Verify that the network is restricted.
- final NetworkCapabilities testNetworkNc = mCm.getNetworkCapabilities(network);
- assertNotNull(testNetworkNc);
- assertFalse(testNetworkNc.hasCapability(
- NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED));
+ testNetworkCb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
+ NETWORK_CALLBACK_TIMEOUT_MS,
+ entry -> network.equals(entry.getNetwork())
+ && (!((CallbackEntry.CapabilitiesChanged) entry).getCaps()
+ .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)));
// CtsNetTestCases package doesn't hold CONNECTIVITY_USE_RESTRICTED_NETWORKS, so it
// does not allow to bind socket to restricted network.
assertThrows(IOException.class, () -> network.bindSocket(socket));
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index 7c380e3..1a131d8 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -1072,6 +1072,7 @@
Executors.newSingleThreadExecutor().let { executor ->
try {
val info = QosSocketInfo(agent.network!!, socket)
+ assertEquals(agent.network, info.getNetwork())
mCM.registerQosCallback(info, executor, qosCallback)
val callbackId = agent.expectCallback<OnRegisterQosCallback>().callbackId
diff --git a/tests/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/integration/util/com/android/server/NetworkAgentWrapper.java
index 95ea401..970b7d2 100644
--- a/tests/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -83,6 +83,12 @@
public NetworkAgentWrapper(int transport, LinkProperties linkProperties,
NetworkCapabilities ncTemplate, Context context) throws Exception {
+ this(transport, linkProperties, ncTemplate, null /* provider */, context);
+ }
+
+ public NetworkAgentWrapper(int transport, LinkProperties linkProperties,
+ NetworkCapabilities ncTemplate, NetworkProvider provider,
+ Context context) throws Exception {
final int type = transportToLegacyType(transport);
final String typeName = ConnectivityManager.getNetworkTypeName(type);
mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
@@ -124,12 +130,12 @@
.setLegacyTypeName(typeName)
.setLegacyExtraInfo(extraInfo)
.build();
- mNetworkAgent = makeNetworkAgent(linkProperties, mNetworkAgentConfig);
+ mNetworkAgent = makeNetworkAgent(linkProperties, mNetworkAgentConfig, provider);
}
protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties,
- final NetworkAgentConfig nac) throws Exception {
- return new InstrumentedNetworkAgent(this, linkProperties, nac);
+ final NetworkAgentConfig nac, NetworkProvider provider) throws Exception {
+ return new InstrumentedNetworkAgent(this, linkProperties, nac, provider);
}
public static class InstrumentedNetworkAgent extends NetworkAgent {
@@ -138,10 +144,15 @@
public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp,
NetworkAgentConfig nac) {
+ this(wrapper, lp, nac, null /* provider */);
+ }
+
+ public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp,
+ NetworkAgentConfig nac, NetworkProvider provider) {
super(wrapper.mContext, wrapper.mHandlerThread.getLooper(), wrapper.mLogTag,
wrapper.mNetworkCapabilities, lp, wrapper.mScore, nac,
- new NetworkProvider(wrapper.mContext, wrapper.mHandlerThread.getLooper(),
- PROVIDER_NAME));
+ null != provider ? provider : new NetworkProvider(wrapper.mContext,
+ wrapper.mHandlerThread.getLooper(), PROVIDER_NAME));
mWrapper = wrapper;
register();
}
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 96ea761..7b23255 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -10,7 +10,6 @@
name: "FrameworksNetTests-jni-defaults",
jni_libs: [
"ld-android",
- "libbacktrace",
"libbase",
"libbinder",
"libbpf",
diff --git a/tests/unit/java/android/net/IpSecAlgorithmTest.java b/tests/unit/java/android/net/IpSecAlgorithmTest.java
index c2a759b..c473e82 100644
--- a/tests/unit/java/android/net/IpSecAlgorithmTest.java
+++ b/tests/unit/java/android/net/IpSecAlgorithmTest.java
@@ -217,8 +217,11 @@
final Set<String> optionalAlgoSet = getOptionalAlgos();
final String[] optionalAlgos = optionalAlgoSet.toArray(new String[0]);
- doReturn(optionalAlgos).when(mMockResources)
- .getStringArray(com.android.internal.R.array.config_optionalIpSecAlgorithms);
+ // Query the identifier instead of using the R.array constant, as the test may be built
+ // separately from the platform and they may not match.
+ final int resId = Resources.getSystem().getIdentifier("config_optionalIpSecAlgorithms",
+ "array", "android");
+ doReturn(optionalAlgos).when(mMockResources).getStringArray(resId);
final Set<String> enabledAlgos = new HashSet<>(IpSecAlgorithm.loadAlgos(mMockResources));
final Set<String> expectedAlgos = ALGO_TO_REQUIRED_FIRST_SDK.keySet();
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 2370b8d..2aba0b4 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -241,6 +241,7 @@
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkPolicyManager;
import android.net.NetworkPolicyManager.NetworkPolicyCallback;
+import android.net.NetworkProvider;
import android.net.NetworkRequest;
import android.net.NetworkScore;
import android.net.NetworkSpecifier;
@@ -338,6 +339,7 @@
import com.android.testutils.HandlerUtils;
import com.android.testutils.RecorderCallback.CallbackEntry;
import com.android.testutils.TestableNetworkCallback;
+import com.android.testutils.TestableNetworkOfferCallback;
import org.junit.After;
import org.junit.Before;
@@ -348,8 +350,11 @@
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
+import org.mockito.MockingDetails;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
+import org.mockito.exceptions.misusing.UnfinishedStubbingException;
import org.mockito.stubbing.Answer;
import java.io.FileDescriptor;
@@ -816,17 +821,22 @@
private String mRedirectUrl;
TestNetworkAgentWrapper(int transport) throws Exception {
- this(transport, new LinkProperties(), null);
+ this(transport, new LinkProperties(), null /* ncTemplate */, null /* provider */);
}
TestNetworkAgentWrapper(int transport, LinkProperties linkProperties)
throws Exception {
- this(transport, linkProperties, null);
+ this(transport, linkProperties, null /* ncTemplate */, null /* provider */);
}
private TestNetworkAgentWrapper(int transport, LinkProperties linkProperties,
NetworkCapabilities ncTemplate) throws Exception {
- super(transport, linkProperties, ncTemplate, mServiceContext);
+ this(transport, linkProperties, ncTemplate, null /* provider */);
+ }
+
+ private TestNetworkAgentWrapper(int transport, LinkProperties linkProperties,
+ NetworkCapabilities ncTemplate, NetworkProvider provider) throws Exception {
+ super(transport, linkProperties, ncTemplate, provider, mServiceContext);
// Waits for the NetworkAgent to be registered, which includes the creation of the
// NetworkMonitor.
@@ -835,9 +845,40 @@
HandlerUtils.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS);
}
+ class TestInstrumentedNetworkAgent extends InstrumentedNetworkAgent {
+ TestInstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp,
+ NetworkAgentConfig nac, NetworkProvider provider) {
+ super(wrapper, lp, nac, provider);
+ }
+
+ @Override
+ public void networkStatus(int status, String redirectUrl) {
+ mRedirectUrl = redirectUrl;
+ mNetworkStatusReceived.open();
+ }
+
+ @Override
+ public void onNetworkCreated() {
+ super.onNetworkCreated();
+ if (mCreatedCallback != null) mCreatedCallback.run();
+ }
+
+ @Override
+ public void onNetworkUnwanted() {
+ super.onNetworkUnwanted();
+ if (mUnwantedCallback != null) mUnwantedCallback.run();
+ }
+
+ @Override
+ public void onNetworkDestroyed() {
+ super.onNetworkDestroyed();
+ if (mDisconnectedCallback != null) mDisconnectedCallback.run();
+ }
+ }
+
@Override
protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties,
- NetworkAgentConfig nac) throws Exception {
+ NetworkAgentConfig nac, NetworkProvider provider) throws Exception {
mNetworkMonitor = mock(INetworkMonitor.class);
final Answer validateAnswer = inv -> {
@@ -857,31 +898,7 @@
nmCbCaptor.capture());
final InstrumentedNetworkAgent na =
- new InstrumentedNetworkAgent(this, linkProperties, nac) {
- @Override
- public void networkStatus(int status, String redirectUrl) {
- mRedirectUrl = redirectUrl;
- mNetworkStatusReceived.open();
- }
-
- @Override
- public void onNetworkCreated() {
- super.onNetworkCreated();
- if (mCreatedCallback != null) mCreatedCallback.run();
- }
-
- @Override
- public void onNetworkUnwanted() {
- super.onNetworkUnwanted();
- if (mUnwantedCallback != null) mUnwantedCallback.run();
- }
-
- @Override
- public void onNetworkDestroyed() {
- super.onNetworkDestroyed();
- if (mDisconnectedCallback != null) mDisconnectedCallback.run();
- }
- };
+ new TestInstrumentedNetworkAgent(this, linkProperties, nac, provider);
assertEquals(na.getNetwork().netId, nmNetworkCaptor.getValue().netId);
mNmCallbacks = nmCbCaptor.getValue();
@@ -1720,7 +1737,15 @@
}
private void returnRealCallingUid() {
- doAnswer((invocationOnMock) -> Binder.getCallingUid()).when(mDeps).getCallingUid();
+ try {
+ doAnswer((invocationOnMock) -> Binder.getCallingUid()).when(mDeps).getCallingUid();
+ } catch (UnfinishedStubbingException e) {
+ final MockingDetails details = Mockito.mockingDetails(mDeps);
+ Log.e("ConnectivityServiceTest", "UnfinishedStubbingException,"
+ + " Stubbings: " + TextUtils.join(", ", details.getStubbings())
+ + " Invocations: " + details.printInvocations(), e);
+ throw e;
+ }
}
private ConnectivityService.Dependencies makeDependencies() {
@@ -4798,6 +4823,123 @@
}
@Test
+ public void testOffersAvoidsBadWifi() throws Exception {
+ // Normal mode : the carrier doesn't restrict moving away from bad wifi.
+ // This has getAvoidBadWifi return true.
+ doReturn(1).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi);
+ // Don't request cell separately for the purposes of this test.
+ setAlwaysOnNetworks(false);
+
+ final NetworkProvider cellProvider = new NetworkProvider(mServiceContext,
+ mCsHandlerThread.getLooper(), "Cell provider");
+ final NetworkProvider wifiProvider = new NetworkProvider(mServiceContext,
+ mCsHandlerThread.getLooper(), "Wifi provider");
+
+ mCm.registerNetworkProvider(cellProvider);
+ mCm.registerNetworkProvider(wifiProvider);
+
+ final NetworkScore cellScore = new NetworkScore.Builder().build();
+ final NetworkScore wifiScore = new NetworkScore.Builder().build();
+ final NetworkCapabilities defaultCaps = new NetworkCapabilities.Builder()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .build();
+ final NetworkCapabilities cellCaps = new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .build();
+ final NetworkCapabilities wifiCaps = new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .build();
+ final TestableNetworkOfferCallback cellCallback = new TestableNetworkOfferCallback(
+ TIMEOUT_MS /* timeout */, TEST_CALLBACK_TIMEOUT_MS /* noCallbackTimeout */);
+ final TestableNetworkOfferCallback wifiCallback = new TestableNetworkOfferCallback(
+ TIMEOUT_MS /* timeout */, TEST_CALLBACK_TIMEOUT_MS /* noCallbackTimeout */);
+
+ // Offer callbacks will run on the CS handler thread in this test.
+ cellProvider.registerNetworkOffer(cellScore, cellCaps, r -> r.run(), cellCallback);
+ wifiProvider.registerNetworkOffer(wifiScore, wifiCaps, r -> r.run(), wifiCallback);
+
+ // Both providers see the default request.
+ cellCallback.expectOnNetworkNeeded(defaultCaps);
+ wifiCallback.expectOnNetworkNeeded(defaultCaps);
+
+ // Listen to cell and wifi to know when agents are finished processing
+ final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest cellRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR).build();
+ mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
+ final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build();
+ mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
+
+ // Cell connects and validates.
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR,
+ new LinkProperties(), null /* ncTemplate */, cellProvider);
+ mCellNetworkAgent.connect(true);
+ cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ cellCallback.assertNoCallback();
+ wifiCallback.assertNoCallback();
+
+ // Bring up wifi. At first it's invalidated, so cell is still needed.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI,
+ new LinkProperties(), null /* ncTemplate */, wifiProvider);
+ mWiFiNetworkAgent.connect(false);
+ wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ cellCallback.assertNoCallback();
+ wifiCallback.assertNoCallback();
+
+ // Wifi validates. Cell is no longer needed, because it's outscored.
+ mWiFiNetworkAgent.setNetworkValid(true /* isStrictMode */);
+ // Have CS reconsider the network (see testPartialConnectivity)
+ mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
+ wifiNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ cellCallback.expectOnNetworkUnneeded(defaultCaps);
+ wifiCallback.assertNoCallback();
+
+ // Wifi is no longer validated. Cell is needed again.
+ mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */);
+ mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
+ wifiNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ cellCallback.expectOnNetworkNeeded(defaultCaps);
+ wifiCallback.assertNoCallback();
+
+ // Disconnect wifi and pretend the carrier restricts moving away from bad wifi.
+ mWiFiNetworkAgent.disconnect();
+ wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ // This has getAvoidBadWifi return false. This test doesn't change the value of the
+ // associated setting.
+ doReturn(0).when(mResources).getInteger(R.integer.config_networkAvoidBadWifi);
+ mPolicyTracker.reevaluate();
+ waitForIdle();
+
+ // Connect wifi again, cell is needed until wifi validates.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI,
+ new LinkProperties(), null /* ncTemplate */, wifiProvider);
+ mWiFiNetworkAgent.connect(false);
+ wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ cellCallback.assertNoCallback();
+ wifiCallback.assertNoCallback();
+ mWiFiNetworkAgent.setNetworkValid(true /* isStrictMode */);
+ mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
+ wifiNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ cellCallback.expectOnNetworkUnneeded(defaultCaps);
+ wifiCallback.assertNoCallback();
+
+ // Wifi loses validation. Because the device doesn't avoid bad wifis, cell is
+ // not needed.
+ mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */);
+ mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
+ wifiNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ cellCallback.assertNoCallback();
+ wifiCallback.assertNoCallback();
+ }
+
+ @Test
public void testAvoidBadWifi() throws Exception {
final ContentResolver cr = mServiceContext.getContentResolver();
@@ -6106,16 +6248,16 @@
mCm.unregisterNetworkCallback(networkCallback);
}
- private void expectNotifyNetworkStatus(List<Network> networks, String defaultIface,
+ private void expectNotifyNetworkStatus(List<Network> defaultNetworks, String defaultIface,
Integer vpnUid, String vpnIfname, List<String> underlyingIfaces) throws Exception {
- ArgumentCaptor<List<Network>> networksCaptor = ArgumentCaptor.forClass(List.class);
+ ArgumentCaptor<List<Network>> defaultNetworksCaptor = ArgumentCaptor.forClass(List.class);
ArgumentCaptor<List<UnderlyingNetworkInfo>> vpnInfosCaptor =
ArgumentCaptor.forClass(List.class);
- verify(mStatsManager, atLeastOnce()).notifyNetworkStatus(networksCaptor.capture(),
+ verify(mStatsManager, atLeastOnce()).notifyNetworkStatus(defaultNetworksCaptor.capture(),
any(List.class), eq(defaultIface), vpnInfosCaptor.capture());
- assertSameElements(networks, networksCaptor.getValue());
+ assertSameElements(defaultNetworks, defaultNetworksCaptor.getValue());
List<UnderlyingNetworkInfo> infos = vpnInfosCaptor.getValue();
if (vpnUid != null) {
@@ -6131,8 +6273,8 @@
}
private void expectNotifyNetworkStatus(
- List<Network> networks, String defaultIface) throws Exception {
- expectNotifyNetworkStatus(networks, defaultIface, null, null, List.of());
+ List<Network> defaultNetworks, String defaultIface) throws Exception {
+ expectNotifyNetworkStatus(defaultNetworks, defaultIface, null, null, List.of());
}
@Test
@@ -12840,21 +12982,26 @@
assertLength(2, snapshots);
assertContainsAll(snapshots, cellSnapshot, wifiSnapshot);
- // Set cellular as suspended, verify the snapshots will not contain suspended networks.
- // TODO: Consider include SUSPENDED networks, which should be considered as
- // temporary shortage of connectivity of a connected network.
+ // Set cellular as suspended, verify the snapshots will contain suspended networks.
mCellNetworkAgent.suspend();
waitForIdle();
+ final NetworkCapabilities cellSuspendedNc =
+ mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork());
+ assertFalse(cellSuspendedNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+ final NetworkStateSnapshot cellSuspendedSnapshot = new NetworkStateSnapshot(
+ mCellNetworkAgent.getNetwork(), cellSuspendedNc, cellLp,
+ null, ConnectivityManager.TYPE_MOBILE);
snapshots = mCm.getAllNetworkStateSnapshots();
- assertLength(1, snapshots);
- assertEquals(wifiSnapshot, snapshots.get(0));
+ assertLength(2, snapshots);
+ assertContainsAll(snapshots, cellSuspendedSnapshot, wifiSnapshot);
- // Disconnect wifi, verify the snapshots contain nothing.
+ // Disconnect wifi, verify the snapshots contain only cellular.
mWiFiNetworkAgent.disconnect();
waitForIdle();
snapshots = mCm.getAllNetworkStateSnapshots();
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertLength(0, snapshots);
+ assertLength(1, snapshots);
+ assertEquals(cellSuspendedSnapshot, snapshots.get(0));
mCellNetworkAgent.resume();
waitForIdle();
diff --git a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
index a9749c4..ecda338 100644
--- a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -32,6 +32,7 @@
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.net.ConnectivitySettingsManager.UIDS_ALLOWED_ON_RESTRICTED_NETWORKS;
import static android.net.INetd.PERMISSION_INTERNET;
+import static android.net.INetd.PERMISSION_NETWORK;
import static android.net.INetd.PERMISSION_NONE;
import static android.net.INetd.PERMISSION_SYSTEM;
import static android.net.INetd.PERMISSION_UNINSTALLED;
@@ -39,8 +40,7 @@
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.Process.SYSTEM_UID;
-import static com.android.server.connectivity.PermissionMonitor.NETWORK;
-import static com.android.server.connectivity.PermissionMonitor.SYSTEM;
+import static com.android.server.connectivity.PermissionMonitor.isHigherNetworkPermission;
import static junit.framework.Assert.fail;
@@ -55,12 +55,12 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.intThat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -80,12 +80,14 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.util.ArraySet;
import android.util.SparseIntArray;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import com.android.net.module.util.CollectionUtils;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
@@ -98,11 +100,8 @@
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
-import java.util.ArrayList;
+import java.lang.reflect.Array;
import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -110,13 +109,19 @@
@SmallTest
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
public class PermissionMonitorTest {
- private static final UserHandle MOCK_USER1 = UserHandle.of(0);
- private static final UserHandle MOCK_USER2 = UserHandle.of(1);
- private static final int MOCK_UID1 = 10001;
- private static final int MOCK_UID2 = 10086;
- private static final int SYSTEM_UID1 = 1000;
- private static final int SYSTEM_UID2 = 1008;
- private static final int VPN_UID = 10002;
+ private static final int MOCK_USER_ID1 = 0;
+ private static final int MOCK_USER_ID2 = 1;
+ private static final UserHandle MOCK_USER1 = UserHandle.of(MOCK_USER_ID1);
+ private static final UserHandle MOCK_USER2 = UserHandle.of(MOCK_USER_ID2);
+ private static final int MOCK_APPID1 = 10001;
+ private static final int MOCK_APPID2 = 10086;
+ private static final int SYSTEM_APPID1 = 1100;
+ private static final int SYSTEM_APPID2 = 1108;
+ private static final int VPN_APPID = 10002;
+ private static final int MOCK_UID1 = MOCK_USER1.getUid(MOCK_APPID1);
+ private static final int MOCK_UID2 = MOCK_USER1.getUid(MOCK_APPID2);
+ private static final int SYSTEM_APP_UID1 = MOCK_USER1.getUid(SYSTEM_APPID1);
+ private static final int VPN_UID = MOCK_USER1.getUid(VPN_APPID);
private static final String REAL_SYSTEM_PACKAGE_NAME = "android";
private static final String MOCK_PACKAGE1 = "appName1";
private static final String MOCK_PACKAGE2 = "appName2";
@@ -146,8 +151,7 @@
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
- when(mUserManager.getUserHandles(eq(true))).thenReturn(
- Arrays.asList(new UserHandle[] { MOCK_USER1, MOCK_USER2 }));
+ doReturn(List.of(MOCK_USER1)).when(mUserManager).getUserHandles(eq(true));
when(mContext.getSystemServiceName(SystemConfigManager.class))
.thenReturn(Context.SYSTEM_CONFIG_SERVICE);
when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE))
@@ -160,19 +164,15 @@
final Context asUserCtx = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
doReturn(UserHandle.ALL).when(asUserCtx).getUser();
when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);
- when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of());
+ // Set DEVICE_INITIAL_SDK_INT to Q that SYSTEM_UID won't have restricted network permission
+ // by default.
+ doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
- mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
+ mPermissionMonitor = new PermissionMonitor(mContext, mNetdService, mDeps);
mNetdMonitor = new NetdMonitor(mNetdService);
- when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
- mPermissionMonitor.startMonitoring();
- }
-
- private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
- String... permissions) {
- return hasRestrictedNetworkPermission(
- partition, targetSdkVersion, "" /* packageName */, uid, permissions);
+ doReturn(List.of()).when(mPackageManager).getInstalledPackages(anyInt());
}
private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion,
@@ -223,13 +223,44 @@
private static PackageInfo buildPackageInfo(String packageName, int uid,
String... permissions) {
- final PackageInfo pkgInfo;
- pkgInfo = systemPackageInfoWithPermissions(permissions);
+ final PackageInfo pkgInfo = systemPackageInfoWithPermissions(permissions);
pkgInfo.packageName = packageName;
pkgInfo.applicationInfo.uid = uid;
return pkgInfo;
}
+ // TODO: Move this method to static lib.
+ private static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element) {
+ final T[] result;
+ if (array != null) {
+ result = Arrays.copyOf(array, array.length + 1);
+ } else {
+ result = (T[]) Array.newInstance(kind, 1);
+ }
+ result[result.length - 1] = element;
+ return result;
+ }
+
+ private void buildAndMockPackageInfoWithPermissions(String packageName, int uid,
+ String... permissions) throws Exception {
+ final PackageInfo packageInfo = buildPackageInfo(packageName, uid, permissions);
+ // This will return the wrong UID for the package when queried with other users.
+ doReturn(packageInfo).when(mPackageManager)
+ .getPackageInfo(eq(packageName), anyInt() /* flag */);
+ final String[] oldPackages = mPackageManager.getPackagesForUid(uid);
+ // If it's duplicated package, no need to set it again.
+ if (CollectionUtils.contains(oldPackages, packageName)) return;
+
+ // Combine the package if this uid is shared with other packages.
+ final String[] newPackages = appendElement(String.class, oldPackages, packageName);
+ doReturn(newPackages).when(mPackageManager).getPackagesForUid(eq(uid));
+ }
+
+ private void addPackage(String packageName, int uid, String... permissions) throws Exception {
+ buildAndMockPackageInfoWithPermissions(packageName, uid, permissions);
+ mPermissionMonitor.onPackageAdded(packageName, uid);
+ }
+
@Test
public void testHasPermission() {
PackageInfo app = systemPackageInfoWithPermissions();
@@ -298,67 +329,77 @@
@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));
+ PARTITION_SYSTEM, VERSION_P, MOCK_PACKAGE1, MOCK_UID1));
assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ PARTITION_SYSTEM, VERSION_P, MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE));
assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ PARTITION_SYSTEM, VERSION_P, MOCK_PACKAGE1, MOCK_UID1, NETWORK_STACK));
assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
+ PARTITION_SYSTEM, VERSION_P, MOCK_PACKAGE1, MOCK_UID1, CONNECTIVITY_INTERNAL));
assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, PERMISSION_MAINLINE_NETWORK_STACK));
+ PARTITION_SYSTEM, VERSION_P, MOCK_PACKAGE1, MOCK_UID1,
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, MOCK_PACKAGE1, MOCK_UID1, CHANGE_WIFI_STATE));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, MOCK_PACKAGE1, MOCK_UID1,
+ PERMISSION_MAINLINE_NETWORK_STACK));
- assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ PARTITION_SYSTEM, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1, CONNECTIVITY_INTERNAL));
}
@Test
public void testHasRestrictedNetworkPermissionSystemUid() {
doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt();
- assertTrue(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_INTERNAL));
+ PARTITION_SYSTEM, VERSION_P, SYSTEM_PACKAGE1, SYSTEM_UID));
assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ PARTITION_SYSTEM, VERSION_P, SYSTEM_PACKAGE1, SYSTEM_UID, CONNECTIVITY_INTERNAL));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, SYSTEM_PACKAGE1, SYSTEM_UID,
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS));
doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
- assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_INTERNAL));
+ PARTITION_SYSTEM, VERSION_Q, SYSTEM_PACKAGE1, SYSTEM_UID));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_Q, SYSTEM_PACKAGE1, SYSTEM_UID, CONNECTIVITY_INTERNAL));
assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ PARTITION_SYSTEM, VERSION_Q, SYSTEM_PACKAGE1, 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));
+ PARTITION_VENDOR, VERSION_P, MOCK_PACKAGE1, MOCK_UID1));
assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, NETWORK_STACK));
+ PARTITION_VENDOR, VERSION_P, MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE));
assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ PARTITION_VENDOR, VERSION_P, MOCK_PACKAGE1, MOCK_UID1, NETWORK_STACK));
assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ PARTITION_VENDOR, VERSION_P, MOCK_PACKAGE1, MOCK_UID1, CONNECTIVITY_INTERNAL));
assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
+ PARTITION_VENDOR, VERSION_P, MOCK_PACKAGE1, MOCK_UID1,
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_P, MOCK_PACKAGE1, MOCK_UID1, CHANGE_WIFI_STATE));
- assertFalse(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
assertFalse(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1));
assertFalse(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_NETWORK_STATE));
+ PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE));
}
@Test
public void testHasRestrictedNetworkPermissionUidAllowedOnRestrictedNetworks() {
- mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(
- new ArraySet<>(new Integer[] { MOCK_UID1 }));
+ mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(Set.of(MOCK_UID1));
assertTrue(hasRestrictedNetworkPermission(
PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1));
assertTrue(hasRestrictedNetworkPermission(
@@ -419,32 +460,26 @@
@Test
public void testIsAppAllowedOnRestrictedNetworks() {
- mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(new ArraySet<>());
+ mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(Set.of());
assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID1));
assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID2));
- mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(
- new ArraySet<>(new Integer[] { MOCK_UID1 }));
+ mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(Set.of(MOCK_UID1));
assertTrue(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID1));
assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID2));
- mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(
- new ArraySet<>(new Integer[] { MOCK_UID2 }));
+ mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(Set.of(MOCK_UID2));
assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID1));
assertTrue(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID2));
- mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(
- new ArraySet<>(new Integer[] { 123 }));
+ mPermissionMonitor.updateUidsAllowedOnRestrictedNetworks(Set.of(123));
assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID1));
assertFalse(wouldBeUidAllowedOnRestrictedNetworks(MOCK_UID2));
}
private void assertBackgroundPermission(boolean hasPermission, String name, int uid,
String... permissions) throws Exception {
- when(mPackageManager.getPackageInfo(eq(name), anyInt()))
- .thenReturn(packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM));
- mPermissionMonitor.onPackageAdded(name, uid);
+ addPackage(name, uid, permissions);
assertEquals(hasPermission, mPermissionMonitor.hasUseBackgroundNetworksPermission(uid));
}
@@ -469,21 +504,22 @@
}
private class NetdMonitor {
- private final HashMap<Integer, Boolean> mUidsNetworkPermission = new HashMap<>();
- private final HashMap<Integer, Integer> mAppIdsTrafficPermission = new HashMap<>();
+ private final SparseIntArray mUidsNetworkPermission = new SparseIntArray();
+ private final SparseIntArray mAppIdsTrafficPermission = new SparseIntArray();
+ private static final int DOES_NOT_EXIST = -2;
NetdMonitor(INetd mockNetd) throws Exception {
// Add hook to verify and track result of networkSetPermission.
doAnswer((InvocationOnMock invocation) -> {
final Object[] args = invocation.getArguments();
- final Boolean isSystem = args[0].equals(PERMISSION_SYSTEM);
+ final int permission = (int) args[0];
for (final int uid : (int[]) args[1]) {
// TODO: Currently, permission monitor will send duplicate commands for each uid
// corresponding to each user. Need to fix that and uncomment below test.
// if (mApps.containsKey(uid) && mApps.get(uid) == isSystem) {
// fail("uid " + uid + " is already set to " + isSystem);
// }
- mUidsNetworkPermission.put(uid, isSystem);
+ mUidsNetworkPermission.put(uid, permission);
}
return null;
}).when(mockNetd).networkSetPermissionForUser(anyInt(), any(int[].class));
@@ -497,7 +533,7 @@
// if (!mApps.containsKey(uid)) {
// fail("uid " + uid + " does not exist.");
// }
- mUidsNetworkPermission.remove(uid);
+ mUidsNetworkPermission.delete(uid);
}
return null;
}).when(mockNetd).networkClearPermissionForUser(any(int[].class));
@@ -513,11 +549,11 @@
}).when(mockNetd).trafficSetNetPermForUids(anyInt(), any(int[].class));
}
- public void expectNetworkPerm(Boolean permission, UserHandle[] users, int... appIds) {
+ public void expectNetworkPerm(int permission, UserHandle[] users, int... appIds) {
for (final UserHandle user : users) {
for (final int appId : appIds) {
final int uid = user.getUid(appId);
- if (!mUidsNetworkPermission.containsKey(uid)) {
+ if (mUidsNetworkPermission.get(uid, DOES_NOT_EXIST) == DOES_NOT_EXIST) {
fail("uid " + uid + " does not exist.");
}
if (mUidsNetworkPermission.get(uid) != permission) {
@@ -531,7 +567,7 @@
for (final UserHandle user : users) {
for (final int appId : appIds) {
final int uid = user.getUid(appId);
- if (mUidsNetworkPermission.containsKey(uid)) {
+ if (mUidsNetworkPermission.get(uid, DOES_NOT_EXIST) != DOES_NOT_EXIST) {
fail("uid " + uid + " has listed permissions, expected none.");
}
}
@@ -540,7 +576,7 @@
public void expectTrafficPerm(int permission, int... appIds) {
for (final int appId : appIds) {
- if (!mAppIdsTrafficPermission.containsKey(appId)) {
+ if (mAppIdsTrafficPermission.get(appId, DOES_NOT_EXIST) == DOES_NOT_EXIST) {
fail("appId " + appId + " does not exist.");
}
if (mAppIdsTrafficPermission.get(appId) != permission) {
@@ -554,85 +590,92 @@
@Test
public void testUserAndPackageAddRemove() throws Exception {
// 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(any(),
- eq(SYSTEM_PACKAGE1));
- doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(SYSTEM_PACKAGE2));
- doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(MOCK_PACKAGE1));
- doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(eq(SYSTEM), anyString());
+ // SYSTEM_APP_UID1: SYSTEM_PACKAGE1 has system permission.
+ // SYSTEM_APP_UID1: SYSTEM_PACKAGE2 only has network permission.
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE);
+ buildAndMockPackageInfoWithPermissions(SYSTEM_PACKAGE1, SYSTEM_APP_UID1,
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ buildAndMockPackageInfoWithPermissions(SYSTEM_PACKAGE2, SYSTEM_APP_UID1,
+ CHANGE_NETWORK_STATE);
- // Add SYSTEM_PACKAGE2, expect only have network permission.
+ // Add user MOCK_USER1.
mPermissionMonitor.onUserAdded(MOCK_USER1);
- addPackageForUsers(new UserHandle[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_UID);
- mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1}, SYSTEM_UID);
+ // Add SYSTEM_PACKAGE2, expect only have network permission.
+ addPackageForUsers(new UserHandle[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_APPID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1},
+ SYSTEM_APPID1);
- // Add SYSTEM_PACKAGE1, expect permission escalate.
- addPackageForUsers(new UserHandle[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_UID);
- mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1}, SYSTEM_UID);
+ // Add SYSTEM_PACKAGE1, expect permission upgrade.
+ addPackageForUsers(new UserHandle[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_APPID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1},
+ SYSTEM_APPID1);
+ // Add user MOCK_USER2.
mPermissionMonitor.onUserAdded(MOCK_USER2);
- mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
- SYSTEM_UID);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ SYSTEM_APPID1);
// Remove SYSTEM_PACKAGE2, expect keep system permission.
- when(mPackageManager.getPackagesForUid(MOCK_USER1.getUid(SYSTEM_UID)))
+ when(mPackageManager.getPackagesForUid(SYSTEM_APP_UID1))
.thenReturn(new String[]{SYSTEM_PACKAGE1});
- when(mPackageManager.getPackagesForUid(MOCK_USER2.getUid(SYSTEM_UID)))
+ when(mPackageManager.getPackagesForUid(MOCK_USER2.getUid(SYSTEM_APPID1)))
.thenReturn(new String[]{SYSTEM_PACKAGE1});
removePackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2},
- SYSTEM_PACKAGE2, SYSTEM_UID);
- mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
- SYSTEM_UID);
+ SYSTEM_PACKAGE2, SYSTEM_APPID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ SYSTEM_APPID1);
// Add SYSTEM_PACKAGE2, expect keep system permission.
- addPackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, SYSTEM_PACKAGE2, SYSTEM_UID);
- mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
- SYSTEM_UID);
+ addPackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, SYSTEM_PACKAGE2,
+ SYSTEM_APPID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ SYSTEM_APPID1);
- addPackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
- SYSTEM_UID);
- mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
- MOCK_UID1);
+ addPackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_APPID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ SYSTEM_APPID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ MOCK_APPID1);
- // Remove MOCK_UID1, expect no permission left for all user.
- when(mPackageManager.getPackagesForUid(MOCK_USER1.getUid(MOCK_UID1)))
+ // Remove MOCK_PACKAGE1, expect no permission left for all user.
+ when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
+ when(mPackageManager.getPackagesForUid(MOCK_USER2.getUid(MOCK_APPID1)))
.thenReturn(new String[]{});
- when(mPackageManager.getPackagesForUid(MOCK_USER2.getUid(MOCK_UID1)))
- .thenReturn(new String[]{});
- mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- removePackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_UID1);
+ removePackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_APPID1);
+ mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_APPID1);
// Remove SYSTEM_PACKAGE1, expect permission downgrade.
- when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{SYSTEM_PACKAGE2});
+ when(mPackageManager.getPackagesForUid(
+ intThat(uid -> UserHandle.getAppId(uid) == SYSTEM_APPID1)))
+ .thenReturn(new String[]{SYSTEM_PACKAGE2});
removePackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2},
- SYSTEM_PACKAGE1, SYSTEM_UID);
- mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
- SYSTEM_UID);
+ SYSTEM_PACKAGE1, SYSTEM_APPID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ SYSTEM_APPID1);
mPermissionMonitor.onUserRemoved(MOCK_USER1);
- mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER2}, SYSTEM_UID);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER2},
+ SYSTEM_APPID1);
+ mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, SYSTEM_APPID1);
// Remove all packages, expect no permission left.
- when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{});
- removePackageForUsers(new UserHandle[]{MOCK_USER2}, SYSTEM_PACKAGE2, SYSTEM_UID);
- mNetdMonitor.expectNoNetworkPerm(
- new UserHandle[]{MOCK_USER1, MOCK_USER2}, SYSTEM_UID, MOCK_UID1);
+ when(mPackageManager.getPackagesForUid(
+ intThat(uid -> UserHandle.getAppId(uid) == SYSTEM_APPID1)))
+ .thenReturn(new String[]{});
+ removePackageForUsers(new UserHandle[]{MOCK_USER2}, SYSTEM_PACKAGE2, SYSTEM_APPID1);
+ mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1, MOCK_USER2}, SYSTEM_APPID1,
+ MOCK_APPID1);
- // Remove last user, expect no redundant clearPermission is invoked.
+ // Remove last user, expect no permission change.
mPermissionMonitor.onUserRemoved(MOCK_USER2);
- mNetdMonitor.expectNoNetworkPerm(
- new UserHandle[]{MOCK_USER1, MOCK_USER2}, SYSTEM_UID, MOCK_UID1);
+ mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1, MOCK_USER2}, SYSTEM_APPID1,
+ MOCK_APPID1);
}
@Test
public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdates() throws Exception {
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
- List.of(buildPackageInfo(SYSTEM_PACKAGE1, SYSTEM_UID1, CHANGE_NETWORK_STATE,
+ List.of(buildPackageInfo(SYSTEM_PACKAGE1, SYSTEM_APP_UID1, CHANGE_NETWORK_STATE,
CONNECTIVITY_USE_RESTRICTED_NETWORKS),
buildPackageInfo(MOCK_PACKAGE1, MOCK_UID1),
buildPackageInfo(MOCK_PACKAGE2, MOCK_UID2),
@@ -640,25 +683,22 @@
buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1);
mPermissionMonitor.startMonitoring();
// Every app on user 0 except MOCK_UID2 are under VPN.
- final Set<UidRange> vpnRange1 = new HashSet<>(Arrays.asList(new UidRange[] {
+ final Set<UidRange> vpnRange1 = Set.of(
new UidRange(0, MOCK_UID2 - 1),
- new UidRange(MOCK_UID2 + 1, UserHandle.PER_USER_RANGE - 1)}));
- final Set<UidRange> vpnRange2 = Collections.singleton(new UidRange(MOCK_UID2, MOCK_UID2));
+ new UidRange(MOCK_UID2 + 1, UserHandle.PER_USER_RANGE - 1));
+ final Set<UidRange> vpnRange2 = Set.of(new UidRange(MOCK_UID2, MOCK_UID2));
// When VPN is connected, expect a rule to be set up for user app MOCK_UID1
mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange1, VPN_UID);
- verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
- aryEq(new int[] {MOCK_UID1}));
+ verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"), aryEq(new int[]{MOCK_UID1}));
reset(mNetdService);
// When MOCK_UID1 package is uninstalled and reinstalled, expect Netd to be updated
- mPermissionMonitor.onPackageRemoved(
- MOCK_PACKAGE1, MOCK_USER1.getUid(MOCK_UID1));
- verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
- mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, MOCK_USER1.getUid(MOCK_UID1));
- verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
- aryEq(new int[] {MOCK_UID1}));
+ mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
+ verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[]{MOCK_UID1}));
+ mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, MOCK_UID1);
+ verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"), aryEq(new int[]{MOCK_UID1}));
reset(mNetdService);
@@ -667,8 +707,7 @@
mPermissionMonitor.onVpnUidRangesRemoved("tun0", vpnRange1, VPN_UID);
verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange2, VPN_UID);
- verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
- aryEq(new int[] {MOCK_UID2}));
+ verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"), aryEq(new int[]{MOCK_UID2}));
reset(mNetdService);
@@ -681,23 +720,21 @@
@Test
public void testUidFilteringDuringPackageInstallAndUninstall() throws Exception {
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
- List.of(buildPackageInfo(SYSTEM_PACKAGE1, SYSTEM_UID1, CHANGE_NETWORK_STATE,
+ List.of(buildPackageInfo(SYSTEM_PACKAGE1, SYSTEM_APP_UID1, CHANGE_NETWORK_STATE,
NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS),
buildPackageInfo(SYSTEM_PACKAGE2, VPN_UID)));
buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1);
mPermissionMonitor.startMonitoring();
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(MOCK_USER1));
+ final Set<UidRange> vpnRange = Set.of(UidRange.createForUser(MOCK_USER1));
mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange, VPN_UID);
// Newly-installed package should have uid rules added
- mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, MOCK_USER1.getUid(MOCK_UID1));
- verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
- aryEq(new int[] {MOCK_UID1}));
+ mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, MOCK_UID1);
+ verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"), aryEq(new int[]{MOCK_UID1}));
// Removed package should have its uid rules removed
- mPermissionMonitor.onPackageRemoved(
- MOCK_PACKAGE1, MOCK_USER1.getUid(MOCK_UID1));
+ mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
}
@@ -705,138 +742,118 @@
// Normal package add/remove operations will trigger multiple intent for uids corresponding to
// each user. To simulate generic package operations, the onPackageAdded/Removed will need to be
// called multiple times with the uid corresponding to each user.
- private void addPackageForUsers(UserHandle[] users, String packageName, int uid) {
+ private void addPackageForUsers(UserHandle[] users, String packageName, int appId) {
for (final UserHandle user : users) {
- mPermissionMonitor.onPackageAdded(packageName, user.getUid(uid));
+ mPermissionMonitor.onPackageAdded(packageName, user.getUid(appId));
}
}
- private void removePackageForUsers(UserHandle[] users, String packageName, int uid) {
+ private void removePackageForUsers(UserHandle[] users, String packageName, int appId) {
for (final UserHandle user : users) {
- mPermissionMonitor.onPackageRemoved(packageName, user.getUid(uid));
+ mPermissionMonitor.onPackageRemoved(packageName, user.getUid(appId));
}
}
@Test
public void testPackagePermissionUpdate() throws Exception {
- // MOCK_UID1: MOCK_PACKAGE1 only has internet permission.
- // MOCK_UID2: MOCK_PACKAGE2 does not have any permission.
- // SYSTEM_UID1: SYSTEM_PACKAGE1 has internet permission and update device stats permission.
- // SYSTEM_UID2: SYSTEM_PACKAGE2 has only update device stats permission.
+ // MOCK_APPID1: MOCK_PACKAGE1 only has internet permission.
+ // MOCK_APPID2: MOCK_PACKAGE2 does not have any permission.
+ // SYSTEM_APPID1: SYSTEM_PACKAGE1 has internet permission and update device stats permission
+ // SYSTEM_APPID2: SYSTEM_PACKAGE2 has only update device stats permission.
SparseIntArray netdPermissionsAppIds = new SparseIntArray();
- netdPermissionsAppIds.put(MOCK_UID1, PERMISSION_INTERNET);
- netdPermissionsAppIds.put(MOCK_UID2, PERMISSION_NONE);
- netdPermissionsAppIds.put(SYSTEM_UID1, PERMISSION_TRAFFIC_ALL);
- netdPermissionsAppIds.put(SYSTEM_UID2, PERMISSION_UPDATE_DEVICE_STATS);
+ netdPermissionsAppIds.put(MOCK_APPID1, PERMISSION_INTERNET);
+ netdPermissionsAppIds.put(MOCK_APPID2, PERMISSION_NONE);
+ netdPermissionsAppIds.put(SYSTEM_APPID1, PERMISSION_TRAFFIC_ALL);
+ netdPermissionsAppIds.put(SYSTEM_APPID2, PERMISSION_UPDATE_DEVICE_STATS);
// Send the permission information to netd, expect permission updated.
mPermissionMonitor.sendPackagePermissionsToNetd(netdPermissionsAppIds);
- mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID1);
- mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_UID2);
- mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, SYSTEM_UID1);
- mNetdMonitor.expectTrafficPerm(PERMISSION_UPDATE_DEVICE_STATS, SYSTEM_UID2);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_APPID2);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, SYSTEM_APPID1);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_UPDATE_DEVICE_STATS, SYSTEM_APPID2);
- // Update permission of MOCK_UID1, expect new permission show up.
- mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1, PERMISSION_TRAFFIC_ALL);
- mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
+ // Update permission of MOCK_APPID1, expect new permission show up.
+ mPermissionMonitor.sendPackagePermissionsForAppId(MOCK_APPID1, PERMISSION_TRAFFIC_ALL);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
- // Change permissions of SYSTEM_UID2, expect new permission show up and old permission
+ // Change permissions of SYSTEM_APPID2, expect new permission show up and old permission
// revoked.
- mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2, PERMISSION_INTERNET);
- mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, SYSTEM_UID2);
+ mPermissionMonitor.sendPackagePermissionsForAppId(SYSTEM_APPID2, PERMISSION_INTERNET);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, SYSTEM_APPID2);
- // Revoke permission from SYSTEM_UID1, expect no permission stored.
- mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, PERMISSION_NONE);
- mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, SYSTEM_UID1);
- }
-
- private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions)
- throws Exception {
- PackageInfo packageInfo = packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM);
- when(mPackageManager.getPackageInfo(eq(packageName), anyInt())).thenReturn(packageInfo);
- when(mPackageManager.getPackagesForUid(eq(uid))).thenReturn(new String[]{packageName});
- return packageInfo;
- }
-
- private PackageInfo addPackage(String packageName, int uid, String[] permissions)
- throws Exception {
- PackageInfo packageInfo = setPackagePermissions(packageName, uid, permissions);
- mPermissionMonitor.onPackageAdded(packageName, uid);
- return packageInfo;
+ // Revoke permission from SYSTEM_APPID1, expect no permission stored.
+ mPermissionMonitor.sendPackagePermissionsForAppId(SYSTEM_APPID1, PERMISSION_NONE);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, SYSTEM_APPID1);
}
@Test
public void testPackageInstall() throws Exception {
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, INTERNET, UPDATE_DEVICE_STATS);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
- addPackage(MOCK_PACKAGE2, MOCK_UID2, new String[] {INTERNET});
- mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID2);
+ addPackage(MOCK_PACKAGE2, MOCK_UID2, INTERNET);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID2);
}
@Test
public void testPackageInstallSharedUid() throws Exception {
- PackageInfo packageInfo1 = addPackage(MOCK_PACKAGE1, MOCK_UID1,
- new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, INTERNET, UPDATE_DEVICE_STATS);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
- // Install another package with the same uid and no permissions should not cause the UID to
- // lose permissions.
- PackageInfo packageInfo2 = systemPackageInfoWithPermissions();
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
- when(mPackageManager.getPackagesForUid(MOCK_UID1))
- .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
- mPermissionMonitor.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1);
- mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
+ // Install another package with the same uid and no permissions should not cause the app id
+ // to lose permissions.
+ addPackage(MOCK_PACKAGE2, MOCK_UID1);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
}
@Test
public void testPackageUninstallBasic() throws Exception {
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, INTERNET, UPDATE_DEVICE_STATS);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectTrafficPerm(PERMISSION_UNINSTALLED, MOCK_UID1);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_UNINSTALLED, MOCK_APPID1);
}
@Test
public void testPackageRemoveThenAdd() throws Exception {
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, INTERNET, UPDATE_DEVICE_STATS);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectTrafficPerm(PERMISSION_UNINSTALLED, MOCK_UID1);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_UNINSTALLED, MOCK_APPID1);
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
- mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID1);
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, INTERNET);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
}
@Test
public void testPackageUpdate() throws Exception {
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {});
- mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_UID1);
+ addPackage(MOCK_PACKAGE1, MOCK_UID1);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_APPID1);
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
- mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID1);
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, INTERNET);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
}
@Test
public void testPackageUninstallWithMultiplePackages() throws Exception {
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, INTERNET, UPDATE_DEVICE_STATS);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
+
+ // Install another package with the same uid but different permissions.
+ addPackage(MOCK_PACKAGE2, MOCK_UID1, INTERNET);
mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
- // Mock another package with the same uid but different permissions.
- PackageInfo packageInfo2 = systemPackageInfoWithPermissions(INTERNET);
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
- when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{
- MOCK_PACKAGE2});
-
+ // Uninstall MOCK_PACKAGE1 and expect only INTERNET permission left.
+ when(mPackageManager.getPackagesForUid(eq(MOCK_UID1)))
+ .thenReturn(new String[]{MOCK_PACKAGE2});
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID1);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
}
@Test
@@ -853,15 +870,14 @@
@Test
public void testUpdateUidPermissionsFromSystemConfig() throws Exception {
- when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(new ArrayList<>());
when(mSystemConfigManager.getSystemPermissionUids(eq(INTERNET)))
.thenReturn(new int[]{ MOCK_UID1, MOCK_UID2 });
when(mSystemConfigManager.getSystemPermissionUids(eq(UPDATE_DEVICE_STATS)))
.thenReturn(new int[]{ MOCK_UID2 });
mPermissionMonitor.startMonitoring();
- mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID1);
- mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID2);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID2);
}
private BroadcastReceiver expectBroadcastReceiver(String... actions) {
@@ -881,6 +897,7 @@
@Test
public void testIntentReceiver() throws Exception {
+ mPermissionMonitor.startMonitoring();
final BroadcastReceiver receiver = expectBroadcastReceiver(
Intent.ACTION_PACKAGE_ADDED, Intent.ACTION_PACKAGE_REMOVED);
@@ -888,18 +905,18 @@
final Intent addedIntent = new Intent(Intent.ACTION_PACKAGE_ADDED,
Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
addedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
- setPackagePermissions(MOCK_PACKAGE1, MOCK_UID1,
- new String[] { INTERNET, UPDATE_DEVICE_STATS });
+ buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1, INTERNET,
+ UPDATE_DEVICE_STATS);
receiver.onReceive(mContext, addedIntent);
- mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
// Verify receiving PACKAGE_REMOVED intent.
- when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(null);
+ when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
final Intent removedIntent = new Intent(Intent.ACTION_PACKAGE_REMOVED,
Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
removedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
receiver.onReceive(mContext, removedIntent);
- mNetdMonitor.expectTrafficPerm(PERMISSION_UNINSTALLED, MOCK_UID1);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_UNINSTALLED, MOCK_APPID1);
}
private ContentObserver expectRegisterContentObserver(Uri expectedUri) {
@@ -910,138 +927,132 @@
return captor.getValue();
}
- private void buildAndMockPackageInfoWithPermissions(String packageName, int uid,
- String... permissions) throws Exception {
- final PackageInfo packageInfo = setPackagePermissions(packageName, uid, permissions);
- packageInfo.packageName = packageName;
- packageInfo.applicationInfo.uid = uid;
- }
-
@Test
public void testUidsAllowedOnRestrictedNetworksChanged() throws Exception {
+ mPermissionMonitor.startMonitoring();
final ContentObserver contentObserver = expectRegisterContentObserver(
Settings.Global.getUriFor(UIDS_ALLOWED_ON_RESTRICTED_NETWORKS));
- mPermissionMonitor.onUserAdded(MOCK_USER1);
// Prepare PackageInfo for MOCK_PACKAGE1 and MOCK_PACKAGE2
buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1);
buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID2);
// MOCK_UID1 is listed in setting that allow to use restricted networks, MOCK_UID1
// should have SYSTEM permission.
- when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(
- new ArraySet<>(new Integer[] { MOCK_UID1 }));
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of(MOCK_UID1));
contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
- mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_UID2);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1},
+ MOCK_APPID1);
+ mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_APPID2);
// MOCK_UID2 is listed in setting that allow to use restricted networks, MOCK_UID2
// should have SYSTEM permission but MOCK_UID1 should revoke permission.
- when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(
- new ArraySet<>(new Integer[] { MOCK_UID2 }));
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of(MOCK_UID2));
contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1}, MOCK_UID2);
- mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_UID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1},
+ MOCK_APPID2);
+ mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_APPID1);
// No uid lists in setting, should revoke permission from all uids.
- when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of());
contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_UID1, MOCK_UID2);
+ mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_APPID1, MOCK_APPID2);
}
@Test
public void testUidsAllowedOnRestrictedNetworksChangedWithSharedUid() throws Exception {
+ mPermissionMonitor.startMonitoring();
final ContentObserver contentObserver = expectRegisterContentObserver(
Settings.Global.getUriFor(UIDS_ALLOWED_ON_RESTRICTED_NETWORKS));
- mPermissionMonitor.onUserAdded(MOCK_USER1);
buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE);
buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID1);
- when(mPackageManager.getPackagesForUid(MOCK_UID1))
- .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
// MOCK_PACKAGE1 have CHANGE_NETWORK_STATE, MOCK_UID1 should have NETWORK permission.
- addPackageForUsers(new UserHandle[]{MOCK_USER1}, MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
+ addPackageForUsers(new UserHandle[]{MOCK_USER1}, MOCK_PACKAGE1, MOCK_APPID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1},
+ MOCK_APPID1);
// MOCK_UID1 is listed in setting that allow to use restricted networks, MOCK_UID1
// should upgrade to SYSTEM permission.
- when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(
- new ArraySet<>(new Integer[] { MOCK_UID1 }));
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of(MOCK_UID1));
contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1},
+ MOCK_APPID1);
// No app lists in setting, MOCK_UID1 should downgrade to NETWORK permission.
- when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of());
contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1},
+ MOCK_APPID1);
// MOCK_PACKAGE1 removed, should revoke permission from MOCK_UID1.
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{MOCK_PACKAGE2});
- removePackageForUsers(new UserHandle[]{MOCK_USER1}, MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_UID1);
+ removePackageForUsers(new UserHandle[]{MOCK_USER1}, MOCK_PACKAGE1, MOCK_APPID1);
+ mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_APPID1);
}
@Test
public void testUidsAllowedOnRestrictedNetworksChangedWithMultipleUsers() throws Exception {
+ mPermissionMonitor.startMonitoring();
final ContentObserver contentObserver = expectRegisterContentObserver(
Settings.Global.getUriFor(UIDS_ALLOWED_ON_RESTRICTED_NETWORKS));
- // One user MOCK_USER1
- mPermissionMonitor.onUserAdded(MOCK_USER1);
// Prepare PackageInfo for MOCK_PACKAGE1 and MOCK_PACKAGE2.
buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1);
buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID2);
// MOCK_UID1 is listed in setting that allow to use restricted networks, MOCK_UID1
- // in MOCK_USER1 should have SYSTEM permission and MOCK_UID2 has no permissions.
- when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(
- new ArraySet<>(new Integer[] { MOCK_UID1 }));
+ // should have SYSTEM permission and MOCK_UID2 has no permissions.
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of(MOCK_UID1));
contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
- mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_UID2);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1},
+ MOCK_APPID1);
+ mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_APPID2);
// Add user MOCK_USER2.
mPermissionMonitor.onUserAdded(MOCK_USER2);
- // MOCK_UID1 in both users should all have SYSTEM permission and MOCK_UID2 has no
+ // MOCK_APPID1 in both users should all have SYSTEM permission and MOCK_APPID2 has no
// permissions in either user.
- mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_UID1);
- mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_UID2);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ MOCK_APPID1);
+ mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_APPID2);
- // MOCK_UID2 is listed in setting that allow to use restricted networks, MOCK_UID2
- // in both users should have SYSTEM permission and MOCK_UID1 has no permissions.
- when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(
- new ArraySet<>(new Integer[] { MOCK_UID2 }));
+ // MOCK_UID2 is listed in setting that allow to use restricted networks, MOCK_APPID2
+ // in both users should have SYSTEM permission and MOCK_APPID1 has no permissions in either
+ // user.
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of(MOCK_UID2));
contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_UID2);
- mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_UID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ MOCK_APPID2);
+ mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_APPID1);
// Remove user MOCK_USER1
mPermissionMonitor.onUserRemoved(MOCK_USER1);
- mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER2}, MOCK_UID2);
- mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER2}, MOCK_UID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER2},
+ MOCK_APPID2);
+ mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER2}, MOCK_APPID1);
+ mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_APPID2);
// No uid lists in setting, should revoke permission from all uids.
- when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
+ when(mDeps.getUidsAllowedOnRestrictedNetworks(any())).thenReturn(Set.of());
contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER2}, MOCK_UID1, MOCK_UID2);
+ mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER2}, MOCK_APPID1, MOCK_APPID2);
}
@Test
public void testOnExternalApplicationsAvailable() throws Exception {
- final BroadcastReceiver receiver = expectBroadcastReceiver(
- Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
-
// Initial the permission state. MOCK_PACKAGE1 and MOCK_PACKAGE2 are installed on external
// and have different uids. There has no permission for both uids.
- when(mUserManager.getUserHandles(eq(true))).thenReturn(List.of(MOCK_USER1));
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
List.of(buildPackageInfo(MOCK_PACKAGE1, MOCK_UID1),
buildPackageInfo(MOCK_PACKAGE2, MOCK_UID2)));
mPermissionMonitor.startMonitoring();
- mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_UID1, MOCK_UID2);
- mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_UID1, MOCK_UID2);
+ mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_APPID1, MOCK_APPID2);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_APPID1, MOCK_APPID2);
+ final BroadcastReceiver receiver = expectBroadcastReceiver(
+ Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
// Verify receiving EXTERNAL_APPLICATIONS_AVAILABLE intent and update permission to netd.
final Intent externalIntent = new Intent(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
externalIntent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST,
@@ -1051,21 +1062,21 @@
buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID2, CHANGE_NETWORK_STATE,
UPDATE_DEVICE_STATS);
receiver.onReceive(mContext, externalIntent);
- mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
- mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1}, MOCK_UID2);
- mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID1);
- mNetdMonitor.expectTrafficPerm(PERMISSION_UPDATE_DEVICE_STATS, MOCK_UID2);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1},
+ MOCK_APPID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1},
+ MOCK_APPID2);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_UPDATE_DEVICE_STATS, MOCK_APPID2);
}
@Test
public void testOnExternalApplicationsAvailable_AppsNotRegisteredOnStartMonitoring()
throws Exception {
+ mPermissionMonitor.startMonitoring();
final BroadcastReceiver receiver = expectBroadcastReceiver(
Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
- // One user MOCK_USER1
- mPermissionMonitor.onUserAdded(MOCK_USER1);
-
// Initial the permission state. MOCK_PACKAGE1 and MOCK_PACKAGE2 are installed on external
// and have different uids. There has no permission for both uids.
buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1,
@@ -1078,58 +1089,56 @@
externalIntent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST,
new String[] { MOCK_PACKAGE1 , MOCK_PACKAGE2});
receiver.onReceive(mContext, externalIntent);
- mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
- mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1}, MOCK_UID2);
- mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID1);
- mNetdMonitor.expectTrafficPerm(PERMISSION_UPDATE_DEVICE_STATS, MOCK_UID2);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1},
+ MOCK_APPID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1},
+ MOCK_APPID2);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_UPDATE_DEVICE_STATS, MOCK_APPID2);
}
@Test
public void testOnExternalApplicationsAvailableWithSharedUid()
throws Exception {
- final BroadcastReceiver receiver = expectBroadcastReceiver(
- Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
-
// Initial the permission state. MOCK_PACKAGE1 and MOCK_PACKAGE2 are installed on external
// storage and shared on MOCK_UID1. There has no permission for MOCK_UID1.
- when(mUserManager.getUserHandles(eq(true))).thenReturn(List.of(MOCK_USER1));
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
List.of(buildPackageInfo(MOCK_PACKAGE1, MOCK_UID1),
buildPackageInfo(MOCK_PACKAGE2, MOCK_UID1)));
mPermissionMonitor.startMonitoring();
- mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_UID1);
- mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_UID1);
+ mNetdMonitor.expectNoNetworkPerm(new UserHandle[]{MOCK_USER1}, MOCK_APPID1);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_APPID1);
+ final BroadcastReceiver receiver = expectBroadcastReceiver(
+ Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
// Verify receiving EXTERNAL_APPLICATIONS_AVAILABLE intent and update permission to netd.
final Intent externalIntent = new Intent(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
externalIntent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST, new String[] {MOCK_PACKAGE1});
buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE);
buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID1, UPDATE_DEVICE_STATS);
- when(mPackageManager.getPackagesForUid(MOCK_UID1))
- .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
receiver.onReceive(mContext, externalIntent);
- mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
- mNetdMonitor.expectTrafficPerm(PERMISSION_UPDATE_DEVICE_STATS, MOCK_UID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1},
+ MOCK_APPID1);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_UPDATE_DEVICE_STATS, MOCK_APPID1);
}
@Test
public void testOnExternalApplicationsAvailableWithSharedUid_DifferentStorage()
throws Exception {
- final BroadcastReceiver receiver = expectBroadcastReceiver(
- Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
-
// Initial the permission state. MOCK_PACKAGE1 is installed on external storage and
// MOCK_PACKAGE2 is installed on device. These two packages are shared on MOCK_UID1.
// MOCK_UID1 has NETWORK and INTERNET permissions.
- when(mUserManager.getUserHandles(eq(true))).thenReturn(List.of(MOCK_USER1));
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
List.of(buildPackageInfo(MOCK_PACKAGE1, MOCK_UID1),
buildPackageInfo(MOCK_PACKAGE2, MOCK_UID1, CHANGE_NETWORK_STATE,
INTERNET)));
mPermissionMonitor.startMonitoring();
- mNetdMonitor.expectNetworkPerm(NETWORK, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
- mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_UID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_NETWORK, new UserHandle[]{MOCK_USER1},
+ MOCK_APPID1);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
+ final BroadcastReceiver receiver = expectBroadcastReceiver(
+ Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
// Verify receiving EXTERNAL_APPLICATIONS_AVAILABLE intent and update permission to netd.
final Intent externalIntent = new Intent(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
externalIntent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST, new String[] {MOCK_PACKAGE1});
@@ -1137,10 +1146,22 @@
CONNECTIVITY_USE_RESTRICTED_NETWORKS, UPDATE_DEVICE_STATS);
buildAndMockPackageInfoWithPermissions(MOCK_PACKAGE2, MOCK_UID1, CHANGE_NETWORK_STATE,
INTERNET);
- when(mPackageManager.getPackagesForUid(MOCK_UID1))
- .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
receiver.onReceive(mContext, externalIntent);
- mNetdMonitor.expectNetworkPerm(SYSTEM, new UserHandle[]{MOCK_USER1}, MOCK_UID1);
- mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_UID1);
+ mNetdMonitor.expectNetworkPerm(PERMISSION_SYSTEM, new UserHandle[]{MOCK_USER1},
+ MOCK_APPID1);
+ mNetdMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
+ }
+
+ @Test
+ public void testIsHigherNetworkPermission() {
+ assertFalse(isHigherNetworkPermission(PERMISSION_NONE, PERMISSION_NONE));
+ assertFalse(isHigherNetworkPermission(PERMISSION_NONE, PERMISSION_NETWORK));
+ assertFalse(isHigherNetworkPermission(PERMISSION_NONE, PERMISSION_SYSTEM));
+ assertTrue(isHigherNetworkPermission(PERMISSION_NETWORK, PERMISSION_NONE));
+ assertFalse(isHigherNetworkPermission(PERMISSION_NETWORK, PERMISSION_NETWORK));
+ assertFalse(isHigherNetworkPermission(PERMISSION_NETWORK, PERMISSION_SYSTEM));
+ assertTrue(isHigherNetworkPermission(PERMISSION_SYSTEM, PERMISSION_NONE));
+ assertTrue(isHigherNetworkPermission(PERMISSION_SYSTEM, PERMISSION_NETWORK));
+ assertFalse(isHigherNetworkPermission(PERMISSION_SYSTEM, PERMISSION_SYSTEM));
}
}