1 /*
2  * Copyright (C) 2014 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 com.android.server.ethernet;
18 
19 import static com.android.internal.util.Preconditions.checkNotNull;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.content.Context;
24 import android.net.ConnectivityManager;
25 import android.net.EthernetNetworkSpecifier;
26 import android.net.IpConfiguration;
27 import android.net.IpConfiguration.IpAssignment;
28 import android.net.IpConfiguration.ProxySettings;
29 import android.net.LinkProperties;
30 import android.net.NetworkAgent;
31 import android.net.NetworkAgentConfig;
32 import android.net.NetworkCapabilities;
33 import android.net.NetworkFactory;
34 import android.net.NetworkRequest;
35 import android.net.NetworkSpecifier;
36 import android.net.ip.IIpClient;
37 import android.net.ip.IpClientCallbacks;
38 import android.net.ip.IpClientUtil;
39 import android.net.shared.ProvisioningConfiguration;
40 import android.net.util.InterfaceParams;
41 import android.os.ConditionVariable;
42 import android.os.Handler;
43 import android.os.RemoteException;
44 import android.text.TextUtils;
45 import android.util.AndroidRuntimeException;
46 import android.util.Log;
47 import android.util.SparseArray;
48 
49 import com.android.internal.util.IndentingPrintWriter;
50 
51 import java.io.FileDescriptor;
52 import java.util.Objects;
53 import java.util.concurrent.ConcurrentHashMap;
54 
55 /**
56  * {@link NetworkFactory} that represents Ethernet networks.
57  *
58  * This class reports a static network score of 70 when it is tracking an interface and that
59  * interface's link is up, and a score of 0 otherwise.
60  */
61 public class EthernetNetworkFactory extends NetworkFactory {
62     private final static String TAG = EthernetNetworkFactory.class.getSimpleName();
63     final static boolean DBG = true;
64 
65     private final static int NETWORK_SCORE = 70;
66     private static final String NETWORK_TYPE = "Ethernet";
67 
68     private final ConcurrentHashMap<String, NetworkInterfaceState> mTrackingInterfaces =
69             new ConcurrentHashMap<>();
70     private final Handler mHandler;
71     private final Context mContext;
72 
73     public static class ConfigurationException extends AndroidRuntimeException {
ConfigurationException(String msg)74         public ConfigurationException(String msg) {
75             super(msg);
76         }
77     }
78 
EthernetNetworkFactory(Handler handler, Context context, NetworkCapabilities filter)79     public EthernetNetworkFactory(Handler handler, Context context, NetworkCapabilities filter) {
80         super(handler.getLooper(), context, NETWORK_TYPE, filter);
81 
82         mHandler = handler;
83         mContext = context;
84 
85         setScoreFilter(NETWORK_SCORE);
86     }
87 
88     @Override
acceptRequest(NetworkRequest request)89     public boolean acceptRequest(NetworkRequest request) {
90         if (DBG) {
91             Log.d(TAG, "acceptRequest, request: " + request);
92         }
93 
94         return networkForRequest(request) != null;
95     }
96 
97     @Override
needNetworkFor(NetworkRequest networkRequest)98     protected void needNetworkFor(NetworkRequest networkRequest) {
99         NetworkInterfaceState network = networkForRequest(networkRequest);
100 
101         if (network == null) {
102             Log.e(TAG, "needNetworkFor, failed to get a network for " + networkRequest);
103             return;
104         }
105 
106         if (++network.refCount == 1) {
107             network.start();
108         }
109     }
110 
111     @Override
releaseNetworkFor(NetworkRequest networkRequest)112     protected void releaseNetworkFor(NetworkRequest networkRequest) {
113         NetworkInterfaceState network = networkForRequest(networkRequest);
114         if (network == null) {
115             Log.e(TAG, "releaseNetworkFor, failed to get a network for " + networkRequest);
116             return;
117         }
118 
119         if (--network.refCount == 0) {
120             network.stop();
121         }
122     }
123 
124     /**
125      * Returns an array of available interface names. The array is sorted: unrestricted interfaces
126      * goes first, then sorted by name.
127      */
getAvailableInterfaces(boolean includeRestricted)128     String[] getAvailableInterfaces(boolean includeRestricted) {
129         return mTrackingInterfaces.values()
130                 .stream()
131                 .filter(iface -> !iface.isRestricted() || includeRestricted)
132                 .sorted((iface1, iface2) -> {
133                     int r = Boolean.compare(iface1.isRestricted(), iface2.isRestricted());
134                     return r == 0 ? iface1.name.compareTo(iface2.name) : r;
135                 })
136                 .map(iface -> iface.name)
137                 .toArray(String[]::new);
138     }
139 
addInterface(String ifaceName, String hwAddress, NetworkCapabilities capabilities, IpConfiguration ipConfiguration)140     void addInterface(String ifaceName, String hwAddress, NetworkCapabilities capabilities,
141              IpConfiguration ipConfiguration) {
142         if (mTrackingInterfaces.containsKey(ifaceName)) {
143             Log.e(TAG, "Interface with name " + ifaceName + " already exists.");
144             return;
145         }
146 
147         if (DBG) {
148             Log.d(TAG, "addInterface, iface: " + ifaceName + ", capabilities: " + capabilities);
149         }
150 
151         NetworkInterfaceState iface = new NetworkInterfaceState(
152                 ifaceName, hwAddress, mHandler, mContext, capabilities, this);
153         iface.setIpConfig(ipConfiguration);
154         mTrackingInterfaces.put(ifaceName, iface);
155 
156         updateCapabilityFilter();
157     }
158 
mixInCapabilities(NetworkCapabilities nc, NetworkCapabilities addedNc)159     private static NetworkCapabilities mixInCapabilities(NetworkCapabilities nc,
160             NetworkCapabilities addedNc) {
161        final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(nc);
162        for (int transport : addedNc.getTransportTypes()) builder.addTransportType(transport);
163        for (int capability : addedNc.getCapabilities()) builder.addCapability(capability);
164        return builder.build();
165     }
166 
updateCapabilityFilter()167     private void updateCapabilityFilter() {
168         NetworkCapabilities capabilitiesFilter =
169                 NetworkCapabilities.Builder.withoutDefaultCapabilities()
170                 .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
171                 .build();
172 
173         for (NetworkInterfaceState iface:  mTrackingInterfaces.values()) {
174             capabilitiesFilter = mixInCapabilities(capabilitiesFilter, iface.mCapabilities);
175         }
176 
177         if (DBG) Log.d(TAG, "updateCapabilityFilter: " + capabilitiesFilter);
178         setCapabilityFilter(capabilitiesFilter);
179     }
180 
removeInterface(String interfaceName)181     void removeInterface(String interfaceName) {
182         NetworkInterfaceState iface = mTrackingInterfaces.remove(interfaceName);
183         if (iface != null) {
184             iface.stop();
185         }
186 
187         updateCapabilityFilter();
188     }
189 
190     /** Returns true if state has been modified */
updateInterfaceLinkState(String ifaceName, boolean up)191     boolean updateInterfaceLinkState(String ifaceName, boolean up) {
192         if (!mTrackingInterfaces.containsKey(ifaceName)) {
193             return false;
194         }
195 
196         if (DBG) {
197             Log.d(TAG, "updateInterfaceLinkState, iface: " + ifaceName + ", up: " + up);
198         }
199 
200         NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName);
201         return iface.updateLinkState(up);
202     }
203 
hasInterface(String interfacName)204     boolean hasInterface(String interfacName) {
205         return mTrackingInterfaces.containsKey(interfacName);
206     }
207 
updateIpConfiguration(String iface, IpConfiguration ipConfiguration)208     void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) {
209         NetworkInterfaceState network = mTrackingInterfaces.get(iface);
210         if (network != null) {
211             network.setIpConfig(ipConfiguration);
212         }
213     }
214 
networkForRequest(NetworkRequest request)215     private NetworkInterfaceState networkForRequest(NetworkRequest request) {
216         String requestedIface = null;
217 
218         NetworkSpecifier specifier = request.getNetworkSpecifier();
219         if (specifier instanceof EthernetNetworkSpecifier) {
220             requestedIface = ((EthernetNetworkSpecifier) specifier)
221                 .getInterfaceName();
222         }
223 
224         NetworkInterfaceState network = null;
225         if (!TextUtils.isEmpty(requestedIface)) {
226             NetworkInterfaceState n = mTrackingInterfaces.get(requestedIface);
227             if (n != null && request.canBeSatisfiedBy(n.mCapabilities)) {
228                 network = n;
229             }
230         } else {
231             for (NetworkInterfaceState n : mTrackingInterfaces.values()) {
232                 if (request.canBeSatisfiedBy(n.mCapabilities) && n.mLinkUp) {
233                     network = n;
234                     break;
235                 }
236             }
237         }
238 
239         if (DBG) {
240             Log.i(TAG, "networkForRequest, request: " + request + ", network: " + network);
241         }
242 
243         return network;
244     }
245 
246     private static class NetworkInterfaceState {
247         final String name;
248 
249         private final String mHwAddress;
250         private final NetworkCapabilities mCapabilities;
251         private final Handler mHandler;
252         private final Context mContext;
253         private final NetworkFactory mNetworkFactory;
254         private final int mLegacyType;
255 
256         private static String sTcpBufferSizes = null;  // Lazy initialized.
257 
258         private boolean mLinkUp;
259         private LinkProperties mLinkProperties = new LinkProperties();
260 
261         private volatile @Nullable IIpClient mIpClient;
262         private @Nullable IpClientCallbacksImpl mIpClientCallback;
263         private @Nullable NetworkAgent mNetworkAgent;
264         private @Nullable IpConfiguration mIpConfig;
265 
266         /**
267          * An object to contain all transport type information, including base network score and
268          * the legacy transport type it maps to (if any)
269          */
270         private static class TransportInfo {
271             final int mLegacyType;
272             final int mScore;
273 
TransportInfo(int legacyType, int score)274             private TransportInfo(int legacyType, int score) {
275                 mLegacyType = legacyType;
276                 mScore = score;
277             }
278         }
279 
280         /**
281          * A map of TRANSPORT_* types to TransportInfo, making scoring and legacy type information
282          * available for each type an ethernet interface could propagate.
283          *
284          * Unfortunately, base scores for the various transports are not yet centrally located.
285          * They've been lifted from the corresponding NetworkFactory files in the meantime.
286          *
287          * Additionally, there are no legacy type equivalents to LOWPAN or WIFI_AWARE. These types
288          * are set to TYPE_NONE to match the behavior of their own network factories.
289          */
290         private static final SparseArray<TransportInfo> sTransports = new SparseArray();
291         static {
292             // LowpanInterfaceTracker.NETWORK_SCORE
sTransports.put(NetworkCapabilities.TRANSPORT_LOWPAN, new TransportInfo(ConnectivityManager.TYPE_NONE, 30))293             sTransports.put(NetworkCapabilities.TRANSPORT_LOWPAN,
294                     new TransportInfo(ConnectivityManager.TYPE_NONE, 30));
295             // WifiAwareDataPathStateManager.NETWORK_FACTORY_SCORE_AVAIL
sTransports.put(NetworkCapabilities.TRANSPORT_WIFI_AWARE, new TransportInfo(ConnectivityManager.TYPE_NONE, 1))296             sTransports.put(NetworkCapabilities.TRANSPORT_WIFI_AWARE,
297                     new TransportInfo(ConnectivityManager.TYPE_NONE, 1));
298             // EthernetNetworkFactory.NETWORK_SCORE
sTransports.put(NetworkCapabilities.TRANSPORT_ETHERNET, new TransportInfo(ConnectivityManager.TYPE_ETHERNET, 70))299             sTransports.put(NetworkCapabilities.TRANSPORT_ETHERNET,
300                     new TransportInfo(ConnectivityManager.TYPE_ETHERNET, 70));
301             // BluetoothTetheringNetworkFactory.NETWORK_SCORE
sTransports.put(NetworkCapabilities.TRANSPORT_BLUETOOTH, new TransportInfo(ConnectivityManager.TYPE_BLUETOOTH, 69))302             sTransports.put(NetworkCapabilities.TRANSPORT_BLUETOOTH,
303                     new TransportInfo(ConnectivityManager.TYPE_BLUETOOTH, 69));
304             // WifiNetworkFactory.SCORE_FILTER / NetworkAgent.WIFI_BASE_SCORE
sTransports.put(NetworkCapabilities.TRANSPORT_WIFI, new TransportInfo(ConnectivityManager.TYPE_WIFI, 60))305             sTransports.put(NetworkCapabilities.TRANSPORT_WIFI,
306                     new TransportInfo(ConnectivityManager.TYPE_WIFI, 60));
307             // TelephonyNetworkFactory.TELEPHONY_NETWORK_SCORE
sTransports.put(NetworkCapabilities.TRANSPORT_CELLULAR, new TransportInfo(ConnectivityManager.TYPE_MOBILE, 50))308             sTransports.put(NetworkCapabilities.TRANSPORT_CELLULAR,
309                     new TransportInfo(ConnectivityManager.TYPE_MOBILE, 50));
310         }
311 
312         long refCount = 0;
313 
314         private class IpClientCallbacksImpl extends IpClientCallbacks {
315             private final ConditionVariable mIpClientStartCv = new ConditionVariable(false);
316             private final ConditionVariable mIpClientShutdownCv = new ConditionVariable(false);
317 
318             @Override
onIpClientCreated(IIpClient ipClient)319             public void onIpClientCreated(IIpClient ipClient) {
320                 mIpClient = ipClient;
321                 mIpClientStartCv.open();
322             }
323 
awaitIpClientStart()324             private void awaitIpClientStart() {
325                 mIpClientStartCv.block();
326             }
327 
awaitIpClientShutdown()328             private void awaitIpClientShutdown() {
329                 mIpClientShutdownCv.block();
330             }
331 
332             @Override
onProvisioningSuccess(LinkProperties newLp)333             public void onProvisioningSuccess(LinkProperties newLp) {
334                 mHandler.post(() -> onIpLayerStarted(newLp));
335             }
336 
337             @Override
onProvisioningFailure(LinkProperties newLp)338             public void onProvisioningFailure(LinkProperties newLp) {
339                 mHandler.post(() -> onIpLayerStopped(newLp));
340             }
341 
342             @Override
onLinkPropertiesChange(LinkProperties newLp)343             public void onLinkPropertiesChange(LinkProperties newLp) {
344                 mHandler.post(() -> updateLinkProperties(newLp));
345             }
346 
347             @Override
onQuit()348             public void onQuit() {
349                 mIpClient = null;
350                 mIpClientShutdownCv.open();
351             }
352         }
353 
shutdownIpClient(IIpClient ipClient)354         private static void shutdownIpClient(IIpClient ipClient) {
355             try {
356                 ipClient.shutdown();
357             } catch (RemoteException e) {
358                 Log.e(TAG, "Error stopping IpClient", e);
359             }
360         }
361 
NetworkInterfaceState(String ifaceName, String hwAddress, Handler handler, Context context, @NonNull NetworkCapabilities capabilities, NetworkFactory networkFactory)362         NetworkInterfaceState(String ifaceName, String hwAddress, Handler handler, Context context,
363                 @NonNull NetworkCapabilities capabilities, NetworkFactory networkFactory) {
364             name = ifaceName;
365             mCapabilities = checkNotNull(capabilities);
366             mHandler = handler;
367             mContext = context;
368             mNetworkFactory = networkFactory;
369             int legacyType = ConnectivityManager.TYPE_NONE;
370             int[] transportTypes = mCapabilities.getTransportTypes();
371 
372             if (transportTypes.length > 0) {
373                 legacyType = getLegacyType(transportTypes[0]);
374             } else {
375                 // Should never happen as transport is always one of ETHERNET or a valid override
376                 throw new ConfigurationException("Network Capabilities do not have an associated "
377                         + "transport type.");
378             }
379 
380             mHwAddress = hwAddress;
381             mLegacyType = legacyType;
382         }
383 
setIpConfig(IpConfiguration ipConfig)384         void setIpConfig(IpConfiguration ipConfig) {
385             if (Objects.equals(this.mIpConfig, ipConfig)) {
386                 if (DBG) Log.d(TAG, "ipConfig have not changed,so ignore setIpConfig");
387                 return;
388             }
389             this.mIpConfig = ipConfig;
390             if (mNetworkAgent != null) {
391                 restart();
392             }
393         }
394 
satisfied(NetworkCapabilities requestedCapabilities)395         boolean satisfied(NetworkCapabilities requestedCapabilities) {
396             return requestedCapabilities.satisfiedByNetworkCapabilities(mCapabilities);
397         }
398 
isRestricted()399         boolean isRestricted() {
400             return !mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
401         }
402 
403         /**
404          * Determines the legacy transport type from a NetworkCapabilities transport type. Defaults
405          * to legacy TYPE_NONE if there is no known conversion
406          */
getLegacyType(int transport)407         private static int getLegacyType(int transport) {
408             TransportInfo transportInfo = sTransports.get(transport, /* if dne */ null);
409             if (transportInfo != null) {
410                 return transportInfo.mLegacyType;
411             }
412             return ConnectivityManager.TYPE_NONE;
413         }
414 
415         /**
416          * Determines the network score based on the transport associated with the interface.
417          * Ethernet interfaces could propagate a transport types forward. Since we can't
418          * get more information about the statuses of the interfaces on the other end of the local
419          * interface, we'll best-effort assign the score as the base score of the assigned transport
420          * when the link is up. When the link is down, the score is set to zero.
421          *
422          * This function is called with the purpose of assigning and updating the network score of
423          * the member NetworkAgent.
424          */
getNetworkScore()425         private int getNetworkScore() {
426             // never set the network score below 0.
427             if (!mLinkUp) {
428                 return 0;
429             }
430 
431             int[] transportTypes = mCapabilities.getTransportTypes();
432             if (transportTypes.length < 1) {
433                 Log.w(TAG, "Network interface '" + mLinkProperties.getInterfaceName() + "' has no "
434                         + "transport type associated with it. Score set to zero");
435                 return 0;
436             }
437             TransportInfo transportInfo = sTransports.get(transportTypes[0], /* if dne */ null);
438             if (transportInfo != null) {
439                 return transportInfo.mScore;
440             }
441             return 0;
442         }
443 
start()444         private void start() {
445             if (mIpClient != null) {
446                 if (DBG) Log.d(TAG, "IpClient already started");
447                 return;
448             }
449             if (DBG) {
450                 Log.d(TAG, String.format("Starting Ethernet IpClient(%s)", name));
451             }
452 
453             mIpClientCallback = new IpClientCallbacksImpl();
454             IpClientUtil.makeIpClient(mContext, name, mIpClientCallback);
455             mIpClientCallback.awaitIpClientStart();
456             if (sTcpBufferSizes == null) {
457                 sTcpBufferSizes = mContext.getResources().getString(
458                         com.android.internal.R.string.config_ethernet_tcp_buffers);
459             }
460             provisionIpClient(mIpClient, mIpConfig, sTcpBufferSizes);
461         }
462 
onIpLayerStarted(LinkProperties linkProperties)463         void onIpLayerStarted(LinkProperties linkProperties) {
464             if (mNetworkAgent != null) {
465                 Log.e(TAG, "Already have a NetworkAgent - aborting new request");
466                 stop();
467                 return;
468             }
469             mLinkProperties = linkProperties;
470 
471             // Create our NetworkAgent.
472             final NetworkAgentConfig config = new NetworkAgentConfig.Builder()
473                     .setLegacyType(mLegacyType)
474                     .setLegacyTypeName(NETWORK_TYPE)
475                     .setLegacyExtraInfo(mHwAddress)
476                     .build();
477             mNetworkAgent = new NetworkAgent(mContext, mHandler.getLooper(),
478                     NETWORK_TYPE, mCapabilities, mLinkProperties,
479                     getNetworkScore(), config, mNetworkFactory.getProvider()) {
480                 public void unwanted() {
481                     if (this == mNetworkAgent) {
482                         stop();
483                     } else if (mNetworkAgent != null) {
484                         Log.d(TAG, "Ignoring unwanted as we have a more modern " +
485                                 "instance");
486                     }  // Otherwise, we've already called stop.
487                 }
488             };
489             mNetworkAgent.register();
490             mNetworkAgent.markConnected();
491         }
492 
onIpLayerStopped(LinkProperties linkProperties)493         void onIpLayerStopped(LinkProperties linkProperties) {
494             // This cannot happen due to provisioning timeout, because our timeout is 0. It can only
495             // happen if we're provisioned and we lose provisioning.
496             stop();
497             // If the interface has disappeared provisioning will fail over and over again, so
498             // there is no point in starting again
499             if (null != InterfaceParams.getByName(name)) {
500                 start();
501             }
502         }
503 
updateLinkProperties(LinkProperties linkProperties)504         void updateLinkProperties(LinkProperties linkProperties) {
505             mLinkProperties = linkProperties;
506             if (mNetworkAgent != null) {
507                 mNetworkAgent.sendLinkProperties(linkProperties);
508             }
509         }
510 
511         /** Returns true if state has been modified */
updateLinkState(boolean up)512         boolean updateLinkState(boolean up) {
513             if (mLinkUp == up) return false;
514             mLinkUp = up;
515 
516             stop();
517             if (up) {
518                 start();
519             }
520 
521             return true;
522         }
523 
stop()524         void stop() {
525             // Invalidate all previous start requests
526             if (mIpClient != null) {
527                 shutdownIpClient(mIpClient);
528                 mIpClientCallback.awaitIpClientShutdown();
529                 mIpClient = null;
530             }
531             mIpClientCallback = null;
532 
533             if (mNetworkAgent != null) {
534                 mNetworkAgent.unregister();
535                 mNetworkAgent = null;
536             }
537             mLinkProperties.clear();
538         }
539 
updateAgent()540         private void updateAgent() {
541             if (mNetworkAgent == null) return;
542             if (DBG) {
543                 Log.i(TAG, "Updating mNetworkAgent with: " +
544                         mCapabilities + ", " +
545                         mLinkProperties);
546             }
547             mNetworkAgent.sendNetworkCapabilities(mCapabilities);
548             mNetworkAgent.sendLinkProperties(mLinkProperties);
549 
550             // As a note, getNetworkScore() is fairly expensive to calculate. This is fine for now
551             // since the agent isn't updated frequently. Consider caching the score in the future if
552             // agent updating is required more often
553             mNetworkAgent.sendNetworkScore(getNetworkScore());
554         }
555 
provisionIpClient(IIpClient ipClient, IpConfiguration config, String tcpBufferSizes)556         private static void provisionIpClient(IIpClient ipClient, IpConfiguration config,
557                 String tcpBufferSizes) {
558             if (config.getProxySettings() == ProxySettings.STATIC ||
559                     config.getProxySettings() == ProxySettings.PAC) {
560                 try {
561                     ipClient.setHttpProxy(config.getHttpProxy());
562                 } catch (RemoteException e) {
563                     e.rethrowFromSystemServer();
564                 }
565             }
566 
567             if (!TextUtils.isEmpty(tcpBufferSizes)) {
568                 try {
569                     ipClient.setTcpBufferSizes(tcpBufferSizes);
570                 } catch (RemoteException e) {
571                     e.rethrowFromSystemServer();
572                 }
573             }
574 
575             final ProvisioningConfiguration provisioningConfiguration;
576             if (config.getIpAssignment() == IpAssignment.STATIC) {
577                 provisioningConfiguration = new ProvisioningConfiguration.Builder()
578                         .withStaticConfiguration(config.getStaticIpConfiguration())
579                         .build();
580             } else {
581                 provisioningConfiguration = new ProvisioningConfiguration.Builder()
582                         .withProvisioningTimeoutMs(0)
583                         .build();
584             }
585 
586             try {
587                 ipClient.startProvisioning(provisioningConfiguration.toStableParcelable());
588             } catch (RemoteException e) {
589                 e.rethrowFromSystemServer();
590             }
591         }
592 
restart()593         void restart(){
594             if (DBG) Log.d(TAG, "reconnecting Etherent");
595             stop();
596             start();
597         }
598 
599         @Override
toString()600         public String toString() {
601             return getClass().getSimpleName() + "{ "
602                     + "refCount: " + refCount + ", "
603                     + "iface: " + name + ", "
604                     + "up: " + mLinkUp + ", "
605                     + "hwAddress: " + mHwAddress + ", "
606                     + "networkCapabilities: " + mCapabilities + ", "
607                     + "networkAgent: " + mNetworkAgent + ", "
608                     + "score: " + getNetworkScore() + ", "
609                     + "ipClient: " + mIpClient + ","
610                     + "linkProperties: " + mLinkProperties
611                     + "}";
612         }
613     }
614 
dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args)615     void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
616         super.dump(fd, pw, args);
617         pw.println(getClass().getSimpleName());
618         pw.println("Tracking interfaces:");
619         pw.increaseIndent();
620         for (String iface: mTrackingInterfaces.keySet()) {
621             NetworkInterfaceState ifaceState = mTrackingInterfaces.get(iface);
622             pw.println(iface + ":" + ifaceState);
623             pw.increaseIndent();
624             final IIpClient ipClient = ifaceState.mIpClient;
625             if (ipClient != null) {
626                 IpClientUtil.dumpIpClient(ipClient, fd, pw, args);
627             } else {
628                 pw.println("IpClient is null");
629             }
630             pw.decreaseIndent();
631         }
632         pw.decreaseIndent();
633     }
634 }
635