Map network identity using ConnectivityService.
Instead of deriving network identity based on raw subsystem broadcasts, listen for updates from ConnectivityService. Added atomic view of all active NetworkState, and build map from "iface" to NetworkIdentity set for stats tracking. To avoid exposing internal complexity, INetworkStatsService calls use general templates. Added TelephonyManager mapping to classify network types using broad labels like "3G" or "4G", used to drive templates. Cleaned up Objects and Preconditions. Change-Id: I1d4c1403f0503bc3635a59bb378841ba42239a91
This commit is contained in:
@@ -256,10 +256,61 @@ public class ConnectivityManager {
|
|||||||
|
|
||||||
private final IConnectivityManager mService;
|
private final IConnectivityManager mService;
|
||||||
|
|
||||||
static public boolean isNetworkTypeValid(int networkType) {
|
public static boolean isNetworkTypeValid(int networkType) {
|
||||||
return networkType >= 0 && networkType <= MAX_NETWORK_TYPE;
|
return networkType >= 0 && networkType <= MAX_NETWORK_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** {@hide} */
|
||||||
|
public static String getNetworkTypeName(int type) {
|
||||||
|
switch (type) {
|
||||||
|
case TYPE_MOBILE:
|
||||||
|
return "MOBILE";
|
||||||
|
case TYPE_WIFI:
|
||||||
|
return "WIFI";
|
||||||
|
case TYPE_MOBILE_MMS:
|
||||||
|
return "MOBILE_MMS";
|
||||||
|
case TYPE_MOBILE_SUPL:
|
||||||
|
return "MOBILE_SUPL";
|
||||||
|
case TYPE_MOBILE_DUN:
|
||||||
|
return "MOBILE_DUN";
|
||||||
|
case TYPE_MOBILE_HIPRI:
|
||||||
|
return "MOBILE_HIPRI";
|
||||||
|
case TYPE_WIMAX:
|
||||||
|
return "WIMAX";
|
||||||
|
case TYPE_BLUETOOTH:
|
||||||
|
return "BLUETOOTH";
|
||||||
|
case TYPE_DUMMY:
|
||||||
|
return "DUMMY";
|
||||||
|
case TYPE_ETHERNET:
|
||||||
|
return "ETHERNET";
|
||||||
|
case TYPE_MOBILE_FOTA:
|
||||||
|
return "MOBILE_FOTA";
|
||||||
|
case TYPE_MOBILE_IMS:
|
||||||
|
return "MOBILE_IMS";
|
||||||
|
case TYPE_MOBILE_CBS:
|
||||||
|
return "MOBILE_CBS";
|
||||||
|
default:
|
||||||
|
return Integer.toString(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@hide} */
|
||||||
|
public static boolean isNetworkTypeMobile(int networkType) {
|
||||||
|
switch (networkType) {
|
||||||
|
case TYPE_MOBILE:
|
||||||
|
case TYPE_MOBILE_MMS:
|
||||||
|
case TYPE_MOBILE_SUPL:
|
||||||
|
case TYPE_MOBILE_DUN:
|
||||||
|
case TYPE_MOBILE_HIPRI:
|
||||||
|
case TYPE_MOBILE_FOTA:
|
||||||
|
case TYPE_MOBILE_IMS:
|
||||||
|
case TYPE_MOBILE_CBS:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setNetworkPreference(int preference) {
|
public void setNetworkPreference(int preference) {
|
||||||
try {
|
try {
|
||||||
mService.setNetworkPreference(preference);
|
mService.setNetworkPreference(preference);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package android.net;
|
|||||||
|
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
|
import android.net.NetworkState;
|
||||||
import android.net.ProxyProperties;
|
import android.net.ProxyProperties;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
||||||
@@ -40,6 +41,8 @@ interface IConnectivityManager
|
|||||||
LinkProperties getActiveLinkProperties();
|
LinkProperties getActiveLinkProperties();
|
||||||
LinkProperties getLinkProperties(int networkType);
|
LinkProperties getLinkProperties(int networkType);
|
||||||
|
|
||||||
|
NetworkState[] getAllNetworkState();
|
||||||
|
|
||||||
boolean setRadios(boolean onOff);
|
boolean setRadios(boolean onOff);
|
||||||
|
|
||||||
boolean setRadio(int networkType, boolean turnOn);
|
boolean setRadio(int networkType, boolean turnOn);
|
||||||
|
|||||||
68
core/java/android/net/NetworkState.java
Normal file
68
core/java/android/net/NetworkState.java
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package android.net;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Snapshot of network state.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public class NetworkState implements Parcelable {
|
||||||
|
|
||||||
|
public final NetworkInfo networkInfo;
|
||||||
|
public final LinkProperties linkProperties;
|
||||||
|
public final LinkCapabilities linkCapabilities;
|
||||||
|
|
||||||
|
public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
|
||||||
|
LinkCapabilities linkCapabilities) {
|
||||||
|
this.networkInfo = networkInfo;
|
||||||
|
this.linkProperties = linkProperties;
|
||||||
|
this.linkCapabilities = linkCapabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetworkState(Parcel in) {
|
||||||
|
networkInfo = in.readParcelable(null);
|
||||||
|
linkProperties = in.readParcelable(null);
|
||||||
|
linkCapabilities = in.readParcelable(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
|
out.writeParcelable(networkInfo, flags);
|
||||||
|
out.writeParcelable(linkProperties, flags);
|
||||||
|
out.writeParcelable(linkCapabilities, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator<NetworkState> CREATOR = new Creator<NetworkState>() {
|
||||||
|
public NetworkState createFromParcel(Parcel in) {
|
||||||
|
return new NetworkState(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetworkState[] newArray(int size) {
|
||||||
|
return new NetworkState[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package android.net;
|
package android.net;
|
||||||
|
|
||||||
import static android.net.ConnectivityManager.TYPE_MOBILE;
|
|
||||||
import static android.net.NetworkStatsHistory.UID_ALL;
|
|
||||||
import static android.text.format.DateUtils.DAY_IN_MILLIS;
|
import static android.text.format.DateUtils.DAY_IN_MILLIS;
|
||||||
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
|
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
|
||||||
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
|
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
|
||||||
@@ -51,7 +49,7 @@ public class NetworkStatsHistoryTest extends TestCase {
|
|||||||
|
|
||||||
public void testRecordSingleBucket() throws Exception {
|
public void testRecordSingleBucket() throws Exception {
|
||||||
final long BUCKET_SIZE = HOUR_IN_MILLIS;
|
final long BUCKET_SIZE = HOUR_IN_MILLIS;
|
||||||
stats = buildStats(BUCKET_SIZE);
|
stats = new NetworkStatsHistory(BUCKET_SIZE);
|
||||||
|
|
||||||
// record data into narrow window to get single bucket
|
// record data into narrow window to get single bucket
|
||||||
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 1024L, 2048L);
|
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 1024L, 2048L);
|
||||||
@@ -62,7 +60,7 @@ public class NetworkStatsHistoryTest extends TestCase {
|
|||||||
|
|
||||||
public void testRecordEqualBuckets() throws Exception {
|
public void testRecordEqualBuckets() throws Exception {
|
||||||
final long bucketDuration = HOUR_IN_MILLIS;
|
final long bucketDuration = HOUR_IN_MILLIS;
|
||||||
stats = buildStats(bucketDuration);
|
stats = new NetworkStatsHistory(bucketDuration);
|
||||||
|
|
||||||
// split equally across two buckets
|
// split equally across two buckets
|
||||||
final long recordStart = TEST_START + (bucketDuration / 2);
|
final long recordStart = TEST_START + (bucketDuration / 2);
|
||||||
@@ -75,7 +73,7 @@ public class NetworkStatsHistoryTest extends TestCase {
|
|||||||
|
|
||||||
public void testRecordTouchingBuckets() throws Exception {
|
public void testRecordTouchingBuckets() throws Exception {
|
||||||
final long BUCKET_SIZE = 15 * MINUTE_IN_MILLIS;
|
final long BUCKET_SIZE = 15 * MINUTE_IN_MILLIS;
|
||||||
stats = buildStats(BUCKET_SIZE);
|
stats = new NetworkStatsHistory(BUCKET_SIZE);
|
||||||
|
|
||||||
// split almost completely into middle bucket, but with a few minutes
|
// split almost completely into middle bucket, but with a few minutes
|
||||||
// overlap into neighboring buckets. total record is 20 minutes.
|
// overlap into neighboring buckets. total record is 20 minutes.
|
||||||
@@ -94,7 +92,7 @@ public class NetworkStatsHistoryTest extends TestCase {
|
|||||||
|
|
||||||
public void testRecordGapBuckets() throws Exception {
|
public void testRecordGapBuckets() throws Exception {
|
||||||
final long BUCKET_SIZE = HOUR_IN_MILLIS;
|
final long BUCKET_SIZE = HOUR_IN_MILLIS;
|
||||||
stats = buildStats(BUCKET_SIZE);
|
stats = new NetworkStatsHistory(BUCKET_SIZE);
|
||||||
|
|
||||||
// record some data today and next week with large gap
|
// record some data today and next week with large gap
|
||||||
final long firstStart = TEST_START;
|
final long firstStart = TEST_START;
|
||||||
@@ -122,7 +120,7 @@ public class NetworkStatsHistoryTest extends TestCase {
|
|||||||
|
|
||||||
public void testRecordOverlapBuckets() throws Exception {
|
public void testRecordOverlapBuckets() throws Exception {
|
||||||
final long BUCKET_SIZE = HOUR_IN_MILLIS;
|
final long BUCKET_SIZE = HOUR_IN_MILLIS;
|
||||||
stats = buildStats(BUCKET_SIZE);
|
stats = new NetworkStatsHistory(BUCKET_SIZE);
|
||||||
|
|
||||||
// record some data in one bucket, and another overlapping buckets
|
// record some data in one bucket, and another overlapping buckets
|
||||||
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 256L, 256L);
|
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 256L, 256L);
|
||||||
@@ -137,7 +135,7 @@ public class NetworkStatsHistoryTest extends TestCase {
|
|||||||
|
|
||||||
public void testRemove() throws Exception {
|
public void testRemove() throws Exception {
|
||||||
final long BUCKET_SIZE = HOUR_IN_MILLIS;
|
final long BUCKET_SIZE = HOUR_IN_MILLIS;
|
||||||
stats = buildStats(BUCKET_SIZE);
|
stats = new NetworkStatsHistory(BUCKET_SIZE);
|
||||||
|
|
||||||
// record some data across 24 buckets
|
// record some data across 24 buckets
|
||||||
stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 24L, 24L);
|
stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 24L, 24L);
|
||||||
@@ -171,7 +169,7 @@ public class NetworkStatsHistoryTest extends TestCase {
|
|||||||
// fuzzing with random events, looking for crashes
|
// fuzzing with random events, looking for crashes
|
||||||
final Random r = new Random();
|
final Random r = new Random();
|
||||||
for (int i = 0; i < 500; i++) {
|
for (int i = 0; i < 500; i++) {
|
||||||
stats = buildStats(r.nextLong());
|
stats = new NetworkStatsHistory(r.nextLong());
|
||||||
for (int j = 0; j < 10000; j++) {
|
for (int j = 0; j < 10000; j++) {
|
||||||
if (r.nextBoolean()) {
|
if (r.nextBoolean()) {
|
||||||
// add range
|
// add range
|
||||||
@@ -191,10 +189,6 @@ public class NetworkStatsHistoryTest extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static NetworkStatsHistory buildStats(long bucketSize) {
|
|
||||||
return new NetworkStatsHistory(TYPE_MOBILE, null, UID_ALL, bucketSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void assertConsistent(NetworkStatsHistory stats) {
|
private static void assertConsistent(NetworkStatsHistory stats) {
|
||||||
// verify timestamps are monotonic
|
// verify timestamps are monotonic
|
||||||
for (int i = 1; i < stats.bucketCount; i++) {
|
for (int i = 1; i < stats.bucketCount; i++) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.server;
|
package com.android.server;
|
||||||
|
|
||||||
|
import static android.Manifest.permission.READ_PHONE_STATE;
|
||||||
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
|
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
|
||||||
import static android.net.ConnectivityManager.isNetworkTypeValid;
|
import static android.net.ConnectivityManager.isNetworkTypeValid;
|
||||||
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
|
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
|
||||||
@@ -38,6 +39,7 @@ import android.net.MobileDataStateTracker;
|
|||||||
import android.net.NetworkConfig;
|
import android.net.NetworkConfig;
|
||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
import android.net.NetworkInfo.DetailedState;
|
import android.net.NetworkInfo.DetailedState;
|
||||||
|
import android.net.NetworkState;
|
||||||
import android.net.NetworkStateTracker;
|
import android.net.NetworkStateTracker;
|
||||||
import android.net.NetworkUtils;
|
import android.net.NetworkUtils;
|
||||||
import android.net.Proxy;
|
import android.net.Proxy;
|
||||||
@@ -65,6 +67,7 @@ import android.util.SparseIntArray;
|
|||||||
|
|
||||||
import com.android.internal.telephony.Phone;
|
import com.android.internal.telephony.Phone;
|
||||||
import com.android.server.connectivity.Tethering;
|
import com.android.server.connectivity.Tethering;
|
||||||
|
import com.google.android.collect.Lists;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -563,25 +566,32 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
*/
|
*/
|
||||||
private boolean isNetworkBlocked(NetworkInfo info, int uid) {
|
private boolean isNetworkBlocked(NetworkInfo info, int uid) {
|
||||||
synchronized (mUidRules) {
|
synchronized (mUidRules) {
|
||||||
return isNetworkBlockedLocked(info, uid);
|
// TODO: expand definition of "paid" network to cover tethered or
|
||||||
|
// paid hotspot use cases.
|
||||||
|
final boolean networkIsPaid = info.getType() != ConnectivityManager.TYPE_WIFI;
|
||||||
|
final int uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
|
||||||
|
|
||||||
|
if (networkIsPaid && (uidRules & RULE_REJECT_PAID) != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no restrictive rules; network is visible
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if UID is blocked from using the given {@link NetworkInfo}.
|
* Return a filtered version of the given {@link NetworkInfo}, potentially
|
||||||
|
* marked {@link DetailedState#BLOCKED} based on
|
||||||
|
* {@link #isNetworkBlocked(NetworkInfo, int)}.
|
||||||
*/
|
*/
|
||||||
private boolean isNetworkBlockedLocked(NetworkInfo info, int uid) {
|
private NetworkInfo filterNetworkInfo(NetworkInfo info, int uid) {
|
||||||
// TODO: expand definition of "paid" network to cover tethered or paid
|
if (isNetworkBlocked(info, uid)) {
|
||||||
// hotspot use cases.
|
// network is blocked; clone and override state
|
||||||
final boolean networkIsPaid = info.getType() != ConnectivityManager.TYPE_WIFI;
|
info = new NetworkInfo(info);
|
||||||
final int uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
|
info.setDetailedState(DetailedState.BLOCKED, null, null);
|
||||||
|
|
||||||
if (networkIsPaid && (uidRules & RULE_REJECT_PAID) != 0) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return info;
|
||||||
// no restrictive rules; network is visible
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -616,12 +626,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
if (isNetworkTypeValid(networkType)) {
|
if (isNetworkTypeValid(networkType)) {
|
||||||
final NetworkStateTracker tracker = mNetTrackers[networkType];
|
final NetworkStateTracker tracker = mNetTrackers[networkType];
|
||||||
if (tracker != null) {
|
if (tracker != null) {
|
||||||
info = tracker.getNetworkInfo();
|
info = filterNetworkInfo(tracker.getNetworkInfo(), uid);
|
||||||
if (isNetworkBlocked(info, uid)) {
|
|
||||||
// network is blocked; clone and override state
|
|
||||||
info = new NetworkInfo(info);
|
|
||||||
info.setDetailedState(DetailedState.BLOCKED, null, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return info;
|
return info;
|
||||||
@@ -631,22 +636,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
public NetworkInfo[] getAllNetworkInfo() {
|
public NetworkInfo[] getAllNetworkInfo() {
|
||||||
enforceAccessPermission();
|
enforceAccessPermission();
|
||||||
final int uid = Binder.getCallingUid();
|
final int uid = Binder.getCallingUid();
|
||||||
final NetworkInfo[] result = new NetworkInfo[mNetworksDefined];
|
final ArrayList<NetworkInfo> result = Lists.newArrayList();
|
||||||
int i = 0;
|
|
||||||
synchronized (mUidRules) {
|
synchronized (mUidRules) {
|
||||||
for (NetworkStateTracker tracker : mNetTrackers) {
|
for (NetworkStateTracker tracker : mNetTrackers) {
|
||||||
if (tracker != null) {
|
if (tracker != null) {
|
||||||
NetworkInfo info = tracker.getNetworkInfo();
|
result.add(filterNetworkInfo(tracker.getNetworkInfo(), uid));
|
||||||
if (isNetworkBlockedLocked(info, uid)) {
|
|
||||||
// network is blocked; clone and override state
|
|
||||||
info = new NetworkInfo(info);
|
|
||||||
info.setDetailedState(DetailedState.BLOCKED, null, null);
|
|
||||||
}
|
|
||||||
result[i++] = info;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result.toArray(new NetworkInfo[result.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -674,6 +672,23 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NetworkState[] getAllNetworkState() {
|
||||||
|
enforceAccessPermission();
|
||||||
|
final int uid = Binder.getCallingUid();
|
||||||
|
final ArrayList<NetworkState> result = Lists.newArrayList();
|
||||||
|
synchronized (mUidRules) {
|
||||||
|
for (NetworkStateTracker tracker : mNetTrackers) {
|
||||||
|
if (tracker != null) {
|
||||||
|
final NetworkInfo info = filterNetworkInfo(tracker.getNetworkInfo(), uid);
|
||||||
|
result.add(new NetworkState(
|
||||||
|
info, tracker.getLinkProperties(), tracker.getLinkCapabilities()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toArray(new NetworkState[result.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean setRadios(boolean turnOn) {
|
public boolean setRadios(boolean turnOn) {
|
||||||
boolean result = true;
|
boolean result = true;
|
||||||
enforceChangePermission();
|
enforceChangePermission();
|
||||||
|
|||||||
Reference in New Issue
Block a user