Implementation of setOemNetworkPreference

Main implementation of ConnectivityService.setOemNetworkPreference. This
covers the main requirements of this method including listener
functionality.

Bug: 176495594
Bug: 177101287
Bug: 176494815
Test: atest FrameworksNetTests
atest NetworkStackTests
atest FrameworksNetIntegrationTests
atest NetworkStackIntegrationTests
atest CtsNetTestCasesLatestSdk

Change-Id: I8d318ab07785e52dd84d6261fdea8f318dce9bc5
This commit is contained in:
James Mattis
2021-01-10 14:24:24 -08:00
parent 5cc3c631e5
commit 45d81845a4
5 changed files with 408 additions and 58 deletions

View File

@@ -31,9 +31,9 @@ import java.util.Objects;
/** @hide */
public final class OemNetworkPreferences implements Parcelable {
/**
* Use default behavior requesting networks. Equivalent to not setting any preference at all.
* Default in case this value is not set. Using it will result in an error.
*/
public static final int OEM_NETWORK_PREFERENCE_DEFAULT = 0;
public static final int OEM_NETWORK_PREFERENCE_UNINITIALIZED = 0;
/**
* If an unmetered network is available, use it.
@@ -160,7 +160,7 @@ public final class OemNetworkPreferences implements Parcelable {
/** @hide */
@IntDef(prefix = "OEM_NETWORK_PREFERENCE_", value = {
OEM_NETWORK_PREFERENCE_DEFAULT,
OEM_NETWORK_PREFERENCE_UNINITIALIZED,
OEM_NETWORK_PREFERENCE_OEM_PAID,
OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK,
OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY,
@@ -178,8 +178,8 @@ public final class OemNetworkPreferences implements Parcelable {
@NonNull
public static String oemNetworkPreferenceToString(@OemNetworkPreference int value) {
switch (value) {
case OEM_NETWORK_PREFERENCE_DEFAULT:
return "OEM_NETWORK_PREFERENCE_DEFAULT";
case OEM_NETWORK_PREFERENCE_UNINITIALIZED:
return "OEM_NETWORK_PREFERENCE_UNINITIALIZED";
case OEM_NETWORK_PREFERENCE_OEM_PAID:
return "OEM_NETWORK_PREFERENCE_OEM_PAID";
case OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK:

View File

@@ -4886,15 +4886,6 @@ public class ConnectivityManager {
}
}
private void setOemNetworkPreference(@NonNull final OemNetworkPreferences preference) {
try {
mService.setOemNetworkPreference(preference);
} catch (RemoteException e) {
Log.e(TAG, "setOemNetworkPreference() failed for preference: " + preference.toString());
throw e.rethrowFromSystemServer();
}
}
@NonNull
private final List<QosCallbackConnection> mQosCallbackConnections = new ArrayList<>();
@@ -5096,4 +5087,55 @@ public class ConnectivityManager {
sendRequestForNetwork(nc, networkCallback, 0, BACKGROUND_REQUEST,
TYPE_NONE, handler == null ? getDefaultHandler() : new CallbackHandler(handler));
}
/**
* Listener for {@link #setOemNetworkPreference(OemNetworkPreferences, Executor,
* OnSetOemNetworkPreferenceListener)}.
*/
private interface OnSetOemNetworkPreferenceListener {
/**
* Called when setOemNetworkPreference() successfully completes.
*/
void onComplete();
}
/**
* Used by automotive devices to set the network preferences used to direct traffic at an
* application level as per the given OemNetworkPreferences. An example use-case would be an
* automotive OEM wanting to provide connectivity for applications critical to the usage of a
* vehicle via a particular network.
*
* Calling this will overwrite the existing preference.
*
* @param preference {@link OemNetworkPreferences} The application network preference to be set.
* @param executor the executor on which listener will be invoked.
* @param listener {@link OnSetOemNetworkPreferenceListener} optional listener used to
* communicate completion of setOemNetworkPreference(). This will only be
* called once upon successful completion of setOemNetworkPreference().
* @throws IllegalArgumentException if {@code preference} contains invalid preference values.
* @throws SecurityException if missing the appropriate permissions.
* @throws UnsupportedOperationException if called on a non-automotive device.
*/
private void setOemNetworkPreference(@NonNull final OemNetworkPreferences preference,
@Nullable @CallbackExecutor final Executor executor,
@Nullable final OnSetOemNetworkPreferenceListener listener) {
Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
if (null != listener) {
Objects.requireNonNull(executor, "Executor must be non-null");
}
final IOnSetOemNetworkPreferenceListener listenerInternal = listener == null ? null :
new IOnSetOemNetworkPreferenceListener.Stub() {
@Override
public void onComplete() {
executor.execute(listener::onComplete);
}
};
try {
mService.setOemNetworkPreference(preference, listenerInternal);
} catch (RemoteException e) {
Log.e(TAG, "setOemNetworkPreference() failed for preference: " + preference.toString());
throw e.rethrowFromSystemServer();
}
}
}

View File

@@ -20,6 +20,7 @@ import android.app.PendingIntent;
import android.net.ConnectionInfo;
import android.net.ConnectivityDiagnosticsManager;
import android.net.IConnectivityDiagnosticsCallback;
import android.net.IOnSetOemNetworkPreferenceListener;
import android.net.IQosCallback;
import android.net.ISocketKeepaliveCallback;
import android.net.LinkProperties;
@@ -245,5 +246,6 @@ interface IConnectivityManager
void registerQosSocketCallback(in QosSocketInfo socketInfo, in IQosCallback callback);
void unregisterQosCallback(in IQosCallback callback);
void setOemNetworkPreference(in OemNetworkPreferences preference);
void setOemNetworkPreference(in OemNetworkPreferences preference,
in IOnSetOemNetworkPreferenceListener listener);
}

View File

@@ -47,6 +47,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -95,6 +97,7 @@ import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener;
import android.net.INetworkStatsService;
import android.net.IOnSetOemNetworkPreferenceListener;
import android.net.IQosCallback;
import android.net.ISocketKeepaliveCallback;
import android.net.InetAddresses;
@@ -570,6 +573,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
*/
private static final int EVENT_SET_REQUIRE_VPN_FOR_UIDS = 47;
/**
* used internally when setting the default networks for OemNetworkPreferences.
* obj = OemNetworkPreferences
*/
private static final int EVENT_SET_OEM_NETWORK_PREFERENCE = 48;
/**
* Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
* should be shown.
@@ -1039,10 +1048,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
mMetricsLog = logger;
mNetworkRanker = new NetworkRanker();
final NetworkRequest defaultInternetRequest = createDefaultInternetRequestForTransport(
-1, NetworkRequest.Type.REQUEST);
mDefaultRequest = new NetworkRequestInfo(null, defaultInternetRequest, new Binder(),
null /* attributionTag */);
final NetworkRequest defaultInternetRequest = createDefaultRequest();
mDefaultRequest = new NetworkRequestInfo(
defaultInternetRequest, null, new Binder(),
null /* attributionTags */);
mNetworkRequests.put(defaultInternetRequest, mDefaultRequest);
mDefaultNetworkRequests.add(mDefaultRequest);
mNetworkRequestInfoLogs.log("REGISTER " + mDefaultRequest);
@@ -1256,15 +1265,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
return netCap;
}
private NetworkRequest createDefaultRequest() {
return createDefaultInternetRequestForTransport(
TYPE_NONE, NetworkRequest.Type.REQUEST);
}
private NetworkRequest createDefaultInternetRequestForTransport(
int transportType, NetworkRequest.Type type) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
if (transportType > -1) {
if (transportType > TYPE_NONE) {
netCap.addTransportType(transportType);
}
return createNetworkRequest(type, netCap);
}
private NetworkRequest createNetworkRequest(
NetworkRequest.Type type, NetworkCapabilities netCap) {
return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), type);
}
@@ -1314,7 +1333,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (enable) {
handleRegisterNetworkRequest(new NetworkRequestInfo(
null, networkRequest, new Binder(), null /* attributionTag */));
networkRequest, null, new Binder(),
null /* attributionTags */));
} else {
handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID,
/* callOnUnavailable */ false);
@@ -2634,6 +2654,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
pw.println();
pw.print("Current per-app default networks: ");
pw.increaseIndent();
dumpPerAppNetworkPreferences(pw);
pw.decreaseIndent();
pw.println();
pw.println("Current Networks:");
pw.increaseIndent();
dumpNetworks(pw);
@@ -2754,6 +2780,40 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
private void dumpPerAppNetworkPreferences(IndentingPrintWriter pw) {
pw.println("Per-App Network Preference:");
pw.increaseIndent();
if (0 == mOemNetworkPreferences.getNetworkPreferences().size()) {
pw.println("none");
} else {
pw.println(mOemNetworkPreferences.toString());
}
pw.decreaseIndent();
for (final NetworkRequestInfo defaultRequest : mDefaultNetworkRequests) {
if (mDefaultRequest == defaultRequest) {
continue;
}
final boolean isActive = null != defaultRequest.getSatisfier();
pw.println("Is per-app network active:");
pw.increaseIndent();
pw.println(isActive);
if (isActive) {
pw.println("Active network: " + defaultRequest.getSatisfier().network.netId);
}
pw.println("Tracked UIDs:");
pw.increaseIndent();
if (0 == defaultRequest.mRequests.size()) {
pw.println("none, this should never occur.");
} else {
pw.println(defaultRequest.mRequests.get(0).networkCapabilities.getUids());
}
pw.decreaseIndent();
pw.decreaseIndent();
}
}
private void dumpNetworkRequests(IndentingPrintWriter pw) {
for (NetworkRequestInfo nri : requestsSortedById()) {
pw.println(nri.toString());
@@ -3586,29 +3646,38 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
private void handleRegisterNetworkRequest(@NonNull final NetworkRequestInfo nri) {
handleRegisterNetworkRequest(Collections.singletonList(nri));
}
private void handleRegisterNetworkRequest(@NonNull final List<NetworkRequestInfo> nris) {
ensureRunningOnConnectivityServiceThread();
mNetworkRequestInfoLogs.log("REGISTER " + nri);
for (final NetworkRequest req : nri.mRequests) {
mNetworkRequests.put(req, nri);
if (req.isListen()) {
for (final NetworkAgentInfo network : mNetworkAgentInfos) {
if (req.networkCapabilities.hasSignalStrength()
&& network.satisfiesImmutableCapabilitiesOf(req)) {
updateSignalStrengthThresholds(network, "REGISTER", req);
for (final NetworkRequestInfo nri : nris) {
mNetworkRequestInfoLogs.log("REGISTER " + nri);
for (final NetworkRequest req : nri.mRequests) {
mNetworkRequests.put(req, nri);
if (req.isListen()) {
for (final NetworkAgentInfo network : mNetworkAgentInfos) {
if (req.networkCapabilities.hasSignalStrength()
&& network.satisfiesImmutableCapabilitiesOf(req)) {
updateSignalStrengthThresholds(network, "REGISTER", req);
}
}
}
}
}
rematchAllNetworksAndRequests();
// If the nri is satisfied, return as its score has already been sent if needed.
if (nri.isBeingSatisfied()) {
return;
}
// As this request was not satisfied on rematch and thus never had any scores sent to the
// factories, send null now for each request of type REQUEST.
for (final NetworkRequest req : nri.mRequests) {
if (req.isRequest()) sendUpdatedScoreToFactories(req, null);
rematchAllNetworksAndRequests();
for (final NetworkRequestInfo nri : nris) {
// If the nri is satisfied, return as its score has already been sent if needed.
if (nri.isBeingSatisfied()) {
return;
}
// As this request was not satisfied on rematch and thus never had any scores sent to
// the factories, send null now for each request of type REQUEST.
for (final NetworkRequest req : nri.mRequests) {
if (req.isRequest()) sendUpdatedScoreToFactories(req, null);
}
}
}
@@ -3781,6 +3850,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
removeListenRequestFromNetworks(req);
}
}
mDefaultNetworkRequests.remove(nri);
mNetworkRequestCounter.decrementCount(nri.mUid);
mNetworkRequestInfoLogs.log("RELEASE " + nri);
@@ -4419,6 +4489,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
case EVENT_SET_REQUIRE_VPN_FOR_UIDS:
handleSetRequireVpnForUids(toBool(msg.arg1), (UidRange[]) msg.obj);
break;
case EVENT_SET_OEM_NETWORK_PREFERENCE:
final Pair<OemNetworkPreferences, IOnSetOemNetworkPreferenceListener> arg =
(Pair<OemNetworkPreferences,
IOnSetOemNetworkPreferenceListener>) msg.obj;
try {
handleSetOemNetworkPreference(arg.first, arg.second);
} catch (RemoteException e) {
loge("handleMessage.EVENT_SET_OEM_NETWORK_PREFERENCE failed", e);
}
break;
}
}
}
@@ -5551,10 +5631,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
final PendingIntent mPendingIntent;
boolean mPendingIntentSent;
@Nullable
final Messenger mMessenger;
@Nullable
private final IBinder mBinder;
final int mPid;
final int mUid;
final Messenger messenger;
@Nullable
final String mCallingAttributionTag;
@@ -5570,12 +5652,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
return uids;
}
NetworkRequestInfo(NetworkRequest r, PendingIntent pi,
NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final PendingIntent pi,
@Nullable String callingAttributionTag) {
this(Collections.singletonList(r), pi, callingAttributionTag);
}
NetworkRequestInfo(@NonNull final List<NetworkRequest> r,
@Nullable final PendingIntent pi, @Nullable String callingAttributionTag) {
mRequests = initializeRequests(r);
ensureAllNetworkRequestsHaveType(mRequests);
mPendingIntent = pi;
messenger = null;
mMessenger = null;
mBinder = null;
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
@@ -5583,11 +5670,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
mCallingAttributionTag = callingAttributionTag;
}
NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder,
@Nullable String callingAttributionTag) {
NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final Messenger m,
@Nullable final IBinder binder, @Nullable String callingAttributionTag) {
this(Collections.singletonList(r), m, binder, callingAttributionTag);
}
NetworkRequestInfo(@NonNull final List<NetworkRequest> r, @Nullable final Messenger m,
@Nullable final IBinder binder, @Nullable String callingAttributionTag) {
super();
messenger = m;
mRequests = initializeRequests(r);
mMessenger = m;
ensureAllNetworkRequestsHaveType(mRequests);
mBinder = binder;
mPid = getCallingPid();
@@ -5603,7 +5695,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
NetworkRequestInfo(NetworkRequest r) {
NetworkRequestInfo(@NonNull final NetworkRequest r) {
this(Collections.singletonList(r));
}
NetworkRequestInfo(@NonNull final List<NetworkRequest> r) {
this(r, null /* pi */, null /* callingAttributionTag */);
}
@@ -5618,9 +5714,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
return mRequests.size() > 1;
}
private List<NetworkRequest> initializeRequests(NetworkRequest r) {
final ArrayList<NetworkRequest> tempRequests = new ArrayList<>();
tempRequests.add(new NetworkRequest(r));
private List<NetworkRequest> initializeRequests(List<NetworkRequest> r) {
// Creating a defensive copy to prevent the sender from modifying the list being
// reflected in the return value of this method.
final List<NetworkRequest> tempRequests = new ArrayList<>(r);
return Collections.unmodifiableList(tempRequests);
}
@@ -5804,7 +5901,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId(), reqType);
NetworkRequestInfo nri =
new NetworkRequestInfo(messenger, networkRequest, binder, callingAttributionTag);
new NetworkRequestInfo(networkRequest, messenger, binder, callingAttributionTag);
if (DBG) log("requestNetwork for " + nri);
// For TRACK_SYSTEM_DEFAULT callbacks, the capabilities have been modified since they were
@@ -5970,7 +6067,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
NetworkRequestInfo nri =
new NetworkRequestInfo(messenger, networkRequest, binder, callingAttributionTag);
new NetworkRequestInfo(networkRequest, messenger, binder, callingAttributionTag);
if (VDBG) log("listenForNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -6098,13 +6195,20 @@ public class ConnectivityService extends IConnectivityManager.Stub
@GuardedBy("mBlockedAppUids")
private final HashSet<Integer> mBlockedAppUids = new HashSet<>();
// Current OEM network preferences.
@NonNull
private OemNetworkPreferences mOemNetworkPreferences =
new OemNetworkPreferences.Builder().build();
// The always-on request for an Internet-capable network that apps without a specific default
// fall back to.
@VisibleForTesting
@NonNull
private final NetworkRequestInfo mDefaultRequest;
final NetworkRequestInfo mDefaultRequest;
// Collection of NetworkRequestInfo's used for default networks.
@VisibleForTesting
@NonNull
private final ArraySet<NetworkRequestInfo> mDefaultNetworkRequests = new ArraySet<>();
final ArraySet<NetworkRequestInfo> mDefaultNetworkRequests = new ArraySet<>();
private boolean isPerAppDefaultRequest(@NonNull final NetworkRequestInfo nri) {
return (mDefaultNetworkRequests.contains(nri) && mDefaultRequest != nri);
@@ -7181,7 +7285,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void callCallbackForRequest(@NonNull final NetworkRequestInfo nri,
@NonNull final NetworkAgentInfo networkAgent, final int notificationType,
final int arg1) {
if (nri.messenger == null) {
if (nri.mMessenger == null) {
// Default request has no msgr. Also prevents callbacks from being invoked for
// NetworkRequestInfos registered with ConnectivityDiagnostics requests. Those callbacks
// are Type.LISTEN, but should not have NetworkCallbacks invoked.
@@ -7250,7 +7354,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
String notification = ConnectivityManager.getCallbackName(notificationType);
log("sending notification " + notification + " for " + nrForCallback);
}
nri.messenger.send(msg);
nri.mMessenger.send(msg);
} catch (RemoteException e) {
// may occur naturally in the race of binder death.
loge("RemoteException caught trying to send a callback msg for " + nrForCallback);
@@ -9205,9 +9309,211 @@ public class ConnectivityService extends IConnectivityManager.Stub
mQosCallbackTracker.unregisterCallback(callback);
}
private void enforceAutomotiveDevice() {
final boolean isAutomotiveDevice =
mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
if (!isAutomotiveDevice) {
throw new UnsupportedOperationException(
"setOemNetworkPreference() is only available on automotive devices.");
}
}
/**
* Used by automotive devices to set the network preferences used to direct traffic at an
* application level as per the given OemNetworkPreferences. An example use-case would be an
* automotive OEM wanting to provide connectivity for applications critical to the usage of a
* vehicle via a particular network.
*
* Calling this will overwrite the existing preference.
*
* @param listener {@link ConnectivityManager.OnSetOemNetworkPreferenceListener} Listener used
* to communicate completion of setOemNetworkPreference();
* @param preference {@link OemNetworkPreferences} The application network preference to be set.
*/
@Override
public void setOemNetworkPreference(@NonNull final OemNetworkPreferences preference) {
// TODO http://b/176495594 track multiple default networks with networkPreferences
if (DBG) log("setOemNetworkPreference() called with: " + preference.toString());
public void setOemNetworkPreference(
@NonNull final OemNetworkPreferences preference,
@Nullable final IOnSetOemNetworkPreferenceListener listener) {
enforceAutomotiveDevice();
// TODO http://b/176496438 add permission check once permissions are added.
Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
validateOemNetworkPreferences(preference);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_OEM_NETWORK_PREFERENCE,
new Pair<>(preference, listener)));
}
private void validateOemNetworkPreferences(@NonNull OemNetworkPreferences preference) {
for (@OemNetworkPreferences.OemNetworkPreference final int pref
: preference.getNetworkPreferences().values()) {
if (OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED == pref) {
final String msg = "OEM_NETWORK_PREFERENCE_UNINITIALIZED is an invalid value.";
throw new IllegalArgumentException(msg);
}
}
}
private void handleSetOemNetworkPreference(
@NonNull final OemNetworkPreferences preference,
@NonNull final IOnSetOemNetworkPreferenceListener listener) throws RemoteException {
Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
if (DBG) {
log("set OEM network preferences :" + preference.toString());
}
final List<NetworkRequestInfo> nris =
new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(preference);
updateDefaultNetworksForOemNetworkPreference(nris);
mOemNetworkPreferences = preference;
// TODO http://b/176496396 persist data to shared preferences.
if (null != listener) {
listener.onComplete();
}
}
private void updateDefaultNetworksForOemNetworkPreference(
@NonNull final List<NetworkRequestInfo> nris) {
ensureRunningOnConnectivityServiceThread();
clearNonDefaultNetworkAgents();
addDefaultNetworkRequests(nris);
}
private void clearNonDefaultNetworkAgents() {
// Copy mDefaultNetworkRequests to iterate and remove elements from it in
// handleRemoveNetworkRequest() without getting a ConcurrentModificationException.
final NetworkRequestInfo[] nris =
mDefaultNetworkRequests.toArray(new NetworkRequestInfo[0]);
for (final NetworkRequestInfo nri : nris) {
if (mDefaultRequest != nri) {
handleRemoveNetworkRequest(nri);
}
}
}
private void addDefaultNetworkRequests(@NonNull final List<NetworkRequestInfo> nris) {
mDefaultNetworkRequests.addAll(nris);
handleRegisterNetworkRequest(nris);
}
/**
* Class used to generate {@link NetworkRequestInfo} based off of {@link OemNetworkPreferences}.
*/
@VisibleForTesting
final class OemNetworkRequestFactory {
List<NetworkRequestInfo> createNrisFromOemNetworkPreferences(
@NonNull final OemNetworkPreferences preference) {
final List<NetworkRequestInfo> nris = new ArrayList<>();
final SparseArray<Set<Integer>> uids =
createUidsFromOemNetworkPreferences(preference);
for (int i = 0; i < uids.size(); i++) {
final int key = uids.keyAt(i);
final Set<Integer> value = uids.valueAt(i);
final NetworkRequestInfo nri = createNriFromOemNetworkPreferences(key, value);
// No need to add an nri without any requests.
if (0 == nri.mRequests.size()) {
continue;
}
nris.add(nri);
}
return nris;
}
private SparseArray<Set<Integer>> createUidsFromOemNetworkPreferences(
@NonNull final OemNetworkPreferences preference) {
final SparseArray<Set<Integer>> uids = new SparseArray<>();
final PackageManager pm = mContext.getPackageManager();
for (final Map.Entry<String, Integer> entry :
preference.getNetworkPreferences().entrySet()) {
@OemNetworkPreferences.OemNetworkPreference final int pref = entry.getValue();
try {
final int uid = pm.getApplicationInfo(entry.getKey(), 0).uid;
if (!uids.contains(pref)) {
uids.put(pref, new ArraySet<>());
}
uids.get(pref).add(uid);
} catch (PackageManager.NameNotFoundException e) {
// Although this may seem like an error scenario, it is ok that uninstalled
// packages are sent on a network preference as the system will watch for
// package installations associated with this network preference and update
// accordingly. This is done so as to minimize race conditions on app install.
// TODO b/177092163 add app install watching.
continue;
}
}
return uids;
}
private NetworkRequestInfo createNriFromOemNetworkPreferences(
@OemNetworkPreferences.OemNetworkPreference final int preference,
@NonNull final Set<Integer> uids) {
final List<NetworkRequest> requests = new ArrayList<>();
// Requests will ultimately be evaluated by order of insertion therefore it matters.
switch (preference) {
case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID:
requests.add(createUnmeteredNetworkRequest());
requests.add(createOemPaidNetworkRequest());
requests.add(createDefaultRequest());
break;
case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK:
requests.add(createUnmeteredNetworkRequest());
requests.add(createOemPaidNetworkRequest());
break;
case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY:
requests.add(createOemPaidNetworkRequest());
break;
case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY:
requests.add(createOemPrivateNetworkRequest());
break;
default:
// This should never happen.
throw new IllegalArgumentException("createNriFromOemNetworkPreferences()"
+ " called with invalid preference of " + preference);
}
setOemNetworkRequestUids(requests, uids);
return new NetworkRequestInfo(requests);
}
private NetworkRequest createUnmeteredNetworkRequest() {
final NetworkCapabilities netcap = createDefaultPerAppNetCap()
.addCapability(NET_CAPABILITY_NOT_METERED)
.addCapability(NET_CAPABILITY_VALIDATED);
return createNetworkRequest(NetworkRequest.Type.LISTEN, netcap);
}
private NetworkRequest createOemPaidNetworkRequest() {
// NET_CAPABILITY_OEM_PAID is a restricted capability.
final NetworkCapabilities netcap = createDefaultPerAppNetCap()
.addCapability(NET_CAPABILITY_OEM_PAID)
.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
return createNetworkRequest(NetworkRequest.Type.REQUEST, netcap);
}
private NetworkRequest createOemPrivateNetworkRequest() {
// NET_CAPABILITY_OEM_PRIVATE is a restricted capability.
final NetworkCapabilities netcap = createDefaultPerAppNetCap()
.addCapability(NET_CAPABILITY_OEM_PRIVATE)
.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
return createNetworkRequest(NetworkRequest.Type.REQUEST, netcap);
}
private NetworkCapabilities createDefaultPerAppNetCap() {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
return netCap;
}
private void setOemNetworkRequestUids(@NonNull final List<NetworkRequest> requests,
@NonNull final Set<Integer> uids) {
final Set<UidRange> ranges = new ArraySet<>();
for (final int uid : uids) {
ranges.add(new UidRange(uid, uid));
}
for (final NetworkRequest req : requests) {
req.networkCapabilities.setUids(ranges);
}
}
}
}

View File

@@ -40,7 +40,7 @@ import java.util.Map;
@SmallTest
public class OemNetworkPreferencesTest {
private static final int TEST_PREF = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_DEFAULT;
private static final int TEST_PREF = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED;
private static final String TEST_PACKAGE = "com.google.apps.contacts";
private final OemNetworkPreferences.Builder mBuilder = new OemNetworkPreferences.Builder();