Add IIpClient API for IpClient

The API will be used to interact with IpClient once it is moved to the
NetworkStack process.
This change keeps compatibility with the previous API so that clients
can be migrated independently.

Test: atest FrameworksNetTests NetworkStackTests
Bug: b/112869080
Change-Id: I57d8164afae849230bbc0e25f17859c0b22d0f29
This commit is contained in:
Remi NGUYEN VAN
2019-01-12 15:36:47 +09:00
parent 6b0b2b735e
commit a5d31f53b6
11 changed files with 536 additions and 524 deletions

View File

@@ -844,6 +844,8 @@ aidl_interface {
"core/java/android/net/dhcp/DhcpServingParamsParcel.aidl",
"core/java/android/net/dhcp/IDhcpServer.aidl",
"core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
"core/java/android/net/ip/IIpClient.aidl",
"core/java/android/net/ip/IIpClientCallbacks.aidl",
"core/java/android/net/ipmemorystore/**/*.aidl",
],
api_dir: "aidl/networkstack",

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2019, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing perNmissions and
* limitations under the License.
*/
package android.net.ip;
import android.net.ProxyInfoParcelable;
import android.net.ProvisioningConfigurationParcelable;
/** @hide */
oneway interface IIpClient {
void completedPreDhcpAction();
void confirmConfiguration();
void readPacketFilterComplete(in byte[] data);
void shutdown();
void startProvisioning(in ProvisioningConfigurationParcelable req);
void stop();
void setTcpBufferSizes(in String tcpBufferSizes);
void setHttpProxy(in ProxyInfoParcelable proxyInfo);
void setMulticastFilter(boolean enabled);
}

View File

@@ -0,0 +1,66 @@
/**
* Copyright (c) 2019, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing perNmissions and
* limitations under the License.
*/
package android.net.ip;
import android.net.LinkPropertiesParcelable;
import android.net.ip.IIpClient;
import android.net.DhcpResultsParcelable;
/** @hide */
oneway interface IIpClientCallbacks {
void onIpClientCreated(in IIpClient ipClient);
void onPreDhcpAction();
void onPostDhcpAction();
// This is purely advisory and not an indication of provisioning
// success or failure. This is only here for callers that want to
// expose DHCPv4 results to other APIs (e.g., WifiInfo#setInetAddress).
// DHCPv4 or static IPv4 configuration failure or success can be
// determined by whether or not the passed-in DhcpResults object is
// null or not.
void onNewDhcpResults(in DhcpResultsParcelable dhcpResults);
void onProvisioningSuccess(in LinkPropertiesParcelable newLp);
void onProvisioningFailure(in LinkPropertiesParcelable newLp);
// Invoked on LinkProperties changes.
void onLinkPropertiesChange(in LinkPropertiesParcelable newLp);
// Called when the internal IpReachabilityMonitor (if enabled) has
// detected the loss of a critical number of required neighbors.
void onReachabilityLost(in String logMsg);
// Called when the IpClient state machine terminates.
void onQuit();
// Install an APF program to filter incoming packets.
void installPacketFilter(in byte[] filter);
// Asynchronously read back the APF program & data buffer from the wifi driver.
// Due to Wifi HAL limitations, the current implementation only supports dumping the entire
// buffer. In response to this request, the driver returns the data buffer asynchronously
// by sending an IpClient#EVENT_READ_PACKET_FILTER_COMPLETE message.
void startReadPacketFilter();
// If multicast filtering cannot be accomplished with APF, this function will be called to
// actuate multicast filtering using another means.
void setFallbackMulticastFilter(boolean enabled);
// Enabled/disable Neighbor Discover offload functionality. This is
// called, for example, whenever 464xlat is being started or stopped.
void setNeighborDiscoveryOffload(boolean enable);
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ip;
import android.net.DhcpResults;
import android.net.LinkProperties;
/**
* Callbacks for handling IpClient events.
*
* This is a convenience class to allow clients not to override all methods of IIpClientCallbacks,
* and avoid unparceling arguments.
* These methods are called asynchronously on a Binder thread, as IpClient lives in a different
* process.
* @hide
*/
public class IpClientCallbacks {
/**
* Callback called upon IpClient creation.
*
* @param ipClient The Binder token to communicate with IpClient.
*/
public void onIpClientCreated(IIpClient ipClient) {}
/**
* Callback called prior to DHCP discovery/renewal.
*
* <p>In order to receive onPreDhcpAction(), call #withPreDhcpAction() when constructing a
* ProvisioningConfiguration.
*
* <p>Implementations of onPreDhcpAction() must call IpClient#completedPreDhcpAction() to
* indicate that DHCP is clear to proceed.
*/
public void onPreDhcpAction() {}
/**
* Callback called after DHCP discovery/renewal.
*/
public void onPostDhcpAction() {}
/**
* Callback called when new DHCP results are available.
*
* <p>This is purely advisory and not an indication of provisioning success or failure. This is
* only here for callers that want to expose DHCPv4 results to other APIs
* (e.g., WifiInfo#setInetAddress).
*
* <p>DHCPv4 or static IPv4 configuration failure or success can be determined by whether or not
* the passed-in DhcpResults object is null.
*/
public void onNewDhcpResults(DhcpResults dhcpResults) {}
/**
* Indicates that provisioning was successful.
*/
public void onProvisioningSuccess(LinkProperties newLp) {}
/**
* Indicates that provisioning failed.
*/
public void onProvisioningFailure(LinkProperties newLp) {}
/**
* Invoked on LinkProperties changes.
*/
public void onLinkPropertiesChange(LinkProperties newLp) {}
/**Called when the internal IpReachabilityMonitor (if enabled) has
* detected the loss of a critical number of required neighbors.
*/
public void onReachabilityLost(String logMsg) {}
/**
* Called when the IpClient state machine terminates.
*/
public void onQuit() {}
/**
* Called to indicate that a new APF program must be installed to filter incoming packets.
*/
public void installPacketFilter(byte[] filter) {}
/**
* Called to indicate that the APF Program & data buffer must be read asynchronously from the
* wifi driver.
*
* <p>Due to Wifi HAL limitations, the current implementation only supports dumping the entire
* buffer. In response to this request, the driver returns the data buffer asynchronously
* by sending an IpClient#EVENT_READ_PACKET_FILTER_COMPLETE message.
*/
public void startReadPacketFilter() {}
/**
* If multicast filtering cannot be accomplished with APF, this function will be called to
* actuate multicast filtering using another means.
*/
public void setFallbackMulticastFilter(boolean enabled) {}
/**
* Enabled/disable Neighbor Discover offload functionality. This is called, for example,
* whenever 464xlat is being started or stopped.
*/
public void setNeighborDiscoveryOffload(boolean enable) {}
}

View File

@@ -16,8 +16,19 @@
package android.net.apf;
import static android.net.util.NetworkConstants.*;
import static android.system.OsConstants.*;
import static android.net.util.NetworkConstants.ICMPV6_ECHO_REQUEST_TYPE;
import static android.net.util.NetworkConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
import static android.net.util.NetworkConstants.ICMPV6_ROUTER_ADVERTISEMENT;
import static android.net.util.NetworkConstants.ICMPV6_ROUTER_SOLICITATION;
import static android.system.OsConstants.AF_PACKET;
import static android.system.OsConstants.ARPHRD_ETHER;
import static android.system.OsConstants.ETH_P_ARP;
import static android.system.OsConstants.ETH_P_IP;
import static android.system.OsConstants.ETH_P_IPV6;
import static android.system.OsConstants.IPPROTO_ICMPV6;
import static android.system.OsConstants.IPPROTO_UDP;
import static android.system.OsConstants.SOCK_RAW;
import static com.android.internal.util.BitUtils.bytesToBEInt;
import static com.android.internal.util.BitUtils.getUint16;
import static com.android.internal.util.BitUtils.getUint32;
@@ -34,7 +45,7 @@ import android.net.LinkProperties;
import android.net.NetworkUtils;
import android.net.apf.ApfGenerator.IllegalInstructionException;
import android.net.apf.ApfGenerator.Register;
import android.net.ip.IpClient;
import android.net.ip.IpClientCallbacks;
import android.net.metrics.ApfProgramEvent;
import android.net.metrics.ApfStats;
import android.net.metrics.IpConnectivityLog;
@@ -48,10 +59,14 @@ import android.system.PacketSocketAddress;
import android.text.format.DateUtils;
import android.util.Log;
import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
import libcore.io.IoBridge;
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.Inet4Address;
@@ -63,7 +78,6 @@ import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import libcore.io.IoBridge;
/**
* For networks that support packet filtering via APF programs, {@code ApfFilter}
@@ -308,7 +322,7 @@ public class ApfFilter {
private static final int APF_MAX_ETH_TYPE_BLACK_LIST_LEN = 20;
private final ApfCapabilities mApfCapabilities;
private final IpClient.Callback mIpClientCallback;
private final IpClientCallbacks mIpClientCallback;
private final InterfaceParams mInterfaceParams;
private final IpConnectivityLog mMetricsLog;
@@ -349,7 +363,7 @@ public class ApfFilter {
@VisibleForTesting
ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams,
IpClient.Callback ipClientCallback, IpConnectivityLog log) {
IpClientCallbacks ipClientCallback, IpConnectivityLog log) {
mApfCapabilities = config.apfCapabilities;
mIpClientCallback = ipClientCallback;
mInterfaceParams = ifParams;
@@ -1390,7 +1404,7 @@ public class ApfFilter {
* filtering using APF programs.
*/
public static ApfFilter maybeCreate(Context context, ApfConfiguration config,
InterfaceParams ifParams, IpClient.Callback ipClientCallback) {
InterfaceParams ifParams, IpClientCallbacks ipClientCallback) {
if (context == null || config == null || ifParams == null) return null;
ApfCapabilities apfCapabilities = config.apfCapabilities;
if (apfCapabilities == null) return null;

View File

@@ -16,19 +16,19 @@
package android.net.ip;
import com.android.internal.util.HexDump;
import com.android.internal.util.MessageUtils;
import com.android.internal.util.WakeupMessage;
import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable;
import android.content.Context;
import android.net.DhcpResults;
import android.net.INetd;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties.ProvisioningChange;
import android.net.LinkProperties;
import android.net.LinkProperties.ProvisioningChange;
import android.net.Network;
import android.net.ProvisioningConfigurationParcelable;
import android.net.ProxyInfo;
import android.net.ProxyInfoParcelable;
import android.net.RouteInfo;
import android.net.StaticIpConfiguration;
import android.net.apf.ApfCapabilities;
@@ -36,10 +36,10 @@ import android.net.apf.ApfFilter;
import android.net.dhcp.DhcpClient;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.IpManagerEvent;
import android.net.shared.InitialConfiguration;
import android.net.util.InterfaceParams;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.NetdService;
import android.net.util.NetworkConstants;
import android.net.util.SharedLog;
import android.os.ConditionVariable;
import android.os.INetworkManagementService;
@@ -52,29 +52,24 @@ import android.util.LocalLog;
import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.IState;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.MessageUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.internal.util.WakeupMessage;
import com.android.server.net.NetlinkTracker;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.function.Predicate;
@@ -134,83 +129,17 @@ public class IpClient extends StateMachine {
}
/**
* Callbacks for handling IpClient events.
*
* These methods are called by IpClient on its own thread. Implementations
* of this class MUST NOT carry out long-running computations or hold locks
* for which there might be contention with other code calling public
* methods of the same IpClient instance.
* TODO: remove after migrating clients to use IpClientCallbacks directly
* @see IpClientCallbacks
*/
public static class Callback {
// In order to receive onPreDhcpAction(), call #withPreDhcpAction()
// when constructing a ProvisioningConfiguration.
//
// Implementations of onPreDhcpAction() must call
// IpClient#completedPreDhcpAction() to indicate that DHCP is clear
// to proceed.
public void onPreDhcpAction() {}
public void onPostDhcpAction() {}
public static class Callback extends IpClientCallbacks {}
// This is purely advisory and not an indication of provisioning
// success or failure. This is only here for callers that want to
// expose DHCPv4 results to other APIs (e.g., WifiInfo#setInetAddress).
// DHCPv4 or static IPv4 configuration failure or success can be
// determined by whether or not the passed-in DhcpResults object is
// null or not.
public void onNewDhcpResults(DhcpResults dhcpResults) {}
public void onProvisioningSuccess(LinkProperties newLp) {}
public void onProvisioningFailure(LinkProperties newLp) {}
// Invoked on LinkProperties changes.
public void onLinkPropertiesChange(LinkProperties newLp) {}
// Called when the internal IpReachabilityMonitor (if enabled) has
// detected the loss of a critical number of required neighbors.
public void onReachabilityLost(String logMsg) {}
// Called when the IpClient state machine terminates.
public void onQuit() {}
// Install an APF program to filter incoming packets.
public void installPacketFilter(byte[] filter) {}
// Asynchronously read back the APF program & data buffer from the wifi driver.
// Due to Wifi HAL limitations, the current implementation only supports dumping the entire
// buffer. In response to this request, the driver returns the data buffer asynchronously
// by sending an IpClient#EVENT_READ_PACKET_FILTER_COMPLETE message.
public void startReadPacketFilter() {}
// If multicast filtering cannot be accomplished with APF, this function will be called to
// actuate multicast filtering using another means.
public void setFallbackMulticastFilter(boolean enabled) {}
// Enabled/disable Neighbor Discover offload functionality. This is
// called, for example, whenever 464xlat is being started or stopped.
public void setNeighborDiscoveryOffload(boolean enable) {}
}
public static class WaitForProvisioningCallback extends Callback {
private final ConditionVariable mCV = new ConditionVariable();
private LinkProperties mCallbackLinkProperties;
public LinkProperties waitForProvisioning() {
mCV.block();
return mCallbackLinkProperties;
}
@Override
public void onProvisioningSuccess(LinkProperties newLp) {
mCallbackLinkProperties = newLp;
mCV.open();
}
@Override
public void onProvisioningFailure(LinkProperties newLp) {
mCallbackLinkProperties = null;
mCV.open();
}
}
/**
* TODO: remove once clients are migrated to IpClientUtil.WaitForProvisioningCallback
* @see IpClientUtil.WaitForProvisioningCallbacks
*/
public static class WaitForProvisioningCallback
extends IpClientUtil.WaitForProvisioningCallbacks {}
// Use a wrapper class to log in order to ensure complete and detailed
// logging. This method is lighter weight than annotations/reflection
@@ -232,12 +161,12 @@ public class IpClient extends StateMachine {
// once passed on to the callback they may be modified by another thread.
//
// TODO: Find an lighter weight approach.
private class LoggingCallbackWrapper extends Callback {
private class LoggingCallbackWrapper extends IpClientCallbacks {
private static final String PREFIX = "INVOKE ";
private final Callback mCallback;
private final IpClientCallbacks mCallback;
public LoggingCallbackWrapper(Callback callback) {
mCallback = (callback != null) ? callback : new Callback();
LoggingCallbackWrapper(IpClientCallbacks callback) {
mCallback = (callback != null) ? callback : new IpClientCallbacks();
}
private void log(String msg) {
@@ -307,288 +236,102 @@ public class IpClient extends StateMachine {
}
/**
* This class encapsulates parameters to be passed to
* IpClient#startProvisioning(). A defensive copy is made by IpClient
* and the values specified herein are in force until IpClient#stop()
* is called.
*
* Example use:
*
* final ProvisioningConfiguration config =
* mIpClient.buildProvisioningConfiguration()
* .withPreDhcpAction()
* .withProvisioningTimeoutMs(36 * 1000)
* .build();
* mIpClient.startProvisioning(config);
* ...
* mIpClient.stop();
*
* The specified provisioning configuration will only be active until
* IpClient#stop() is called. Future calls to IpClient#startProvisioning()
* must specify the configuration again.
* TODO: remove after migrating clients to use the shared configuration class directly.
* @see android.net.shared.ProvisioningConfiguration
*/
public static class ProvisioningConfiguration {
// TODO: Delete this default timeout once those callers that care are
// fixed to pass in their preferred timeout.
//
// We pick 36 seconds so we can send DHCP requests at
//
// t=0, t=2, t=6, t=14, t=30
//
// allowing for 10% jitter.
private static final int DEFAULT_TIMEOUT_MS = 36 * 1000;
public static class Builder {
private ProvisioningConfiguration mConfig = new ProvisioningConfiguration();
public Builder withoutIPv4() {
mConfig.mEnableIPv4 = false;
return this;
}
public Builder withoutIPv6() {
mConfig.mEnableIPv6 = false;
return this;
}
public Builder withoutMultinetworkPolicyTracker() {
mConfig.mUsingMultinetworkPolicyTracker = false;
return this;
}
public Builder withoutIpReachabilityMonitor() {
mConfig.mUsingIpReachabilityMonitor = false;
return this;
}
public Builder withPreDhcpAction() {
mConfig.mRequestedPreDhcpActionMs = DEFAULT_TIMEOUT_MS;
return this;
}
public Builder withPreDhcpAction(int dhcpActionTimeoutMs) {
mConfig.mRequestedPreDhcpActionMs = dhcpActionTimeoutMs;
return this;
}
public Builder withInitialConfiguration(InitialConfiguration initialConfig) {
mConfig.mInitialConfig = initialConfig;
return this;
}
public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
mConfig.mStaticIpConfig = staticConfig;
return this;
}
public Builder withApfCapabilities(ApfCapabilities apfCapabilities) {
mConfig.mApfCapabilities = apfCapabilities;
return this;
}
public Builder withProvisioningTimeoutMs(int timeoutMs) {
mConfig.mProvisioningTimeoutMs = timeoutMs;
return this;
}
public Builder withRandomMacAddress() {
mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_EUI64;
return this;
}
public Builder withStableMacAddress() {
mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
return this;
}
public Builder withNetwork(Network network) {
mConfig.mNetwork = network;
return this;
}
public Builder withDisplayName(String displayName) {
mConfig.mDisplayName = displayName;
return this;
}
public ProvisioningConfiguration build() {
return new ProvisioningConfiguration(mConfig);
}
}
/* package */ boolean mEnableIPv4 = true;
/* package */ boolean mEnableIPv6 = true;
/* package */ boolean mUsingMultinetworkPolicyTracker = true;
/* package */ boolean mUsingIpReachabilityMonitor = true;
/* package */ int mRequestedPreDhcpActionMs;
/* package */ InitialConfiguration mInitialConfig;
/* package */ StaticIpConfiguration mStaticIpConfig;
/* package */ ApfCapabilities mApfCapabilities;
/* package */ int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
/* package */ int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
/* package */ Network mNetwork = null;
/* package */ String mDisplayName = null;
public ProvisioningConfiguration() {} // used by Builder
public ProvisioningConfiguration(ProvisioningConfiguration other) {
mEnableIPv4 = other.mEnableIPv4;
mEnableIPv6 = other.mEnableIPv6;
mUsingMultinetworkPolicyTracker = other.mUsingMultinetworkPolicyTracker;
mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs;
mInitialConfig = InitialConfiguration.copy(other.mInitialConfig);
mStaticIpConfig = other.mStaticIpConfig;
mApfCapabilities = other.mApfCapabilities;
mProvisioningTimeoutMs = other.mProvisioningTimeoutMs;
mIPv6AddrGenMode = other.mIPv6AddrGenMode;
mNetwork = other.mNetwork;
mDisplayName = other.mDisplayName;
}
@Override
public String toString() {
return new StringJoiner(", ", getClass().getSimpleName() + "{", "}")
.add("mEnableIPv4: " + mEnableIPv4)
.add("mEnableIPv6: " + mEnableIPv6)
.add("mUsingMultinetworkPolicyTracker: " + mUsingMultinetworkPolicyTracker)
.add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor)
.add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs)
.add("mInitialConfig: " + mInitialConfig)
.add("mStaticIpConfig: " + mStaticIpConfig)
.add("mApfCapabilities: " + mApfCapabilities)
.add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs)
.add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
.add("mNetwork: " + mNetwork)
.add("mDisplayName: " + mDisplayName)
.toString();
}
public boolean isValid() {
return (mInitialConfig == null) || mInitialConfig.isValid();
}
}
public static class InitialConfiguration {
public final Set<LinkAddress> ipAddresses = new HashSet<>();
public final Set<IpPrefix> directlyConnectedRoutes = new HashSet<>();
public final Set<InetAddress> dnsServers = new HashSet<>();
public Inet4Address gateway; // WiFi legacy behavior with static ipv4 config
public static InitialConfiguration copy(InitialConfiguration config) {
if (config == null) {
return null;
}
InitialConfiguration configCopy = new InitialConfiguration();
configCopy.ipAddresses.addAll(config.ipAddresses);
configCopy.directlyConnectedRoutes.addAll(config.directlyConnectedRoutes);
configCopy.dnsServers.addAll(config.dnsServers);
return configCopy;
}
@Override
public String toString() {
return String.format(
"InitialConfiguration(IPs: {%s}, prefixes: {%s}, DNS: {%s}, v4 gateway: %s)",
join(", ", ipAddresses), join(", ", directlyConnectedRoutes),
join(", ", dnsServers), gateway);
}
public boolean isValid() {
if (ipAddresses.isEmpty()) {
return false;
}
// For every IP address, there must be at least one prefix containing that address.
for (LinkAddress addr : ipAddresses) {
if (!any(directlyConnectedRoutes, (p) -> p.contains(addr.getAddress()))) {
return false;
}
}
// For every dns server, there must be at least one prefix containing that address.
for (InetAddress addr : dnsServers) {
if (!any(directlyConnectedRoutes, (p) -> p.contains(addr))) {
return false;
}
}
// All IPv6 LinkAddresses have an RFC7421-suitable prefix length
// (read: compliant with RFC4291#section2.5.4).
if (any(ipAddresses, not(InitialConfiguration::isPrefixLengthCompliant))) {
return false;
}
// If directlyConnectedRoutes contains an IPv6 default route
// then ipAddresses MUST contain at least one non-ULA GUA.
if (any(directlyConnectedRoutes, InitialConfiguration::isIPv6DefaultRoute)
&& all(ipAddresses, not(InitialConfiguration::isIPv6GUA))) {
return false;
}
// The prefix length of routes in directlyConnectedRoutes be within reasonable
// bounds for IPv6: /48-/64 just as wed accept in RIOs.
if (any(directlyConnectedRoutes, not(InitialConfiguration::isPrefixLengthCompliant))) {
return false;
}
// There no more than one IPv4 address
if (ipAddresses.stream().filter(LinkAddress::isIPv4).count() > 1) {
return false;
}
return true;
public static class ProvisioningConfiguration
extends android.net.shared.ProvisioningConfiguration {
public ProvisioningConfiguration(android.net.shared.ProvisioningConfiguration other) {
super(other);
}
/**
* @return true if the given list of addressess and routes satisfies provisioning for this
* InitialConfiguration. LinkAddresses and RouteInfo objects are not compared with equality
* because addresses and routes seen by Netlink will contain additional fields like flags,
* interfaces, and so on. If this InitialConfiguration has no IP address specified, the
* provisioning check always fails.
*
* If the given list of routes is null, only addresses are taken into considerations.
* @see android.net.shared.ProvisioningConfiguration.Builder
*/
public boolean isProvisionedBy(List<LinkAddress> addresses, List<RouteInfo> routes) {
if (ipAddresses.isEmpty()) {
return false;
public static class Builder extends android.net.shared.ProvisioningConfiguration.Builder {
// Override all methods to have a return type matching this Builder
@Override
public Builder withoutIPv4() {
super.withoutIPv4();
return this;
}
for (LinkAddress addr : ipAddresses) {
if (!any(addresses, (addrSeen) -> addr.isSameAddressAs(addrSeen))) {
return false;
}
@Override
public Builder withoutIPv6() {
super.withoutIPv6();
return this;
}
if (routes != null) {
for (IpPrefix prefix : directlyConnectedRoutes) {
if (!any(routes, (routeSeen) -> isDirectlyConnectedRoute(routeSeen, prefix))) {
return false;
}
}
@Override
public Builder withoutMultinetworkPolicyTracker() {
super.withoutMultinetworkPolicyTracker();
return this;
}
return true;
}
@Override
public Builder withoutIpReachabilityMonitor() {
super.withoutIpReachabilityMonitor();
return this;
}
private static boolean isDirectlyConnectedRoute(RouteInfo route, IpPrefix prefix) {
return !route.hasGateway() && prefix.equals(route.getDestination());
}
@Override
public Builder withPreDhcpAction() {
super.withPreDhcpAction();
return this;
}
private static boolean isPrefixLengthCompliant(LinkAddress addr) {
return addr.isIPv4() || isCompliantIPv6PrefixLength(addr.getPrefixLength());
}
@Override
public Builder withPreDhcpAction(int dhcpActionTimeoutMs) {
super.withPreDhcpAction(dhcpActionTimeoutMs);
return this;
}
private static boolean isPrefixLengthCompliant(IpPrefix prefix) {
return prefix.isIPv4() || isCompliantIPv6PrefixLength(prefix.getPrefixLength());
}
@Override
public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
super.withStaticConfiguration(staticConfig);
return this;
}
private static boolean isCompliantIPv6PrefixLength(int prefixLength) {
return (NetworkConstants.RFC6177_MIN_PREFIX_LENGTH <= prefixLength)
&& (prefixLength <= NetworkConstants.RFC7421_PREFIX_LENGTH);
}
@Override
public Builder withApfCapabilities(ApfCapabilities apfCapabilities) {
super.withApfCapabilities(apfCapabilities);
return this;
}
private static boolean isIPv6DefaultRoute(IpPrefix prefix) {
return prefix.getAddress().equals(Inet6Address.ANY);
}
@Override
public Builder withProvisioningTimeoutMs(int timeoutMs) {
super.withProvisioningTimeoutMs(timeoutMs);
return this;
}
private static boolean isIPv6GUA(LinkAddress addr) {
return addr.isIPv6() && addr.isGlobalPreferred();
@Override
public Builder withRandomMacAddress() {
super.withRandomMacAddress();
return this;
}
@Override
public Builder withStableMacAddress() {
super.withStableMacAddress();
return this;
}
@Override
public Builder withNetwork(Network network) {
super.withNetwork(network);
return this;
}
@Override
public Builder withDisplayName(String displayName) {
super.withDisplayName(displayName);
return this;
}
@Override
public ProvisioningConfiguration build() {
return new ProvisioningConfiguration(mConfig);
}
}
}
@@ -638,7 +381,7 @@ public class IpClient extends StateMachine {
private final String mInterfaceName;
private final String mClatInterfaceName;
@VisibleForTesting
protected final Callback mCallback;
protected final IpClientCallbacks mCallback;
private final Dependencies mDependencies;
private final CountDownLatch mShutdownLatch;
private final INetworkManagementService mNwService;
@@ -657,7 +400,7 @@ public class IpClient extends StateMachine {
* Non-final member variables accessed only from within our StateMachine.
*/
private LinkProperties mLinkProperties;
private ProvisioningConfiguration mConfiguration;
private android.net.shared.ProvisioningConfiguration mConfiguration;
private MultinetworkPolicyTracker mMultinetworkPolicyTracker;
private IpReachabilityMonitor mIpReachabilityMonitor;
private DhcpClient mDhcpClient;
@@ -691,7 +434,7 @@ public class IpClient extends StateMachine {
}
}
public IpClient(Context context, String ifName, Callback callback) {
public IpClient(Context context, String ifName, IpClientCallbacks callback) {
this(context, ifName, callback, new Dependencies());
}
@@ -699,7 +442,7 @@ public class IpClient extends StateMachine {
* An expanded constructor, useful for dependency injection.
* TODO: migrate all test users to mock IpClient directly and remove this ctor.
*/
public IpClient(Context context, String ifName, Callback callback,
public IpClient(Context context, String ifName, IpClientCallbacks callback,
INetworkManagementService nwService) {
this(context, ifName, callback, new Dependencies() {
@Override
@@ -708,7 +451,7 @@ public class IpClient extends StateMachine {
}
@VisibleForTesting
IpClient(Context context, String ifName, Callback callback, Dependencies deps) {
IpClient(Context context, String ifName, IpClientCallbacks callback, Dependencies deps) {
super(IpClient.class.getSimpleName() + "." + ifName);
Preconditions.checkNotNull(ifName);
Preconditions.checkNotNull(callback);
@@ -795,6 +538,57 @@ public class IpClient extends StateMachine {
startStateMachineUpdaters();
}
/**
* Make a IIpClient connector to communicate with this IpClient.
*/
public IIpClient makeConnector() {
return new IpClientConnector();
}
class IpClientConnector extends IIpClient.Stub {
@Override
public void completedPreDhcpAction() {
IpClient.this.completedPreDhcpAction();
}
@Override
public void confirmConfiguration() {
IpClient.this.confirmConfiguration();
}
@Override
public void readPacketFilterComplete(byte[] data) {
IpClient.this.readPacketFilterComplete(data);
}
@Override
public void shutdown() {
IpClient.this.shutdown();
}
@Override
public void startProvisioning(ProvisioningConfigurationParcelable req) {
IpClient.this.startProvisioning(
android.net.shared.ProvisioningConfiguration.fromStableParcelable(req));
}
@Override
public void stop() {
IpClient.this.stop();
}
@Override
public void setTcpBufferSizes(String tcpBufferSizes) {
IpClient.this.setTcpBufferSizes(tcpBufferSizes);
}
@Override
public void setHttpProxy(ProxyInfoParcelable proxyInfo) {
IpClient.this.setHttpProxy(fromStableParcelable(proxyInfo));
}
@Override
public void setMulticastFilter(boolean enabled) {
IpClient.this.setMulticastFilter(enabled);
}
// TODO: remove and have IpClient logs dumped in NetworkStack dumpsys
public void dumpIpClientLogs(FileDescriptor fd, PrintWriter pw, String[] args) {
IpClient.this.dump(fd, pw, args);
}
}
private void configureAndStartStateMachine() {
addState(mStoppedState);
addState(mStartedState);
@@ -828,7 +622,9 @@ public class IpClient extends StateMachine {
mShutdownLatch.countDown();
}
// Shut down this IpClient instance altogether.
/**
* Shut down this IpClient instance altogether.
*/
public void shutdown() {
stop();
sendMessage(CMD_TERMINATE_AFTER_STOP);
@@ -849,7 +645,10 @@ public class IpClient extends StateMachine {
return new ProvisioningConfiguration.Builder();
}
public void startProvisioning(ProvisioningConfiguration req) {
/**
* Start provisioning with the provided parameters.
*/
public void startProvisioning(android.net.shared.ProvisioningConfiguration req) {
if (!req.isValid()) {
doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
return;
@@ -863,7 +662,7 @@ public class IpClient extends StateMachine {
}
mCallback.setNeighborDiscoveryOffload(true);
sendMessage(CMD_START, new ProvisioningConfiguration(req));
sendMessage(CMD_START, new android.net.shared.ProvisioningConfiguration(req));
}
// TODO: Delete this.
@@ -874,7 +673,7 @@ public class IpClient extends StateMachine {
}
public void startProvisioning() {
startProvisioning(new ProvisioningConfiguration());
startProvisioning(new android.net.shared.ProvisioningConfiguration());
}
public void stop() {
@@ -930,7 +729,7 @@ public class IpClient extends StateMachine {
// Thread-unsafe access to mApfFilter but just used for debugging.
final ApfFilter apfFilter = mApfFilter;
final ProvisioningConfiguration provisioningConfig = mConfiguration;
final android.net.shared.ProvisioningConfiguration provisioningConfig = mConfiguration;
final ApfCapabilities apfCapabilities = (provisioningConfig != null)
? provisioningConfig.mApfCapabilities : null;
@@ -1463,7 +1262,7 @@ public class IpClient extends StateMachine {
break;
case CMD_START:
mConfiguration = (ProvisioningConfiguration) msg.obj;
mConfiguration = (android.net.shared.ProvisioningConfiguration) msg.obj;
transitionTo(mStartedState);
break;

View File

@@ -0,0 +1,92 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net.ip;
import android.content.Context;
import android.net.LinkProperties;
import android.os.ConditionVariable;
import java.io.FileDescriptor;
import java.io.PrintWriter;
/**
* Utilities and wrappers to simplify communication with IpClient, which lives in the NetworkStack
* process.
*
* @hide
*/
public class IpClientUtil {
// TODO: remove once IpClient dumps are moved to NetworkStack and callers don't need this arg
public static final String DUMP_ARG = IpClient.DUMP_ARG;
/**
* Subclass of {@link IpClientCallbacks} allowing clients to block until provisioning is
* complete with {@link WaitForProvisioningCallbacks#waitForProvisioning()}.
*/
public static class WaitForProvisioningCallbacks extends IpClientCallbacks {
private final ConditionVariable mCV = new ConditionVariable();
private LinkProperties mCallbackLinkProperties;
/**
* Block until either {@link #onProvisioningSuccess(LinkProperties)} or
* {@link #onProvisioningFailure(LinkProperties)} is called.
*/
public LinkProperties waitForProvisioning() {
mCV.block();
return mCallbackLinkProperties;
}
@Override
public void onProvisioningSuccess(LinkProperties newLp) {
mCallbackLinkProperties = newLp;
mCV.open();
}
@Override
public void onProvisioningFailure(LinkProperties newLp) {
mCallbackLinkProperties = null;
mCV.open();
}
}
/**
* Create a new IpClient.
*
* <p>This is a convenience method to allow clients to use {@link IpClientCallbacks} instead of
* {@link IIpClientCallbacks}.
*/
public static void makeIpClient(Context context, String ifName, IpClientCallbacks callback) {
// TODO: request IpClient asynchronously from NetworkStack.
final IpClient ipClient = new IpClient(context, ifName, callback);
callback.onIpClientCreated(ipClient.makeConnector());
}
/**
* Dump logs for the specified IpClient.
* TODO: remove logging from this method once IpClient logs are dumped in NetworkStack dumpsys,
* then remove callers and delete.
*/
public static void dumpIpClient(
IIpClient connector, FileDescriptor fd, PrintWriter pw, String[] args) {
if (!(connector instanceof IpClient.IpClientConnector)) {
pw.println("Invalid connector");
return;
}
((IpClient.IpClientConnector) connector).dumpIpClientLogs(fd, pw, args);
}
}

View File

@@ -1,124 +0,0 @@
/*
* Copyright (C) 2017 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.ip;
import android.content.Context;
import android.net.INetd;
import android.net.LinkProperties;
import android.net.Network;
import android.net.StaticIpConfiguration;
import android.net.apf.ApfCapabilities;
import android.net.util.NetdService;
import android.os.INetworkManagementService;
import android.os.ServiceManager;
import android.net.apf.ApfCapabilities;
import com.android.internal.annotations.VisibleForTesting;
/*
* TODO: Delete this altogether in favor of its renamed successor: IpClient.
*
* @hide
*/
public class IpManager extends IpClient {
public static class ProvisioningConfiguration extends IpClient.ProvisioningConfiguration {
public ProvisioningConfiguration(IpClient.ProvisioningConfiguration ipcConfig) {
super(ipcConfig);
}
public static class Builder extends IpClient.ProvisioningConfiguration.Builder {
@Override
public Builder withoutIPv4() {
super.withoutIPv4();
return this;
}
@Override
public Builder withoutIPv6() {
super.withoutIPv6();
return this;
}
@Override
public Builder withoutIpReachabilityMonitor() {
super.withoutIpReachabilityMonitor();
return this;
}
@Override
public Builder withPreDhcpAction() {
super.withPreDhcpAction();
return this;
}
@Override
public Builder withPreDhcpAction(int dhcpActionTimeoutMs) {
super.withPreDhcpAction(dhcpActionTimeoutMs);
return this;
}
// No Override; locally defined type.
public Builder withInitialConfiguration(InitialConfiguration initialConfig) {
super.withInitialConfiguration((IpClient.InitialConfiguration) initialConfig);
return this;
}
@Override
public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
super.withStaticConfiguration(staticConfig);
return this;
}
@Override
public Builder withApfCapabilities(ApfCapabilities apfCapabilities) {
super.withApfCapabilities(apfCapabilities);
return this;
}
@Override
public Builder withProvisioningTimeoutMs(int timeoutMs) {
super.withProvisioningTimeoutMs(timeoutMs);
return this;
}
@Override
public Builder withNetwork(Network network) {
super.withNetwork(network);
return this;
}
@Override
public Builder withDisplayName(String displayName) {
super.withDisplayName(displayName);
return this;
}
@Override
public ProvisioningConfiguration build() {
return new ProvisioningConfiguration(super.build());
}
}
}
public static ProvisioningConfiguration.Builder buildProvisioningConfiguration() {
return new ProvisioningConfiguration.Builder();
}
public static class InitialConfiguration extends IpClient.InitialConfiguration {
}
public static class Callback extends IpClient.Callback {
}
public IpManager(Context context, String ifName, Callback callback) {
super(context, ifName, callback);
}
public void startProvisioning(ProvisioningConfiguration req) {
super.startProvisioning((IpClient.ProvisioningConfiguration) req);
}
}

View File

@@ -22,6 +22,7 @@ import android.net.Network;
import android.net.ProvisioningConfigurationParcelable;
import android.net.StaticIpConfiguration;
import android.net.apf.ApfCapabilities;
import android.net.ip.IIpClient;
import java.util.Objects;
import java.util.StringJoiner;

View File

@@ -16,10 +16,19 @@
package android.net.apf;
import static android.net.util.NetworkConstants.*;
import static android.system.OsConstants.*;
import static android.net.util.NetworkConstants.ICMPV6_ECHO_REQUEST_TYPE;
import static android.net.util.NetworkConstants.ICMPV6_ROUTER_ADVERTISEMENT;
import static android.system.OsConstants.AF_UNIX;
import static android.system.OsConstants.ARPHRD_ETHER;
import static android.system.OsConstants.ETH_P_ARP;
import static android.system.OsConstants.ETH_P_IP;
import static android.system.OsConstants.ETH_P_IPV6;
import static android.system.OsConstants.IPPROTO_ICMPV6;
import static android.system.OsConstants.IPPROTO_UDP;
import static android.system.OsConstants.SOCK_STREAM;
import static com.android.internal.util.BitUtils.bytesToBEInt;
import static com.android.internal.util.BitUtils.put;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -33,7 +42,7 @@ import android.net.LinkProperties;
import android.net.apf.ApfFilter.ApfConfiguration;
import android.net.apf.ApfGenerator.IllegalInstructionException;
import android.net.apf.ApfGenerator.Register;
import android.net.ip.IpClient;
import android.net.ip.IpClientCallbacks;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.RaEvent;
import android.net.util.InterfaceParams;
@@ -47,8 +56,20 @@ import android.system.ErrnoException;
import android.system.Os;
import android.text.format.DateUtils;
import android.util.Log;
import com.android.frameworks.tests.net.R;
import com.android.internal.util.HexDump;
import libcore.io.IoUtils;
import libcore.io.Streams;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
@@ -59,14 +80,6 @@ import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Random;
import libcore.io.IoUtils;
import libcore.io.Streams;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
* Tests for APF program generator and interpreter.
@@ -902,7 +915,7 @@ public class ApfTest {
HexDump.toHexString(data, false), result);
}
private class MockIpClientCallback extends IpClient.Callback {
private class MockIpClientCallback extends IpClientCallbacks {
private final ConditionVariable mGotApfProgram = new ConditionVariable();
private byte[] mLastApfProgram;
@@ -933,7 +946,7 @@ public class ApfTest {
private final long mFixedTimeMs = SystemClock.elapsedRealtime();
public TestApfFilter(Context context, ApfConfiguration config,
IpClient.Callback ipClientCallback, IpConnectivityLog log) throws Exception {
IpClientCallbacks ipClientCallback, IpConnectivityLog log) throws Exception {
super(context, config, InterfaceParams.getByName("lo"), ipClientCallback, log);
}
@@ -1062,7 +1075,7 @@ public class ApfTest {
private static final byte[] IPV4_ANY_HOST_ADDR = {0, 0, 0, 0};
// Helper to initialize a default apfFilter.
private ApfFilter setupApfFilter(IpClient.Callback ipClientCallback, ApfConfiguration config)
private ApfFilter setupApfFilter(IpClientCallbacks ipClientCallback, ApfConfiguration config)
throws Exception {
LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
LinkProperties lp = new LinkProperties();

View File

@@ -23,7 +23,6 @@ import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.timeout;
@@ -40,9 +39,8 @@ import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.MacAddress;
import android.net.RouteInfo;
import android.net.ip.IpClient.Callback;
import android.net.ip.IpClient.InitialConfiguration;
import android.net.ip.IpClient.ProvisioningConfiguration;
import android.net.shared.InitialConfiguration;
import android.net.shared.ProvisioningConfiguration;
import android.net.util.InterfaceParams;
import android.os.INetworkManagementService;
import android.provider.Settings;
@@ -50,8 +48,8 @@ import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.test.mock.MockContentResolver;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.R;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.net.BaseNetworkObserver;
import org.junit.Before;
@@ -63,8 +61,8 @@ import org.mockito.MockitoAnnotations;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.List;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
@@ -87,7 +85,7 @@ public class IpClientTest {
@Mock private INetworkManagementService mNMService;
@Mock private INetd mNetd;
@Mock private Resources mResources;
@Mock private Callback mCb;
@Mock private IpClientCallbacks mCb;
@Mock private AlarmManager mAlarm;
@Mock private IpClient.Dependencies mDependecies;
private MockContentResolver mContentResolver;
@@ -179,7 +177,7 @@ public class IpClientTest {
public void testInterfaceNotFoundFailsImmediately() throws Exception {
setTestInterfaceParams(null);
final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mDependecies);
ipc.startProvisioning(new IpClient.ProvisioningConfiguration());
ipc.startProvisioning(new ProvisioningConfiguration());
verify(mCb, times(1)).onProvisioningFailure(any());
ipc.shutdown();
}