Merge "Add a NetworkProvider class to the SDK."

This commit is contained in:
Lorenzo Colitti
2020-01-09 15:09:58 +00:00
committed by Gerrit Code Review
4 changed files with 322 additions and 12 deletions

View File

@@ -3107,6 +3107,63 @@ public class ConnectivityManager {
}
}
/**
* Registers the specified {@link NetworkProvider}.
* Each listener must only be registered once. The listener can be unregistered with
* {@link #unregisterNetworkProvider}.
*
* @param provider the provider to register
* @return the ID of the provider. This ID must be used by the provider when registering
* {@link android.net.NetworkAgent}s.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
public int registerNetworkProvider(@NonNull NetworkProvider provider) {
if (provider.getProviderId() != NetworkProvider.ID_NONE) {
// TODO: Provide a better method for checking this by moving NetworkFactory.SerialNumber
// out of NetworkFactory.
throw new IllegalStateException("NetworkProviders can only be registered once");
}
try {
int providerId = mService.registerNetworkProvider(provider.getMessenger(),
provider.getName());
provider.setProviderId(providerId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
return provider.getProviderId();
}
/**
* Unregisters the specified NetworkProvider.
*
* @param provider the provider to unregister
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
public void unregisterNetworkProvider(@NonNull NetworkProvider provider) {
try {
mService.unregisterNetworkProvider(provider.getMessenger());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
provider.setProviderId(NetworkProvider.ID_NONE);
}
/** @hide exposed via the NetworkProvider class. */
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) {
try {
mService.declareNetworkRequestUnfulfillable(request);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
// TODO : remove this method. It is a stopgap measure to help sheperding a number
// of dependent changes that would conflict throughout the automerger graph. Having this
// temporarily helps with the process of going through with all these dependent changes across

View File

@@ -142,12 +142,16 @@ interface IConnectivityManager
void setAirplaneMode(boolean enable);
int registerNetworkFactory(in Messenger messenger, in String name);
boolean requestBandwidthUpdate(in Network network);
int registerNetworkFactory(in Messenger messenger, in String name);
void unregisterNetworkFactory(in Messenger messenger);
int registerNetworkProvider(in Messenger messenger, in String name);
void unregisterNetworkProvider(in Messenger messenger);
void declareNetworkRequestUnfulfillable(in NetworkRequest request);
int registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
in NetworkCapabilities nc, int score, in NetworkMisc misc, in int factorySerialNumber);

View File

@@ -0,0 +1,166 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
/**
* Base class for network providers such as telephony or Wi-Fi. NetworkProviders connect the device
* to networks and makes them available to to the core network stack by creating
* {@link NetworkAgent}s. The networks can then provide connectivity to apps and can be interacted
* with via networking APIs such as {@link ConnectivityManager}.
*
* Subclasses should implement {@link #onNetworkRequested} and {@link #onRequestWithdrawn} to
* receive {@link NetworkRequest}s sent by the system and by apps. A network that is not the
* best (highest-scoring) network for any request is generally not used by the system, and torn
* down.
*
* @hide
*/
@SystemApi
public class NetworkProvider {
/**
* {@code providerId} value that indicates the absence of a provider. It is the providerId of
* any NetworkProvider that is not currently registered, and of any NetworkRequest that is not
* currently being satisfied by a network.
*/
public static final int ID_NONE = -1;
/**
* A hardcoded ID for NetworkAgents representing VPNs. These agents are not created by any
* provider, so they use this constant for clarity instead of NONE.
* @hide only used by ConnectivityService.
*/
public static final int ID_VPN = -2;
/**
* The first providerId value that will be allocated.
* @hide only used by ConnectivityService.
*/
public static final int FIRST_PROVIDER_ID = 1;
/** @hide only used by ConnectivityService */
public static final int CMD_REQUEST_NETWORK = 1;
/** @hide only used by ConnectivityService */
public static final int CMD_CANCEL_REQUEST = 2;
private final Messenger mMessenger;
private final String mName;
private final ConnectivityManager mCm;
private int mProviderId = ID_NONE;
/**
* Constructs a new NetworkProvider.
*
* @param looper the Looper on which to run {@link #onNetworkRequested} and
* {@link #onRequestWithdrawn}.
* @param name the name of the listener, used only for debugging.
*
* @hide
*/
@SystemApi
public NetworkProvider(@NonNull Context context, @NonNull Looper looper, @NonNull String name) {
mCm = ConnectivityManager.from(context);
Handler handler = new Handler(looper) {
@Override
public void handleMessage(Message m) {
switch (m.what) {
case CMD_REQUEST_NETWORK:
onNetworkRequested((NetworkRequest) m.obj, m.arg1, m.arg2);
break;
case CMD_CANCEL_REQUEST:
onRequestWithdrawn((NetworkRequest) m.obj);
break;
default:
Log.e(mName, "Unhandled message: " + m.what);
}
}
};
mMessenger = new Messenger(handler);
mName = name;
}
// TODO: consider adding a register() method so ConnectivityManager does not need to call this.
public @Nullable Messenger getMessenger() {
return mMessenger;
}
public @NonNull String getName() {
return mName;
}
/**
* Returns the ID of this provider. This is known only once the provider is registered via
* {@link ConnectivityManager#registerNetworkProvider()}, otherwise the ID is {@link #ID_NONE}.
* This ID must be used when registering any {@link NetworkAgent}s.
*/
public int getProviderId() {
return mProviderId;
}
/** @hide */
public void setProviderId(int providerId) {
mProviderId = providerId;
}
/**
* Called when a NetworkRequest is received. The request may be a new request or an existing
* request with a different score.
*
* @param request the NetworkRequest being received
* @param score the score of the network currently satisfying the request, or 0 if none.
* @param providerId the ID of the provider that created the network currently satisfying this
* request, or {@link #ID_NONE} if none.
*
* @hide
*/
@SystemApi
public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {}
/**
* Called when a NetworkRequest is withdrawn.
* @hide
*/
@SystemApi
public void onRequestWithdrawn(@NonNull NetworkRequest request) {}
/**
* Asserts that no provider will ever be able to satisfy the specified request. The provider
* must only call this method if it knows that it is the only provider on the system capable of
* satisfying this request, and that the request cannot be satisfied. The application filing the
* request will receive an {@link NetworkCallback#onUnavailable()} callback.
*
* @param request the request that cannot be fulfilled
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) {
mCm.declareNetworkRequestUnfulfillable(request);
}
}

View File

@@ -94,6 +94,7 @@ import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMisc;
import android.net.NetworkMonitorManager;
import android.net.NetworkPolicyManager;
import android.net.NetworkProvider;
import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
import android.net.NetworkScore;
@@ -221,6 +222,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @hide
@@ -597,6 +599,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
// sequence number of NetworkRequests
private int mNextNetworkRequestId = 1;
// Sequence number for NetworkProvider IDs.
private final AtomicInteger mNextNetworkProviderId = new AtomicInteger(
NetworkProvider.FIRST_PROVIDER_ID);
// NetworkRequest activity String log entries.
private static final int MAX_NETWORK_REQUEST_LOGS = 20;
private final LocalLog mNetworkRequestInfoLogs = new LocalLog(MAX_NETWORK_REQUEST_LOGS);
@@ -4904,33 +4910,71 @@ public class ConnectivityService extends IConnectivityManager.Stub
public final String name;
public final Messenger messenger;
private final AsyncChannel mAsyncChannel;
private final IBinder.DeathRecipient mDeathRecipient;
public final int factorySerialNumber;
NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel,
int factorySerialNumber) {
int factorySerialNumber, IBinder.DeathRecipient deathRecipient) {
this.name = name;
this.messenger = messenger;
this.mAsyncChannel = asyncChannel;
this.factorySerialNumber = factorySerialNumber;
mAsyncChannel = asyncChannel;
mDeathRecipient = deathRecipient;
if ((mAsyncChannel == null) == (mDeathRecipient == null)) {
throw new AssertionError("Must pass exactly one of asyncChannel or deathRecipient");
}
}
boolean isLegacyNetworkFactory() {
return mAsyncChannel != null;
}
void sendMessageToNetworkProvider(int what, int arg1, int arg2, Object obj) {
try {
messenger.send(Message.obtain(null /* handler */, what, arg1, arg2, obj));
} catch (RemoteException e) {
// Remote process died. Ignore; the death recipient will remove this
// NetworkFactoryInfo from mNetworkFactoryInfos.
}
}
void requestNetwork(NetworkRequest request, int score, int servingSerialNumber) {
if (isLegacyNetworkFactory()) {
mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score,
servingSerialNumber, request);
} else {
sendMessageToNetworkProvider(NetworkProvider.CMD_REQUEST_NETWORK, score,
servingSerialNumber, request);
}
}
void cancelRequest(NetworkRequest request) {
if (isLegacyNetworkFactory()) {
mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST, request);
} else {
sendMessageToNetworkProvider(NetworkProvider.CMD_CANCEL_REQUEST, 0, 0, request);
}
}
void connect(Context context, Handler handler) {
if (isLegacyNetworkFactory()) {
mAsyncChannel.connect(context, handler, messenger);
} else {
try {
messenger.getBinder().linkToDeath(mDeathRecipient, 0);
} catch (RemoteException e) {
mDeathRecipient.binderDied();
}
}
}
void completeConnection() {
if (isLegacyNetworkFactory()) {
mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
}
}
}
private void ensureNetworkRequestHasType(NetworkRequest request) {
if (request.type == NetworkRequest.Type.NONE) {
@@ -5299,6 +5343,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
}
/** Returns the next Network provider ID. */
public final int nextNetworkProviderId() {
return mNextNetworkProviderId.getAndIncrement();
}
@Override
public void releaseNetworkRequest(NetworkRequest networkRequest) {
ensureNetworkRequestHasType(networkRequest);
@@ -5310,21 +5359,49 @@ public class ConnectivityService extends IConnectivityManager.Stub
public int registerNetworkFactory(Messenger messenger, String name) {
enforceNetworkFactoryPermission();
NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel(),
NetworkFactory.SerialNumber.nextSerialNumber());
nextNetworkProviderId(), null /* deathRecipient */);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
return nfi.factorySerialNumber;
}
private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) {
if (mNetworkFactoryInfos.containsKey(nfi.messenger)) {
// Avoid creating duplicates. even if an app makes a direct AIDL call.
// This will never happen if an app calls ConnectivityManager#registerNetworkProvider,
// as that will throw if a duplicate provider is registered.
Slog.e(TAG, "Attempt to register existing NetworkFactoryInfo "
+ mNetworkFactoryInfos.get(nfi.messenger).name);
return;
}
if (DBG) log("Got NetworkFactory Messenger for " + nfi.name);
mNetworkFactoryInfos.put(nfi.messenger, nfi);
nfi.connect(mContext, mTrackerHandler);
if (!nfi.isLegacyNetworkFactory()) {
// Legacy NetworkFactories get their requests when their AsyncChannel connects.
sendAllRequestsToFactory(nfi);
}
}
@Override
public int registerNetworkProvider(Messenger messenger, String name) {
enforceNetworkFactoryPermission();
NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger,
null /* asyncChannel */, nextNetworkProviderId(),
() -> unregisterNetworkProvider(messenger));
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
return nfi.factorySerialNumber;
}
@Override
public void unregisterNetworkProvider(Messenger messenger) {
enforceNetworkFactoryPermission();
mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_FACTORY, messenger));
}
@Override
public void unregisterNetworkFactory(Messenger messenger) {
enforceNetworkFactoryPermission();
mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_FACTORY, messenger));
unregisterNetworkProvider(messenger);
}
private void handleUnregisterNetworkFactory(Messenger messenger) {
@@ -5336,6 +5413,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (DBG) log("unregisterNetworkFactory for " + nfi.name);
}
@Override
public void declareNetworkRequestUnfulfillable(NetworkRequest request) {
enforceNetworkFactoryPermission();
mHandler.post(() -> handleReleaseNetworkRequest(request, Binder.getCallingUid(), true));
}
// NOTE: Accessed on multiple threads, must be synchronized on itself.
@GuardedBy("mNetworkForNetId")
private final SparseArray<NetworkAgentInfo> mNetworkForNetId = new SparseArray<>();