Merge "[NS01] Create NetworkScore"
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 43ea589..ff4bf2d 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -16,6 +16,7 @@
package android.net;
+import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Build;
@@ -418,7 +419,16 @@
if (score < 0) {
throw new IllegalArgumentException("Score must be >= 0");
}
- queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, score, 0);
+ final NetworkScore ns = new NetworkScore();
+ ns.putIntExtension(NetworkScore.LEGACY_SCORE, score);
+ updateScore(ns);
+ }
+
+ /**
+ * Called by the bearer code when it has a new NetworkScore for this network.
+ */
+ public void updateScore(@NonNull NetworkScore ns) {
+ queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new NetworkScore(ns));
}
/**
diff --git a/core/java/android/net/NetworkScore.java b/core/java/android/net/NetworkScore.java
new file mode 100644
index 0000000..1ab6335
--- /dev/null
+++ b/core/java/android/net/NetworkScore.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2019 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.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Object representing the quality of a network as perceived by the user.
+ *
+ * A NetworkScore object represents the characteristics of a network that affects how good the
+ * network is considered for a particular use.
+ * @hide
+ */
+public final class NetworkScore implements Parcelable {
+
+ // The key of bundle which is used to get the legacy network score of NetworkAgentInfo.
+ // TODO: Remove this when the transition to NetworkScore is over.
+ public static final String LEGACY_SCORE = "LEGACY_SCORE";
+ @NonNull
+ private final Bundle mExtensions;
+
+ public NetworkScore() {
+ mExtensions = new Bundle();
+ }
+
+ public NetworkScore(@NonNull NetworkScore source) {
+ mExtensions = new Bundle(source.mExtensions);
+ }
+
+ /**
+ * Put the value of parcelable inside the bundle by key.
+ */
+ public void putExtension(@Nullable String key, @Nullable Parcelable value) {
+ mExtensions.putParcelable(key, value);
+ }
+
+ /**
+ * Put the value of int inside the bundle by key.
+ */
+ public void putIntExtension(@Nullable String key, int value) {
+ mExtensions.putInt(key, value);
+ }
+
+ /**
+ * Get the value of non primitive type by key.
+ */
+ public <T extends Parcelable> T getExtension(@Nullable String key) {
+ return mExtensions.getParcelable(key);
+ }
+
+ /**
+ * Get the value of int by key.
+ */
+ public int getIntExtension(@Nullable String key) {
+ return mExtensions.getInt(key);
+ }
+
+ /**
+ * Remove the entry by given key.
+ */
+ public void removeExtension(@Nullable String key) {
+ mExtensions.remove(key);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ synchronized (this) {
+ dest.writeBundle(mExtensions);
+ }
+ }
+
+ public static final @NonNull Creator<NetworkScore> CREATOR = new Creator<NetworkScore>() {
+ @Override
+ public NetworkScore createFromParcel(@NonNull Parcel in) {
+ return new NetworkScore(in);
+ }
+
+ @Override
+ public NetworkScore[] newArray(int size) {
+ return new NetworkScore[size];
+ }
+ };
+
+ private NetworkScore(@NonNull Parcel in) {
+ mExtensions = in.readBundle();
+ }
+
+ // TODO: Modify this method once new fields are added into this class.
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof NetworkScore)) {
+ return false;
+ }
+ final NetworkScore other = (NetworkScore) obj;
+ return bundlesEqual(mExtensions, other.mExtensions);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 29;
+ for (String key : mExtensions.keySet()) {
+ final Object value = mExtensions.get(key);
+ // The key may be null, so call Objects.hash() is safer.
+ result += 31 * value.hashCode() + 37 * Objects.hash(key);
+ }
+ return result;
+ }
+
+ // mExtensions won't be null since the constructor will create it.
+ private boolean bundlesEqual(@NonNull Bundle bundle1, @NonNull Bundle bundle2) {
+ if (bundle1 == bundle2) {
+ return true;
+ }
+
+ // This is unlikely but it's fine to add this clause here.
+ if (null == bundle1 || null == bundle2) {
+ return false;
+ }
+
+ if (bundle1.size() != bundle2.size()) {
+ return false;
+ }
+
+ for (String key : bundle1.keySet()) {
+ final Object value1 = bundle1.get(key);
+ final Object value2 = bundle2.get(key);
+ if (!Objects.equals(value1, value2)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index ce0e9e7..81eb4b3 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -97,6 +97,7 @@
import android.net.NetworkPolicyManager;
import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
import android.net.NetworkSpecifier;
import android.net.NetworkStack;
import android.net.NetworkStackClient;
@@ -2643,7 +2644,8 @@
break;
}
case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: {
- updateNetworkScore(nai, msg.arg1);
+ final NetworkScore ns = (NetworkScore) msg.obj;
+ updateNetworkScore(nai, ns);
break;
}
case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: {
@@ -5594,9 +5596,11 @@
// TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
// satisfies mDefaultRequest.
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
+ final NetworkScore ns = new NetworkScore();
+ ns.putIntExtension(NetworkScore.LEGACY_SCORE, currentScore);
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
- currentScore, mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd,
+ ns, mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd,
mDnsResolver, mNMS, factorySerialNumber);
// Make sure the network capabilities reflect what the agent info says.
nai.setNetworkCapabilities(mixInCapabilities(nai, nc));
@@ -6729,7 +6733,8 @@
}
}
- private void updateNetworkScore(NetworkAgentInfo nai, int score) {
+ private void updateNetworkScore(NetworkAgentInfo nai, NetworkScore ns) {
+ int score = ns.getIntExtension(NetworkScore.LEGACY_SCORE);
if (VDBG || DDBG) log("updateNetworkScore for " + nai.name() + " to " + score);
if (score < 0) {
loge("updateNetworkScore for " + nai.name() + " got a negative score (" + score +
@@ -6738,7 +6743,7 @@
}
final int oldScore = nai.getCurrentScore();
- nai.setCurrentScore(score);
+ nai.setNetworkScore(ns);
rematchAllNetworksAndRequests(nai, oldScore);
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 96b7cb3..24a5b7f 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -28,6 +28,7 @@
import android.net.NetworkMisc;
import android.net.NetworkMonitorManager;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
import android.net.NetworkState;
import android.os.Handler;
import android.os.INetworkManagementService;
@@ -227,8 +228,10 @@
// validated).
private boolean mLingering;
- // This represents the last score received from the NetworkAgent.
- private int currentScore;
+ // This represents the characteristics of a network that affects how good the network is
+ // considered for a particular use.
+ @NonNull
+ private NetworkScore mNetworkScore;
// The list of NetworkRequests being satisfied by this Network.
private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
@@ -257,8 +260,8 @@
private final Handler mHandler;
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
- LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
- NetworkMisc misc, ConnectivityService connService, INetd netd,
+ LinkProperties lp, NetworkCapabilities nc, @NonNull NetworkScore ns, Context context,
+ Handler handler, NetworkMisc misc, ConnectivityService connService, INetd netd,
IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber) {
this.messenger = messenger;
asyncChannel = ac;
@@ -266,7 +269,7 @@
networkInfo = info;
linkProperties = lp;
networkCapabilities = nc;
- currentScore = score;
+ mNetworkScore = ns;
clatd = new Nat464Xlat(this, netd, dnsResolver, nms);
mConnService = connService;
mContext = context;
@@ -483,7 +486,7 @@
return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE;
}
- int score = currentScore;
+ int score = mNetworkScore.getIntExtension(NetworkScore.LEGACY_SCORE);
if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) {
score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY;
}
@@ -512,8 +515,13 @@
return getCurrentScore(true);
}
- public void setCurrentScore(int newScore) {
- currentScore = newScore;
+ public void setNetworkScore(@NonNull NetworkScore ns) {
+ mNetworkScore = ns;
+ }
+
+ @NonNull
+ public NetworkScore getNetworkScore() {
+ return mNetworkScore;
}
public NetworkState getNetworkState() {
diff --git a/tests/net/common/java/android/net/NetworkScoreTest.kt b/tests/net/common/java/android/net/NetworkScoreTest.kt
new file mode 100644
index 0000000..30836b7
--- /dev/null
+++ b/tests/net/common/java/android/net/NetworkScoreTest.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2019 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.Parcelable
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.assertParcelSane
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val TEST_SCORE = 80
+private const val KEY_DEFAULT_CAPABILITIES = "DEFAULT_CAPABILITIES"
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class NetworkScoreTest {
+ @Test
+ fun testParcelNetworkScore() {
+ val networkScore = NetworkScore()
+ val defaultCap = NetworkCapabilities()
+ networkScore.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
+ assertEquals(defaultCap, networkScore.getExtension(KEY_DEFAULT_CAPABILITIES))
+ networkScore.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
+ assertEquals(TEST_SCORE, networkScore.getIntExtension(NetworkScore.LEGACY_SCORE))
+ assertParcelSane(networkScore, 1)
+ }
+
+ @Test
+ fun testNullKeyAndValue() {
+ val networkScore = NetworkScore()
+ val defaultCap = NetworkCapabilities()
+ networkScore.putIntExtension(null, TEST_SCORE)
+ assertEquals(TEST_SCORE, networkScore.getIntExtension(null))
+ networkScore.putExtension(null, defaultCap)
+ assertEquals(defaultCap, networkScore.getExtension(null))
+ networkScore.putExtension(null, null)
+ val result: Parcelable? = networkScore.getExtension(null)
+ assertEquals(null, result)
+ }
+
+ @Test
+ fun testRemoveExtension() {
+ val networkScore = NetworkScore()
+ val defaultCap = NetworkCapabilities()
+ networkScore.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
+ networkScore.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
+ assertEquals(defaultCap, networkScore.getExtension(KEY_DEFAULT_CAPABILITIES))
+ assertEquals(TEST_SCORE, networkScore.getIntExtension(NetworkScore.LEGACY_SCORE))
+ networkScore.removeExtension(KEY_DEFAULT_CAPABILITIES)
+ networkScore.removeExtension(NetworkScore.LEGACY_SCORE)
+ val result: Parcelable? = networkScore.getExtension(KEY_DEFAULT_CAPABILITIES)
+ assertEquals(null, result)
+ assertEquals(0, networkScore.getIntExtension(NetworkScore.LEGACY_SCORE))
+ }
+
+ @Test
+ fun testEqualsNetworkScore() {
+ val ns1 = NetworkScore()
+ val ns2 = NetworkScore()
+ assertTrue(ns1.equals(ns2))
+ assertEquals(ns1.hashCode(), ns2.hashCode())
+
+ ns1.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
+ assertFalse(ns1.equals(ns2))
+ assertNotEquals(ns1.hashCode(), ns2.hashCode())
+ ns2.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
+ assertTrue(ns1.equals(ns2))
+ assertEquals(ns1.hashCode(), ns2.hashCode())
+
+ val defaultCap = NetworkCapabilities()
+ ns1.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
+ assertFalse(ns1.equals(ns2))
+ assertNotEquals(ns1.hashCode(), ns2.hashCode())
+ ns2.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
+ assertTrue(ns1.equals(ns2))
+ assertEquals(ns1.hashCode(), ns2.hashCode())
+
+ ns1.putIntExtension(null, 10)
+ assertFalse(ns1.equals(ns2))
+ assertNotEquals(ns1.hashCode(), ns2.hashCode())
+ ns2.putIntExtension(null, 10)
+ assertTrue(ns1.equals(ns2))
+ assertEquals(ns1.hashCode(), ns2.hashCode())
+ }
+}
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 142769f..535298f 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -39,6 +39,7 @@
import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkMisc;
+import android.net.NetworkScore;
import android.os.INetworkManagementService;
import android.text.format.DateUtils;
@@ -354,8 +355,10 @@
NetworkCapabilities caps = new NetworkCapabilities();
caps.addCapability(0);
caps.addTransportType(transport);
+ NetworkScore ns = new NetworkScore();
+ ns.putIntExtension(NetworkScore.LEGACY_SCORE, 50);
NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
- caps, 50, mCtx, null, mMisc, mConnService, mNetd, mDnsResolver, mNMS,
+ caps, ns, mCtx, null, mMisc, mConnService, mNetd, mDnsResolver, mNMS,
NetworkFactory.SerialNumber.NONE);
nai.everValidated = true;
return nai;