• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.ip;
18 
19 import static android.net.RouteInfo.RTN_UNICAST;
20 import static android.net.shared.IpConfigurationParcelableUtil.toStableParcelable;
21 
22 import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission;
23 
24 import android.annotation.NonNull;
25 import android.content.Context;
26 import android.net.ConnectivityManager;
27 import android.net.DhcpResults;
28 import android.net.INetd;
29 import android.net.IpPrefix;
30 import android.net.LinkAddress;
31 import android.net.LinkProperties;
32 import android.net.NattKeepalivePacketDataParcelable;
33 import android.net.NetworkStackIpMemoryStore;
34 import android.net.ProvisioningConfigurationParcelable;
35 import android.net.ProxyInfo;
36 import android.net.RouteInfo;
37 import android.net.TcpKeepalivePacketDataParcelable;
38 import android.net.apf.ApfCapabilities;
39 import android.net.apf.ApfFilter;
40 import android.net.dhcp.DhcpClient;
41 import android.net.metrics.IpConnectivityLog;
42 import android.net.metrics.IpManagerEvent;
43 import android.net.shared.InitialConfiguration;
44 import android.net.shared.ProvisioningConfiguration;
45 import android.net.util.InterfaceParams;
46 import android.net.util.SharedLog;
47 import android.os.ConditionVariable;
48 import android.os.IBinder;
49 import android.os.Message;
50 import android.os.RemoteException;
51 import android.os.SystemClock;
52 import android.text.TextUtils;
53 import android.util.LocalLog;
54 import android.util.Log;
55 import android.util.Pair;
56 import android.util.SparseArray;
57 
58 import com.android.internal.annotations.VisibleForTesting;
59 import com.android.internal.util.IState;
60 import com.android.internal.util.IndentingPrintWriter;
61 import com.android.internal.util.MessageUtils;
62 import com.android.internal.util.Preconditions;
63 import com.android.internal.util.State;
64 import com.android.internal.util.StateMachine;
65 import com.android.internal.util.WakeupMessage;
66 import com.android.server.NetworkObserverRegistry;
67 import com.android.server.NetworkStackService.NetworkStackServiceManager;
68 
69 import java.io.FileDescriptor;
70 import java.io.PrintWriter;
71 import java.net.InetAddress;
72 import java.util.Collection;
73 import java.util.List;
74 import java.util.Objects;
75 import java.util.Set;
76 import java.util.concurrent.ConcurrentHashMap;
77 import java.util.concurrent.CountDownLatch;
78 import java.util.function.Predicate;
79 import java.util.stream.Collectors;
80 
81 
82 /**
83  * IpClient
84  *
85  * This class provides the interface to IP-layer provisioning and maintenance
86  * functionality that can be used by transport layers like Wi-Fi, Ethernet,
87  * et cetera.
88  *
89  * [ Lifetime ]
90  * IpClient is designed to be instantiated as soon as the interface name is
91  * known and can be as long-lived as the class containing it (i.e. declaring
92  * it "private final" is okay).
93  *
94  * @hide
95  */
96 public class IpClient extends StateMachine {
97     private static final boolean DBG = false;
98 
99     // For message logging.
100     private static final Class[] sMessageClasses = { IpClient.class, DhcpClient.class };
101     private static final SparseArray<String> sWhatToString =
102             MessageUtils.findMessageNames(sMessageClasses);
103     // Two static concurrent hashmaps of interface name to logging classes.
104     // One holds StateMachine logs and the other connectivity packet logs.
105     private static final ConcurrentHashMap<String, SharedLog> sSmLogs = new ConcurrentHashMap<>();
106     private static final ConcurrentHashMap<String, LocalLog> sPktLogs = new ConcurrentHashMap<>();
107     private final NetworkStackIpMemoryStore mIpMemoryStore;
108 
109     /**
110      * Dump all state machine and connectivity packet logs to the specified writer.
111      * @param skippedIfaces Interfaces for which logs should not be dumped.
112      */
dumpAllLogs(PrintWriter writer, Set<String> skippedIfaces)113     public static void dumpAllLogs(PrintWriter writer, Set<String> skippedIfaces) {
114         for (String ifname : sSmLogs.keySet()) {
115             if (skippedIfaces.contains(ifname)) continue;
116 
117             writer.println(String.format("--- BEGIN %s ---", ifname));
118 
119             final SharedLog smLog = sSmLogs.get(ifname);
120             if (smLog != null) {
121                 writer.println("State machine log:");
122                 smLog.dump(null, writer, null);
123             }
124 
125             writer.println("");
126 
127             final LocalLog pktLog = sPktLogs.get(ifname);
128             if (pktLog != null) {
129                 writer.println("Connectivity packet log:");
130                 pktLog.readOnlyLocalLog().dump(null, writer, null);
131             }
132 
133             writer.println(String.format("--- END %s ---", ifname));
134         }
135     }
136 
137     // Use a wrapper class to log in order to ensure complete and detailed
138     // logging. This method is lighter weight than annotations/reflection
139     // and has the following benefits:
140     //
141     //     - No invoked method can be forgotten.
142     //       Any new method added to IpClient.Callback must be overridden
143     //       here or it will never be called.
144     //
145     //     - No invoking call site can be forgotten.
146     //       Centralized logging in this way means call sites don't need to
147     //       remember to log, and therefore no call site can be forgotten.
148     //
149     //     - No variation in log format among call sites.
150     //       Encourages logging of any available arguments, and all call sites
151     //       are necessarily logged identically.
152     //
153     // NOTE: Log first because passed objects may or may not be thread-safe and
154     // once passed on to the callback they may be modified by another thread.
155     //
156     // TODO: Find an lighter weight approach.
157     public static class IpClientCallbacksWrapper {
158         private static final String PREFIX = "INVOKE ";
159         private final IIpClientCallbacks mCallback;
160         private final SharedLog mLog;
161 
162         @VisibleForTesting
IpClientCallbacksWrapper(IIpClientCallbacks callback, SharedLog log)163         protected IpClientCallbacksWrapper(IIpClientCallbacks callback, SharedLog log) {
164             mCallback = callback;
165             mLog = log;
166         }
167 
log(String msg)168         private void log(String msg) {
169             mLog.log(PREFIX + msg);
170         }
171 
log(String msg, Throwable e)172         private void log(String msg, Throwable e) {
173             mLog.e(PREFIX + msg, e);
174         }
175 
onPreDhcpAction()176         public void onPreDhcpAction() {
177             log("onPreDhcpAction()");
178             try {
179                 mCallback.onPreDhcpAction();
180             } catch (RemoteException e) {
181                 log("Failed to call onPreDhcpAction", e);
182             }
183         }
184 
onPostDhcpAction()185         public void onPostDhcpAction() {
186             log("onPostDhcpAction()");
187             try {
188                 mCallback.onPostDhcpAction();
189             } catch (RemoteException e) {
190                 log("Failed to call onPostDhcpAction", e);
191             }
192         }
193 
onNewDhcpResults(DhcpResults dhcpResults)194         public void onNewDhcpResults(DhcpResults dhcpResults) {
195             log("onNewDhcpResults({" + dhcpResults + "})");
196             try {
197                 mCallback.onNewDhcpResults(toStableParcelable(dhcpResults));
198             } catch (RemoteException e) {
199                 log("Failed to call onNewDhcpResults", e);
200             }
201         }
202 
onProvisioningSuccess(LinkProperties newLp)203         public void onProvisioningSuccess(LinkProperties newLp) {
204             log("onProvisioningSuccess({" + newLp + "})");
205             try {
206                 mCallback.onProvisioningSuccess(newLp);
207             } catch (RemoteException e) {
208                 log("Failed to call onProvisioningSuccess", e);
209             }
210         }
211 
onProvisioningFailure(LinkProperties newLp)212         public void onProvisioningFailure(LinkProperties newLp) {
213             log("onProvisioningFailure({" + newLp + "})");
214             try {
215                 mCallback.onProvisioningFailure(newLp);
216             } catch (RemoteException e) {
217                 log("Failed to call onProvisioningFailure", e);
218             }
219         }
220 
onLinkPropertiesChange(LinkProperties newLp)221         public void onLinkPropertiesChange(LinkProperties newLp) {
222             log("onLinkPropertiesChange({" + newLp + "})");
223             try {
224                 mCallback.onLinkPropertiesChange(newLp);
225             } catch (RemoteException e) {
226                 log("Failed to call onLinkPropertiesChange", e);
227             }
228         }
229 
onReachabilityLost(String logMsg)230         public void onReachabilityLost(String logMsg) {
231             log("onReachabilityLost(" + logMsg + ")");
232             try {
233                 mCallback.onReachabilityLost(logMsg);
234             } catch (RemoteException e) {
235                 log("Failed to call onReachabilityLost", e);
236             }
237         }
238 
onQuit()239         public void onQuit() {
240             log("onQuit()");
241             try {
242                 mCallback.onQuit();
243             } catch (RemoteException e) {
244                 log("Failed to call onQuit", e);
245             }
246         }
247 
installPacketFilter(byte[] filter)248         public void installPacketFilter(byte[] filter) {
249             log("installPacketFilter(byte[" + filter.length + "])");
250             try {
251                 mCallback.installPacketFilter(filter);
252             } catch (RemoteException e) {
253                 log("Failed to call installPacketFilter", e);
254             }
255         }
256 
startReadPacketFilter()257         public void startReadPacketFilter() {
258             log("startReadPacketFilter()");
259             try {
260                 mCallback.startReadPacketFilter();
261             } catch (RemoteException e) {
262                 log("Failed to call startReadPacketFilter", e);
263             }
264         }
265 
setFallbackMulticastFilter(boolean enabled)266         public void setFallbackMulticastFilter(boolean enabled) {
267             log("setFallbackMulticastFilter(" + enabled + ")");
268             try {
269                 mCallback.setFallbackMulticastFilter(enabled);
270             } catch (RemoteException e) {
271                 log("Failed to call setFallbackMulticastFilter", e);
272             }
273         }
274 
setNeighborDiscoveryOffload(boolean enable)275         public void setNeighborDiscoveryOffload(boolean enable) {
276             log("setNeighborDiscoveryOffload(" + enable + ")");
277             try {
278                 mCallback.setNeighborDiscoveryOffload(enable);
279             } catch (RemoteException e) {
280                 log("Failed to call setNeighborDiscoveryOffload", e);
281             }
282         }
283     }
284 
285     public static final String DUMP_ARG_CONFIRM = "confirm";
286 
287     // Below constants are picked up by MessageUtils and exempt from ProGuard optimization.
288     private static final int CMD_TERMINATE_AFTER_STOP             = 1;
289     private static final int CMD_STOP                             = 2;
290     private static final int CMD_START                            = 3;
291     private static final int CMD_CONFIRM                          = 4;
292     private static final int EVENT_PRE_DHCP_ACTION_COMPLETE       = 5;
293     // Triggered by NetlinkTracker to communicate netlink events.
294     private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 6;
295     private static final int CMD_UPDATE_TCP_BUFFER_SIZES          = 7;
296     private static final int CMD_UPDATE_HTTP_PROXY                = 8;
297     private static final int CMD_SET_MULTICAST_FILTER             = 9;
298     private static final int EVENT_PROVISIONING_TIMEOUT           = 10;
299     private static final int EVENT_DHCPACTION_TIMEOUT             = 11;
300     private static final int EVENT_READ_PACKET_FILTER_COMPLETE    = 12;
301     private static final int CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF = 13;
302     private static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF = 14;
303     private static final int CMD_UPDATE_L2KEY_GROUPHINT = 15;
304 
305     // Internal commands to use instead of trying to call transitionTo() inside
306     // a given State's enter() method. Calling transitionTo() from enter/exit
307     // encounters a Log.wtf() that can cause trouble on eng builds.
308     private static final int CMD_JUMP_STARTED_TO_RUNNING          = 100;
309     private static final int CMD_JUMP_RUNNING_TO_STOPPING         = 101;
310     private static final int CMD_JUMP_STOPPING_TO_STOPPED         = 102;
311 
312     // IpClient shares a handler with DhcpClient: commands must not overlap
313     public static final int DHCPCLIENT_CMD_BASE = 1000;
314 
315     private static final int MAX_LOG_RECORDS = 500;
316     private static final int MAX_PACKET_RECORDS = 100;
317 
318     private static final boolean NO_CALLBACKS = false;
319     private static final boolean SEND_CALLBACKS = true;
320 
321     // This must match the interface prefix in clatd.c.
322     // TODO: Revert this hack once IpClient and Nat464Xlat work in concert.
323     private static final String CLAT_PREFIX = "v4-";
324 
325     private static final int IMMEDIATE_FAILURE_DURATION = 0;
326 
327     private static final int PROV_CHANGE_STILL_NOT_PROVISIONED = 1;
328     private static final int PROV_CHANGE_LOST_PROVISIONING = 2;
329     private static final int PROV_CHANGE_GAINED_PROVISIONING = 3;
330     private static final int PROV_CHANGE_STILL_PROVISIONED = 4;
331 
332     private final State mStoppedState = new StoppedState();
333     private final State mStoppingState = new StoppingState();
334     private final State mStartedState = new StartedState();
335     private final State mRunningState = new RunningState();
336 
337     private final String mTag;
338     private final Context mContext;
339     private final String mInterfaceName;
340     private final String mClatInterfaceName;
341     @VisibleForTesting
342     protected final IpClientCallbacksWrapper mCallback;
343     private final Dependencies mDependencies;
344     private final CountDownLatch mShutdownLatch;
345     private final ConnectivityManager mCm;
346     private final INetd mNetd;
347     private final NetworkObserverRegistry mObserverRegistry;
348     private final IpClientLinkObserver mLinkObserver;
349     private final WakeupMessage mProvisioningTimeoutAlarm;
350     private final WakeupMessage mDhcpActionTimeoutAlarm;
351     private final SharedLog mLog;
352     private final LocalLog mConnectivityPacketLog;
353     private final MessageHandlingLogger mMsgStateLogger;
354     private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
355     private final InterfaceController mInterfaceCtrl;
356 
357     private InterfaceParams mInterfaceParams;
358 
359     /**
360      * Non-final member variables accessed only from within our StateMachine.
361      */
362     private LinkProperties mLinkProperties;
363     private android.net.shared.ProvisioningConfiguration mConfiguration;
364     private IpReachabilityMonitor mIpReachabilityMonitor;
365     private DhcpClient mDhcpClient;
366     private DhcpResults mDhcpResults;
367     private String mTcpBufferSizes;
368     private ProxyInfo mHttpProxy;
369     private ApfFilter mApfFilter;
370     private String mL2Key; // The L2 key for this network, for writing into the memory store
371     private String mGroupHint; // The group hint for this network, for writing into the memory store
372     private boolean mMulticastFiltering;
373     private long mStartTimeMillis;
374 
375     /**
376      * Reading the snapshot is an asynchronous operation initiated by invoking
377      * Callback.startReadPacketFilter() and completed when the WiFi Service responds with an
378      * EVENT_READ_PACKET_FILTER_COMPLETE message. The mApfDataSnapshotComplete condition variable
379      * signals when a new snapshot is ready.
380      */
381     private final ConditionVariable mApfDataSnapshotComplete = new ConditionVariable();
382 
383     public static class Dependencies {
384         /**
385          * Get interface parameters for the specified interface.
386          */
getInterfaceParams(String ifname)387         public InterfaceParams getInterfaceParams(String ifname) {
388             return InterfaceParams.getByName(ifname);
389         }
390 
391         /**
392          * Get a INetd connector.
393          */
getNetd(Context context)394         public INetd getNetd(Context context) {
395             return INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE));
396         }
397     }
398 
IpClient(Context context, String ifName, IIpClientCallbacks callback, NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager)399     public IpClient(Context context, String ifName, IIpClientCallbacks callback,
400             NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager) {
401         this(context, ifName, callback, observerRegistry, nssManager, new Dependencies());
402     }
403 
404     @VisibleForTesting
IpClient(Context context, String ifName, IIpClientCallbacks callback, NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager, Dependencies deps)405     IpClient(Context context, String ifName, IIpClientCallbacks callback,
406             NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager,
407             Dependencies deps) {
408         super(IpClient.class.getSimpleName() + "." + ifName);
409         Preconditions.checkNotNull(ifName);
410         Preconditions.checkNotNull(callback);
411 
412         mTag = getName();
413 
414         mContext = context;
415         mInterfaceName = ifName;
416         mClatInterfaceName = CLAT_PREFIX + ifName;
417         mDependencies = deps;
418         mShutdownLatch = new CountDownLatch(1);
419         mCm = mContext.getSystemService(ConnectivityManager.class);
420         mObserverRegistry = observerRegistry;
421         mIpMemoryStore =
422                 new NetworkStackIpMemoryStore(context, nssManager.getIpMemoryStoreService());
423 
424         sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag));
425         mLog = sSmLogs.get(mInterfaceName);
426         sPktLogs.putIfAbsent(mInterfaceName, new LocalLog(MAX_PACKET_RECORDS));
427         mConnectivityPacketLog = sPktLogs.get(mInterfaceName);
428         mMsgStateLogger = new MessageHandlingLogger();
429         mCallback = new IpClientCallbacksWrapper(callback, mLog);
430 
431         // TODO: Consider creating, constructing, and passing in some kind of
432         // InterfaceController.Dependencies class.
433         mNetd = deps.getNetd(mContext);
434         mInterfaceCtrl = new InterfaceController(mInterfaceName, mNetd, mLog);
435 
436         mLinkObserver = new IpClientLinkObserver(
437                 mInterfaceName,
438                 () -> sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED)) {
439             @Override
440             public void onInterfaceAdded(String iface) {
441                 super.onInterfaceAdded(iface);
442                 if (mClatInterfaceName.equals(iface)) {
443                     mCallback.setNeighborDiscoveryOffload(false);
444                 } else if (!mInterfaceName.equals(iface)) {
445                     return;
446                 }
447 
448                 final String msg = "interfaceAdded(" + iface + ")";
449                 logMsg(msg);
450             }
451 
452             @Override
453             public void onInterfaceRemoved(String iface) {
454                 super.onInterfaceRemoved(iface);
455                 // TODO: Also observe mInterfaceName going down and take some
456                 // kind of appropriate action.
457                 if (mClatInterfaceName.equals(iface)) {
458                     // TODO: consider sending a message to the IpClient main
459                     // StateMachine thread, in case "NDO enabled" state becomes
460                     // tied to more things that 464xlat operation.
461                     mCallback.setNeighborDiscoveryOffload(true);
462                 } else if (!mInterfaceName.equals(iface)) {
463                     return;
464                 }
465 
466                 final String msg = "interfaceRemoved(" + iface + ")";
467                 logMsg(msg);
468             }
469 
470             private void logMsg(String msg) {
471                 Log.d(mTag, msg);
472                 getHandler().post(() -> mLog.log("OBSERVED " + msg));
473             }
474         };
475 
476         mLinkProperties = new LinkProperties();
477         mLinkProperties.setInterfaceName(mInterfaceName);
478 
479         mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
480                 mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT);
481         mDhcpActionTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
482                 mTag + ".EVENT_DHCPACTION_TIMEOUT", EVENT_DHCPACTION_TIMEOUT);
483 
484         // Anything the StateMachine may access must have been instantiated
485         // before this point.
486         configureAndStartStateMachine();
487 
488         // Anything that may send messages to the StateMachine must only be
489         // configured to do so after the StateMachine has started (above).
490         startStateMachineUpdaters();
491     }
492 
493     /**
494      * Make a IIpClient connector to communicate with this IpClient.
495      */
makeConnector()496     public IIpClient makeConnector() {
497         return new IpClientConnector();
498     }
499 
500     class IpClientConnector extends IIpClient.Stub {
501         @Override
completedPreDhcpAction()502         public void completedPreDhcpAction() {
503             checkNetworkStackCallingPermission();
504             IpClient.this.completedPreDhcpAction();
505         }
506         @Override
confirmConfiguration()507         public void confirmConfiguration() {
508             checkNetworkStackCallingPermission();
509             IpClient.this.confirmConfiguration();
510         }
511         @Override
readPacketFilterComplete(byte[] data)512         public void readPacketFilterComplete(byte[] data) {
513             checkNetworkStackCallingPermission();
514             IpClient.this.readPacketFilterComplete(data);
515         }
516         @Override
shutdown()517         public void shutdown() {
518             checkNetworkStackCallingPermission();
519             IpClient.this.shutdown();
520         }
521         @Override
startProvisioning(ProvisioningConfigurationParcelable req)522         public void startProvisioning(ProvisioningConfigurationParcelable req) {
523             checkNetworkStackCallingPermission();
524             IpClient.this.startProvisioning(ProvisioningConfiguration.fromStableParcelable(req));
525         }
526         @Override
stop()527         public void stop() {
528             checkNetworkStackCallingPermission();
529             IpClient.this.stop();
530         }
531         @Override
setL2KeyAndGroupHint(String l2Key, String groupHint)532         public void setL2KeyAndGroupHint(String l2Key, String groupHint) {
533             checkNetworkStackCallingPermission();
534             IpClient.this.setL2KeyAndGroupHint(l2Key, groupHint);
535         }
536         @Override
setTcpBufferSizes(String tcpBufferSizes)537         public void setTcpBufferSizes(String tcpBufferSizes) {
538             checkNetworkStackCallingPermission();
539             IpClient.this.setTcpBufferSizes(tcpBufferSizes);
540         }
541         @Override
setHttpProxy(ProxyInfo proxyInfo)542         public void setHttpProxy(ProxyInfo proxyInfo) {
543             checkNetworkStackCallingPermission();
544             IpClient.this.setHttpProxy(proxyInfo);
545         }
546         @Override
setMulticastFilter(boolean enabled)547         public void setMulticastFilter(boolean enabled) {
548             checkNetworkStackCallingPermission();
549             IpClient.this.setMulticastFilter(enabled);
550         }
551         @Override
addKeepalivePacketFilter(int slot, TcpKeepalivePacketDataParcelable pkt)552         public void addKeepalivePacketFilter(int slot, TcpKeepalivePacketDataParcelable pkt) {
553             checkNetworkStackCallingPermission();
554             IpClient.this.addKeepalivePacketFilter(slot, pkt);
555         }
556         @Override
addNattKeepalivePacketFilter(int slot, NattKeepalivePacketDataParcelable pkt)557         public void addNattKeepalivePacketFilter(int slot, NattKeepalivePacketDataParcelable pkt) {
558             checkNetworkStackCallingPermission();
559             IpClient.this.addNattKeepalivePacketFilter(slot, pkt);
560         }
561         @Override
removeKeepalivePacketFilter(int slot)562         public void removeKeepalivePacketFilter(int slot) {
563             checkNetworkStackCallingPermission();
564             IpClient.this.removeKeepalivePacketFilter(slot);
565         }
566 
567         @Override
getInterfaceVersion()568         public int getInterfaceVersion() {
569             return this.VERSION;
570         }
571     }
572 
getInterfaceName()573     public String getInterfaceName() {
574         return mInterfaceName;
575     }
576 
configureAndStartStateMachine()577     private void configureAndStartStateMachine() {
578         // CHECKSTYLE:OFF IndentationCheck
579         addState(mStoppedState);
580         addState(mStartedState);
581             addState(mRunningState, mStartedState);
582         addState(mStoppingState);
583         // CHECKSTYLE:ON IndentationCheck
584 
585         setInitialState(mStoppedState);
586 
587         super.start();
588     }
589 
startStateMachineUpdaters()590     private void startStateMachineUpdaters() {
591         mObserverRegistry.registerObserverForNonblockingCallback(mLinkObserver);
592     }
593 
stopStateMachineUpdaters()594     private void stopStateMachineUpdaters() {
595         mObserverRegistry.unregisterObserver(mLinkObserver);
596     }
597 
598     @Override
onQuitting()599     protected void onQuitting() {
600         mCallback.onQuit();
601         mShutdownLatch.countDown();
602     }
603 
604     /**
605      * Shut down this IpClient instance altogether.
606      */
shutdown()607     public void shutdown() {
608         stop();
609         sendMessage(CMD_TERMINATE_AFTER_STOP);
610     }
611 
612     /**
613      * Start provisioning with the provided parameters.
614      */
startProvisioning(ProvisioningConfiguration req)615     public void startProvisioning(ProvisioningConfiguration req) {
616         if (!req.isValid()) {
617             doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
618             return;
619         }
620 
621         mInterfaceParams = mDependencies.getInterfaceParams(mInterfaceName);
622         if (mInterfaceParams == null) {
623             logError("Failed to find InterfaceParams for " + mInterfaceName);
624             doImmediateProvisioningFailure(IpManagerEvent.ERROR_INTERFACE_NOT_FOUND);
625             return;
626         }
627 
628         mCallback.setNeighborDiscoveryOffload(true);
629         sendMessage(CMD_START, new android.net.shared.ProvisioningConfiguration(req));
630     }
631 
632     /**
633      * Stop this IpClient.
634      *
635      * <p>This does not shut down the StateMachine itself, which is handled by {@link #shutdown()}.
636      */
stop()637     public void stop() {
638         sendMessage(CMD_STOP);
639     }
640 
641     /**
642      * Confirm the provisioning configuration.
643      */
confirmConfiguration()644     public void confirmConfiguration() {
645         sendMessage(CMD_CONFIRM);
646     }
647 
648     /**
649      * For clients using {@link ProvisioningConfiguration.Builder#withPreDhcpAction()}, must be
650      * called after {@link IIpClientCallbacks#onPreDhcpAction} to indicate that DHCP is clear to
651      * proceed.
652      */
completedPreDhcpAction()653     public void completedPreDhcpAction() {
654         sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
655     }
656 
657     /**
658      * Indicate that packet filter read is complete.
659      */
readPacketFilterComplete(byte[] data)660     public void readPacketFilterComplete(byte[] data) {
661         sendMessage(EVENT_READ_PACKET_FILTER_COMPLETE, data);
662     }
663 
664     /**
665      * Set the TCP buffer sizes to use.
666      *
667      * This may be called, repeatedly, at any time before or after a call to
668      * #startProvisioning(). The setting is cleared upon calling #stop().
669      */
setTcpBufferSizes(String tcpBufferSizes)670     public void setTcpBufferSizes(String tcpBufferSizes) {
671         sendMessage(CMD_UPDATE_TCP_BUFFER_SIZES, tcpBufferSizes);
672     }
673 
674     /**
675      * Set the L2 key and group hint for storing info into the memory store.
676      */
setL2KeyAndGroupHint(String l2Key, String groupHint)677     public void setL2KeyAndGroupHint(String l2Key, String groupHint) {
678         sendMessage(CMD_UPDATE_L2KEY_GROUPHINT, new Pair<>(l2Key, groupHint));
679     }
680 
681     /**
682      * Set the HTTP Proxy configuration to use.
683      *
684      * This may be called, repeatedly, at any time before or after a call to
685      * #startProvisioning(). The setting is cleared upon calling #stop().
686      */
setHttpProxy(ProxyInfo proxyInfo)687     public void setHttpProxy(ProxyInfo proxyInfo) {
688         sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo);
689     }
690 
691     /**
692      * Enable or disable the multicast filter.  Attempts to use APF to accomplish the filtering,
693      * if not, Callback.setFallbackMulticastFilter() is called.
694      */
setMulticastFilter(boolean enabled)695     public void setMulticastFilter(boolean enabled) {
696         sendMessage(CMD_SET_MULTICAST_FILTER, enabled);
697     }
698 
699     /**
700      * Called by WifiStateMachine to add TCP keepalive packet filter before setting up
701      * keepalive offload.
702      */
addKeepalivePacketFilter(int slot, @NonNull TcpKeepalivePacketDataParcelable pkt)703     public void addKeepalivePacketFilter(int slot, @NonNull TcpKeepalivePacketDataParcelable pkt) {
704         sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0 /* Unused */, pkt);
705     }
706 
707     /**
708      *  Called by WifiStateMachine to add NATT keepalive packet filter before setting up
709      *  keepalive offload.
710      */
addNattKeepalivePacketFilter(int slot, @NonNull NattKeepalivePacketDataParcelable pkt)711     public void addNattKeepalivePacketFilter(int slot,
712             @NonNull NattKeepalivePacketDataParcelable pkt) {
713         sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0 /* Unused */ , pkt);
714     }
715 
716     /**
717      * Called by WifiStateMachine to remove keepalive packet filter after stopping keepalive
718      * offload.
719      */
removeKeepalivePacketFilter(int slot)720     public void removeKeepalivePacketFilter(int slot) {
721         sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF, slot, 0 /* Unused */);
722     }
723 
724     /**
725      * Dump logs of this IpClient.
726      */
dump(FileDescriptor fd, PrintWriter writer, String[] args)727     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
728         if (args != null && args.length > 0 && DUMP_ARG_CONFIRM.equals(args[0])) {
729             // Execute confirmConfiguration() and take no further action.
730             confirmConfiguration();
731             return;
732         }
733 
734         // Thread-unsafe access to mApfFilter but just used for debugging.
735         final ApfFilter apfFilter = mApfFilter;
736         final android.net.shared.ProvisioningConfiguration provisioningConfig = mConfiguration;
737         final ApfCapabilities apfCapabilities = (provisioningConfig != null)
738                 ? provisioningConfig.mApfCapabilities : null;
739 
740         IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
741         pw.println(mTag + " APF dump:");
742         pw.increaseIndent();
743         if (apfFilter != null) {
744             if (apfCapabilities.hasDataAccess()) {
745                 // Request a new snapshot, then wait for it.
746                 mApfDataSnapshotComplete.close();
747                 mCallback.startReadPacketFilter();
748                 if (!mApfDataSnapshotComplete.block(1000)) {
749                     pw.print("TIMEOUT: DUMPING STALE APF SNAPSHOT");
750                 }
751             }
752             apfFilter.dump(pw);
753 
754         } else {
755             pw.print("No active ApfFilter; ");
756             if (provisioningConfig == null) {
757                 pw.println("IpClient not yet started.");
758             } else if (apfCapabilities == null || apfCapabilities.apfVersionSupported == 0) {
759                 pw.println("Hardware does not support APF.");
760             } else {
761                 pw.println("ApfFilter not yet started, APF capabilities: " + apfCapabilities);
762             }
763         }
764         pw.decreaseIndent();
765         pw.println();
766         pw.println(mTag + " current ProvisioningConfiguration:");
767         pw.increaseIndent();
768         pw.println(Objects.toString(provisioningConfig, "N/A"));
769         pw.decreaseIndent();
770 
771         final IpReachabilityMonitor iprm = mIpReachabilityMonitor;
772         if (iprm != null) {
773             pw.println();
774             pw.println(mTag + " current IpReachabilityMonitor state:");
775             pw.increaseIndent();
776             iprm.dump(pw);
777             pw.decreaseIndent();
778         }
779 
780         pw.println();
781         pw.println(mTag + " StateMachine dump:");
782         pw.increaseIndent();
783         mLog.dump(fd, pw, args);
784         pw.decreaseIndent();
785 
786         pw.println();
787         pw.println(mTag + " connectivity packet log:");
788         pw.println();
789         pw.println("Debug with python and scapy via:");
790         pw.println("shell$ python");
791         pw.println(">>> from scapy import all as scapy");
792         pw.println(">>> scapy.Ether(\"<paste_hex_string>\".decode(\"hex\")).show2()");
793         pw.println();
794 
795         pw.increaseIndent();
796         mConnectivityPacketLog.readOnlyLocalLog().dump(fd, pw, args);
797         pw.decreaseIndent();
798     }
799 
800 
801     /**
802      * Internals.
803      */
804 
805     @Override
getWhatToString(int what)806     protected String getWhatToString(int what) {
807         return sWhatToString.get(what, "UNKNOWN: " + Integer.toString(what));
808     }
809 
810     @Override
getLogRecString(Message msg)811     protected String getLogRecString(Message msg) {
812         final String logLine = String.format(
813                 "%s/%d %d %d %s [%s]",
814                 mInterfaceName, (mInterfaceParams == null) ? -1 : mInterfaceParams.index,
815                 msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger);
816 
817         final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
818         mLog.log(richerLogLine);
819         if (DBG) {
820             Log.d(mTag, richerLogLine);
821         }
822 
823         mMsgStateLogger.reset();
824         return logLine;
825     }
826 
827     @Override
recordLogRec(Message msg)828     protected boolean recordLogRec(Message msg) {
829         // Don't log EVENT_NETLINK_LINKPROPERTIES_CHANGED. They can be noisy,
830         // and we already log any LinkProperties change that results in an
831         // invocation of IpClient.Callback#onLinkPropertiesChange().
832         final boolean shouldLog = (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
833         if (!shouldLog) {
834             mMsgStateLogger.reset();
835         }
836         return shouldLog;
837     }
838 
logError(String fmt, Object... args)839     private void logError(String fmt, Object... args) {
840         final String msg = "ERROR " + String.format(fmt, args);
841         Log.e(mTag, msg);
842         mLog.log(msg);
843     }
844 
845     // This needs to be called with care to ensure that our LinkProperties
846     // are in sync with the actual LinkProperties of the interface. For example,
847     // we should only call this if we know for sure that there are no IP addresses
848     // assigned to the interface, etc.
resetLinkProperties()849     private void resetLinkProperties() {
850         mLinkObserver.clearLinkProperties();
851         mConfiguration = null;
852         mDhcpResults = null;
853         mTcpBufferSizes = "";
854         mHttpProxy = null;
855 
856         mLinkProperties = new LinkProperties();
857         mLinkProperties.setInterfaceName(mInterfaceName);
858     }
859 
recordMetric(final int type)860     private void recordMetric(final int type) {
861         // We may record error metrics prior to starting.
862         // Map this to IMMEDIATE_FAILURE_DURATION.
863         final long duration = (mStartTimeMillis > 0)
864                 ? (SystemClock.elapsedRealtime() - mStartTimeMillis)
865                 : IMMEDIATE_FAILURE_DURATION;
866         mMetricsLog.log(mInterfaceName, new IpManagerEvent(type, duration));
867     }
868 
869     // For now: use WifiStateMachine's historical notion of provisioned.
870     @VisibleForTesting
isProvisioned(LinkProperties lp, InitialConfiguration config)871     static boolean isProvisioned(LinkProperties lp, InitialConfiguration config) {
872         // For historical reasons, we should connect even if all we have is
873         // an IPv4 address and nothing else.
874         if (lp.hasIpv4Address() || lp.isProvisioned()) {
875             return true;
876         }
877         if (config == null) {
878             return false;
879         }
880 
881         // When an InitialConfiguration is specified, ignore any difference with previous
882         // properties and instead check if properties observed match the desired properties.
883         return config.isProvisionedBy(lp.getLinkAddresses(), lp.getRoutes());
884     }
885 
886     // TODO: Investigate folding all this into the existing static function
887     // LinkProperties.compareProvisioning() or some other single function that
888     // takes two LinkProperties objects and returns a ProvisioningChange
889     // object that is a correct and complete assessment of what changed, taking
890     // account of the asymmetries described in the comments in this function.
891     // Then switch to using it everywhere (IpReachabilityMonitor, etc.).
compareProvisioning(LinkProperties oldLp, LinkProperties newLp)892     private int compareProvisioning(LinkProperties oldLp, LinkProperties newLp) {
893         int delta;
894         InitialConfiguration config = mConfiguration != null ? mConfiguration.mInitialConfig : null;
895         final boolean wasProvisioned = isProvisioned(oldLp, config);
896         final boolean isProvisioned = isProvisioned(newLp, config);
897 
898         if (!wasProvisioned && isProvisioned) {
899             delta = PROV_CHANGE_GAINED_PROVISIONING;
900         } else if (wasProvisioned && isProvisioned) {
901             delta = PROV_CHANGE_STILL_PROVISIONED;
902         } else if (!wasProvisioned && !isProvisioned) {
903             delta = PROV_CHANGE_STILL_NOT_PROVISIONED;
904         } else {
905             // (wasProvisioned && !isProvisioned)
906             //
907             // Note that this is true even if we lose a configuration element
908             // (e.g., a default gateway) that would not be required to advance
909             // into provisioned state. This is intended: if we have a default
910             // router and we lose it, that's a sure sign of a problem, but if
911             // we connect to a network with no IPv4 DNS servers, we consider
912             // that to be a network without DNS servers and connect anyway.
913             //
914             // See the comment below.
915             delta = PROV_CHANGE_LOST_PROVISIONING;
916         }
917 
918         final boolean lostIPv6 = oldLp.isIpv6Provisioned() && !newLp.isIpv6Provisioned();
919         final boolean lostIPv4Address = oldLp.hasIpv4Address() && !newLp.hasIpv4Address();
920         final boolean lostIPv6Router = oldLp.hasIpv6DefaultRoute() && !newLp.hasIpv6DefaultRoute();
921 
922         // If bad wifi avoidance is disabled, then ignore IPv6 loss of
923         // provisioning. Otherwise, when a hotspot that loses Internet
924         // access sends out a 0-lifetime RA to its clients, the clients
925         // will disconnect and then reconnect, avoiding the bad hotspot,
926         // instead of getting stuck on the bad hotspot. http://b/31827713 .
927         //
928         // This is incorrect because if the hotspot then regains Internet
929         // access with a different prefix, TCP connections on the
930         // deprecated addresses will remain stuck.
931         //
932         // Note that we can still be disconnected by IpReachabilityMonitor
933         // if the IPv6 default gateway (but not the IPv6 DNS servers; see
934         // accompanying code in IpReachabilityMonitor) is unreachable.
935         final boolean ignoreIPv6ProvisioningLoss =
936                 mConfiguration != null && mConfiguration.mUsingMultinetworkPolicyTracker
937                 && mCm.shouldAvoidBadWifi();
938 
939         // Additionally:
940         //
941         // Partial configurations (e.g., only an IPv4 address with no DNS
942         // servers and no default route) are accepted as long as DHCPv4
943         // succeeds. On such a network, isProvisioned() will always return
944         // false, because the configuration is not complete, but we want to
945         // connect anyway. It might be a disconnected network such as a
946         // Chromecast or a wireless printer, for example.
947         //
948         // Because on such a network isProvisioned() will always return false,
949         // delta will never be LOST_PROVISIONING. So check for loss of
950         // provisioning here too.
951         if (lostIPv4Address || (lostIPv6 && !ignoreIPv6ProvisioningLoss)) {
952             delta = PROV_CHANGE_LOST_PROVISIONING;
953         }
954 
955         // Additionally:
956         //
957         // If the previous link properties had a global IPv6 address and an
958         // IPv6 default route then also consider the loss of that default route
959         // to be a loss of provisioning. See b/27962810.
960         if (oldLp.hasGlobalIpv6Address() && (lostIPv6Router && !ignoreIPv6ProvisioningLoss)) {
961             delta = PROV_CHANGE_LOST_PROVISIONING;
962         }
963 
964         return delta;
965     }
966 
dispatchCallback(int delta, LinkProperties newLp)967     private void dispatchCallback(int delta, LinkProperties newLp) {
968         switch (delta) {
969             case PROV_CHANGE_GAINED_PROVISIONING:
970                 if (DBG) {
971                     Log.d(mTag, "onProvisioningSuccess()");
972                 }
973                 recordMetric(IpManagerEvent.PROVISIONING_OK);
974                 mCallback.onProvisioningSuccess(newLp);
975                 break;
976 
977             case PROV_CHANGE_LOST_PROVISIONING:
978                 if (DBG) {
979                     Log.d(mTag, "onProvisioningFailure()");
980                 }
981                 recordMetric(IpManagerEvent.PROVISIONING_FAIL);
982                 mCallback.onProvisioningFailure(newLp);
983                 break;
984 
985             default:
986                 if (DBG) {
987                     Log.d(mTag, "onLinkPropertiesChange()");
988                 }
989                 mCallback.onLinkPropertiesChange(newLp);
990                 break;
991         }
992     }
993 
994     // Updates all IpClient-related state concerned with LinkProperties.
995     // Returns a ProvisioningChange for possibly notifying other interested
996     // parties that are not fronted by IpClient.
setLinkProperties(LinkProperties newLp)997     private int setLinkProperties(LinkProperties newLp) {
998         if (mApfFilter != null) {
999             mApfFilter.setLinkProperties(newLp);
1000         }
1001         if (mIpReachabilityMonitor != null) {
1002             mIpReachabilityMonitor.updateLinkProperties(newLp);
1003         }
1004 
1005         int delta = compareProvisioning(mLinkProperties, newLp);
1006         mLinkProperties = new LinkProperties(newLp);
1007 
1008         if (delta == PROV_CHANGE_GAINED_PROVISIONING) {
1009             // TODO: Add a proper ProvisionedState and cancel the alarm in
1010             // its enter() method.
1011             mProvisioningTimeoutAlarm.cancel();
1012         }
1013 
1014         return delta;
1015     }
1016 
assembleLinkProperties()1017     private LinkProperties assembleLinkProperties() {
1018         // [1] Create a new LinkProperties object to populate.
1019         LinkProperties newLp = new LinkProperties();
1020         newLp.setInterfaceName(mInterfaceName);
1021 
1022         // [2] Pull in data from netlink:
1023         //         - IPv4 addresses
1024         //         - IPv6 addresses
1025         //         - IPv6 routes
1026         //         - IPv6 DNS servers
1027         //
1028         // N.B.: this is fundamentally race-prone and should be fixed by
1029         // changing IpClientLinkObserver from a hybrid edge/level model to an
1030         // edge-only model, or by giving IpClient its own netlink socket(s)
1031         // so as to track all required information directly.
1032         LinkProperties netlinkLinkProperties = mLinkObserver.getLinkProperties();
1033         newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
1034         for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
1035             newLp.addRoute(route);
1036         }
1037         addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers());
1038 
1039         // [3] Add in data from DHCPv4, if available.
1040         //
1041         // mDhcpResults is never shared with any other owner so we don't have
1042         // to worry about concurrent modification.
1043         if (mDhcpResults != null) {
1044             final List<RouteInfo> routes =
1045                     mDhcpResults.toStaticIpConfiguration().getRoutes(mInterfaceName);
1046             for (RouteInfo route : routes) {
1047                 newLp.addRoute(route);
1048             }
1049             addAllReachableDnsServers(newLp, mDhcpResults.dnsServers);
1050             newLp.setDomains(mDhcpResults.domains);
1051 
1052             if (mDhcpResults.mtu != 0) {
1053                 newLp.setMtu(mDhcpResults.mtu);
1054             }
1055         }
1056 
1057         // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
1058         if (!TextUtils.isEmpty(mTcpBufferSizes)) {
1059             newLp.setTcpBufferSizes(mTcpBufferSizes);
1060         }
1061         if (mHttpProxy != null) {
1062             newLp.setHttpProxy(mHttpProxy);
1063         }
1064 
1065         // [5] Add data from InitialConfiguration
1066         if (mConfiguration != null && mConfiguration.mInitialConfig != null) {
1067             InitialConfiguration config = mConfiguration.mInitialConfig;
1068             // Add InitialConfiguration routes and dns server addresses once all addresses
1069             // specified in the InitialConfiguration have been observed with Netlink.
1070             if (config.isProvisionedBy(newLp.getLinkAddresses(), null)) {
1071                 for (IpPrefix prefix : config.directlyConnectedRoutes) {
1072                     newLp.addRoute(new RouteInfo(prefix, null, mInterfaceName, RTN_UNICAST));
1073                 }
1074             }
1075             addAllReachableDnsServers(newLp, config.dnsServers);
1076         }
1077         final LinkProperties oldLp = mLinkProperties;
1078         if (DBG) {
1079             Log.d(mTag, String.format("Netlink-seen LPs: %s, new LPs: %s; old LPs: %s",
1080                     netlinkLinkProperties, newLp, oldLp));
1081         }
1082 
1083         // TODO: also learn via netlink routes specified by an InitialConfiguration and specified
1084         // from a static IP v4 config instead of manually patching them in in steps [3] and [5].
1085         return newLp;
1086     }
1087 
addAllReachableDnsServers( LinkProperties lp, Iterable<InetAddress> dnses)1088     private static void addAllReachableDnsServers(
1089             LinkProperties lp, Iterable<InetAddress> dnses) {
1090         // TODO: Investigate deleting this reachability check.  We should be
1091         // able to pass everything down to netd and let netd do evaluation
1092         // and RFC6724-style sorting.
1093         for (InetAddress dns : dnses) {
1094             if (!dns.isAnyLocalAddress() && lp.isReachable(dns)) {
1095                 lp.addDnsServer(dns);
1096             }
1097         }
1098     }
1099 
1100     // Returns false if we have lost provisioning, true otherwise.
handleLinkPropertiesUpdate(boolean sendCallbacks)1101     private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) {
1102         final LinkProperties newLp = assembleLinkProperties();
1103         if (Objects.equals(newLp, mLinkProperties)) {
1104             return true;
1105         }
1106         final int delta = setLinkProperties(newLp);
1107         // Most of the attributes stored in the memory store are deduced from
1108         // the link properties, therefore when the properties update the memory
1109         // store record should be updated too.
1110         maybeSaveNetworkToIpMemoryStore();
1111         if (sendCallbacks) {
1112             dispatchCallback(delta, newLp);
1113         }
1114         return (delta != PROV_CHANGE_LOST_PROVISIONING);
1115     }
1116 
handleIPv4Success(DhcpResults dhcpResults)1117     private void handleIPv4Success(DhcpResults dhcpResults) {
1118         mDhcpResults = new DhcpResults(dhcpResults);
1119         final LinkProperties newLp = assembleLinkProperties();
1120         final int delta = setLinkProperties(newLp);
1121 
1122         if (DBG) {
1123             Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")");
1124         }
1125         mCallback.onNewDhcpResults(dhcpResults);
1126         maybeSaveNetworkToIpMemoryStore();
1127         dispatchCallback(delta, newLp);
1128     }
1129 
handleIPv4Failure()1130     private void handleIPv4Failure() {
1131         // TODO: Investigate deleting this clearIPv4Address() call.
1132         //
1133         // DhcpClient will send us CMD_CLEAR_LINKADDRESS in all circumstances
1134         // that could trigger a call to this function. If we missed handling
1135         // that message in StartedState for some reason we would still clear
1136         // any addresses upon entry to StoppedState.
1137         mInterfaceCtrl.clearIPv4Address();
1138         mDhcpResults = null;
1139         if (DBG) {
1140             Log.d(mTag, "onNewDhcpResults(null)");
1141         }
1142         mCallback.onNewDhcpResults(null);
1143 
1144         handleProvisioningFailure();
1145     }
1146 
handleProvisioningFailure()1147     private void handleProvisioningFailure() {
1148         final LinkProperties newLp = assembleLinkProperties();
1149         int delta = setLinkProperties(newLp);
1150         // If we've gotten here and we're still not provisioned treat that as
1151         // a total loss of provisioning.
1152         //
1153         // Either (a) static IP configuration failed or (b) DHCPv4 failed AND
1154         // there was no usable IPv6 obtained before a non-zero provisioning
1155         // timeout expired.
1156         //
1157         // Regardless: GAME OVER.
1158         if (delta == PROV_CHANGE_STILL_NOT_PROVISIONED) {
1159             delta = PROV_CHANGE_LOST_PROVISIONING;
1160         }
1161 
1162         dispatchCallback(delta, newLp);
1163         if (delta == PROV_CHANGE_LOST_PROVISIONING) {
1164             transitionTo(mStoppingState);
1165         }
1166     }
1167 
doImmediateProvisioningFailure(int failureType)1168     private void doImmediateProvisioningFailure(int failureType) {
1169         logError("onProvisioningFailure(): %s", failureType);
1170         recordMetric(failureType);
1171         mCallback.onProvisioningFailure(new LinkProperties(mLinkProperties));
1172     }
1173 
startIPv4()1174     private boolean startIPv4() {
1175         // If we have a StaticIpConfiguration attempt to apply it and
1176         // handle the result accordingly.
1177         if (mConfiguration.mStaticIpConfig != null) {
1178             if (mInterfaceCtrl.setIPv4Address(mConfiguration.mStaticIpConfig.getIpAddress())) {
1179                 handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
1180             } else {
1181                 return false;
1182             }
1183         } else {
1184             // Start DHCPv4.
1185             mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceParams);
1186             mDhcpClient.registerForPreDhcpNotification();
1187             mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP);
1188         }
1189 
1190         return true;
1191     }
1192 
startIPv6()1193     private boolean startIPv6() {
1194         return mInterfaceCtrl.setIPv6PrivacyExtensions(true)
1195                 && mInterfaceCtrl.setIPv6AddrGenModeIfSupported(mConfiguration.mIPv6AddrGenMode)
1196                 && mInterfaceCtrl.enableIPv6();
1197     }
1198 
applyInitialConfig(InitialConfiguration config)1199     private boolean applyInitialConfig(InitialConfiguration config) {
1200         // TODO: also support specifying a static IPv4 configuration in InitialConfiguration.
1201         for (LinkAddress addr : findAll(config.ipAddresses, LinkAddress::isIpv6)) {
1202             if (!mInterfaceCtrl.addAddress(addr)) return false;
1203         }
1204 
1205         return true;
1206     }
1207 
startIpReachabilityMonitor()1208     private boolean startIpReachabilityMonitor() {
1209         try {
1210             // TODO: Fetch these parameters from settings, and install a
1211             // settings observer to watch for update and re-program these
1212             // parameters (Q: is this level of dynamic updatability really
1213             // necessary or does reading from settings at startup suffice?).
1214             final int numSolicits = 5;
1215             final int interSolicitIntervalMs = 750;
1216             setNeighborParameters(mNetd, mInterfaceName, numSolicits, interSolicitIntervalMs);
1217         } catch (Exception e) {
1218             mLog.e("Failed to adjust neighbor parameters", e);
1219             // Carry on using the system defaults (currently: 3, 1000);
1220         }
1221 
1222         try {
1223             mIpReachabilityMonitor = new IpReachabilityMonitor(
1224                     mContext,
1225                     mInterfaceParams,
1226                     getHandler(),
1227                     mLog,
1228                     new IpReachabilityMonitor.Callback() {
1229                         @Override
1230                         public void notifyLost(InetAddress ip, String logMsg) {
1231                             mCallback.onReachabilityLost(logMsg);
1232                         }
1233                     },
1234                     mConfiguration.mUsingMultinetworkPolicyTracker);
1235         } catch (IllegalArgumentException iae) {
1236             // Failed to start IpReachabilityMonitor. Log it and call
1237             // onProvisioningFailure() immediately.
1238             //
1239             // See http://b/31038971.
1240             logError("IpReachabilityMonitor failure: %s", iae);
1241             mIpReachabilityMonitor = null;
1242         }
1243 
1244         return (mIpReachabilityMonitor != null);
1245     }
1246 
stopAllIP()1247     private void stopAllIP() {
1248         // We don't need to worry about routes, just addresses, because:
1249         //     - disableIpv6() will clear autoconf IPv6 routes as well, and
1250         //     - we don't get IPv4 routes from netlink
1251         // so we neither react to nor need to wait for changes in either.
1252 
1253         mInterfaceCtrl.disableIPv6();
1254         mInterfaceCtrl.clearAllAddresses();
1255     }
1256 
maybeSaveNetworkToIpMemoryStore()1257     private void maybeSaveNetworkToIpMemoryStore() {
1258         // TODO : implement this
1259     }
1260 
1261     class StoppedState extends State {
1262         @Override
enter()1263         public void enter() {
1264             stopAllIP();
1265 
1266             resetLinkProperties();
1267             if (mStartTimeMillis > 0) {
1268                 // Completed a life-cycle; send a final empty LinkProperties
1269                 // (cleared in resetLinkProperties() above) and record an event.
1270                 mCallback.onLinkPropertiesChange(new LinkProperties(mLinkProperties));
1271                 recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE);
1272                 mStartTimeMillis = 0;
1273             }
1274         }
1275 
1276         @Override
processMessage(Message msg)1277         public boolean processMessage(Message msg) {
1278             switch (msg.what) {
1279                 case CMD_TERMINATE_AFTER_STOP:
1280                     stopStateMachineUpdaters();
1281                     quit();
1282                     break;
1283 
1284                 case CMD_STOP:
1285                     break;
1286 
1287                 case CMD_START:
1288                     mConfiguration = (android.net.shared.ProvisioningConfiguration) msg.obj;
1289                     transitionTo(mStartedState);
1290                     break;
1291 
1292                 case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
1293                     handleLinkPropertiesUpdate(NO_CALLBACKS);
1294                     break;
1295 
1296                 case CMD_UPDATE_TCP_BUFFER_SIZES:
1297                     mTcpBufferSizes = (String) msg.obj;
1298                     handleLinkPropertiesUpdate(NO_CALLBACKS);
1299                     break;
1300 
1301                 case CMD_UPDATE_HTTP_PROXY:
1302                     mHttpProxy = (ProxyInfo) msg.obj;
1303                     handleLinkPropertiesUpdate(NO_CALLBACKS);
1304                     break;
1305 
1306                 case CMD_UPDATE_L2KEY_GROUPHINT: {
1307                     final Pair<String, String> args = (Pair<String, String>) msg.obj;
1308                     mL2Key = args.first;
1309                     mGroupHint = args.second;
1310                     break;
1311                 }
1312 
1313                 case CMD_SET_MULTICAST_FILTER:
1314                     mMulticastFiltering = (boolean) msg.obj;
1315                     break;
1316 
1317                 case DhcpClient.CMD_ON_QUIT:
1318                     // Everything is already stopped.
1319                     logError("Unexpected CMD_ON_QUIT (already stopped).");
1320                     break;
1321 
1322                 default:
1323                     return NOT_HANDLED;
1324             }
1325 
1326             mMsgStateLogger.handled(this, getCurrentState());
1327             return HANDLED;
1328         }
1329     }
1330 
1331     class StoppingState extends State {
1332         @Override
enter()1333         public void enter() {
1334             if (mDhcpClient == null) {
1335                 // There's no DHCPv4 for which to wait; proceed to stopped.
1336                 deferMessage(obtainMessage(CMD_JUMP_STOPPING_TO_STOPPED));
1337             }
1338         }
1339 
1340         @Override
processMessage(Message msg)1341         public boolean processMessage(Message msg) {
1342             switch (msg.what) {
1343                 case CMD_JUMP_STOPPING_TO_STOPPED:
1344                     transitionTo(mStoppedState);
1345                     break;
1346 
1347                 case CMD_STOP:
1348                     break;
1349 
1350                 case DhcpClient.CMD_CLEAR_LINKADDRESS:
1351                     mInterfaceCtrl.clearIPv4Address();
1352                     break;
1353 
1354                 case DhcpClient.CMD_ON_QUIT:
1355                     mDhcpClient = null;
1356                     transitionTo(mStoppedState);
1357                     break;
1358 
1359                 default:
1360                     deferMessage(msg);
1361             }
1362 
1363             mMsgStateLogger.handled(this, getCurrentState());
1364             return HANDLED;
1365         }
1366     }
1367 
1368     class StartedState extends State {
1369         @Override
enter()1370         public void enter() {
1371             mStartTimeMillis = SystemClock.elapsedRealtime();
1372 
1373             if (mConfiguration.mProvisioningTimeoutMs > 0) {
1374                 final long alarmTime = SystemClock.elapsedRealtime()
1375                         + mConfiguration.mProvisioningTimeoutMs;
1376                 mProvisioningTimeoutAlarm.schedule(alarmTime);
1377             }
1378 
1379             if (readyToProceed()) {
1380                 deferMessage(obtainMessage(CMD_JUMP_STARTED_TO_RUNNING));
1381             } else {
1382                 // Clear all IPv4 and IPv6 before proceeding to RunningState.
1383                 // Clean up any leftover state from an abnormal exit from
1384                 // tethering or during an IpClient restart.
1385                 stopAllIP();
1386             }
1387         }
1388 
1389         @Override
exit()1390         public void exit() {
1391             mProvisioningTimeoutAlarm.cancel();
1392         }
1393 
1394         @Override
processMessage(Message msg)1395         public boolean processMessage(Message msg) {
1396             switch (msg.what) {
1397                 case CMD_JUMP_STARTED_TO_RUNNING:
1398                     transitionTo(mRunningState);
1399                     break;
1400 
1401                 case CMD_STOP:
1402                     transitionTo(mStoppingState);
1403                     break;
1404 
1405                 case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
1406                     handleLinkPropertiesUpdate(NO_CALLBACKS);
1407                     if (readyToProceed()) {
1408                         transitionTo(mRunningState);
1409                     }
1410                     break;
1411 
1412                 case CMD_UPDATE_L2KEY_GROUPHINT: {
1413                     final Pair<String, String> args = (Pair<String, String>) msg.obj;
1414                     mL2Key = args.first;
1415                     mGroupHint = args.second;
1416                     // TODO : attributes should be saved to the memory store with
1417                     // these new values if they differ from the previous ones.
1418                     // If the state machine is in pure StartedState, then the values to input
1419                     // are not known yet and should be updated when the LinkProperties are updated.
1420                     // If the state machine is in RunningState (which is a child of StartedState)
1421                     // then the next NUD check should be used to store the new values to avoid
1422                     // inputting current values for what may be a different L3 network.
1423                     break;
1424                 }
1425 
1426                 case EVENT_PROVISIONING_TIMEOUT:
1427                     handleProvisioningFailure();
1428                     break;
1429 
1430                 default:
1431                     // It's safe to process messages out of order because the
1432                     // only message that can both
1433                     //     a) be received at this time and
1434                     //     b) affect provisioning state
1435                     // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
1436                     deferMessage(msg);
1437             }
1438 
1439             mMsgStateLogger.handled(this, getCurrentState());
1440             return HANDLED;
1441         }
1442 
readyToProceed()1443         private boolean readyToProceed() {
1444             return (!mLinkProperties.hasIpv4Address() && !mLinkProperties.hasGlobalIpv6Address());
1445         }
1446     }
1447 
1448     class RunningState extends State {
1449         private ConnectivityPacketTracker mPacketTracker;
1450         private boolean mDhcpActionInFlight;
1451 
1452         @Override
enter()1453         public void enter() {
1454             ApfFilter.ApfConfiguration apfConfig = new ApfFilter.ApfConfiguration();
1455             apfConfig.apfCapabilities = mConfiguration.mApfCapabilities;
1456             apfConfig.multicastFilter = mMulticastFiltering;
1457             // Get the Configuration for ApfFilter from Context
1458             apfConfig.ieee802_3Filter = ApfCapabilities.getApfDrop8023Frames();
1459             apfConfig.ethTypeBlackList = ApfCapabilities.getApfEtherTypeBlackList();
1460             mApfFilter = ApfFilter.maybeCreate(mContext, apfConfig, mInterfaceParams, mCallback);
1461             // TODO: investigate the effects of any multicast filtering racing/interfering with the
1462             // rest of this IP configuration startup.
1463             if (mApfFilter == null) {
1464                 mCallback.setFallbackMulticastFilter(mMulticastFiltering);
1465             }
1466 
1467             mPacketTracker = createPacketTracker();
1468             if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName);
1469 
1470             if (mConfiguration.mEnableIPv6 && !startIPv6()) {
1471                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
1472                 enqueueJumpToStoppingState();
1473                 return;
1474             }
1475 
1476             if (mConfiguration.mEnableIPv4 && !startIPv4()) {
1477                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
1478                 enqueueJumpToStoppingState();
1479                 return;
1480             }
1481 
1482             final InitialConfiguration config = mConfiguration.mInitialConfig;
1483             if ((config != null) && !applyInitialConfig(config)) {
1484                 // TODO introduce a new IpManagerEvent constant to distinguish this error case.
1485                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
1486                 enqueueJumpToStoppingState();
1487                 return;
1488             }
1489 
1490             if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
1491                 doImmediateProvisioningFailure(
1492                         IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
1493                 enqueueJumpToStoppingState();
1494                 return;
1495             }
1496         }
1497 
1498         @Override
exit()1499         public void exit() {
1500             stopDhcpAction();
1501 
1502             if (mIpReachabilityMonitor != null) {
1503                 mIpReachabilityMonitor.stop();
1504                 mIpReachabilityMonitor = null;
1505             }
1506 
1507             if (mDhcpClient != null) {
1508                 mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP);
1509                 mDhcpClient.doQuit();
1510             }
1511 
1512             if (mPacketTracker != null) {
1513                 mPacketTracker.stop();
1514                 mPacketTracker = null;
1515             }
1516 
1517             if (mApfFilter != null) {
1518                 mApfFilter.shutdown();
1519                 mApfFilter = null;
1520             }
1521 
1522             resetLinkProperties();
1523         }
1524 
enqueueJumpToStoppingState()1525         private void enqueueJumpToStoppingState() {
1526             deferMessage(obtainMessage(CMD_JUMP_RUNNING_TO_STOPPING));
1527         }
1528 
createPacketTracker()1529         private ConnectivityPacketTracker createPacketTracker() {
1530             try {
1531                 return new ConnectivityPacketTracker(
1532                         getHandler(), mInterfaceParams, mConnectivityPacketLog);
1533             } catch (IllegalArgumentException e) {
1534                 return null;
1535             }
1536         }
1537 
ensureDhcpAction()1538         private void ensureDhcpAction() {
1539             if (!mDhcpActionInFlight) {
1540                 mCallback.onPreDhcpAction();
1541                 mDhcpActionInFlight = true;
1542                 final long alarmTime = SystemClock.elapsedRealtime()
1543                         + mConfiguration.mRequestedPreDhcpActionMs;
1544                 mDhcpActionTimeoutAlarm.schedule(alarmTime);
1545             }
1546         }
1547 
stopDhcpAction()1548         private void stopDhcpAction() {
1549             mDhcpActionTimeoutAlarm.cancel();
1550             if (mDhcpActionInFlight) {
1551                 mCallback.onPostDhcpAction();
1552                 mDhcpActionInFlight = false;
1553             }
1554         }
1555 
1556         @Override
processMessage(Message msg)1557         public boolean processMessage(Message msg) {
1558             switch (msg.what) {
1559                 case CMD_JUMP_RUNNING_TO_STOPPING:
1560                 case CMD_STOP:
1561                     transitionTo(mStoppingState);
1562                     break;
1563 
1564                 case CMD_START:
1565                     logError("ALERT: START received in StartedState. Please fix caller.");
1566                     break;
1567 
1568                 case CMD_CONFIRM:
1569                     // TODO: Possibly introduce a second type of confirmation
1570                     // that both probes (a) on-link neighbors and (b) does
1571                     // a DHCPv4 RENEW.  We used to do this on Wi-Fi framework
1572                     // roams.
1573                     if (mIpReachabilityMonitor != null) {
1574                         mIpReachabilityMonitor.probeAll();
1575                     }
1576                     break;
1577 
1578                 case EVENT_PRE_DHCP_ACTION_COMPLETE:
1579                     // It's possible to reach here if, for example, someone
1580                     // calls completedPreDhcpAction() after provisioning with
1581                     // a static IP configuration.
1582                     if (mDhcpClient != null) {
1583                         mDhcpClient.sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE);
1584                     }
1585                     break;
1586 
1587                 case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
1588                     if (!handleLinkPropertiesUpdate(SEND_CALLBACKS)) {
1589                         transitionTo(mStoppingState);
1590                     }
1591                     break;
1592 
1593                 case CMD_UPDATE_TCP_BUFFER_SIZES:
1594                     mTcpBufferSizes = (String) msg.obj;
1595                     // This cannot possibly change provisioning state.
1596                     handleLinkPropertiesUpdate(SEND_CALLBACKS);
1597                     break;
1598 
1599                 case CMD_UPDATE_HTTP_PROXY:
1600                     mHttpProxy = (ProxyInfo) msg.obj;
1601                     // This cannot possibly change provisioning state.
1602                     handleLinkPropertiesUpdate(SEND_CALLBACKS);
1603                     break;
1604 
1605                 case CMD_SET_MULTICAST_FILTER: {
1606                     mMulticastFiltering = (boolean) msg.obj;
1607                     if (mApfFilter != null) {
1608                         mApfFilter.setMulticastFilter(mMulticastFiltering);
1609                     } else {
1610                         mCallback.setFallbackMulticastFilter(mMulticastFiltering);
1611                     }
1612                     break;
1613                 }
1614 
1615                 case EVENT_READ_PACKET_FILTER_COMPLETE: {
1616                     if (mApfFilter != null) {
1617                         mApfFilter.setDataSnapshot((byte[]) msg.obj);
1618                     }
1619                     mApfDataSnapshotComplete.open();
1620                     break;
1621                 }
1622 
1623                 case CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF: {
1624                     final int slot = msg.arg1;
1625 
1626                     if (mApfFilter != null) {
1627                         if (msg.obj instanceof NattKeepalivePacketDataParcelable) {
1628                             mApfFilter.addNattKeepalivePacketFilter(slot,
1629                                     (NattKeepalivePacketDataParcelable) msg.obj);
1630                         } else if (msg.obj instanceof TcpKeepalivePacketDataParcelable) {
1631                             mApfFilter.addTcpKeepalivePacketFilter(slot,
1632                                     (TcpKeepalivePacketDataParcelable) msg.obj);
1633                         }
1634                     }
1635                     break;
1636                 }
1637 
1638                 case CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF: {
1639                     final int slot = msg.arg1;
1640                     if (mApfFilter != null) {
1641                         mApfFilter.removeKeepalivePacketFilter(slot);
1642                     }
1643                     break;
1644                 }
1645 
1646                 case EVENT_DHCPACTION_TIMEOUT:
1647                     stopDhcpAction();
1648                     break;
1649 
1650                 case DhcpClient.CMD_PRE_DHCP_ACTION:
1651                     if (mConfiguration.mRequestedPreDhcpActionMs > 0) {
1652                         ensureDhcpAction();
1653                     } else {
1654                         sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
1655                     }
1656                     break;
1657 
1658                 case DhcpClient.CMD_CLEAR_LINKADDRESS:
1659                     mInterfaceCtrl.clearIPv4Address();
1660                     break;
1661 
1662                 case DhcpClient.CMD_CONFIGURE_LINKADDRESS: {
1663                     final LinkAddress ipAddress = (LinkAddress) msg.obj;
1664                     if (mInterfaceCtrl.setIPv4Address(ipAddress)) {
1665                         mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED);
1666                     } else {
1667                         logError("Failed to set IPv4 address.");
1668                         dispatchCallback(PROV_CHANGE_LOST_PROVISIONING,
1669                                 new LinkProperties(mLinkProperties));
1670                         transitionTo(mStoppingState);
1671                     }
1672                     break;
1673                 }
1674 
1675                 // This message is only received when:
1676                 //
1677                 //     a) initial address acquisition succeeds,
1678                 //     b) renew succeeds or is NAK'd,
1679                 //     c) rebind succeeds or is NAK'd, or
1680                 //     c) the lease expires,
1681                 //
1682                 // but never when initial address acquisition fails. The latter
1683                 // condition is now governed by the provisioning timeout.
1684                 case DhcpClient.CMD_POST_DHCP_ACTION:
1685                     stopDhcpAction();
1686 
1687                     switch (msg.arg1) {
1688                         case DhcpClient.DHCP_SUCCESS:
1689                             handleIPv4Success((DhcpResults) msg.obj);
1690                             break;
1691                         case DhcpClient.DHCP_FAILURE:
1692                             handleIPv4Failure();
1693                             break;
1694                         default:
1695                             logError("Unknown CMD_POST_DHCP_ACTION status: %s", msg.arg1);
1696                     }
1697                     break;
1698 
1699                 case DhcpClient.CMD_ON_QUIT:
1700                     // DHCPv4 quit early for some reason.
1701                     logError("Unexpected CMD_ON_QUIT.");
1702                     mDhcpClient = null;
1703                     break;
1704 
1705                 default:
1706                     return NOT_HANDLED;
1707             }
1708 
1709             mMsgStateLogger.handled(this, getCurrentState());
1710             return HANDLED;
1711         }
1712     }
1713 
1714     private static class MessageHandlingLogger {
1715         public String processedInState;
1716         public String receivedInState;
1717 
reset()1718         public void reset() {
1719             processedInState = null;
1720             receivedInState = null;
1721         }
1722 
handled(State processedIn, IState receivedIn)1723         public void handled(State processedIn, IState receivedIn) {
1724             processedInState = processedIn.getClass().getSimpleName();
1725             receivedInState = receivedIn.getName();
1726         }
1727 
toString()1728         public String toString() {
1729             return String.format("rcvd_in=%s, proc_in=%s",
1730                                  receivedInState, processedInState);
1731         }
1732     }
1733 
setNeighborParameters( INetd netd, String ifName, int numSolicits, int interSolicitIntervalMs)1734     private static void setNeighborParameters(
1735             INetd netd, String ifName, int numSolicits, int interSolicitIntervalMs)
1736             throws RemoteException, IllegalArgumentException {
1737         Preconditions.checkNotNull(netd);
1738         Preconditions.checkArgument(!TextUtils.isEmpty(ifName));
1739         Preconditions.checkArgument(numSolicits > 0);
1740         Preconditions.checkArgument(interSolicitIntervalMs > 0);
1741 
1742         for (int family : new Integer[]{INetd.IPV4, INetd.IPV6}) {
1743             netd.setProcSysNet(family, INetd.NEIGH, ifName, "retrans_time_ms",
1744                     Integer.toString(interSolicitIntervalMs));
1745             netd.setProcSysNet(family, INetd.NEIGH, ifName, "ucast_solicit",
1746                     Integer.toString(numSolicits));
1747         }
1748     }
1749 
1750     // TODO: extract out into CollectionUtils.
any(Iterable<T> coll, Predicate<T> fn)1751     static <T> boolean any(Iterable<T> coll, Predicate<T> fn) {
1752         for (T t : coll) {
1753             if (fn.test(t)) {
1754                 return true;
1755             }
1756         }
1757         return false;
1758     }
1759 
all(Iterable<T> coll, Predicate<T> fn)1760     static <T> boolean all(Iterable<T> coll, Predicate<T> fn) {
1761         return !any(coll, not(fn));
1762     }
1763 
not(Predicate<T> fn)1764     static <T> Predicate<T> not(Predicate<T> fn) {
1765         return (t) -> !fn.test(t);
1766     }
1767 
join(String delimiter, Collection<T> coll)1768     static <T> String join(String delimiter, Collection<T> coll) {
1769         return coll.stream().map(Object::toString).collect(Collectors.joining(delimiter));
1770     }
1771 
find(Iterable<T> coll, Predicate<T> fn)1772     static <T> T find(Iterable<T> coll, Predicate<T> fn) {
1773         for (T t: coll) {
1774             if (fn.test(t)) {
1775                 return t;
1776             }
1777         }
1778         return null;
1779     }
1780 
findAll(Collection<T> coll, Predicate<T> fn)1781     static <T> List<T> findAll(Collection<T> coll, Predicate<T> fn) {
1782         return coll.stream().filter(fn).collect(Collectors.toList());
1783     }
1784 }
1785