Merge "Refactor based on new NetworkMonitor"
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 75af41c..56bacf2 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -52,13 +52,12 @@
import android.os.ServiceSpecificException;
import android.provider.Settings;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.telephony.ITelephony;
-import com.android.internal.telephony.PhoneConstants;
import com.android.internal.util.Preconditions;
import com.android.internal.util.Protocol;
@@ -711,6 +710,12 @@
@Deprecated
public static final int TYPE_TEST = 18; // TODO: Remove this once NetworkTypes are unused.
+ // Deprecated constants for return values of startUsingNetworkFeature. They used to live
+ // in com.android.internal.telephony.PhoneConstants until they were made inaccessible.
+ private static final int DEPRECATED_PHONE_CONSTANT_APN_ALREADY_ACTIVE = 0;
+ private static final int DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED = 1;
+ private static final int DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED = 3;
+
/** {@hide} */
public static final int MAX_RADIO_TYPE = TYPE_TEST;
@@ -1407,7 +1412,7 @@
if (netCap == null) {
Log.d(TAG, "Can't satisfy startUsingNetworkFeature for " + networkType + ", " +
feature);
- return PhoneConstants.APN_REQUEST_FAILED;
+ return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED;
}
NetworkRequest request = null;
@@ -1417,9 +1422,9 @@
Log.d(TAG, "renewing startUsingNetworkFeature request " + l.networkRequest);
renewRequestLocked(l);
if (l.currentNetwork != null) {
- return PhoneConstants.APN_ALREADY_ACTIVE;
+ return DEPRECATED_PHONE_CONSTANT_APN_ALREADY_ACTIVE;
} else {
- return PhoneConstants.APN_REQUEST_STARTED;
+ return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED;
}
}
@@ -1427,10 +1432,10 @@
}
if (request != null) {
Log.d(TAG, "starting startUsingNetworkFeature for request " + request);
- return PhoneConstants.APN_REQUEST_STARTED;
+ return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED;
} else {
Log.d(TAG, " request Failed");
- return PhoneConstants.APN_REQUEST_FAILED;
+ return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED;
}
}
@@ -2149,19 +2154,14 @@
@Deprecated
@UnsupportedAppUsage
public boolean getMobileDataEnabled() {
- IBinder b = ServiceManager.getService(Context.TELEPHONY_SERVICE);
- if (b != null) {
- try {
- ITelephony it = ITelephony.Stub.asInterface(b);
- int subId = SubscriptionManager.getDefaultDataSubscriptionId();
- Log.d("ConnectivityManager", "getMobileDataEnabled()+ subId=" + subId);
- boolean retVal = it.isUserDataEnabled(subId);
- Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId
- + " retVal=" + retVal);
- return retVal;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+ if (tm != null) {
+ int subId = SubscriptionManager.getDefaultDataSubscriptionId();
+ Log.d("ConnectivityManager", "getMobileDataEnabled()+ subId=" + subId);
+ boolean retVal = tm.createForSubscriptionId(subId).isDataEnabled();
+ Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId
+ + " retVal=" + retVal);
+ return retVal;
}
Log.d("ConnectivityManager", "getMobileDataEnabled()- remote exception retVal=false");
return false;
diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java
index 2af82d7..143467b 100644
--- a/core/java/android/net/IpConfiguration.java
+++ b/core/java/android/net/IpConfiguration.java
@@ -16,6 +16,10 @@
package android.net;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.net.StaticIpConfiguration;
import android.os.Parcel;
@@ -27,13 +31,17 @@
* A class representing a configured network.
* @hide
*/
-public class IpConfiguration implements Parcelable {
+@SystemApi
+public final class IpConfiguration implements Parcelable {
private static final String TAG = "IpConfiguration";
+ // This enum has been used by apps through reflection for many releases.
+ // Therefore they can't just be removed. Duplicating these constants to
+ // give an alternate SystemApi is a worse option than exposing them.
+ @SuppressLint("Enum")
public enum IpAssignment {
/* Use statically configured IP settings. Configuration can be accessed
* with staticIpConfiguration */
- @UnsupportedAppUsage
STATIC,
/* Use dynamically configured IP settings */
DHCP,
@@ -42,14 +50,19 @@
UNASSIGNED
}
+ /** @hide */
public IpAssignment ipAssignment;
+ /** @hide */
public StaticIpConfiguration staticIpConfiguration;
+ // This enum has been used by apps through reflection for many releases.
+ // Therefore they can't just be removed. Duplicating these constants to
+ // give an alternate SystemApi is a worse option than exposing them.
+ @SuppressLint("Enum")
public enum ProxySettings {
/* No proxy is to be used. Any existing proxy settings
* should be cleared. */
- @UnsupportedAppUsage
NONE,
/* Use statically configured proxy. Configuration can be accessed
* with httpProxy. */
@@ -62,8 +75,10 @@
PAC
}
+ /** @hide */
public ProxySettings proxySettings;
+ /** @hide */
@UnsupportedAppUsage
public ProxyInfo httpProxy;
@@ -83,6 +98,7 @@
init(IpAssignment.UNASSIGNED, ProxySettings.UNASSIGNED, null, null);
}
+ /** @hide */
@UnsupportedAppUsage
public IpConfiguration(IpAssignment ipAssignment,
ProxySettings proxySettings,
@@ -91,7 +107,7 @@
init(ipAssignment, proxySettings, staticIpConfiguration, httpProxy);
}
- public IpConfiguration(IpConfiguration source) {
+ public IpConfiguration(@NonNull IpConfiguration source) {
this();
if (source != null) {
init(source.ipAssignment, source.proxySettings,
@@ -99,35 +115,35 @@
}
}
- public IpAssignment getIpAssignment() {
+ public @NonNull IpAssignment getIpAssignment() {
return ipAssignment;
}
- public void setIpAssignment(IpAssignment ipAssignment) {
+ public void setIpAssignment(@NonNull IpAssignment ipAssignment) {
this.ipAssignment = ipAssignment;
}
- public StaticIpConfiguration getStaticIpConfiguration() {
+ public @Nullable StaticIpConfiguration getStaticIpConfiguration() {
return staticIpConfiguration;
}
- public void setStaticIpConfiguration(StaticIpConfiguration staticIpConfiguration) {
+ public void setStaticIpConfiguration(@Nullable StaticIpConfiguration staticIpConfiguration) {
this.staticIpConfiguration = staticIpConfiguration;
}
- public ProxySettings getProxySettings() {
+ public @NonNull ProxySettings getProxySettings() {
return proxySettings;
}
- public void setProxySettings(ProxySettings proxySettings) {
+ public void setProxySettings(@NonNull ProxySettings proxySettings) {
this.proxySettings = proxySettings;
}
- public ProxyInfo getHttpProxy() {
+ public @Nullable ProxyInfo getHttpProxy() {
return httpProxy;
}
- public void setHttpProxy(ProxyInfo httpProxy) {
+ public void setHttpProxy(@Nullable ProxyInfo httpProxy) {
this.httpProxy = httpProxy;
}
@@ -175,13 +191,19 @@
83 * httpProxy.hashCode();
}
- /** Implement the Parcelable interface */
+ /**
+ * Implement the Parcelable interface
+ * @hide
+ */
public int describeContents() {
return 0;
}
- /** Implement the Parcelable interface */
- public void writeToParcel(Parcel dest, int flags) {
+ /**
+ * Implement the Parcelable interface
+ * @hide
+ */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(ipAssignment.name());
dest.writeString(proxySettings.name());
dest.writeParcelable(staticIpConfiguration, flags);
@@ -189,7 +211,7 @@
}
/** Implement the Parcelable interface */
- public static final @android.annotation.NonNull Creator<IpConfiguration> CREATOR =
+ public static final @NonNull Creator<IpConfiguration> CREATOR =
new Creator<IpConfiguration>() {
public IpConfiguration createFromParcel(Parcel in) {
IpConfiguration config = new IpConfiguration();
diff --git a/core/java/android/net/NetworkScore.java b/core/java/android/net/NetworkScore.java
index 1ab6335..13f2994 100644
--- a/core/java/android/net/NetworkScore.java
+++ b/core/java/android/net/NetworkScore.java
@@ -154,4 +154,9 @@
}
return true;
}
+
+ /** Convert to a string */
+ public String toString() {
+ return "NetworkScore[" + mExtensions.toString() + "]";
+ }
}
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index 807c467..9d92db4 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -16,7 +16,8 @@
package android.net;
-
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
@@ -89,6 +90,15 @@
}
/**
+ * Construct a {@link ProxyInfo} object that will download and run the PAC script at the
+ * specified URL and port.
+ */
+ @NonNull
+ public static ProxyInfo buildPacProxy(@NonNull Uri pacUrl, int port) {
+ return new ProxyInfo(pacUrl, port);
+ }
+
+ /**
* Create a ProxyProperties that points at a HTTP Proxy.
* @hide
*/
@@ -105,7 +115,7 @@
* Create a ProxyProperties that points at a PAC URL.
* @hide
*/
- public ProxyInfo(Uri pacFileUrl) {
+ public ProxyInfo(@NonNull Uri pacFileUrl) {
mHost = LOCAL_HOST;
mPort = LOCAL_PORT;
mExclusionList = LOCAL_EXCL_LIST;
@@ -132,7 +142,7 @@
* Only used in PacManager after Local Proxy is bound.
* @hide
*/
- public ProxyInfo(Uri pacFileUrl, int localProxyPort) {
+ public ProxyInfo(@NonNull Uri pacFileUrl, int localProxyPort) {
mHost = LOCAL_HOST;
mPort = localProxyPort;
mExclusionList = LOCAL_EXCL_LIST;
@@ -159,11 +169,10 @@
mPacFileUrl = Uri.EMPTY;
}
- // copy constructor instead of clone
/**
- * @hide
+ * A copy constructor to hold proxy properties.
*/
- public ProxyInfo(ProxyInfo source) {
+ public ProxyInfo(@Nullable ProxyInfo source) {
if (source != null) {
mHost = source.getHost();
mPort = source.getPort();
@@ -226,12 +235,13 @@
* comma separated
* @hide
*/
+ @Nullable
public String getExclusionListAsString() {
return mExclusionList;
}
/**
- * @hide
+ * Return true if the pattern of proxy is valid, otherwise return false.
*/
public boolean isValid() {
if (!Uri.EMPTY.equals(mPacFileUrl)) return true;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 81eb4b3..bb7406a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -146,6 +146,7 @@
import android.security.KeyStore;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LocalLog;
import android.util.Log;
@@ -2185,6 +2186,11 @@
*/
@VisibleForTesting
public void systemReady() {
+ // Let PermissionMonitor#startMonitoring() running in the beginning of the systemReady
+ // before MultipathPolicyTracker.start(). Since mApps in PermissionMonitor needs to be
+ // populated first to ensure that listening network request which is sent by
+ // MultipathPolicyTracker won't be added NET_CAPABILITY_FOREGROUND capability.
+ mPermissionMonitor.startMonitoring();
mProxyTracker.loadGlobalProxy();
registerNetdEventCallback();
mTethering.systemReady();
@@ -2205,8 +2211,6 @@
mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS));
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_READY));
-
- mPermissionMonitor.startMonitoring();
}
/**
@@ -3050,7 +3054,8 @@
}
private void handleAsyncChannelHalfConnect(Message msg) {
- AsyncChannel ac = (AsyncChannel) msg.obj;
+ ensureRunningOnConnectivityServiceThread();
+ final AsyncChannel ac = (AsyncChannel) msg.obj;
if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
if (VDBG) log("NetworkFactory connected");
@@ -3060,7 +3065,8 @@
// A network factory has connected. Send it all current NetworkRequests.
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
if (nri.request.isListen()) continue;
- NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId);
+ ensureRunningOnConnectivityServiceThread();
+ NetworkAgentInfo nai = nri.mSatisfier;
final int score;
final int serial;
if (nai != null) {
@@ -3116,6 +3122,7 @@
// ConnectivityService, free its interfaces and clean up.
// Must be called on the Handler thread.
private void disconnectAndDestroyNetwork(NetworkAgentInfo nai) {
+ ensureRunningOnConnectivityServiceThread();
if (DBG) {
log(nai.name() + " got DISCONNECTED, was satisfying " + nai.numNetworkRequests());
}
@@ -3162,14 +3169,17 @@
// Remove all previously satisfied requests.
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest request = nai.requestAt(i);
- NetworkAgentInfo currentNetwork = getNetworkForRequest(request.requestId);
+ final NetworkRequestInfo nri = mNetworkRequests.get(request);
+ ensureRunningOnConnectivityServiceThread();
+ final NetworkAgentInfo currentNetwork = nri.mSatisfier;
if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
- clearNetworkForRequest(request.requestId);
+ nri.mSatisfier = null;
sendUpdatedScoreToFactories(request, null);
}
}
nai.clearLingerState();
if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
+ mDefaultNetworkNai = null;
updateDataActivityTracking(null /* newNetwork */, nai);
notifyLockdownVpn(nai);
ensureNetworkTransitionWakelock(nai.name());
@@ -3178,7 +3188,7 @@
if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
updateAllVpnsCapabilities();
}
- rematchAllNetworksAndRequests(null, 0);
+ rematchAllNetworksAndRequests();
mLingerMonitor.noteDisconnect(nai);
if (nai.created) {
// Tell netd to clean up the configuration for this network
@@ -3253,6 +3263,7 @@
}
private void handleRegisterNetworkRequest(NetworkRequestInfo nri) {
+ ensureRunningOnConnectivityServiceThread();
mNetworkRequests.put(nri.request, nri);
mNetworkRequestInfoLogs.log("REGISTER " + nri);
if (nri.request.isListen()) {
@@ -3263,8 +3274,8 @@
}
}
}
- rematchAllNetworksAndRequests(null, 0);
- if (nri.request.isRequest() && getNetworkForRequest(nri.request.requestId) == null) {
+ rematchAllNetworksAndRequests();
+ if (nri.request.isRequest() && nri.mSatisfier == null) {
sendUpdatedScoreToFactories(nri.request, null);
}
}
@@ -3286,6 +3297,7 @@
// - UnneededFor.LINGER: foreground NetworkRequests. If a network is unneeded for this reason,
// then it should be lingered.
private boolean unneeded(NetworkAgentInfo nai, UnneededFor reason) {
+ ensureRunningOnConnectivityServiceThread();
final int numRequests;
switch (reason) {
case TEARDOWN:
@@ -3310,6 +3322,7 @@
// If this Network is already the highest scoring Network for a request, or if
// there is hope for it to become one if it validated, then it is needed.
+ ensureRunningOnConnectivityServiceThread();
if (nri.request.isRequest() && nai.satisfies(nri.request) &&
(nai.isSatisfyingRequest(nri.request.requestId) ||
// Note that this catches two important cases:
@@ -3319,8 +3332,8 @@
// 2. Unvalidated WiFi will not be reaped when validated cellular
// is currently satisfying the request. This is desirable when
// WiFi ends up validating and out scoring cellular.
- getNetworkForRequest(nri.request.requestId).getCurrentScore() <
- nai.getCurrentScoreAsValidated())) {
+ nri.mSatisfier.getCurrentScore()
+ < nai.getCurrentScoreAsValidated())) {
return false;
}
}
@@ -3344,10 +3357,12 @@
}
private void handleTimedOutNetworkRequest(final NetworkRequestInfo nri) {
+ ensureRunningOnConnectivityServiceThread();
if (mNetworkRequests.get(nri.request) == null) {
return;
}
- if (getNetworkForRequest(nri.request.requestId) != null) {
+ ensureRunningOnConnectivityServiceThread();
+ if (nri.mSatisfier != null) {
return;
}
if (VDBG || (DBG && nri.request.isRequest())) {
@@ -3374,6 +3389,8 @@
}
private void handleRemoveNetworkRequest(final NetworkRequestInfo nri) {
+ ensureRunningOnConnectivityServiceThread();
+
nri.unlinkDeathRecipient();
mNetworkRequests.remove(nri.request);
@@ -3393,7 +3410,8 @@
mNetworkRequestInfoLogs.log("RELEASE " + nri);
if (nri.request.isRequest()) {
boolean wasKept = false;
- NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId);
+ ensureRunningOnConnectivityServiceThread();
+ final NetworkAgentInfo nai = nri.mSatisfier;
if (nai != null) {
boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
nai.removeRequest(nri.request.requestId);
@@ -3410,7 +3428,7 @@
} else {
wasKept = true;
}
- clearNetworkForRequest(nri.request.requestId);
+ nri.mSatisfier = null;
if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) {
// Went from foreground to background.
updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
@@ -3499,13 +3517,12 @@
}
if (accept != nai.networkMisc.acceptUnvalidated) {
- int oldScore = nai.getCurrentScore();
nai.networkMisc.acceptUnvalidated = accept;
// If network becomes partial connectivity and user already accepted to use this
// network, we should respect the user's option and don't need to popup the
// PARTIAL_CONNECTIVITY notification to user again.
nai.networkMisc.acceptPartialConnectivity = accept;
- rematchAllNetworksAndRequests(nai, oldScore);
+ rematchAllNetworksAndRequests();
sendUpdatedScoreToFactories(nai);
}
@@ -3574,9 +3591,8 @@
return;
}
if (!nai.avoidUnvalidated) {
- int oldScore = nai.getCurrentScore();
nai.avoidUnvalidated = true;
- rematchAllNetworksAndRequests(nai, oldScore);
+ rematchAllNetworksAndRequests();
sendUpdatedScoreToFactories(nai);
}
}
@@ -3677,7 +3693,7 @@
private void rematchForAvoidBadWifiUpdate() {
- rematchAllNetworksAndRequests(null, 0);
+ rematchAllNetworksAndRequests();
for (NetworkAgentInfo nai: mNetworkAgentInfos.values()) {
if (nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
sendUpdatedScoreToFactories(nai);
@@ -5093,6 +5109,11 @@
*/
private class NetworkRequestInfo implements IBinder.DeathRecipient {
final NetworkRequest request;
+ // The network currently satisfying this request, or null if none. Must only be touched
+ // on the handler thread. This only makes sense for network requests and not for listens,
+ // as defined by NetworkRequest#isRequest(). For listens, this is always null.
+ @Nullable
+ NetworkAgentInfo mSatisfier;
final PendingIntent mPendingIntent;
boolean mPendingIntentSent;
private final IBinder mBinder;
@@ -5479,16 +5500,6 @@
if (DBG) log("unregisterNetworkFactory for " + nfi.name);
}
- /**
- * NetworkAgentInfo supporting a request by requestId.
- * These have already been vetted (their Capabilities satisfy the request)
- * and the are the highest scored network available.
- * the are keyed off the Requests requestId.
- */
- // NOTE: Accessed on multiple threads, must be synchronized on itself.
- @GuardedBy("mNetworkForRequestId")
- private final SparseArray<NetworkAgentInfo> mNetworkForRequestId = new SparseArray<>();
-
// NOTE: Accessed on multiple threads, must be synchronized on itself.
@GuardedBy("mNetworkForNetId")
private final SparseArray<NetworkAgentInfo> mNetworkForNetId = new SparseArray<>();
@@ -5506,7 +5517,11 @@
private final HashSet<Integer> mBlockedAppUids = new HashSet<>();
// Note: if mDefaultRequest is changed, NetworkMonitor needs to be updated.
+ @NonNull
private final NetworkRequest mDefaultRequest;
+ // The NetworkAgentInfo currently satisfying the default request, if any.
+ @Nullable
+ private volatile NetworkAgentInfo mDefaultNetworkNai = null;
// Request used to optionally keep mobile data active even when higher
// priority networks like Wi-Fi are active.
@@ -5516,26 +5531,8 @@
// priority networks like ethernet are active.
private final NetworkRequest mDefaultWifiRequest;
- private NetworkAgentInfo getNetworkForRequest(int requestId) {
- synchronized (mNetworkForRequestId) {
- return mNetworkForRequestId.get(requestId);
- }
- }
-
- private void clearNetworkForRequest(int requestId) {
- synchronized (mNetworkForRequestId) {
- mNetworkForRequestId.remove(requestId);
- }
- }
-
- private void setNetworkForRequest(int requestId, NetworkAgentInfo nai) {
- synchronized (mNetworkForRequestId) {
- mNetworkForRequestId.put(requestId, nai);
- }
- }
-
private NetworkAgentInfo getDefaultNetwork() {
- return getNetworkForRequest(mDefaultRequest.requestId);
+ return mDefaultNetworkNai;
}
@Nullable
@@ -5968,7 +5965,7 @@
} else {
// If the requestable capabilities have changed or the score changed, we can't have been
// called by rematchNetworkAndRequests, so it's safe to start a rematch.
- rematchAllNetworksAndRequests(nai, oldScore);
+ rematchAllNetworksAndRequests();
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
@@ -6253,7 +6250,7 @@
}
}
- private void makeDefault(NetworkAgentInfo newNetwork) {
+ private void makeDefault(@NonNull final NetworkAgentInfo newNetwork) {
if (DBG) log("Switching to new default network: " + newNetwork);
try {
@@ -6262,6 +6259,7 @@
loge("Exception setting default network :" + e);
}
+ mDefaultNetworkNai = newNetwork;
notifyLockdownVpn(newNetwork);
handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
updateTcpBufferSizes(newNetwork.linkProperties.getTcpBufferSizes());
@@ -6296,6 +6294,41 @@
}
}
+ private ArrayMap<NetworkRequestInfo, NetworkAgentInfo> computeRequestReassignmentForNetwork(
+ @NonNull final NetworkAgentInfo newNetwork) {
+ final int score = newNetwork.getCurrentScore();
+ final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests = new ArrayMap<>();
+ for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+ // Process requests in the first pass and listens in the second pass. This allows us to
+ // change a network's capabilities depending on which requests it has. This is only
+ // correct if the change in capabilities doesn't affect whether the network satisfies
+ // requests or not, and doesn't affect the network's score.
+ if (nri.request.isListen()) continue;
+
+ final NetworkAgentInfo currentNetwork = nri.mSatisfier;
+ final boolean satisfies = newNetwork.satisfies(nri.request);
+ if (newNetwork == currentNetwork && satisfies) continue;
+
+ // check if it satisfies the NetworkCapabilities
+ if (VDBG) log(" checking if request is satisfied: " + nri.request);
+ if (satisfies) {
+ // next check if it's better than any current network we're using for
+ // this request
+ if (VDBG || DDBG) {
+ log("currentScore = "
+ + (currentNetwork != null ? currentNetwork.getCurrentScore() : 0)
+ + ", newScore = " + score);
+ }
+ if (currentNetwork == null || currentNetwork.getCurrentScore() < score) {
+ reassignedRequests.put(nri, newNetwork);
+ }
+ } else if (newNetwork.isSatisfyingRequest(nri.request.requestId)) {
+ reassignedRequests.put(nri, null);
+ }
+ }
+ return reassignedRequests;
+ }
+
// Handles a network appearing or improving its score.
//
// - Evaluates all current NetworkRequests that can be
@@ -6309,10 +6342,6 @@
// - Tears down newNetwork if it just became validated
// but turns out to be unneeded.
//
- // - If reapUnvalidatedNetworks==REAP, tears down unvalidated
- // networks that have no chance (i.e. even if validated)
- // of becoming the highest scoring network.
- //
// NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy,
// it does not remove NetworkRequests that other Networks could better satisfy.
// If you need to handle decreases in score, use {@link rematchAllNetworksAndRequests}.
@@ -6320,13 +6349,10 @@
// as it performs better by a factor of the number of Networks.
//
// @param newNetwork is the network to be matched against NetworkRequests.
- // @param reapUnvalidatedNetworks indicates if an additional pass over all networks should be
- // performed to tear down unvalidated networks that have no chance (i.e. even if
- // validated) of becoming the highest scoring network.
- private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork,
- ReapUnvalidatedNetworks reapUnvalidatedNetworks, long now) {
+ // @param now the time the rematch starts, as returned by SystemClock.elapsedRealtime();
+ private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, long now) {
+ ensureRunningOnConnectivityServiceThread();
if (!newNetwork.everConnected) return;
- boolean keep = newNetwork.isVPN();
boolean isNewDefault = false;
NetworkAgentInfo oldDefaultNetwork = null;
@@ -6335,74 +6361,53 @@
if (VDBG || DDBG) log("rematching " + newNetwork.name());
- // Find and migrate to this Network any NetworkRequests for
- // which this network is now the best.
- ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<>();
- ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<>();
+ final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests =
+ computeRequestReassignmentForNetwork(newNetwork);
+
NetworkCapabilities nc = newNetwork.networkCapabilities;
if (VDBG) log(" network has: " + nc);
- for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- // Process requests in the first pass and listens in the second pass. This allows us to
- // change a network's capabilities depending on which requests it has. This is only
- // correct if the change in capabilities doesn't affect whether the network satisfies
- // requests or not, and doesn't affect the network's score.
- if (nri.request.isListen()) continue;
- final NetworkAgentInfo currentNetwork = getNetworkForRequest(nri.request.requestId);
- final boolean satisfies = newNetwork.satisfies(nri.request);
- if (newNetwork == currentNetwork && satisfies) {
- if (VDBG) {
- log("Network " + newNetwork.name() + " was already satisfying" +
- " request " + nri.request.requestId + ". No change.");
- }
- keep = true;
- continue;
- }
-
- // check if it satisfies the NetworkCapabilities
- if (VDBG) log(" checking if request is satisfied: " + nri.request);
- if (satisfies) {
- // next check if it's better than any current network we're using for
- // this request
- if (VDBG || DDBG) {
- log("currentScore = " +
- (currentNetwork != null ? currentNetwork.getCurrentScore() : 0) +
- ", newScore = " + score);
- }
- if (currentNetwork == null || currentNetwork.getCurrentScore() < score) {
- if (VDBG) log("rematch for " + newNetwork.name());
- if (currentNetwork != null) {
- if (VDBG || DDBG){
- log(" accepting network in place of " + currentNetwork.name());
- }
- currentNetwork.removeRequest(nri.request.requestId);
- currentNetwork.lingerRequest(nri.request, now, mLingerDelayMs);
- affectedNetworks.add(currentNetwork);
- } else {
- if (VDBG || DDBG) log(" accepting network in place of null");
+ // Find and migrate to this Network any NetworkRequests for
+ // which this network is now the best.
+ final ArrayList<NetworkAgentInfo> removedRequests = new ArrayList<>();
+ final ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<>();
+ for (final Map.Entry<NetworkRequestInfo, NetworkAgentInfo> entry :
+ reassignedRequests.entrySet()) {
+ final NetworkRequestInfo nri = entry.getKey();
+ final NetworkAgentInfo previousSatisfier = nri.mSatisfier;
+ final NetworkAgentInfo newSatisfier = entry.getValue();
+ if (newSatisfier != null) {
+ if (VDBG) log("rematch for " + newSatisfier.name());
+ if (previousSatisfier != null) {
+ if (VDBG || DDBG) {
+ log(" accepting network in place of " + previousSatisfier.name());
}
- newNetwork.unlingerRequest(nri.request);
- setNetworkForRequest(nri.request.requestId, newNetwork);
- if (!newNetwork.addRequest(nri.request)) {
- Slog.wtf(TAG, "BUG: " + newNetwork.name() + " already has " + nri.request);
- }
- addedRequests.add(nri);
- keep = true;
- // Tell NetworkFactories about the new score, so they can stop
- // trying to connect if they know they cannot match it.
- // TODO - this could get expensive if we have a lot of requests for this
- // network. Think about if there is a way to reduce this. Push
- // netid->request mapping to each factory?
- sendUpdatedScoreToFactories(nri.request, newNetwork);
- if (isDefaultRequest(nri)) {
- isNewDefault = true;
- oldDefaultNetwork = currentNetwork;
- if (currentNetwork != null) {
- mLingerMonitor.noteLingerDefaultNetwork(currentNetwork, newNetwork);
- }
+ previousSatisfier.removeRequest(nri.request.requestId);
+ previousSatisfier.lingerRequest(nri.request, now, mLingerDelayMs);
+ removedRequests.add(previousSatisfier);
+ } else {
+ if (VDBG || DDBG) log(" accepting network in place of null");
+ }
+ newSatisfier.unlingerRequest(nri.request);
+ nri.mSatisfier = newSatisfier;
+ if (!newSatisfier.addRequest(nri.request)) {
+ Slog.wtf(TAG, "BUG: " + newSatisfier.name() + " already has " + nri.request);
+ }
+ addedRequests.add(nri);
+ // Tell NetworkFactories about the new score, so they can stop
+ // trying to connect if they know they cannot match it.
+ // TODO - this could get expensive if we have a lot of requests for this
+ // network. Think about if there is a way to reduce this. Push
+ // netid->request mapping to each factory?
+ sendUpdatedScoreToFactories(nri.request, newSatisfier);
+ if (isDefaultRequest(nri)) {
+ isNewDefault = true;
+ oldDefaultNetwork = previousSatisfier;
+ if (previousSatisfier != null) {
+ mLingerMonitor.noteLingerDefaultNetwork(previousSatisfier, newSatisfier);
}
}
- } else if (newNetwork.isSatisfyingRequest(nri.request.requestId)) {
+ } else {
// If "newNetwork" is listed as satisfying "nri" but no longer satisfies "nri",
// mark it as no longer satisfying "nri". Because networks are processed by
// rematchAllNetworksAndRequests() in descending score order, "currentNetwork" will
@@ -6415,13 +6420,14 @@
" request " + nri.request.requestId);
}
newNetwork.removeRequest(nri.request.requestId);
- if (currentNetwork == newNetwork) {
- clearNetworkForRequest(nri.request.requestId);
+ if (previousSatisfier == newNetwork) {
+ nri.mSatisfier = null;
+ if (isDefaultRequest(nri)) mDefaultNetworkNai = null;
sendUpdatedScoreToFactories(nri.request, null);
} else {
Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
newNetwork.name() +
- " without updating mNetworkForRequestId or factories!");
+ " without updating mSatisfier or factories!");
}
// TODO: Technically, sending CALLBACK_LOST here is
// incorrect if there is a replacement network currently
@@ -6433,6 +6439,7 @@
callCallbackForRequest(nri, newNetwork, ConnectivityManager.CALLBACK_LOST, 0);
}
}
+
if (isNewDefault) {
updateDataActivityTracking(newNetwork, oldDefaultNetwork);
// Notify system services that this network is up.
@@ -6472,7 +6479,7 @@
// Linger any networks that are no longer needed. This should be done after sending the
// available callback for newNetwork.
- for (NetworkAgentInfo nai : affectedNetworks) {
+ for (NetworkAgentInfo nai : removedRequests) {
updateLingerState(nai, now);
}
// Possibly unlinger newNetwork. Unlingering a network does not send any callbacks so it
@@ -6493,7 +6500,7 @@
notifyLockdownVpn(newNetwork);
}
- if (keep) {
+ if (reassignedRequests.containsValue(newNetwork) || newNetwork.isVPN()) {
// Notify battery stats service about this network, both the normal
// interface and any stacked links.
// TODO: Avoid redoing this; this must only be done once when a network comes online.
@@ -6540,66 +6547,43 @@
mLegacyTypeTracker.add(TYPE_VPN, newNetwork);
}
}
- if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) {
- for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
- if (unneeded(nai, UnneededFor.TEARDOWN)) {
- if (nai.getLingerExpiry() > 0) {
- // This network has active linger timers and no requests, but is not
- // lingering. Linger it.
- //
- // One way (the only way?) this can happen if this network is unvalidated
- // and became unneeded due to another network improving its score to the
- // point where this network will no longer be able to satisfy any requests
- // even if it validates.
- updateLingerState(nai, now);
- } else {
- if (DBG) log("Reaping " + nai.name());
- teardownUnneededNetwork(nai);
- }
- }
- }
- }
}
/**
* Attempt to rematch all Networks with NetworkRequests. This may result in Networks
* being disconnected.
- * @param changed If only one Network's score or capabilities have been modified since the last
- * time this function was called, pass this Network in this argument, otherwise pass
- * null.
- * @param oldScore If only one Network has been changed but its NetworkCapabilities have not
- * changed, pass in the Network's score (from getCurrentScore()) prior to the change via
- * this argument, otherwise pass {@code changed.getCurrentScore()} or 0 if
- * {@code changed} is {@code null}. This is because NetworkCapabilities influence a
- * network's score.
*/
- private void rematchAllNetworksAndRequests(NetworkAgentInfo changed, int oldScore) {
- // TODO: This may get slow. The "changed" parameter is provided for future optimization
- // to avoid the slowness. It is not simply enough to process just "changed", for
- // example in the case where "changed"'s score decreases and another network should begin
- // satisfying a NetworkRequest that "changed" currently satisfies.
-
- // Optimization: Only reprocess "changed" if its score improved. This is safe because it
- // can only add more NetworkRequests satisfied by "changed", and this is exactly what
- // rematchNetworkAndRequests() handles.
+ private void rematchAllNetworksAndRequests() {
+ // TODO: This may be slow, and should be optimized. Unfortunately at this moment the
+ // processing is network-major instead of request-major (the code iterates through all
+ // networks, then for each it iterates for all requests), which is a problem for re-scoring
+ // requests. Once the code has switched to a request-major iteration style, this can
+ // be optimized to only do the processing needed.
final long now = SystemClock.elapsedRealtime();
- if (changed != null && oldScore < changed.getCurrentScore()) {
- rematchNetworkAndRequests(changed, ReapUnvalidatedNetworks.REAP, now);
- } else {
- final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray(
- new NetworkAgentInfo[mNetworkAgentInfos.size()]);
- // Rematch higher scoring networks first to prevent requests first matching a lower
- // scoring network and then a higher scoring network, which could produce multiple
- // callbacks and inadvertently unlinger networks.
- Arrays.sort(nais);
- for (NetworkAgentInfo nai : nais) {
- rematchNetworkAndRequests(nai,
- // Only reap the last time through the loop. Reaping before all rematching
- // is complete could incorrectly teardown a network that hasn't yet been
- // rematched.
- (nai != nais[nais.length-1]) ? ReapUnvalidatedNetworks.DONT_REAP
- : ReapUnvalidatedNetworks.REAP,
- now);
+ final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray(
+ new NetworkAgentInfo[mNetworkAgentInfos.size()]);
+ // Rematch higher scoring networks first to prevent requests first matching a lower
+ // scoring network and then a higher scoring network, which could produce multiple
+ // callbacks and inadvertently unlinger networks.
+ Arrays.sort(nais);
+ for (NetworkAgentInfo nai : nais) {
+ rematchNetworkAndRequests(nai, now);
+ }
+ for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ if (unneeded(nai, UnneededFor.TEARDOWN)) {
+ if (nai.getLingerExpiry() > 0) {
+ // This network has active linger timers and no requests, but is not
+ // lingering. Linger it.
+ //
+ // One way (the only way?) this can happen if this network is unvalidated
+ // and became unneeded due to another network improving its score to the
+ // point where this network will no longer be able to satisfy any requests
+ // even if it validates.
+ updateLingerState(nai, now);
+ } else {
+ if (DBG) log("Reaping " + nai.name());
+ teardownUnneededNetwork(nai);
+ }
}
}
}
@@ -6698,8 +6682,7 @@
}
// Consider network even though it is not yet validated.
- final long now = SystemClock.elapsedRealtime();
- rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP, now);
+ rematchAllNetworksAndRequests();
// This has to happen after matching the requests, because callbacks are just requests.
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);
@@ -6720,7 +6703,7 @@
state == NetworkInfo.State.SUSPENDED)) {
// going into or coming out of SUSPEND: re-score and notify
if (networkAgent.getCurrentScore() != oldScore) {
- rematchAllNetworksAndRequests(networkAgent, oldScore);
+ rematchAllNetworksAndRequests();
}
updateCapabilities(networkAgent.getCurrentScore(), networkAgent,
networkAgent.networkCapabilities);
@@ -6734,19 +6717,9 @@
}
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 +
- "). Bumping score to min of 0");
- score = 0;
- }
-
- final int oldScore = nai.getCurrentScore();
+ if (VDBG || DDBG) log("updateNetworkScore for " + nai.name() + " to " + ns);
nai.setNetworkScore(ns);
-
- rematchAllNetworksAndRequests(nai, oldScore);
-
+ rematchAllNetworksAndRequests();
sendUpdatedScoreToFactories(nai);
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index d13e675..bc83780 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -18,6 +18,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import android.app.Notification;
@@ -89,14 +90,22 @@
mNotificationTypeMap = new SparseIntArray();
}
+ @VisibleForTesting
+ protected static int approximateTransportType(NetworkAgentInfo nai) {
+ return nai.isVPN() ? TRANSPORT_VPN : getFirstTransportType(nai);
+ }
+
// TODO: deal more gracefully with multi-transport networks.
private static int getFirstTransportType(NetworkAgentInfo nai) {
+ // TODO: The range is wrong, the safer and correct way is to change the range from
+ // MIN_TRANSPORT to MAX_TRANSPORT.
for (int i = 0; i < 64; i++) {
if (nai.networkCapabilities.hasTransport(i)) return i;
}
return -1;
}
+ // TODO: Remove @TransportType or change it to @Transport.
private static String getTransportName(@TransportType int transportType) {
Resources r = Resources.getSystem();
String[] networkTypes = r.getStringArray(R.array.network_switch_type_name);
@@ -146,7 +155,7 @@
final int transportType;
final String name;
if (nai != null) {
- transportType = getFirstTransportType(nai);
+ transportType = approximateTransportType(nai);
final String extraInfo = nai.networkInfo.getExtraInfo();
name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSSID() : extraInfo;
// Only notify for Internet-capable networks.
@@ -175,7 +184,7 @@
tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
}
- Resources r = Resources.getSystem();
+ Resources r = mContext.getResources();
final CharSequence title;
final CharSequence details;
int icon = getIcon(transportType, notifyType);
@@ -239,7 +248,7 @@
details = r.getString(R.string.captive_portal_logged_in_detailed);
} else if (notifyType == NotificationType.NETWORK_SWITCH) {
String fromTransport = getTransportName(transportType);
- String toTransport = getTransportName(getFirstTransportType(switchToNai));
+ String toTransport = getTransportName(approximateTransportType(switchToNai));
title = r.getString(R.string.network_switch_metered, toTransport);
details = r.getString(R.string.network_switch_metered_detail, toTransport,
fromTransport);
@@ -340,8 +349,8 @@
}
public void showToast(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
- String fromTransport = getTransportName(getFirstTransportType(fromNai));
- String toTransport = getTransportName(getFirstTransportType(toNai));
+ String fromTransport = getTransportName(approximateTransportType(fromNai));
+ String toTransport = getTransportName(approximateTransportType(toNai));
String text = mContext.getResources().getString(
R.string.network_switch_metered_toast, fromTransport, toTransport);
Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 29c4bad..56f4959 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -229,22 +229,22 @@
}
@VisibleForTesting
- boolean hasPermission(PackageInfo app, String permission) {
- if (app.requestedPermissions != null) {
- for (String p : app.requestedPermissions) {
- if (permission.equals(p)) {
- return true;
- }
- }
+ boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) {
+ if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
+ return false;
}
- return false;
+ final int index = ArrayUtils.indexOf(app.requestedPermissions, permission);
+ if (index < 0 || index >= app.requestedPermissionsFlags.length) return false;
+ return (app.requestedPermissionsFlags[index] & REQUESTED_PERMISSION_GRANTED) != 0;
}
- private boolean hasNetworkPermission(PackageInfo app) {
+ @VisibleForTesting
+ boolean hasNetworkPermission(@NonNull final PackageInfo app) {
return hasPermission(app, CHANGE_NETWORK_STATE);
}
- private boolean hasRestrictedNetworkPermission(PackageInfo app) {
+ @VisibleForTesting
+ boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) {
// TODO : remove this check in the future(b/31479477). All apps should just
// request the appropriate permission for their use case since android Q.
if (app.applicationInfo != null) {
@@ -260,33 +260,18 @@
}
}
return hasPermission(app, CONNECTIVITY_INTERNAL)
+ || hasPermission(app, NETWORK_STACK)
|| hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
}
- private boolean hasUseBackgroundNetworksPermission(PackageInfo app) {
- // This function defines what it means to hold the permission to use
- // background networks.
- return hasPermission(app, CHANGE_NETWORK_STATE)
- || hasPermission(app, NETWORK_STACK)
- || hasRestrictedNetworkPermission(app);
- }
-
- public boolean hasUseBackgroundNetworksPermission(int uid) {
- final String[] names = mPackageManager.getPackagesForUid(uid);
- if (null == names || names.length == 0) return false;
- try {
- // Only using the first package name. There may be multiple names if multiple
- // apps share the same UID, but in that case they also share permissions so
- // querying with any of the names will return the same results.
- int userId = UserHandle.getUserId(uid);
- final PackageInfo app = mPackageManager.getPackageInfoAsUser(
- names[0], GET_PERMISSIONS, userId);
- return hasUseBackgroundNetworksPermission(app);
- } catch (NameNotFoundException e) {
- // App not found.
- loge("NameNotFoundException " + names[0], e);
- return false;
- }
+ /** Returns whether the given uid has using background network permission. */
+ public synchronized boolean hasUseBackgroundNetworksPermission(final int uid) {
+ // Apps with any of the CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_INTERNAL or
+ // CONNECTIVITY_USE_RESTRICTED_NETWORKS permission has the permission to use background
+ // 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(uid);
}
private int[] toIntArray(Collection<Integer> list) {
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index aad2f3d..7ea9bcf 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -16,6 +16,9 @@
package com.android.server;
+import static android.Manifest.permission.CHANGE_NETWORK_STATE;
+import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
@@ -2000,9 +2003,17 @@
mCm.unregisterNetworkCallback(trackDefaultCallback);
}
+ private void grantUsingBackgroundNetworksPermissionForUid(final int uid) throws Exception {
+ final String testPackageName = mContext.getPackageName();
+ when(mPackageManager.getPackageInfo(eq(testPackageName), eq(GET_PERMISSIONS)))
+ .thenReturn(buildPackageInfo(true, uid));
+ mService.mPermissionMonitor.onPackageAdded(testPackageName, uid);
+ }
+
@Test
public void testNetworkGoesIntoBackgroundAfterLinger() throws Exception {
setAlwaysOnNetworks(true);
+ grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
NetworkRequest request = new NetworkRequest.Builder()
.clearCapabilities()
.build();
@@ -3077,6 +3088,7 @@
// Create a background request. We can't do this ourselves because ConnectivityService
// doesn't have an API for it. So just turn on mobile data always on.
setAlwaysOnNetworks(true);
+ grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
final NetworkRequest request = new NetworkRequest.Builder().build();
final NetworkRequest fgRequest = new NetworkRequest.Builder()
.addCapability(NET_CAPABILITY_FOREGROUND).build();
@@ -3223,6 +3235,7 @@
@Test
public void testMobileDataAlwaysOn() throws Exception {
+ grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
final NetworkRequest cellRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR).build();
@@ -6176,7 +6189,14 @@
private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid) {
final PackageInfo packageInfo = new PackageInfo();
- packageInfo.requestedPermissions = new String[0];
+ if (hasSystemPermission) {
+ packageInfo.requestedPermissions = new String[] {
+ CHANGE_NETWORK_STATE, CONNECTIVITY_USE_RESTRICTED_NETWORKS };
+ packageInfo.requestedPermissionsFlags = new int[] {
+ REQUESTED_PERMISSION_GRANTED, REQUESTED_PERMISSION_GRANTED };
+ } else {
+ packageInfo.requestedPermissions = new String[0];
+ }
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.privateFlags = 0;
packageInfo.applicationInfo.uid = UserHandle.getUid(UserHandle.USER_SYSTEM,
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index 9580763..d57f225 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -20,6 +20,7 @@
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -40,6 +41,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.R;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import org.junit.Before;
@@ -60,12 +62,19 @@
static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
+ static final NetworkCapabilities VPN_CAPABILITIES = new NetworkCapabilities();
static {
CELL_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
CELL_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
WIFI_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
WIFI_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+
+ // Set the underyling network to wifi.
+ VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+ VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
+ VPN_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ VPN_CAPABILITIES.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
}
@Mock Context mCtx;
@@ -75,6 +84,7 @@
@Mock NotificationManager mNotificationManager;
@Mock NetworkAgentInfo mWifiNai;
@Mock NetworkAgentInfo mCellNai;
+ @Mock NetworkAgentInfo mVpnNai;
@Mock NetworkInfo mNetworkInfo;
ArgumentCaptor<Notification> mCaptor;
@@ -88,6 +98,9 @@
mWifiNai.networkInfo = mNetworkInfo;
mCellNai.networkCapabilities = CELL_CAPABILITIES;
mCellNai.networkInfo = mNetworkInfo;
+ mVpnNai.networkCapabilities = VPN_CAPABILITIES;
+ mVpnNai.networkInfo = mNetworkInfo;
+ doReturn(true).when(mVpnNai).isVPN();
when(mCtx.getResources()).thenReturn(mResources);
when(mCtx.getPackageManager()).thenReturn(mPm);
when(mCtx.getApplicationInfo()).thenReturn(new ApplicationInfo());
@@ -97,6 +110,35 @@
mManager = new NetworkNotificationManager(mCtx, mTelephonyManager, mNotificationManager);
}
+ private void verifyTitleByNetwork(final int id, final NetworkAgentInfo nai, final int title) {
+ final String tag = NetworkNotificationManager.tagFor(id);
+ mManager.showNotification(id, PRIVATE_DNS_BROKEN, nai, null, null, true);
+ verify(mNotificationManager, times(1))
+ .notifyAsUser(eq(tag), eq(PRIVATE_DNS_BROKEN.eventId), any(), any());
+ final int transportType = NetworkNotificationManager.approximateTransportType(nai);
+ if (transportType == NetworkCapabilities.TRANSPORT_WIFI) {
+ verify(mResources, times(1)).getString(title, eq(any()));
+ } else {
+ verify(mResources, times(1)).getString(title);
+ }
+ verify(mResources, times(1)).getString(R.string.private_dns_broken_detailed);
+ }
+
+ @Test
+ public void testTitleOfPrivateDnsBroken() {
+ // Test the title of mobile data.
+ verifyTitleByNetwork(100, mCellNai, R.string.mobile_no_internet);
+ reset(mResources);
+
+ // Test the title of wifi.
+ verifyTitleByNetwork(101, mWifiNai, R.string.wifi_no_internet);
+ reset(mResources);
+
+ // Test the title of other networks.
+ verifyTitleByNetwork(102, mVpnNai, R.string.other_networks_no_internet);
+ reset(mResources);
+ }
+
@Test
public void testNotificationsShownAndCleared() {
final int NETWORK_ID_BASE = 100;
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 7029218..7fee7b7 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -27,6 +27,7 @@
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_REQUIRED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.os.Process.SYSTEM_UID;
@@ -36,6 +37,7 @@
import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -102,7 +104,6 @@
private static final String MOCK_PACKAGE2 = "appName2";
private static final String SYSTEM_PACKAGE1 = "sysName1";
private static final String SYSTEM_PACKAGE2 = "sysName2";
- private static final String VPN_PACKAGE = "vpnApp";
private static final String PARTITION_SYSTEM = "system";
private static final String PARTITION_OEM = "oem";
private static final String PARTITION_PRODUCT = "product";
@@ -145,28 +146,31 @@
mObserver = observerCaptor.getValue();
}
- private boolean hasBgPermission(String partition, int targetSdkVersion, int uid,
- String... permission) throws Exception {
- final PackageInfo packageInfo = packageInfoWithPermissions(permission, partition);
+ private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
+ String... permissions) {
+ final PackageInfo packageInfo =
+ packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, permissions, partition);
packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
packageInfo.applicationInfo.uid = uid;
- when(mPackageManager.getPackageInfoAsUser(
- eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
- when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[] {MOCK_PACKAGE1});
- return mPermissionMonitor.hasUseBackgroundNetworksPermission(uid);
+ return mPermissionMonitor.hasRestrictedNetworkPermission(packageInfo);
}
- private static PackageInfo packageInfoWithPermissions(String[] permissions, String partition) {
+ private static PackageInfo systemPackageInfoWithPermissions(String... permissions) {
+ return packageInfoWithPermissions(
+ REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM);
+ }
+
+ private static PackageInfo vendorPackageInfoWithPermissions(String... permissions) {
+ return packageInfoWithPermissions(
+ REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_VENDOR);
+ }
+
+ private static PackageInfo packageInfoWithPermissions(int permissionsFlags,
+ String[] permissions, String partition) {
int[] requestedPermissionsFlags = new int[permissions.length];
for (int i = 0; i < permissions.length; i++) {
- requestedPermissionsFlags[i] = REQUESTED_PERMISSION_GRANTED;
+ requestedPermissionsFlags[i] = permissionsFlags;
}
- return packageInfoWithPermissions(permissions, partition,
- requestedPermissionsFlags);
- }
-
- private static PackageInfo packageInfoWithPermissions(String[] permissions, String partition,
- int[] requestedPermissionsFlags) {
final PackageInfo packageInfo = new PackageInfo();
packageInfo.requestedPermissions = permissions;
packageInfo.applicationInfo = new ApplicationInfo();
@@ -190,12 +194,10 @@
private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid, int userId) {
final PackageInfo pkgInfo;
if (hasSystemPermission) {
- final String[] systemPermissions = new String[]{
- CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS
- };
- pkgInfo = packageInfoWithPermissions(systemPermissions, PARTITION_SYSTEM);
+ pkgInfo = systemPackageInfoWithPermissions(
+ CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
} else {
- pkgInfo = packageInfoWithPermissions(new String[] {}, "");
+ pkgInfo = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, new String[] {}, "");
}
pkgInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
return pkgInfo;
@@ -203,82 +205,151 @@
@Test
public void testHasPermission() {
- PackageInfo app = packageInfoWithPermissions(new String[] {}, PARTITION_SYSTEM);
+ PackageInfo app = systemPackageInfoWithPermissions();
assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
- app = packageInfoWithPermissions(new String[] {
- CHANGE_NETWORK_STATE, NETWORK_STACK
- }, PARTITION_SYSTEM);
+ app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE, NETWORK_STACK);
assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
- app = packageInfoWithPermissions(new String[] {
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL
- }, PARTITION_SYSTEM);
+ app = systemPackageInfoWithPermissions(
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL);
assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
+
+ app = packageInfoWithPermissions(REQUESTED_PERMISSION_REQUIRED, new String[] {
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL, NETWORK_STACK },
+ PARTITION_SYSTEM);
+ assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+ assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
+
+ app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
+ app.requestedPermissions = null;
+ assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+
+ app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
+ app.requestedPermissionsFlags = null;
+ assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
}
@Test
public void testIsVendorApp() {
- PackageInfo app = packageInfoWithPermissions(new String[] {}, PARTITION_SYSTEM);
+ PackageInfo app = systemPackageInfoWithPermissions();
assertFalse(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPermissions(new String[] {}, PARTITION_OEM);
+ app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED,
+ new String[] {}, PARTITION_OEM);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPermissions(new String[] {}, PARTITION_PRODUCT);
+ app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED,
+ new String[] {}, PARTITION_PRODUCT);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPermissions(new String[] {}, PARTITION_VENDOR);
+ app = vendorPackageInfoWithPermissions();
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
}
@Test
+ public void testHasNetworkPermission() {
+ PackageInfo app = systemPackageInfoWithPermissions();
+ assertFalse(mPermissionMonitor.hasNetworkPermission(app));
+ app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
+ assertTrue(mPermissionMonitor.hasNetworkPermission(app));
+ app = systemPackageInfoWithPermissions(NETWORK_STACK);
+ assertFalse(mPermissionMonitor.hasNetworkPermission(app));
+ app = systemPackageInfoWithPermissions(CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ assertFalse(mPermissionMonitor.hasNetworkPermission(app));
+ }
+
+ @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));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
+
+ assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE));
+ }
+
+ @Test
+ public void testHasRestrictedNetworkPermissionSystemUid() {
+ doReturn(VERSION_P).when(mPermissionMonitor).getDeviceFirstSdkInt();
+ assertTrue(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CHANGE_WIFI_STATE));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+
+ doReturn(VERSION_Q).when(mPermissionMonitor).getDeviceFirstSdkInt();
+ assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CHANGE_WIFI_STATE));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_SYSTEM, VERSION_Q, 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));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_P, MOCK_UID1, NETWORK_STACK));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertTrue(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
+
+ assertFalse(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE));
+ assertFalse(hasRestrictedNetworkPermission(
+ PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_NETWORK_STATE));
+ }
+
+ 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);
+ assertEquals(hasPermission, mPermissionMonitor.hasUseBackgroundNetworksPermission(uid));
+ }
+
+ @Test
public void testHasUseBackgroundNetworksPermission() throws Exception {
- assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
- assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
- assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, NETWORK_STACK));
- assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
- assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1,
- CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
+ assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(SYSTEM_UID));
+ assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID);
+ assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID, CHANGE_WIFI_STATE);
+ assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, CHANGE_NETWORK_STATE);
+ assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, NETWORK_STACK);
- assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
- assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE));
- }
+ assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID1));
+ assertBackgroundPermission(false, MOCK_PACKAGE1, MOCK_UID1);
+ assertBackgroundPermission(true, MOCK_PACKAGE1, MOCK_UID1,
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS);
- @Test
- public void testHasUseBackgroundNetworksPermissionSystemUid() throws Exception {
- doReturn(VERSION_P).when(mPermissionMonitor).getDeviceFirstSdkInt();
- assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
- assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CHANGE_WIFI_STATE));
- assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID,
- CONNECTIVITY_USE_RESTRICTED_NETWORKS));
-
- doReturn(VERSION_Q).when(mPermissionMonitor).getDeviceFirstSdkInt();
- assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
- assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CHANGE_WIFI_STATE));
- assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID,
- CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- }
-
- @Test
- public void testHasUseBackgroundNetworksPermissionVendorApp() throws Exception {
- assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
- assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
- assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, NETWORK_STACK));
- assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
- assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1,
- CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
-
- assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
- assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE));
+ assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID2));
+ assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2);
+ assertBackgroundPermission(true, MOCK_PACKAGE2, MOCK_UID2,
+ CONNECTIVITY_INTERNAL);
}
private class NetdMonitor {
@@ -563,7 +634,8 @@
private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions)
throws Exception {
- PackageInfo packageInfo = packageInfoWithPermissions(permissions, PARTITION_SYSTEM);
+ 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;
@@ -599,7 +671,7 @@
// Install another package with the same uid and no permissions should not cause the UID to
// lose permissions.
- PackageInfo packageInfo2 = packageInfoWithPermissions(new String[]{}, PARTITION_SYSTEM);
+ PackageInfo packageInfo2 = systemPackageInfoWithPermissions();
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
when(mPackageManager.getPackagesForUid(MOCK_UID1))
.thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
@@ -660,8 +732,7 @@
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Mock another package with the same uid but different permissions.
- PackageInfo packageInfo2 = packageInfoWithPermissions(new String[] {INTERNET},
- PARTITION_SYSTEM);
+ PackageInfo packageInfo2 = systemPackageInfoWithPermissions(INTERNET);
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{
MOCK_PACKAGE2});