diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index c72c4b0fad..21cce44a15 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -256,10 +256,61 @@ public class ConnectivityManager { private final IConnectivityManager mService; - static public boolean isNetworkTypeValid(int networkType) { + public static boolean isNetworkTypeValid(int networkType) { 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) { try { mService.setNetworkPreference(preference); diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 647a60a97d..07f6cecea5 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -18,6 +18,7 @@ package android.net; import android.net.LinkProperties; import android.net.NetworkInfo; +import android.net.NetworkState; import android.net.ProxyProperties; import android.os.IBinder; @@ -40,6 +41,8 @@ interface IConnectivityManager LinkProperties getActiveLinkProperties(); LinkProperties getLinkProperties(int networkType); + NetworkState[] getAllNetworkState(); + boolean setRadios(boolean onOff); boolean setRadio(int networkType, boolean turnOn); diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java new file mode 100644 index 0000000000..749039a1af --- /dev/null +++ b/core/java/android/net/NetworkState.java @@ -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 CREATOR = new Creator() { + public NetworkState createFromParcel(Parcel in) { + return new NetworkState(in); + } + + public NetworkState[] newArray(int size) { + return new NetworkState[size]; + } + }; + +} diff --git a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java index eb63c0d66e..69bbcd74af 100644 --- a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java +++ b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java @@ -16,8 +16,6 @@ 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.HOUR_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 { 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 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 { final long bucketDuration = HOUR_IN_MILLIS; - stats = buildStats(bucketDuration); + stats = new NetworkStatsHistory(bucketDuration); // split equally across two buckets final long recordStart = TEST_START + (bucketDuration / 2); @@ -75,7 +73,7 @@ public class NetworkStatsHistoryTest extends TestCase { public void testRecordTouchingBuckets() throws Exception { 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 // overlap into neighboring buckets. total record is 20 minutes. @@ -94,7 +92,7 @@ public class NetworkStatsHistoryTest extends TestCase { public void testRecordGapBuckets() throws Exception { 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 final long firstStart = TEST_START; @@ -122,7 +120,7 @@ public class NetworkStatsHistoryTest extends TestCase { public void testRecordOverlapBuckets() throws Exception { 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 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 { final long BUCKET_SIZE = HOUR_IN_MILLIS; - stats = buildStats(BUCKET_SIZE); + stats = new NetworkStatsHistory(BUCKET_SIZE); // record some data across 24 buckets 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 final Random r = new Random(); for (int i = 0; i < 500; i++) { - stats = buildStats(r.nextLong()); + stats = new NetworkStatsHistory(r.nextLong()); for (int j = 0; j < 10000; j++) { if (r.nextBoolean()) { // 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) { // verify timestamps are monotonic for (int i = 1; i < stats.bucketCount; i++) { diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index b559fb900d..e3d4c45cf6 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -16,6 +16,7 @@ package com.android.server; +import static android.Manifest.permission.READ_PHONE_STATE; import static android.Manifest.permission.UPDATE_DEVICE_STATS; import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; @@ -38,6 +39,7 @@ import android.net.MobileDataStateTracker; import android.net.NetworkConfig; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; +import android.net.NetworkState; import android.net.NetworkStateTracker; import android.net.NetworkUtils; import android.net.Proxy; @@ -65,6 +67,7 @@ import android.util.SparseIntArray; import com.android.internal.telephony.Phone; import com.android.server.connectivity.Tethering; +import com.google.android.collect.Lists; import java.io.FileDescriptor; import java.io.IOException; @@ -563,25 +566,32 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private boolean isNetworkBlocked(NetworkInfo info, int uid) { 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) { - // 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; + private NetworkInfo filterNetworkInfo(NetworkInfo info, int uid) { + if (isNetworkBlocked(info, uid)) { + // network is blocked; clone and override state + info = new NetworkInfo(info); + info.setDetailedState(DetailedState.BLOCKED, null, null); } - - // no restrictive rules; network is visible - return false; + return info; } /** @@ -616,12 +626,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (isNetworkTypeValid(networkType)) { final NetworkStateTracker tracker = mNetTrackers[networkType]; if (tracker != null) { - info = tracker.getNetworkInfo(); - if (isNetworkBlocked(info, uid)) { - // network is blocked; clone and override state - info = new NetworkInfo(info); - info.setDetailedState(DetailedState.BLOCKED, null, null); - } + info = filterNetworkInfo(tracker.getNetworkInfo(), uid); } } return info; @@ -631,22 +636,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { public NetworkInfo[] getAllNetworkInfo() { enforceAccessPermission(); final int uid = Binder.getCallingUid(); - final NetworkInfo[] result = new NetworkInfo[mNetworksDefined]; - int i = 0; + final ArrayList result = Lists.newArrayList(); synchronized (mUidRules) { for (NetworkStateTracker tracker : mNetTrackers) { if (tracker != null) { - NetworkInfo info = tracker.getNetworkInfo(); - if (isNetworkBlockedLocked(info, uid)) { - // network is blocked; clone and override state - info = new NetworkInfo(info); - info.setDetailedState(DetailedState.BLOCKED, null, null); - } - result[i++] = info; + result.add(filterNetworkInfo(tracker.getNetworkInfo(), uid)); } } } - return result; + return result.toArray(new NetworkInfo[result.size()]); } /** @@ -674,6 +672,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { return null; } + @Override + public NetworkState[] getAllNetworkState() { + enforceAccessPermission(); + final int uid = Binder.getCallingUid(); + final ArrayList 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) { boolean result = true; enforceChangePermission();