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 */ /** @hide */
public final class OemNetworkPreferences implements Parcelable { 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. * If an unmetered network is available, use it.
@@ -160,7 +160,7 @@ public final class OemNetworkPreferences implements Parcelable {
/** @hide */ /** @hide */
@IntDef(prefix = "OEM_NETWORK_PREFERENCE_", value = { @IntDef(prefix = "OEM_NETWORK_PREFERENCE_", value = {
OEM_NETWORK_PREFERENCE_DEFAULT, OEM_NETWORK_PREFERENCE_UNINITIALIZED,
OEM_NETWORK_PREFERENCE_OEM_PAID, OEM_NETWORK_PREFERENCE_OEM_PAID,
OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK, OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK,
OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY, OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY,
@@ -178,8 +178,8 @@ public final class OemNetworkPreferences implements Parcelable {
@NonNull @NonNull
public static String oemNetworkPreferenceToString(@OemNetworkPreference int value) { public static String oemNetworkPreferenceToString(@OemNetworkPreference int value) {
switch (value) { switch (value) {
case OEM_NETWORK_PREFERENCE_DEFAULT: case OEM_NETWORK_PREFERENCE_UNINITIALIZED:
return "OEM_NETWORK_PREFERENCE_DEFAULT"; return "OEM_NETWORK_PREFERENCE_UNINITIALIZED";
case OEM_NETWORK_PREFERENCE_OEM_PAID: case OEM_NETWORK_PREFERENCE_OEM_PAID:
return "OEM_NETWORK_PREFERENCE_OEM_PAID"; return "OEM_NETWORK_PREFERENCE_OEM_PAID";
case OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK: 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 @NonNull
private final List<QosCallbackConnection> mQosCallbackConnections = new ArrayList<>(); private final List<QosCallbackConnection> mQosCallbackConnections = new ArrayList<>();
@@ -5096,4 +5087,55 @@ public class ConnectivityManager {
sendRequestForNetwork(nc, networkCallback, 0, BACKGROUND_REQUEST, sendRequestForNetwork(nc, networkCallback, 0, BACKGROUND_REQUEST,
TYPE_NONE, handler == null ? getDefaultHandler() : new CallbackHandler(handler)); 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.ConnectionInfo;
import android.net.ConnectivityDiagnosticsManager; import android.net.ConnectivityDiagnosticsManager;
import android.net.IConnectivityDiagnosticsCallback; import android.net.IConnectivityDiagnosticsCallback;
import android.net.IOnSetOemNetworkPreferenceListener;
import android.net.IQosCallback; import android.net.IQosCallback;
import android.net.ISocketKeepaliveCallback; import android.net.ISocketKeepaliveCallback;
import android.net.LinkProperties; import android.net.LinkProperties;
@@ -245,5 +246,6 @@ interface IConnectivityManager
void registerQosSocketCallback(in QosSocketInfo socketInfo, in IQosCallback callback); void registerQosSocketCallback(in QosSocketInfo socketInfo, in IQosCallback callback);
void unregisterQosCallback(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_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; 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_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_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -95,6 +97,7 @@ import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks; import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener; import android.net.INetworkPolicyListener;
import android.net.INetworkStatsService; import android.net.INetworkStatsService;
import android.net.IOnSetOemNetworkPreferenceListener;
import android.net.IQosCallback; import android.net.IQosCallback;
import android.net.ISocketKeepaliveCallback; import android.net.ISocketKeepaliveCallback;
import android.net.InetAddresses; 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; 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 * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
* should be shown. * should be shown.
@@ -1039,10 +1048,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
mMetricsLog = logger; mMetricsLog = logger;
mNetworkRanker = new NetworkRanker(); mNetworkRanker = new NetworkRanker();
final NetworkRequest defaultInternetRequest = createDefaultInternetRequestForTransport( final NetworkRequest defaultInternetRequest = createDefaultRequest();
-1, NetworkRequest.Type.REQUEST); mDefaultRequest = new NetworkRequestInfo(
mDefaultRequest = new NetworkRequestInfo(null, defaultInternetRequest, new Binder(), defaultInternetRequest, null, new Binder(),
null /* attributionTag */); null /* attributionTags */);
mNetworkRequests.put(defaultInternetRequest, mDefaultRequest); mNetworkRequests.put(defaultInternetRequest, mDefaultRequest);
mDefaultNetworkRequests.add(mDefaultRequest); mDefaultNetworkRequests.add(mDefaultRequest);
mNetworkRequestInfoLogs.log("REGISTER " + mDefaultRequest); mNetworkRequestInfoLogs.log("REGISTER " + mDefaultRequest);
@@ -1256,15 +1265,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
return netCap; return netCap;
} }
private NetworkRequest createDefaultRequest() {
return createDefaultInternetRequestForTransport(
TYPE_NONE, NetworkRequest.Type.REQUEST);
}
private NetworkRequest createDefaultInternetRequestForTransport( private NetworkRequest createDefaultInternetRequestForTransport(
int transportType, NetworkRequest.Type type) { int transportType, NetworkRequest.Type type) {
final NetworkCapabilities netCap = new NetworkCapabilities(); final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET); netCap.addCapability(NET_CAPABILITY_INTERNET);
netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName()); netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
if (transportType > -1) { if (transportType > TYPE_NONE) {
netCap.addTransportType(transportType); netCap.addTransportType(transportType);
} }
return createNetworkRequest(type, netCap);
}
private NetworkRequest createNetworkRequest(
NetworkRequest.Type type, NetworkCapabilities netCap) {
return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), type); return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), type);
} }
@@ -1314,7 +1333,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (enable) { if (enable) {
handleRegisterNetworkRequest(new NetworkRequestInfo( handleRegisterNetworkRequest(new NetworkRequestInfo(
null, networkRequest, new Binder(), null /* attributionTag */)); networkRequest, null, new Binder(),
null /* attributionTags */));
} else { } else {
handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID, handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID,
/* callOnUnavailable */ false); /* callOnUnavailable */ false);
@@ -2634,6 +2654,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
pw.println(); pw.println();
pw.print("Current per-app default networks: ");
pw.increaseIndent();
dumpPerAppNetworkPreferences(pw);
pw.decreaseIndent();
pw.println();
pw.println("Current Networks:"); pw.println("Current Networks:");
pw.increaseIndent(); pw.increaseIndent();
dumpNetworks(pw); 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) { private void dumpNetworkRequests(IndentingPrintWriter pw) {
for (NetworkRequestInfo nri : requestsSortedById()) { for (NetworkRequestInfo nri : requestsSortedById()) {
pw.println(nri.toString()); pw.println(nri.toString());
@@ -3586,7 +3646,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
private void handleRegisterNetworkRequest(@NonNull final NetworkRequestInfo nri) { private void handleRegisterNetworkRequest(@NonNull final NetworkRequestInfo nri) {
handleRegisterNetworkRequest(Collections.singletonList(nri));
}
private void handleRegisterNetworkRequest(@NonNull final List<NetworkRequestInfo> nris) {
ensureRunningOnConnectivityServiceThread(); ensureRunningOnConnectivityServiceThread();
for (final NetworkRequestInfo nri : nris) {
mNetworkRequestInfoLogs.log("REGISTER " + nri); mNetworkRequestInfoLogs.log("REGISTER " + nri);
for (final NetworkRequest req : nri.mRequests) { for (final NetworkRequest req : nri.mRequests) {
mNetworkRequests.put(req, nri); mNetworkRequests.put(req, nri);
@@ -3599,18 +3664,22 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
} }
} }
}
rematchAllNetworksAndRequests(); rematchAllNetworksAndRequests();
for (final NetworkRequestInfo nri : nris) {
// If the nri is satisfied, return as its score has already been sent if needed. // If the nri is satisfied, return as its score has already been sent if needed.
if (nri.isBeingSatisfied()) { if (nri.isBeingSatisfied()) {
return; return;
} }
// As this request was not satisfied on rematch and thus never had any scores sent to the // As this request was not satisfied on rematch and thus never had any scores sent to
// factories, send null now for each request of type REQUEST. // the factories, send null now for each request of type REQUEST.
for (final NetworkRequest req : nri.mRequests) { for (final NetworkRequest req : nri.mRequests) {
if (req.isRequest()) sendUpdatedScoreToFactories(req, null); if (req.isRequest()) sendUpdatedScoreToFactories(req, null);
} }
} }
}
private void handleReleaseNetworkRequestWithIntent(@NonNull final PendingIntent pendingIntent, private void handleReleaseNetworkRequestWithIntent(@NonNull final PendingIntent pendingIntent,
final int callingUid) { final int callingUid) {
@@ -3781,6 +3850,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
removeListenRequestFromNetworks(req); removeListenRequestFromNetworks(req);
} }
} }
mDefaultNetworkRequests.remove(nri);
mNetworkRequestCounter.decrementCount(nri.mUid); mNetworkRequestCounter.decrementCount(nri.mUid);
mNetworkRequestInfoLogs.log("RELEASE " + nri); mNetworkRequestInfoLogs.log("RELEASE " + nri);
@@ -4419,6 +4489,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
case EVENT_SET_REQUIRE_VPN_FOR_UIDS: case EVENT_SET_REQUIRE_VPN_FOR_UIDS:
handleSetRequireVpnForUids(toBool(msg.arg1), (UidRange[]) msg.obj); handleSetRequireVpnForUids(toBool(msg.arg1), (UidRange[]) msg.obj);
break; 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; final PendingIntent mPendingIntent;
boolean mPendingIntentSent; boolean mPendingIntentSent;
@Nullable
final Messenger mMessenger;
@Nullable
private final IBinder mBinder; private final IBinder mBinder;
final int mPid; final int mPid;
final int mUid; final int mUid;
final Messenger messenger;
@Nullable @Nullable
final String mCallingAttributionTag; final String mCallingAttributionTag;
@@ -5570,12 +5652,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
return uids; return uids;
} }
NetworkRequestInfo(NetworkRequest r, PendingIntent pi, NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final PendingIntent pi,
@Nullable String callingAttributionTag) { @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); mRequests = initializeRequests(r);
ensureAllNetworkRequestsHaveType(mRequests); ensureAllNetworkRequestsHaveType(mRequests);
mPendingIntent = pi; mPendingIntent = pi;
messenger = null; mMessenger = null;
mBinder = null; mBinder = null;
mPid = getCallingPid(); mPid = getCallingPid();
mUid = mDeps.getCallingUid(); mUid = mDeps.getCallingUid();
@@ -5583,11 +5670,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
mCallingAttributionTag = callingAttributionTag; mCallingAttributionTag = callingAttributionTag;
} }
NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder, NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final Messenger m,
@Nullable String callingAttributionTag) { @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(); super();
messenger = m;
mRequests = initializeRequests(r); mRequests = initializeRequests(r);
mMessenger = m;
ensureAllNetworkRequestsHaveType(mRequests); ensureAllNetworkRequestsHaveType(mRequests);
mBinder = binder; mBinder = binder;
mPid = getCallingPid(); 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 */); this(r, null /* pi */, null /* callingAttributionTag */);
} }
@@ -5618,9 +5714,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
return mRequests.size() > 1; return mRequests.size() > 1;
} }
private List<NetworkRequest> initializeRequests(NetworkRequest r) { private List<NetworkRequest> initializeRequests(List<NetworkRequest> r) {
final ArrayList<NetworkRequest> tempRequests = new ArrayList<>(); // Creating a defensive copy to prevent the sender from modifying the list being
tempRequests.add(new NetworkRequest(r)); // reflected in the return value of this method.
final List<NetworkRequest> tempRequests = new ArrayList<>(r);
return Collections.unmodifiableList(tempRequests); return Collections.unmodifiableList(tempRequests);
} }
@@ -5804,7 +5901,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType, NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId(), reqType); nextNetworkRequestId(), reqType);
NetworkRequestInfo nri = NetworkRequestInfo nri =
new NetworkRequestInfo(messenger, networkRequest, binder, callingAttributionTag); new NetworkRequestInfo(networkRequest, messenger, binder, callingAttributionTag);
if (DBG) log("requestNetwork for " + nri); if (DBG) log("requestNetwork for " + nri);
// For TRACK_SYSTEM_DEFAULT callbacks, the capabilities have been modified since they were // 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 networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN); NetworkRequest.Type.LISTEN);
NetworkRequestInfo nri = NetworkRequestInfo nri =
new NetworkRequestInfo(messenger, networkRequest, binder, callingAttributionTag); new NetworkRequestInfo(networkRequest, messenger, binder, callingAttributionTag);
if (VDBG) log("listenForNetwork for " + nri); if (VDBG) log("listenForNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri)); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -6098,13 +6195,20 @@ public class ConnectivityService extends IConnectivityManager.Stub
@GuardedBy("mBlockedAppUids") @GuardedBy("mBlockedAppUids")
private final HashSet<Integer> mBlockedAppUids = new HashSet<>(); 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 // The always-on request for an Internet-capable network that apps without a specific default
// fall back to. // fall back to.
@VisibleForTesting
@NonNull @NonNull
private final NetworkRequestInfo mDefaultRequest; final NetworkRequestInfo mDefaultRequest;
// Collection of NetworkRequestInfo's used for default networks. // Collection of NetworkRequestInfo's used for default networks.
@VisibleForTesting
@NonNull @NonNull
private final ArraySet<NetworkRequestInfo> mDefaultNetworkRequests = new ArraySet<>(); final ArraySet<NetworkRequestInfo> mDefaultNetworkRequests = new ArraySet<>();
private boolean isPerAppDefaultRequest(@NonNull final NetworkRequestInfo nri) { private boolean isPerAppDefaultRequest(@NonNull final NetworkRequestInfo nri) {
return (mDefaultNetworkRequests.contains(nri) && mDefaultRequest != nri); return (mDefaultNetworkRequests.contains(nri) && mDefaultRequest != nri);
@@ -7181,7 +7285,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void callCallbackForRequest(@NonNull final NetworkRequestInfo nri, private void callCallbackForRequest(@NonNull final NetworkRequestInfo nri,
@NonNull final NetworkAgentInfo networkAgent, final int notificationType, @NonNull final NetworkAgentInfo networkAgent, final int notificationType,
final int arg1) { final int arg1) {
if (nri.messenger == null) { if (nri.mMessenger == null) {
// Default request has no msgr. Also prevents callbacks from being invoked for // Default request has no msgr. Also prevents callbacks from being invoked for
// NetworkRequestInfos registered with ConnectivityDiagnostics requests. Those callbacks // NetworkRequestInfos registered with ConnectivityDiagnostics requests. Those callbacks
// are Type.LISTEN, but should not have NetworkCallbacks invoked. // are Type.LISTEN, but should not have NetworkCallbacks invoked.
@@ -7250,7 +7354,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
String notification = ConnectivityManager.getCallbackName(notificationType); String notification = ConnectivityManager.getCallbackName(notificationType);
log("sending notification " + notification + " for " + nrForCallback); log("sending notification " + notification + " for " + nrForCallback);
} }
nri.messenger.send(msg); nri.mMessenger.send(msg);
} catch (RemoteException e) { } catch (RemoteException e) {
// may occur naturally in the race of binder death. // may occur naturally in the race of binder death.
loge("RemoteException caught trying to send a callback msg for " + nrForCallback); loge("RemoteException caught trying to send a callback msg for " + nrForCallback);
@@ -9205,9 +9309,211 @@ public class ConnectivityService extends IConnectivityManager.Stub
mQosCallbackTracker.unregisterCallback(callback); 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 @Override
public void setOemNetworkPreference(@NonNull final OemNetworkPreferences preference) { public void setOemNetworkPreference(
// TODO http://b/176495594 track multiple default networks with networkPreferences @NonNull final OemNetworkPreferences preference,
if (DBG) log("setOemNetworkPreference() called with: " + preference.toString()); @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 @SmallTest
public class OemNetworkPreferencesTest { 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 static final String TEST_PACKAGE = "com.google.apps.contacts";
private final OemNetworkPreferences.Builder mBuilder = new OemNetworkPreferences.Builder(); private final OemNetworkPreferences.Builder mBuilder = new OemNetworkPreferences.Builder();