• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.shared;
18 
19 import static android.net.ip.IIpClient.PROV_IPV4_DHCP;
20 import static android.net.ip.IIpClient.PROV_IPV4_DISABLED;
21 import static android.net.ip.IIpClient.PROV_IPV4_STATIC;
22 import static android.net.ip.IIpClient.PROV_IPV6_DISABLED;
23 import static android.net.ip.IIpClient.PROV_IPV6_LINKLOCAL;
24 import static android.net.ip.IIpClient.PROV_IPV6_SLAAC;
25 import static android.net.shared.ParcelableUtil.fromParcelableArray;
26 import static android.net.shared.ParcelableUtil.toParcelableArray;
27 
28 import android.annotation.NonNull;
29 import android.annotation.Nullable;
30 import android.net.InformationElementParcelable;
31 import android.net.Network;
32 import android.net.ProvisioningConfigurationParcelable;
33 import android.net.ScanResultInfoParcelable;
34 import android.net.StaticIpConfiguration;
35 import android.net.apf.ApfCapabilities;
36 import android.net.ip.IIpClient;
37 import android.net.networkstack.aidl.dhcp.DhcpOption;
38 import android.util.Log;
39 
40 import com.android.internal.annotations.VisibleForTesting;
41 
42 import java.nio.BufferUnderflowException;
43 import java.nio.ByteBuffer;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.Collections;
47 import java.util.List;
48 import java.util.Objects;
49 import java.util.StringJoiner;
50 
51 /**
52  * This class encapsulates parameters to be passed to
53  * IpClient#startProvisioning(). A defensive copy is made by IpClient
54  * and the values specified herein are in force until IpClient#stop()
55  * is called.
56  *
57  * Example use:
58  *
59  *     final ProvisioningConfiguration config =
60  *             new ProvisioningConfiguration.Builder()
61  *                     .withPreDhcpAction()
62  *                     .withProvisioningTimeoutMs(36 * 1000)
63  *                     .build();
64  *     mIpClient.startProvisioning(config.toStableParcelable());
65  *     ...
66  *     mIpClient.stop();
67  *
68  * The specified provisioning configuration will only be active until
69  * IIpClient#stop() is called. Future calls to IIpClient#startProvisioning()
70  * must specify the configuration again.
71  * @hide
72  */
73 public class ProvisioningConfiguration {
74     private static final String TAG = "ProvisioningConfiguration";
75 
76     // TODO: Delete this default timeout once those callers that care are
77     // fixed to pass in their preferred timeout.
78     //
79     // We pick 18 seconds so we can send DHCP requests at
80     //
81     //     t=0, t=1, t=3, t=7, t=16
82     //
83     // allowing for 10% jitter.
84     private static final int DEFAULT_TIMEOUT_MS = 18 * 1000;
85 
86     // TODO: These cannot be imported from INetd.aidl, because networkstack-client cannot depend on
87     // INetd, as there are users of IpClient that depend on INetd directly (potentially at a
88     // different version, which is not allowed by the build system).
89     // Find a better way to express these constants.
90     public static final int IPV6_ADDR_GEN_MODE_EUI64 = 0;
91     public static final int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
92 
93     // ipv4ProvisioningMode and ipv6ProvisioningMode members are introduced since
94     // networkstack-aidl-interfaces-v12.
95     public static final int VERSION_ADDED_PROVISIONING_ENUM = 12;
96 
97     /**
98      * Builder to create a {@link ProvisioningConfiguration}.
99      */
100     public static class Builder {
101         protected ProvisioningConfiguration mConfig = new ProvisioningConfiguration();
102 
103         /**
104          * Specify that the configuration should not enable IPv4. It is enabled by default.
105          */
withoutIPv4()106         public Builder withoutIPv4() {
107             mConfig.mIPv4ProvisioningMode = PROV_IPV4_DISABLED;
108             return this;
109         }
110 
111         /**
112          * Specify that the configuration should not enable IPv6. It is enabled by default.
113          */
withoutIPv6()114         public Builder withoutIPv6() {
115             mConfig.mIPv6ProvisioningMode = PROV_IPV6_DISABLED;
116             return this;
117         }
118 
119         /**
120          * Specify that the configuration should not use a MultinetworkPolicyTracker. It is used
121          * by default.
122          */
withoutMultinetworkPolicyTracker()123         public Builder withoutMultinetworkPolicyTracker() {
124             mConfig.mUsingMultinetworkPolicyTracker = false;
125             return this;
126         }
127 
128         /**
129          * Specify that the configuration should not use a IpReachabilityMonitor. It is used by
130          * default.
131          */
withoutIpReachabilityMonitor()132         public Builder withoutIpReachabilityMonitor() {
133             mConfig.mUsingIpReachabilityMonitor = false;
134             return this;
135         }
136 
137         /**
138          * Identical to {@link #withPreDhcpAction(int)}, using a default timeout.
139          * @see #withPreDhcpAction(int)
140          */
withPreDhcpAction()141         public Builder withPreDhcpAction() {
142             mConfig.mRequestedPreDhcpActionMs = DEFAULT_TIMEOUT_MS;
143             return this;
144         }
145 
146         /**
147          * Specify that {@link IpClientCallbacks#onPreDhcpAction()} should be called. Clients must
148          * call {@link IIpClient#completedPreDhcpAction()} when the callback called. This behavior
149          * is disabled by default.
150          * @param dhcpActionTimeoutMs Timeout for clients to call completedPreDhcpAction().
151          */
withPreDhcpAction(int dhcpActionTimeoutMs)152         public Builder withPreDhcpAction(int dhcpActionTimeoutMs) {
153             mConfig.mRequestedPreDhcpActionMs = dhcpActionTimeoutMs;
154             return this;
155         }
156 
157         /**
158          * Specify that preconnection feature would be enabled. It's not used by default.
159          */
withPreconnection()160         public Builder withPreconnection() {
161             mConfig.mEnablePreconnection = true;
162             return this;
163         }
164 
165         /**
166          * Specify the initial provisioning configuration.
167          */
withInitialConfiguration(InitialConfiguration initialConfig)168         public Builder withInitialConfiguration(InitialConfiguration initialConfig) {
169             mConfig.mInitialConfig = initialConfig;
170             return this;
171         }
172 
173         /**
174          * Specify a static configuration for provisioning.
175          */
withStaticConfiguration(StaticIpConfiguration staticConfig)176         public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
177             mConfig.mIPv4ProvisioningMode = PROV_IPV4_STATIC;
178             mConfig.mStaticIpConfig = staticConfig;
179             return this;
180         }
181 
182         /**
183          * Specify ApfCapabilities.
184          */
withApfCapabilities(ApfCapabilities apfCapabilities)185         public Builder withApfCapabilities(ApfCapabilities apfCapabilities) {
186             mConfig.mApfCapabilities = apfCapabilities;
187             return this;
188         }
189 
190         /**
191          * Specify the timeout to use for provisioning.
192          */
withProvisioningTimeoutMs(int timeoutMs)193         public Builder withProvisioningTimeoutMs(int timeoutMs) {
194             mConfig.mProvisioningTimeoutMs = timeoutMs;
195             return this;
196         }
197 
198         /**
199          * Specify that IPv6 address generation should use a random MAC address.
200          */
withRandomMacAddress()201         public Builder withRandomMacAddress() {
202             mConfig.mIPv6AddrGenMode = IPV6_ADDR_GEN_MODE_EUI64;
203             return this;
204         }
205 
206         /**
207          * Specify that IPv6 address generation should use a stable MAC address.
208          */
withStableMacAddress()209         public Builder withStableMacAddress() {
210             mConfig.mIPv6AddrGenMode = IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
211             return this;
212         }
213 
214         /**
215          * Specify the network to use for provisioning.
216          */
withNetwork(Network network)217         public Builder withNetwork(Network network) {
218             mConfig.mNetwork = network;
219             return this;
220         }
221 
222         /**
223          * Specify the display name that the IpClient should use.
224          */
withDisplayName(String displayName)225         public Builder withDisplayName(String displayName) {
226             mConfig.mDisplayName = displayName;
227             return this;
228         }
229 
230         /**
231          * Specify the information elements included in wifi scan result that was obtained
232          * prior to connecting to the access point, if this is a WiFi network.
233          *
234          * <p>The scan result can be used to infer whether the network is metered.
235          */
withScanResultInfo(ScanResultInfo scanResultInfo)236         public Builder withScanResultInfo(ScanResultInfo scanResultInfo) {
237             mConfig.mScanResultInfo = scanResultInfo;
238             return this;
239         }
240 
241         /**
242          * Specify the L2 information(bssid, l2key and cluster) that the IpClient should use.
243          */
withLayer2Information(Layer2Information layer2Info)244         public Builder withLayer2Information(Layer2Information layer2Info) {
245             mConfig.mLayer2Info = layer2Info;
246             return this;
247         }
248 
249         /**
250          * Specify the customized DHCP options to be put in the PRL or in the DHCP packet. Options
251          * with null value will be put in the PRL.
252          *
253          * @param: options customized DHCP option stable parcelable list.
254          */
withDhcpOptions(@ullable List<DhcpOption> options)255         public Builder withDhcpOptions(@Nullable List<DhcpOption> options) {
256             mConfig.mDhcpOptions = options;
257             return this;
258         }
259 
260         /**
261          * Specify that the configuration should enable IPv6 link-local only mode used for
262          * WiFi Neighbor Aware Networking and other link-local-only technologies. It's not
263          * used by default, and IPv4 must be disabled when this mode is enabled.
264          *
265          * @note This API is only supported since Android T.
266          */
withIpv6LinkLocalOnly()267         public Builder withIpv6LinkLocalOnly() {
268             mConfig.mIPv6ProvisioningMode = PROV_IPV6_LINKLOCAL;
269             return this;
270         }
271 
272         /**
273          * Build the configuration using previously specified parameters.
274          */
build()275         public ProvisioningConfiguration build() {
276             if (mConfig.mIPv6ProvisioningMode == PROV_IPV6_LINKLOCAL
277                     && mConfig.mIPv4ProvisioningMode != PROV_IPV4_DISABLED) {
278                 throw new IllegalArgumentException("IPv4 must be disabled in IPv6 link-local"
279                         + "only mode.");
280             }
281             return new ProvisioningConfiguration(mConfig);
282         }
283     }
284 
285     /**
286      * Class wrapper of {@link android.net.wifi.ScanResult} to encapsulate the SSID and
287      * InformationElements fields of ScanResult.
288      */
289     public static class ScanResultInfo {
290         @NonNull
291         private final String mSsid;
292         @NonNull
293         private final String mBssid;
294         @NonNull
295         private final List<InformationElement> mInformationElements;
296 
297        /**
298         * Class wrapper of {@link android.net.wifi.ScanResult.InformationElement} to encapsulate
299         * the specific IE id and payload fields.
300         */
301         public static class InformationElement {
302             private final int mId;
303             @NonNull
304             private final byte[] mPayload;
305 
InformationElement(int id, @NonNull ByteBuffer payload)306             public InformationElement(int id, @NonNull ByteBuffer payload) {
307                 mId = id;
308                 mPayload = convertToByteArray(payload.asReadOnlyBuffer());
309             }
310 
311            /**
312             * Get the element ID of the information element.
313             */
getId()314             public int getId() {
315                 return mId;
316             }
317 
318            /**
319             * Get the specific content of the information element.
320             */
321             @NonNull
getPayload()322             public ByteBuffer getPayload() {
323                 return ByteBuffer.wrap(mPayload).asReadOnlyBuffer();
324             }
325 
326             @Override
equals(Object o)327             public boolean equals(Object o) {
328                 if (o == this) return true;
329                 if (!(o instanceof InformationElement)) return false;
330                 InformationElement other = (InformationElement) o;
331                 return mId == other.mId && Arrays.equals(mPayload, other.mPayload);
332             }
333 
334             @Override
hashCode()335             public int hashCode() {
336                 return Objects.hash(mId, mPayload);
337             }
338 
339             @Override
toString()340             public String toString() {
341                 return "ID: " + mId + ", " + Arrays.toString(mPayload);
342             }
343 
344             /**
345              * Convert this InformationElement to a {@link InformationElementParcelable}.
346              */
toStableParcelable()347             public InformationElementParcelable toStableParcelable() {
348                 final InformationElementParcelable p = new InformationElementParcelable();
349                 p.id = mId;
350                 p.payload = mPayload != null ? mPayload.clone() : null;
351                 return p;
352             }
353 
354             /**
355              * Create an instance of {@link InformationElement} based on the contents of the
356              * specified {@link InformationElementParcelable}.
357              */
358             @Nullable
fromStableParcelable(InformationElementParcelable p)359             public static InformationElement fromStableParcelable(InformationElementParcelable p) {
360                 if (p == null) return null;
361                 return new InformationElement(p.id,
362                         ByteBuffer.wrap(p.payload.clone()).asReadOnlyBuffer());
363             }
364         }
365 
ScanResultInfo(@onNull String ssid, @NonNull String bssid, @NonNull List<InformationElement> informationElements)366         public ScanResultInfo(@NonNull String ssid, @NonNull String bssid,
367                 @NonNull List<InformationElement> informationElements) {
368             Objects.requireNonNull(ssid, "ssid must not be null.");
369             Objects.requireNonNull(bssid, "bssid must not be null.");
370             mSsid = ssid;
371             mBssid = bssid;
372             mInformationElements =
373                     Collections.unmodifiableList(new ArrayList<>(informationElements));
374         }
375 
376         /**
377          * Get the scanned network name.
378          */
379         @NonNull
getSsid()380         public String getSsid() {
381             return mSsid;
382         }
383 
384         /**
385          * Get the address of the access point.
386          */
387         @NonNull
getBssid()388         public String getBssid() {
389             return mBssid;
390         }
391 
392         /**
393          * Get all information elements found in the beacon.
394          */
395         @NonNull
getInformationElements()396         public List<InformationElement> getInformationElements() {
397             return mInformationElements;
398         }
399 
400         @Override
toString()401         public String toString() {
402             StringBuffer str = new StringBuffer();
403             str.append("SSID: ").append(mSsid);
404             str.append(", BSSID: ").append(mBssid);
405             str.append(", Information Elements: {");
406             for (InformationElement ie : mInformationElements) {
407                 str.append("[").append(ie.toString()).append("]");
408             }
409             str.append("}");
410             return str.toString();
411         }
412 
413         @Override
equals(Object o)414         public boolean equals(Object o) {
415             if (o == this) return true;
416             if (!(o instanceof ScanResultInfo)) return false;
417             ScanResultInfo other = (ScanResultInfo) o;
418             return Objects.equals(mSsid, other.mSsid)
419                     && Objects.equals(mBssid, other.mBssid)
420                     && mInformationElements.equals(other.mInformationElements);
421         }
422 
423         @Override
hashCode()424         public int hashCode() {
425             return Objects.hash(mSsid, mBssid, mInformationElements);
426         }
427 
428         /**
429          * Convert this ScanResultInfo to a {@link ScanResultInfoParcelable}.
430          */
toStableParcelable()431         public ScanResultInfoParcelable toStableParcelable() {
432             final ScanResultInfoParcelable p = new ScanResultInfoParcelable();
433             p.ssid = mSsid;
434             p.bssid = mBssid;
435             p.informationElements = toParcelableArray(mInformationElements,
436                     InformationElement::toStableParcelable, InformationElementParcelable.class);
437             return p;
438         }
439 
440         /**
441          * Create an instance of {@link ScanResultInfo} based on the contents of the specified
442          * {@link ScanResultInfoParcelable}.
443          */
fromStableParcelable(ScanResultInfoParcelable p)444         public static ScanResultInfo fromStableParcelable(ScanResultInfoParcelable p) {
445             if (p == null) return null;
446             final List<InformationElement> ies = new ArrayList<InformationElement>();
447             ies.addAll(fromParcelableArray(p.informationElements,
448                     InformationElement::fromStableParcelable));
449             return new ScanResultInfo(p.ssid, p.bssid, ies);
450         }
451 
convertToByteArray(@onNull final ByteBuffer buffer)452         private static byte[] convertToByteArray(@NonNull final ByteBuffer buffer) {
453             final byte[] bytes = new byte[buffer.limit()];
454             final ByteBuffer copy = buffer.asReadOnlyBuffer();
455             try {
456                 copy.position(0);
457                 copy.get(bytes);
458             } catch (BufferUnderflowException e) {
459                 Log.wtf(TAG, "Buffer under flow exception should never happen.");
460             } finally {
461                 return bytes;
462             }
463         }
464     }
465 
466     public boolean mEnablePreconnection = false;
467     public boolean mUsingMultinetworkPolicyTracker = true;
468     public boolean mUsingIpReachabilityMonitor = true;
469     public int mRequestedPreDhcpActionMs;
470     public InitialConfiguration mInitialConfig;
471     public StaticIpConfiguration mStaticIpConfig;
472     public ApfCapabilities mApfCapabilities;
473     public int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
474     public int mIPv6AddrGenMode = IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
475     public Network mNetwork = null;
476     public String mDisplayName = null;
477     public ScanResultInfo mScanResultInfo;
478     public Layer2Information mLayer2Info;
479     public List<DhcpOption> mDhcpOptions;
480     public int mIPv4ProvisioningMode = PROV_IPV4_DHCP;
481     public int mIPv6ProvisioningMode = PROV_IPV6_SLAAC;
482 
ProvisioningConfiguration()483     public ProvisioningConfiguration() {} // used by Builder
484 
ProvisioningConfiguration(ProvisioningConfiguration other)485     public ProvisioningConfiguration(ProvisioningConfiguration other) {
486         mEnablePreconnection = other.mEnablePreconnection;
487         mUsingMultinetworkPolicyTracker = other.mUsingMultinetworkPolicyTracker;
488         mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
489         mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs;
490         mInitialConfig = InitialConfiguration.copy(other.mInitialConfig);
491         mStaticIpConfig = other.mStaticIpConfig == null
492                 ? null
493                 : new StaticIpConfiguration(other.mStaticIpConfig);
494         mApfCapabilities = other.mApfCapabilities;
495         mProvisioningTimeoutMs = other.mProvisioningTimeoutMs;
496         mIPv6AddrGenMode = other.mIPv6AddrGenMode;
497         mNetwork = other.mNetwork;
498         mDisplayName = other.mDisplayName;
499         mScanResultInfo = other.mScanResultInfo;
500         mLayer2Info = other.mLayer2Info;
501         mDhcpOptions = other.mDhcpOptions;
502         mIPv4ProvisioningMode = other.mIPv4ProvisioningMode;
503         mIPv6ProvisioningMode = other.mIPv6ProvisioningMode;
504     }
505 
506     /**
507      * Create a ProvisioningConfigurationParcelable from this ProvisioningConfiguration.
508      */
toStableParcelable()509     public ProvisioningConfigurationParcelable toStableParcelable() {
510         final ProvisioningConfigurationParcelable p = new ProvisioningConfigurationParcelable();
511         p.enableIPv4 = (mIPv4ProvisioningMode != PROV_IPV4_DISABLED);
512         p.ipv4ProvisioningMode = mIPv4ProvisioningMode;
513         p.enableIPv6 = (mIPv6ProvisioningMode != PROV_IPV6_DISABLED);
514         p.ipv6ProvisioningMode = mIPv6ProvisioningMode;
515         p.enablePreconnection = mEnablePreconnection;
516         p.usingMultinetworkPolicyTracker = mUsingMultinetworkPolicyTracker;
517         p.usingIpReachabilityMonitor = mUsingIpReachabilityMonitor;
518         p.requestedPreDhcpActionMs = mRequestedPreDhcpActionMs;
519         p.initialConfig = (mInitialConfig == null) ? null : mInitialConfig.toStableParcelable();
520         p.staticIpConfig = (mStaticIpConfig == null)
521                 ? null
522                 : new StaticIpConfiguration(mStaticIpConfig);
523         p.apfCapabilities = mApfCapabilities; // ApfCapabilities is immutable
524         p.provisioningTimeoutMs = mProvisioningTimeoutMs;
525         p.ipv6AddrGenMode = mIPv6AddrGenMode;
526         p.network = mNetwork;
527         p.displayName = mDisplayName;
528         p.scanResultInfo = (mScanResultInfo == null) ? null : mScanResultInfo.toStableParcelable();
529         p.layer2Info = (mLayer2Info == null) ? null : mLayer2Info.toStableParcelable();
530         p.options = (mDhcpOptions == null) ? null : new ArrayList<>(mDhcpOptions);
531         return p;
532     }
533 
534     /**
535      * Create a ProvisioningConfiguration from a ProvisioningConfigurationParcelable.
536      *
537      * @param p stable parcelable instance to be converted to a {@link ProvisioningConfiguration}.
538      * @param interfaceVersion IIpClientCallbacks interface version called by the remote peer,
539      *                         which is used to determine the appropriate parcelable members for
540      *                         backwards compatibility.
541      */
fromStableParcelable( @ullable ProvisioningConfigurationParcelable p, int interfaceVersion)542     public static ProvisioningConfiguration fromStableParcelable(
543             @Nullable ProvisioningConfigurationParcelable p, int interfaceVersion) {
544         if (p == null) return null;
545         final ProvisioningConfiguration config = new ProvisioningConfiguration();
546         config.mEnablePreconnection = p.enablePreconnection;
547         config.mUsingMultinetworkPolicyTracker = p.usingMultinetworkPolicyTracker;
548         config.mUsingIpReachabilityMonitor = p.usingIpReachabilityMonitor;
549         config.mRequestedPreDhcpActionMs = p.requestedPreDhcpActionMs;
550         config.mInitialConfig = InitialConfiguration.fromStableParcelable(p.initialConfig);
551         config.mStaticIpConfig = (p.staticIpConfig == null)
552                 ? null
553                 : new StaticIpConfiguration(p.staticIpConfig);
554         config.mApfCapabilities = p.apfCapabilities; // ApfCapabilities is immutable
555         config.mProvisioningTimeoutMs = p.provisioningTimeoutMs;
556         config.mIPv6AddrGenMode = p.ipv6AddrGenMode;
557         config.mNetwork = p.network;
558         config.mDisplayName = p.displayName;
559         config.mScanResultInfo = ScanResultInfo.fromStableParcelable(p.scanResultInfo);
560         config.mLayer2Info = Layer2Information.fromStableParcelable(p.layer2Info);
561         config.mDhcpOptions = (p.options == null) ? null : new ArrayList<>(p.options);
562         if (interfaceVersion < VERSION_ADDED_PROVISIONING_ENUM) {
563             config.mIPv4ProvisioningMode = p.enableIPv4 ? PROV_IPV4_DHCP : PROV_IPV4_DISABLED;
564             config.mIPv6ProvisioningMode = p.enableIPv6 ? PROV_IPV6_SLAAC : PROV_IPV6_DISABLED;
565         } else {
566             config.mIPv4ProvisioningMode = p.ipv4ProvisioningMode;
567             config.mIPv6ProvisioningMode = p.ipv6ProvisioningMode;
568         }
569         return config;
570     }
571 
572     @VisibleForTesting
ipv4ProvisioningModeToString(int mode)573     static String ipv4ProvisioningModeToString(int mode) {
574         switch (mode) {
575             case PROV_IPV4_DISABLED:
576                 return "disabled";
577             case PROV_IPV4_STATIC:
578                 return "static";
579             case PROV_IPV4_DHCP:
580                 return "dhcp";
581             default:
582                 return "unknown";
583         }
584     }
585 
586     @VisibleForTesting
ipv6ProvisioningModeToString(int mode)587     static String ipv6ProvisioningModeToString(int mode) {
588         switch (mode) {
589             case PROV_IPV6_DISABLED:
590                 return "disabled";
591             case PROV_IPV6_SLAAC:
592                 return "slaac";
593             case PROV_IPV6_LINKLOCAL:
594                 return "link-local";
595             default:
596                 return "unknown";
597         }
598     }
599 
600     @Override
toString()601     public String toString() {
602         final String ipv4ProvisioningMode = ipv4ProvisioningModeToString(mIPv4ProvisioningMode);
603         final String ipv6ProvisioningMode = ipv6ProvisioningModeToString(mIPv6ProvisioningMode);
604         return new StringJoiner(", ", getClass().getSimpleName() + "{", "}")
605                 .add("mEnablePreconnection: " + mEnablePreconnection)
606                 .add("mUsingMultinetworkPolicyTracker: " + mUsingMultinetworkPolicyTracker)
607                 .add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor)
608                 .add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs)
609                 .add("mInitialConfig: " + mInitialConfig)
610                 .add("mStaticIpConfig: " + mStaticIpConfig)
611                 .add("mApfCapabilities: " + mApfCapabilities)
612                 .add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs)
613                 .add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
614                 .add("mNetwork: " + mNetwork)
615                 .add("mDisplayName: " + mDisplayName)
616                 .add("mScanResultInfo: " + mScanResultInfo)
617                 .add("mLayer2Info: " + mLayer2Info)
618                 .add("mDhcpOptions: " + mDhcpOptions)
619                 .add("mIPv4ProvisioningMode: " + ipv4ProvisioningMode)
620                 .add("mIPv6ProvisioningMode: " + ipv6ProvisioningMode)
621                 .toString();
622     }
623 
624     // TODO: mark DhcpOption stable parcelable with @JavaDerive(equals=true, toString=true)
625     // and @JavaOnlyImmutable.
dhcpOptionEquals(@ullable DhcpOption obj1, @Nullable DhcpOption obj2)626     private static boolean dhcpOptionEquals(@Nullable DhcpOption obj1, @Nullable DhcpOption obj2) {
627         if (obj1 == obj2) return true;
628         if (obj1 == null || obj2 == null) return false;
629         return obj1.type == obj2.type && Arrays.equals(obj1.value, obj2.value);
630     }
631 
632     // TODO: use Objects.equals(List<DhcpOption>, List<DhcpOption>) method instead once
633     // auto-generated equals() method of stable parcelable is supported in mainline-prod.
dhcpOptionListEquals(@ullable List<DhcpOption> l1, @Nullable List<DhcpOption> l2)634     private static boolean dhcpOptionListEquals(@Nullable List<DhcpOption> l1,
635             @Nullable List<DhcpOption> l2) {
636         if (l1 == l2) return true;
637         if (l1 == null || l2 == null) return false;
638         if (l1.size() != l2.size()) return false;
639 
640         for (int i = 0; i < l1.size(); i++) {
641             if (!dhcpOptionEquals(l1.get(i), l2.get(i))) return false;
642         }
643         return true;
644     }
645 
646     @Override
equals(Object obj)647     public boolean equals(Object obj) {
648         if (!(obj instanceof ProvisioningConfiguration)) return false;
649         final ProvisioningConfiguration other = (ProvisioningConfiguration) obj;
650         return mEnablePreconnection == other.mEnablePreconnection
651                 && mUsingMultinetworkPolicyTracker == other.mUsingMultinetworkPolicyTracker
652                 && mUsingIpReachabilityMonitor == other.mUsingIpReachabilityMonitor
653                 && mRequestedPreDhcpActionMs == other.mRequestedPreDhcpActionMs
654                 && Objects.equals(mInitialConfig, other.mInitialConfig)
655                 && Objects.equals(mStaticIpConfig, other.mStaticIpConfig)
656                 && Objects.equals(mApfCapabilities, other.mApfCapabilities)
657                 && mProvisioningTimeoutMs == other.mProvisioningTimeoutMs
658                 && mIPv6AddrGenMode == other.mIPv6AddrGenMode
659                 && Objects.equals(mNetwork, other.mNetwork)
660                 && Objects.equals(mDisplayName, other.mDisplayName)
661                 && Objects.equals(mScanResultInfo, other.mScanResultInfo)
662                 && Objects.equals(mLayer2Info, other.mLayer2Info)
663                 && dhcpOptionListEquals(mDhcpOptions, other.mDhcpOptions)
664                 && mIPv4ProvisioningMode == other.mIPv4ProvisioningMode
665                 && mIPv6ProvisioningMode == other.mIPv6ProvisioningMode;
666     }
667 
isValid()668     public boolean isValid() {
669         return (mInitialConfig == null) || mInitialConfig.isValid();
670     }
671 }
672