• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.net;
18 
19 import android.annotation.IntDef;
20 import android.annotation.IntRange;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.SuppressLint;
24 import android.annotation.SystemApi;
25 import android.annotation.TestApi;
26 import android.compat.annotation.UnsupportedAppUsage;
27 import android.content.Context;
28 import android.os.Build;
29 import android.os.Bundle;
30 import android.os.ConditionVariable;
31 import android.os.Handler;
32 import android.os.Looper;
33 import android.os.Message;
34 import android.os.Process;
35 import android.os.RemoteException;
36 import android.telephony.data.EpsBearerQosSessionAttributes;
37 import android.telephony.data.NrQosSessionAttributes;
38 import android.util.Log;
39 
40 import com.android.internal.annotations.GuardedBy;
41 import com.android.internal.annotations.VisibleForTesting;
42 import com.android.net.module.util.FrameworkConnectivityStatsLog;
43 
44 import java.lang.annotation.Retention;
45 import java.lang.annotation.RetentionPolicy;
46 import java.time.Duration;
47 import java.util.ArrayList;
48 import java.util.List;
49 import java.util.Objects;
50 import java.util.concurrent.atomic.AtomicBoolean;
51 
52 /**
53  * A utility class for handling for communicating between bearer-specific
54  * code and ConnectivityService.
55  *
56  * An agent manages the life cycle of a network. A network starts its
57  * life cycle when {@link register} is called on NetworkAgent. The network
58  * is then connecting. When full L3 connectivity has been established,
59  * the agent should call {@link markConnected} to inform the system that
60  * this network is ready to use. When the network disconnects its life
61  * ends and the agent should call {@link unregister}, at which point the
62  * system will clean up and free resources.
63  * Any reconnection becomes a new logical network, so after a network
64  * is disconnected the agent cannot be used any more. Network providers
65  * should create a new NetworkAgent instance to handle new connections.
66  *
67  * A bearer may have more than one NetworkAgent if it can simultaneously
68  * support separate networks (IMS / Internet / MMS Apns on cellular, or
69  * perhaps connections with different SSID or P2P for Wi-Fi).
70  *
71  * This class supports methods to start and stop sending keepalive packets.
72  * Keepalive packets are typically sent at periodic intervals over a network
73  * with NAT when there is no other traffic to avoid the network forcefully
74  * closing the connection. NetworkAgents that manage technologies that
75  * have hardware support for keepalive should implement the related
76  * methods to save battery life. NetworkAgent that cannot get support
77  * without waking up the CPU should not, as this would be prohibitive in
78  * terms of battery - these agents should simply not override the related
79  * methods, which results in the implementation returning
80  * {@link SocketKeepalive.ERROR_UNSUPPORTED} as appropriate.
81  *
82  * Keepalive packets need to be sent at relatively frequent intervals
83  * (a few seconds to a few minutes). As the contents of keepalive packets
84  * depend on the current network status, hardware needs to be configured
85  * to send them and has a limited amount of memory to do so. The HAL
86  * formalizes this as slots that an implementation can configure to send
87  * the correct packets. Devices typically have a small number of slots
88  * per radio technology, and the specific number of slots for each
89  * technology is specified in configuration files.
90  * See {@link SocketKeepalive} for details.
91  *
92  * @hide
93  */
94 @SystemApi
95 public abstract class NetworkAgent {
96     /**
97      * The {@link Network} corresponding to this object.
98      */
99     @Nullable
100     private volatile Network mNetwork;
101 
102     // Null before the agent is registered
103     @Nullable
104     private volatile INetworkAgentRegistry mRegistry;
105 
106     private interface RegistryAction {
execute(@onNull INetworkAgentRegistry registry)107         void execute(@NonNull INetworkAgentRegistry registry) throws RemoteException;
108     }
109 
110     private final Handler mHandler;
111     private final String LOG_TAG;
112     private static final boolean DBG = true;
113     private static final boolean VDBG = false;
114     /** @hide */
115     @TestApi
116     public static final int MIN_LINGER_TIMER_MS = 2000;
117     private final ArrayList<RegistryAction> mPreConnectedQueue = new ArrayList<>();
118     private volatile long mLastBwRefreshTime = 0;
119     private static final long BW_REFRESH_MIN_WIN_MS = 500;
120 
121     private final boolean mQueueRemoved;
122 
123     private boolean mBandwidthUpdateScheduled = false;
124     private AtomicBoolean mBandwidthUpdatePending = new AtomicBoolean(false);
125     @NonNull
126     private NetworkInfo mNetworkInfo;
127     @NonNull
128     private final Object mRegisterLock = new Object();
129     // TODO : when ConnectivityFlags.QUEUE_NETWORK_AGENT_EVENTS_IN_SYSTEM_SERVER is
130     // not chickened out this is never read. Remove when retiring this flag.
131     private boolean mConnected = false;
132 
133     /** @hide */
134     @Retention(RetentionPolicy.SOURCE)
135     @IntDef(prefix = { "STATE_" }, value = {
136         STATE_CREATED,
137         STATE_REGISTERED,
138         STATE_UNREGISTERED
139     })
140     public @interface NetworkAgentState {}
141     private static final int STATE_CREATED = 0;
142     private static final int STATE_REGISTERED = 1;
143     private static final int STATE_UNREGISTERED = 2;
144     @GuardedBy("mRegisterLock")
145     private int mState = STATE_CREATED;
146 
147     /**
148      * The ID of the {@link NetworkProvider} that created this object, or
149      * {@link NetworkProvider#ID_NONE} if unknown.
150      * @hide
151      */
152     public final int providerId;
153 
154     // ConnectivityService parses message constants from itself and NetworkAgent with MessageUtils
155     // for debugging purposes, and crashes if some messages have the same values.
156     // TODO: have ConnectivityService store message names in different maps and remove this base
157     private static final int BASE = 200;
158 
159     /**
160      * Sent by ConnectivityService to the NetworkAgent to inform it of
161      * suspected connectivity problems on its network.  The NetworkAgent
162      * should take steps to verify and correct connectivity.
163      * @hide
164      */
165     public static final int CMD_SUSPECT_BAD = BASE;
166 
167     /**
168      * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to
169      * ConnectivityService to pass the current NetworkInfo (connection state).
170      * Sent when the NetworkInfo changes, mainly due to change of state.
171      * obj = NetworkInfo
172      * @hide
173      */
174     public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 1;
175 
176     /**
177      * Sent by the NetworkAgent to ConnectivityService to pass the current
178      * NetworkCapabilities.
179      * obj = NetworkCapabilities
180      * @hide
181      */
182     public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 2;
183 
184     /**
185      * Sent by the NetworkAgent to ConnectivityService to pass the current
186      * NetworkProperties.
187      * obj = NetworkProperties
188      * @hide
189      */
190     public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3;
191 
192     /**
193      * Centralize the place where base network score, and network score scaling, will be
194      * stored, so as we can consistently compare apple and oranges, or wifi, ethernet and LTE
195      * @hide
196      */
197     public static final int WIFI_BASE_SCORE = 60;
198 
199     /**
200      * Sent by the NetworkAgent to ConnectivityService to pass the current
201      * network score.
202      * arg1 = network score int
203      * @hide
204      */
205     public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4;
206 
207     /**
208      * Sent by the NetworkAgent to ConnectivityService to pass the current
209      * list of underlying networks.
210      * obj = array of Network objects
211      * @hide
212      */
213     public static final int EVENT_UNDERLYING_NETWORKS_CHANGED = BASE + 5;
214 
215     /**
216      * Sent by the NetworkAgent to ConnectivityService to pass the current value of the teardown
217      * delay.
218      * arg1 = teardown delay in milliseconds
219      * @hide
220      */
221     public static final int EVENT_TEARDOWN_DELAY_CHANGED = BASE + 6;
222 
223     /**
224      * The maximum value for the teardown delay, in milliseconds.
225      * @hide
226      */
227     public static final int MAX_TEARDOWN_DELAY_MS = 5000;
228 
229     /**
230      * Sent by ConnectivityService to the NetworkAgent to inform the agent of the
231      * networks status - whether we could use the network or could not, due to
232      * either a bad network configuration (no internet link) or captive portal.
233      *
234      * arg1 = either {@code VALID_NETWORK} or {@code INVALID_NETWORK}
235      * obj = Bundle containing map from {@code REDIRECT_URL_KEY} to {@code String}
236      *       representing URL that Internet probe was redirect to, if it was redirected,
237      *       or mapping to {@code null} otherwise.
238      * @hide
239      */
240     public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7;
241 
242     /**
243      * Network validation suceeded.
244      * Corresponds to {@link NetworkCapabilities.NET_CAPABILITY_VALIDATED}.
245      */
246     public static final int VALIDATION_STATUS_VALID = 1;
247 
248     /**
249      * Network validation was attempted and failed. This may be received more than once as
250      * subsequent validation attempts are made.
251      */
252     public static final int VALIDATION_STATUS_NOT_VALID = 2;
253 
254     /** @hide */
255     @Retention(RetentionPolicy.SOURCE)
256     @IntDef(prefix = { "VALIDATION_STATUS_" }, value = {
257             VALIDATION_STATUS_VALID,
258             VALIDATION_STATUS_NOT_VALID
259     })
260     public @interface ValidationStatus {}
261 
262     // TODO: remove.
263     /** @hide */
264     public static final int VALID_NETWORK = 1;
265     /** @hide */
266     public static final int INVALID_NETWORK = 2;
267 
268     /**
269      * The key for the redirect URL in the Bundle argument of {@code CMD_REPORT_NETWORK_STATUS}.
270      * @hide
271      */
272     public static final String REDIRECT_URL_KEY = "redirect URL";
273 
274     /**
275      * Sent by the NetworkAgent to ConnectivityService to indicate this network was
276      * explicitly selected.  This should be sent before the NetworkInfo is marked
277      * CONNECTED so it can be given special treatment at that time.
278      *
279      * obj = boolean indicating whether to use this network even if unvalidated
280      * @hide
281      */
282     public static final int EVENT_SET_EXPLICITLY_SELECTED = BASE + 8;
283 
284     /**
285      * Sent by ConnectivityService to the NetworkAgent to inform the agent of
286      * whether the network should in the future be used even if not validated.
287      * This decision is made by the user, but it is the network transport's
288      * responsibility to remember it.
289      *
290      * arg1 = 1 if true, 0 if false
291      * @hide
292      */
293     public static final int CMD_SAVE_ACCEPT_UNVALIDATED = BASE + 9;
294 
295     /**
296      * Sent by ConnectivityService to the NetworkAgent to inform the agent to pull
297      * the underlying network connection for updated bandwidth information.
298      * @hide
299      */
300     public static final int CMD_REQUEST_BANDWIDTH_UPDATE = BASE + 10;
301 
302     /**
303      * Sent by ConnectivityService to the NetworkAgent to request that the specified packet be sent
304      * periodically on the given interval.
305      *
306      *   arg1 = the hardware slot number of the keepalive to start
307      *   arg2 = interval in seconds
308      *   obj = KeepalivePacketData object describing the data to be sent
309      *
310      * @hide
311      */
312     public static final int CMD_START_SOCKET_KEEPALIVE = BASE + 11;
313 
314     /**
315      * Requests that the specified keepalive packet be stopped.
316      *
317      * arg1 = unused
318      * arg2 = error code (SUCCESS)
319      * obj = callback to identify the keepalive
320      *
321      * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics.
322      * @hide
323      */
324     public static final int CMD_STOP_SOCKET_KEEPALIVE = BASE + 12;
325 
326     /**
327      * Sent by the NetworkAgent to ConnectivityService to provide status on a socket keepalive
328      * request. This may either be the reply to a CMD_START_SOCKET_KEEPALIVE, or an asynchronous
329      * error notification.
330      *
331      * This is also sent by KeepaliveTracker to the app's {@link SocketKeepalive},
332      * so that the app's {@link SocketKeepalive.Callback} methods can be called.
333      *
334      * arg1 = hardware slot number of the keepalive
335      * arg2 = error code
336      * @hide
337      */
338     public static final int EVENT_SOCKET_KEEPALIVE = BASE + 13;
339 
340     /**
341      * Sent by ConnectivityService to inform this network transport of signal strength thresholds
342      * that when crossed should trigger a system wakeup and a NetworkCapabilities update.
343      *
344      *   obj = int[] describing signal strength thresholds.
345      * @hide
346      */
347     public static final int CMD_SET_SIGNAL_STRENGTH_THRESHOLDS = BASE + 14;
348 
349     /**
350      * Sent by ConnectivityService to the NeworkAgent to inform the agent to avoid
351      * automatically reconnecting to this network (e.g. via autojoin).  Happens
352      * when user selects "No" option on the "Stay connected?" dialog box.
353      * @hide
354      */
355     public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15;
356 
357     /**
358      * Sent by the KeepaliveTracker to NetworkAgent to add a packet filter.
359      *
360      * For TCP keepalive offloads, keepalive packets are sent by the firmware. However, because the
361      * remote site will send ACK packets in response to the keepalive packets, the firmware also
362      * needs to be configured to properly filter the ACKs to prevent the system from waking up.
363      * This does not happen with UDP, so this message is TCP-specific.
364      * arg1 = hardware slot number of the keepalive to filter for.
365      * obj = the keepalive packet to send repeatedly.
366      * @hide
367      */
368     public static final int CMD_ADD_KEEPALIVE_PACKET_FILTER = BASE + 16;
369 
370     /**
371      * Sent by the KeepaliveTracker to NetworkAgent to remove a packet filter. See
372      * {@link #CMD_ADD_KEEPALIVE_PACKET_FILTER}.
373      * arg1 = hardware slot number of the keepalive packet filter to remove.
374      * @hide
375      */
376     public static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER = BASE + 17;
377 
378     /**
379      * Sent by ConnectivityService to the NetworkAgent to complete the bidirectional connection.
380      * obj = INetworkAgentRegistry
381      */
382     private static final int EVENT_AGENT_CONNECTED = BASE + 18;
383 
384     /**
385      * Sent by ConnectivityService to the NetworkAgent to inform the agent that it was disconnected.
386      */
387     private static final int EVENT_AGENT_DISCONNECTED = BASE + 19;
388 
389     /**
390      * Sent by QosCallbackTracker to {@link NetworkAgent} to register a new filter with
391      * callback.
392      *
393      * arg1 = QoS agent callback ID
394      * obj = {@link QosFilter}
395      * @hide
396      */
397     public static final int CMD_REGISTER_QOS_CALLBACK = BASE + 20;
398 
399     /**
400      * Sent by QosCallbackTracker to {@link NetworkAgent} to unregister a callback.
401      *
402      * arg1 = QoS agent callback ID
403      * @hide
404      */
405     public static final int CMD_UNREGISTER_QOS_CALLBACK = BASE + 21;
406 
407     /**
408      * Sent by ConnectivityService to {@link NetworkAgent} to inform the agent that its native
409      * network was created and the Network object is now valid.
410      *
411      * @hide
412      */
413     public static final int CMD_NETWORK_CREATED = BASE + 22;
414 
415     /**
416      * Sent by ConnectivityService to {@link NetworkAgent} to inform the agent that its native
417      * network was destroyed.
418      *
419      * @hide
420      */
421     public static final int CMD_NETWORK_DESTROYED = BASE + 23;
422 
423     /**
424      * Sent by the NetworkAgent to ConnectivityService to set the linger duration for this network
425      * agent.
426      * arg1 = the linger duration, represents by {@link Duration}.
427      *
428      * @hide
429      */
430     public static final int EVENT_LINGER_DURATION_CHANGED = BASE + 24;
431 
432     /**
433      * Sent by the NetworkAgent to ConnectivityService to set add a DSCP policy.
434      *
435      * @hide
436      */
437     public static final int EVENT_ADD_DSCP_POLICY = BASE + 25;
438 
439     /**
440      * Sent by the NetworkAgent to ConnectivityService to set remove a DSCP policy.
441      *
442      * @hide
443      */
444     public static final int EVENT_REMOVE_DSCP_POLICY = BASE + 26;
445 
446     /**
447      * Sent by the NetworkAgent to ConnectivityService to remove all DSCP policies.
448      *
449      * @hide
450      */
451     public static final int EVENT_REMOVE_ALL_DSCP_POLICIES = BASE + 27;
452 
453     /**
454      * Sent by ConnectivityService to {@link NetworkAgent} to inform the agent of an updated
455      * status for a DSCP policy.
456      *
457      * @hide
458      */
459     public static final int CMD_DSCP_POLICY_STATUS = BASE + 28;
460 
461     /**
462      * Sent by the NetworkAgent to ConnectivityService to notify that this network is expected to be
463      * replaced within the specified time by a similar network.
464      * arg1 = timeout in milliseconds
465      * @hide
466      */
467     public static final int EVENT_UNREGISTER_AFTER_REPLACEMENT = BASE + 29;
468 
469     /**
470      * Sent by the NetworkAgent to ConnectivityService to pass the new value of the local
471      * network agent config.
472      * obj = {@code Pair<NetworkAgentInfo, LocalNetworkConfig>}
473      * @hide
474      */
475     public static final int EVENT_LOCAL_NETWORK_CONFIG_CHANGED = BASE + 30;
476 
477     /**
478      * DSCP policy was successfully added.
479      */
480     public static final int DSCP_POLICY_STATUS_SUCCESS = 0;
481 
482     /**
483      * DSCP policy was rejected for any reason besides invalid classifier or insufficient resources.
484      */
485     public static final int DSCP_POLICY_STATUS_REQUEST_DECLINED = 1;
486 
487     /**
488      * Requested DSCP policy contained a classifier which is not supported.
489      */
490     public static final int DSCP_POLICY_STATUS_REQUESTED_CLASSIFIER_NOT_SUPPORTED = 2;
491 
492     /**
493      * Requested DSCP policy was not added due to insufficient processing resources.
494      */
495     // TODO: should this error case be supported?
496     public static final int DSCP_POLICY_STATUS_INSUFFICIENT_PROCESSING_RESOURCES = 3;
497 
498     /**
499      * DSCP policy was deleted.
500      */
501     public static final int DSCP_POLICY_STATUS_DELETED = 4;
502 
503     /**
504      * DSCP policy was not found during deletion.
505      */
506     public static final int DSCP_POLICY_STATUS_POLICY_NOT_FOUND = 5;
507 
508     /** @hide */
509     @IntDef(prefix = "DSCP_POLICY_STATUS_", value = {
510         DSCP_POLICY_STATUS_SUCCESS,
511         DSCP_POLICY_STATUS_REQUEST_DECLINED,
512         DSCP_POLICY_STATUS_REQUESTED_CLASSIFIER_NOT_SUPPORTED,
513         DSCP_POLICY_STATUS_INSUFFICIENT_PROCESSING_RESOURCES,
514         DSCP_POLICY_STATUS_DELETED
515     })
516     @Retention(RetentionPolicy.SOURCE)
517     public @interface DscpPolicyStatus {}
518 
getLegacyNetworkInfo(final NetworkAgentConfig config)519     private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
520         final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacySubType,
521                 config.legacyTypeName, config.legacySubTypeName);
522         ni.setIsAvailable(true);
523         ni.setDetailedState(NetworkInfo.DetailedState.CONNECTING, null /* reason */,
524                 config.getLegacyExtraInfo());
525         return ni;
526     }
527 
528     /**
529      * Returns whether a given ConnectivityManager feature is enabled.
530      *
531      * Tests can override this.
532      * @hide
533      */
534     @VisibleForTesting
isFeatureEnabled(@onNull Context context, @ConnectivityManager.ConnectivityManagerFeature long feature)535     public boolean isFeatureEnabled(@NonNull Context context,
536             @ConnectivityManager.ConnectivityManagerFeature long feature) {
537         return context.getSystemService(ConnectivityManager.class).isFeatureEnabled(feature);
538     }
539 
540     // Temporary backward compatibility constructor
NetworkAgent(@onNull Context context, @NonNull Looper looper, @NonNull String logTag, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score, @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider)541     public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag,
542             @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score,
543             @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider) {
544         this(context, looper, logTag, nc, lp,
545                 new NetworkScore.Builder().setLegacyInt(score).build(), config, provider);
546     }
547 
548     /**
549      * Create a new network agent.
550      * @param context a {@link Context} to get system services from.
551      * @param looper the {@link Looper} on which to invoke the callbacks.
552      * @param logTag the tag for logs
553      * @param nc the initial {@link NetworkCapabilities} of this network. Update with
554      *           sendNetworkCapabilities.
555      * @param lp the initial {@link LinkProperties} of this network. Update with sendLinkProperties.
556      * @param score the initial score of this network. Update with sendNetworkScore.
557      * @param config an immutable {@link NetworkAgentConfig} for this agent.
558      * @param provider the {@link NetworkProvider} managing this agent.
559      */
NetworkAgent(@onNull Context context, @NonNull Looper looper, @NonNull String logTag, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, @NonNull NetworkScore score, @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider)560     public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag,
561             @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp,
562             @NonNull NetworkScore score, @NonNull NetworkAgentConfig config,
563             @Nullable NetworkProvider provider) {
564         this(context, looper, logTag, nc, lp, null /* localNetworkConfig */, score, config,
565                 provider);
566     }
567 
568     /**
569      * Create a new network agent.
570      * @param context a {@link Context} to get system services from.
571      * @param looper the {@link Looper} on which to invoke the callbacks.
572      * @param logTag the tag for logs
573      * @param nc the initial {@link NetworkCapabilities} of this network. Update with
574      *           sendNetworkCapabilities.
575      * @param lp the initial {@link LinkProperties} of this network. Update with sendLinkProperties.
576      * @param localNetworkConfig the initial {@link LocalNetworkConfig} of this
577      *                                  network. Update with sendLocalNetworkConfig. Must be
578      *                                  non-null iff the nc have NET_CAPABILITY_LOCAL_NETWORK.
579      * @param score the initial score of this network. Update with sendNetworkScore.
580      * @param config an immutable {@link NetworkAgentConfig} for this agent.
581      * @param provider the {@link NetworkProvider} managing this agent.
582      * @hide
583      */
584     // TODO : expose
NetworkAgent(@onNull Context context, @NonNull Looper looper, @NonNull String logTag, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, @Nullable LocalNetworkConfig localNetworkConfig, @NonNull NetworkScore score, @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider)585     public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag,
586             @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp,
587             @Nullable LocalNetworkConfig localNetworkConfig, @NonNull NetworkScore score,
588             @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider) {
589         this(looper, context, logTag, nc, lp, localNetworkConfig, score, config,
590                 provider == null ? NetworkProvider.ID_NONE : provider.getProviderId(),
591                 getLegacyNetworkInfo(config));
592     }
593 
594     private static class InitialConfiguration {
595         @NonNull public final Context context;
596         @NonNull public final NetworkCapabilities capabilities;
597         @NonNull public final LinkProperties properties;
598         @NonNull public final NetworkScore score;
599         @NonNull public final NetworkAgentConfig config;
600         @NonNull public final NetworkInfo info;
601         @Nullable public final LocalNetworkConfig localNetworkConfig;
InitialConfiguration(@onNull Context context, @NonNull NetworkCapabilities capabilities, @NonNull LinkProperties properties, @Nullable LocalNetworkConfig localNetworkConfig, @NonNull NetworkScore score, @NonNull NetworkAgentConfig config, @NonNull NetworkInfo info)602         InitialConfiguration(@NonNull Context context, @NonNull NetworkCapabilities capabilities,
603                 @NonNull LinkProperties properties,
604                 @Nullable LocalNetworkConfig localNetworkConfig, @NonNull NetworkScore score,
605                 @NonNull NetworkAgentConfig config, @NonNull NetworkInfo info) {
606             this.context = context;
607             this.capabilities = capabilities;
608             this.properties = properties;
609             this.score = score;
610             this.config = config;
611             this.info = info;
612             this.localNetworkConfig = localNetworkConfig;
613         }
614     }
615     private volatile InitialConfiguration mInitialConfiguration;
616 
NetworkAgent(@onNull Looper looper, @NonNull Context context, @NonNull String logTag, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, @Nullable LocalNetworkConfig localNetworkConfig, @NonNull NetworkScore score, @NonNull NetworkAgentConfig config, int providerId, @NonNull NetworkInfo ni)617     private NetworkAgent(@NonNull Looper looper, @NonNull Context context, @NonNull String logTag,
618             @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp,
619             @Nullable LocalNetworkConfig localNetworkConfig, @NonNull NetworkScore score,
620             @NonNull NetworkAgentConfig config, int providerId, @NonNull NetworkInfo ni) {
621         mHandler = new NetworkAgentHandler(looper);
622         // If the feature is enabled, then events are queued in the system
623         // server, and it's removed from this NetworkAgent.
624         mQueueRemoved = isFeatureEnabled(context,
625                 ConnectivityManager.FEATURE_QUEUE_NETWORK_AGENT_EVENTS_IN_SYSTEM_SERVER);
626         LOG_TAG = logTag;
627         mNetworkInfo = new NetworkInfo(ni);
628         this.providerId = providerId;
629         if (ni == null || nc == null || lp == null) {
630             throw new IllegalArgumentException();
631         }
632 
633         mInitialConfiguration = new InitialConfiguration(context,
634                 new NetworkCapabilities(nc, NetworkCapabilities.REDACT_NONE),
635                 new LinkProperties(lp), localNetworkConfig, score, config, ni);
636     }
637 
638     private class NetworkAgentHandler extends Handler {
NetworkAgentHandler(Looper looper)639         NetworkAgentHandler(Looper looper) {
640             super(looper);
641         }
642 
643         @Override
handleMessage(Message msg)644         public void handleMessage(Message msg) {
645             switch (msg.what) {
646                 case EVENT_AGENT_CONNECTED: {
647                     if (mQueueRemoved) {
648                         // No handling. This message is legacy from a time where the
649                         // agent had to wait until the registry was sent to it, which
650                         // would only happen after the corresponding NetworkMonitor
651                         // was created.
652                         mConnected = true; // never read, but mConnected = false would be confusing
653                     } else {
654                         // Feature chickened out, keep the old queueing behavior
655                         synchronized (mRegisterLock) {
656                             if (mConnected) {
657                                 log("Received new connection while already connected!");
658                             } else {
659                                 if (VDBG) log("NetworkAgent fully connected");
660                                 for (RegistryAction a : mPreConnectedQueue) {
661                                     try {
662                                         a.execute(mRegistry);
663                                     } catch (RemoteException e) {
664                                         Log.wtf(LOG_TAG, "Communication error with registry", e);
665                                         // Fall through
666                                     }
667                                 }
668                                 mPreConnectedQueue.clear();
669                             }
670                             mConnected = true;
671                         }
672                     }
673                     break;
674                 }
675                 case EVENT_AGENT_DISCONNECTED: {
676                     if (DBG) log("NetworkAgent channel lost");
677                     // let the client know CS is done with us.
678                     onNetworkUnwanted();
679                     synchronized (mRegisterLock) {
680                         mState = STATE_UNREGISTERED;
681                         mConnected = false;
682                     }
683                     break;
684                 }
685                 case CMD_SUSPECT_BAD: {
686                     log("Unhandled Message " + msg);
687                     break;
688                 }
689                 case CMD_REQUEST_BANDWIDTH_UPDATE: {
690                     long currentTimeMs = System.currentTimeMillis();
691                     if (VDBG) {
692                         log("CMD_REQUEST_BANDWIDTH_UPDATE request received.");
693                     }
694                     if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) {
695                         mBandwidthUpdateScheduled = false;
696                         if (!mBandwidthUpdatePending.getAndSet(true)) {
697                             onBandwidthUpdateRequested();
698                         }
699                     } else {
700                         // deliver the request at a later time rather than discard it completely.
701                         if (!mBandwidthUpdateScheduled) {
702                             long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS
703                                     - currentTimeMs + 1;
704                             mBandwidthUpdateScheduled = sendEmptyMessageDelayed(
705                                     CMD_REQUEST_BANDWIDTH_UPDATE, waitTime);
706                         }
707                     }
708                     break;
709                 }
710                 case CMD_REPORT_NETWORK_STATUS: {
711                     String redirectUrl = ((Bundle) msg.obj).getString(REDIRECT_URL_KEY);
712                     if (VDBG) {
713                         log("CMD_REPORT_NETWORK_STATUS("
714                                 + (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ")
715                                 + redirectUrl);
716                     }
717                     Uri uri = null;
718                     try {
719                         if (null != redirectUrl) {
720                             uri = Uri.parse(redirectUrl);
721                         }
722                     } catch (Exception e) {
723                         Log.wtf(LOG_TAG, "Surprising URI : " + redirectUrl, e);
724                     }
725                     onValidationStatus(msg.arg1 /* status */, uri);
726                     break;
727                 }
728                 case CMD_SAVE_ACCEPT_UNVALIDATED: {
729                     onSaveAcceptUnvalidated(msg.arg1 != 0);
730                     break;
731                 }
732                 case CMD_START_SOCKET_KEEPALIVE: {
733                     onStartSocketKeepalive(msg.arg1 /* slot */,
734                             Duration.ofSeconds(msg.arg2) /* interval */,
735                             (KeepalivePacketData) msg.obj /* packet */);
736                     break;
737                 }
738                 case CMD_STOP_SOCKET_KEEPALIVE: {
739                     onStopSocketKeepalive(msg.arg1 /* slot */);
740                     break;
741                 }
742 
743                 case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: {
744                     onSignalStrengthThresholdsUpdated((int[]) msg.obj);
745                     break;
746                 }
747                 case CMD_PREVENT_AUTOMATIC_RECONNECT: {
748                     onAutomaticReconnectDisabled();
749                     break;
750                 }
751                 case CMD_ADD_KEEPALIVE_PACKET_FILTER: {
752                     onAddKeepalivePacketFilter(msg.arg1 /* slot */,
753                             (KeepalivePacketData) msg.obj /* packet */);
754                     break;
755                 }
756                 case CMD_REMOVE_KEEPALIVE_PACKET_FILTER: {
757                     onRemoveKeepalivePacketFilter(msg.arg1 /* slot */);
758                     break;
759                 }
760                 case CMD_REGISTER_QOS_CALLBACK: {
761                     onQosCallbackRegistered(
762                             msg.arg1 /* QoS callback id */,
763                             (QosFilter) msg.obj /* QoS filter */);
764                     break;
765                 }
766                 case CMD_UNREGISTER_QOS_CALLBACK: {
767                     onQosCallbackUnregistered(
768                             msg.arg1 /* QoS callback id */);
769                     break;
770                 }
771                 case CMD_NETWORK_CREATED: {
772                     onNetworkCreated();
773                     break;
774                 }
775                 case CMD_NETWORK_DESTROYED: {
776                     onNetworkDestroyed();
777                     break;
778                 }
779                 case CMD_DSCP_POLICY_STATUS: {
780                     onDscpPolicyStatusUpdated(
781                             msg.arg1 /* Policy ID */,
782                             msg.arg2 /* DSCP Policy Status */);
783                     break;
784                 }
785             }
786         }
787     }
788 
789     /**
790      * Register this network agent with ConnectivityService.
791      *
792      * This method can only be called once per network agent.
793      *
794      * @return the Network associated with this network agent (which can also be obtained later
795      *         by calling getNetwork() on this agent).
796      * @throws IllegalStateException thrown by the system server if this network agent is
797      *         already registered.
798      */
799     @NonNull
register()800     public Network register() {
801         if (VDBG) log("Registering NetworkAgent");
802         synchronized (mRegisterLock) {
803             if (mQueueRemoved) {
804                 switch (mState) {
805                     case STATE_REGISTERED:
806                         throw new IllegalStateException("Agent already registered");
807                     case STATE_UNREGISTERED:
808                         throw new IllegalStateException("Agent already unregistered");
809                     default: // CREATED, this is the normal case
810                 }
811             } else {
812                 // Feature is chickened out, do the old processing
813                 if (mNetwork != null) {
814                     throw new IllegalStateException("Agent already registered");
815                 }
816             }
817             final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context
818                     .getSystemService(Context.CONNECTIVITY_SERVICE);
819             final NetworkAndAgentRegistryParcelable result;
820             if (mInitialConfiguration.localNetworkConfig == null) {
821                 // Call registerNetworkAgent without localNetworkConfig argument to pass
822                 // android.net.cts.NetworkAgentTest#testAgentStartsInConnecting in old cts
823                 result = cm.registerNetworkAgent(new NetworkAgentBinder(mHandler),
824                         new NetworkInfo(mInitialConfiguration.info),
825                         mInitialConfiguration.properties, mInitialConfiguration.capabilities,
826                         mInitialConfiguration.score, mInitialConfiguration.config, providerId);
827             } else {
828                 result = cm.registerNetworkAgent(new NetworkAgentBinder(mHandler),
829                         new NetworkInfo(mInitialConfiguration.info),
830                         mInitialConfiguration.properties, mInitialConfiguration.capabilities,
831                         mInitialConfiguration.localNetworkConfig, mInitialConfiguration.score,
832                         mInitialConfiguration.config, providerId);
833             }
834             if (null == result && Process.isApplicationUid(Process.myUid())) {
835                 // Let it slide in tests to allow mocking, since NetworkAndAgentRegistryParcelable
836                 // is not public and can't be instantiated by CTS. The danger here is that if
837                 // this happens in production for some reason the code will crash later instead
838                 // of here. If this is a system app, it will still crash as expected.
839                 Log.e(LOG_TAG, "registerNetworkAgent returned null. This agent will not work. "
840                         + "Is ConnectivityManager a mock ?");
841             } else {
842                 mNetwork = result.network;
843                 mRegistry = result.registry;
844                 mState = STATE_REGISTERED;
845             }
846             mInitialConfiguration = null; // All this memory can now be GC'd
847         }
848         return mNetwork;
849     }
850 
851     private static class NetworkAgentBinder extends INetworkAgent.Stub {
852         private static final String LOG_TAG = NetworkAgentBinder.class.getSimpleName();
853 
854         private final Handler mHandler;
855 
NetworkAgentBinder(Handler handler)856         private NetworkAgentBinder(Handler handler) {
857             mHandler = handler;
858         }
859 
860         @Override
onRegistered()861         public void onRegistered() {
862             mHandler.sendMessage(mHandler.obtainMessage(EVENT_AGENT_CONNECTED));
863         }
864 
865         @Override
onDisconnected()866         public void onDisconnected() {
867             mHandler.sendMessage(mHandler.obtainMessage(EVENT_AGENT_DISCONNECTED));
868         }
869 
870         @Override
onBandwidthUpdateRequested()871         public void onBandwidthUpdateRequested() {
872             mHandler.sendMessage(mHandler.obtainMessage(CMD_REQUEST_BANDWIDTH_UPDATE));
873         }
874 
875         @Override
onValidationStatusChanged( int validationStatus, @Nullable String captivePortalUrl)876         public void onValidationStatusChanged(
877                 int validationStatus, @Nullable String captivePortalUrl) {
878             // TODO: consider using a parcelable as argument when the interface is structured
879             Bundle redirectUrlBundle = new Bundle();
880             redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, captivePortalUrl);
881             mHandler.sendMessage(mHandler.obtainMessage(CMD_REPORT_NETWORK_STATUS,
882                     validationStatus, 0, redirectUrlBundle));
883         }
884 
885         @Override
onSaveAcceptUnvalidated(boolean acceptUnvalidated)886         public void onSaveAcceptUnvalidated(boolean acceptUnvalidated) {
887             mHandler.sendMessage(mHandler.obtainMessage(CMD_SAVE_ACCEPT_UNVALIDATED,
888                     acceptUnvalidated ? 1 : 0, 0));
889         }
890 
891         @Override
onStartNattSocketKeepalive(int slot, int intervalDurationMs, @NonNull NattKeepalivePacketData packetData)892         public void onStartNattSocketKeepalive(int slot, int intervalDurationMs,
893                 @NonNull NattKeepalivePacketData packetData) {
894             mHandler.sendMessage(mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE,
895                     slot, intervalDurationMs, packetData));
896         }
897 
898         @Override
onStartTcpSocketKeepalive(int slot, int intervalDurationMs, @NonNull TcpKeepalivePacketData packetData)899         public void onStartTcpSocketKeepalive(int slot, int intervalDurationMs,
900                 @NonNull TcpKeepalivePacketData packetData) {
901             mHandler.sendMessage(mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE,
902                     slot, intervalDurationMs, packetData));
903         }
904 
905         @Override
onStopSocketKeepalive(int slot)906         public void onStopSocketKeepalive(int slot) {
907             mHandler.sendMessage(mHandler.obtainMessage(CMD_STOP_SOCKET_KEEPALIVE, slot, 0));
908         }
909 
910         @Override
onSignalStrengthThresholdsUpdated(@onNull int[] thresholds)911         public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) {
912             mHandler.sendMessage(mHandler.obtainMessage(
913                     CMD_SET_SIGNAL_STRENGTH_THRESHOLDS, thresholds));
914         }
915 
916         @Override
onPreventAutomaticReconnect()917         public void onPreventAutomaticReconnect() {
918             mHandler.sendMessage(mHandler.obtainMessage(CMD_PREVENT_AUTOMATIC_RECONNECT));
919         }
920 
921         @Override
onAddNattKeepalivePacketFilter(int slot, @NonNull NattKeepalivePacketData packetData)922         public void onAddNattKeepalivePacketFilter(int slot,
923                 @NonNull NattKeepalivePacketData packetData) {
924             mHandler.sendMessage(mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER,
925                     slot, 0, packetData));
926         }
927 
928         @Override
onAddTcpKeepalivePacketFilter(int slot, @NonNull TcpKeepalivePacketData packetData)929         public void onAddTcpKeepalivePacketFilter(int slot,
930                 @NonNull TcpKeepalivePacketData packetData) {
931             mHandler.sendMessage(mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER,
932                     slot, 0, packetData));
933         }
934 
935         @Override
onRemoveKeepalivePacketFilter(int slot)936         public void onRemoveKeepalivePacketFilter(int slot) {
937             mHandler.sendMessage(mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER,
938                     slot, 0));
939         }
940 
941         @Override
onQosFilterCallbackRegistered(final int qosCallbackId, final QosFilterParcelable qosFilterParcelable)942         public void onQosFilterCallbackRegistered(final int qosCallbackId,
943                 final QosFilterParcelable qosFilterParcelable) {
944             if (qosFilterParcelable.getQosFilter() != null) {
945                 mHandler.sendMessage(
946                         mHandler.obtainMessage(CMD_REGISTER_QOS_CALLBACK, qosCallbackId, 0,
947                                 qosFilterParcelable.getQosFilter()));
948                 return;
949             }
950 
951             Log.wtf(LOG_TAG, "onQosFilterCallbackRegistered: qos filter is null.");
952         }
953 
954         @Override
onQosCallbackUnregistered(final int qosCallbackId)955         public void onQosCallbackUnregistered(final int qosCallbackId) {
956             mHandler.sendMessage(mHandler.obtainMessage(
957                     CMD_UNREGISTER_QOS_CALLBACK, qosCallbackId, 0, null));
958         }
959 
960         @Override
onNetworkCreated()961         public void onNetworkCreated() {
962             mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_CREATED));
963         }
964 
965         @Override
onNetworkDestroyed()966         public void onNetworkDestroyed() {
967             mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_DESTROYED));
968         }
969 
970         @Override
onDscpPolicyStatusUpdated(final int policyId, @DscpPolicyStatus final int status)971         public void onDscpPolicyStatusUpdated(final int policyId,
972                 @DscpPolicyStatus final int status) {
973             mHandler.sendMessage(mHandler.obtainMessage(
974                     CMD_DSCP_POLICY_STATUS, policyId, status));
975         }
976     }
977 
978     /**
979      * Register this network agent with a testing harness.
980      *
981      * The returned Messenger sends messages to the Handler. This allows a test to send
982      * this object {@code CMD_*} messages as if they came from ConnectivityService, which
983      * is useful for testing the behavior.
984      *
985      * @hide
986      */
registerForTest(final Network network, final INetworkAgentRegistry registry)987     public INetworkAgent registerForTest(final Network network,
988             final INetworkAgentRegistry registry) {
989         log("Registering NetworkAgent for test");
990         synchronized (mRegisterLock) {
991             mNetwork = network;
992             mInitialConfiguration = null;
993             mRegistry = registry;
994             mState = STATE_REGISTERED;
995         }
996         return new NetworkAgentBinder(mHandler);
997     }
998 
999     /**
1000      * Waits for the handler to be idle.
1001      * This is useful for testing, and has smaller scope than an accessor to mHandler.
1002      * TODO : move the implementation in common library with the tests
1003      * @hide
1004      */
1005     @VisibleForTesting
waitForIdle(final long timeoutMs)1006     public boolean waitForIdle(final long timeoutMs) {
1007         final ConditionVariable cv = new ConditionVariable(false);
1008         mHandler.post(cv::open);
1009         return cv.block(timeoutMs);
1010     }
1011 
1012     /**
1013      * @return The Network associated with this agent, or null if it's not registered yet.
1014      */
1015     @Nullable
getNetwork()1016     public Network getNetwork() {
1017         return mNetwork;
1018     }
1019 
logTerribleErrorMessageBeforeConnect()1020     private void logTerribleErrorMessageBeforeConnect() {
1021         FrameworkConnectivityStatsLog.write(
1022                 FrameworkConnectivityStatsLog.CORE_NETWORKING_TERRIBLE_ERROR_OCCURRED,
1023                 FrameworkConnectivityStatsLog.CORE_NETWORKING_TERRIBLE_ERROR_OCCURRED__ERROR_TYPE__TYPE_MESSAGE_QUEUED_BEFORE_CONNECT
1024         );
1025     }
1026 
send(@onNull RegistryAction action)1027     private void send(@NonNull RegistryAction action) {
1028         synchronized (mRegisterLock) {
1029             if (mQueueRemoved) {
1030                 if (mState <= STATE_CREATED) {
1031                     // Log a terrible error. There is nothing to do with this message
1032                     // so drop it.
1033                     logTerribleErrorMessageBeforeConnect();
1034                     Log.e(LOG_TAG, "Agent not yet registered, ignoring command");
1035                     return;
1036                 }
1037                 if (mState >= STATE_UNREGISTERED) {
1038                     // This should not crash for two reasons : first, the agent may
1039                     // be disconnected by ConnectivityService at any time and the message
1040                     // typically arrives on another thread, so it's not feasible for
1041                     // apps to check before sending, they'd have to always catch. Second,
1042                     // historically this hasn't thrown and some code may be relying on
1043                     // the historical behavior.
1044                     Log.e(LOG_TAG, "Agent already unregistered, ignoring command");
1045                     return;
1046                 }
1047             } else {
1048                 if (null == mNetwork) {
1049                     // Log a terrible error but still enqueue the message for backward
1050                     // compatibility.
1051                     logTerribleErrorMessageBeforeConnect();
1052                 }
1053                 if (!mConnected) {
1054                     mPreConnectedQueue.add(action);
1055                     return;
1056                 }
1057             }
1058             try {
1059                 action.execute(mRegistry);
1060             } catch (RemoteException e) {
1061                 Log.wtf(LOG_TAG, "Error executing registry action", e);
1062                 // Fall through: the channel is asynchronous and does not report errors back
1063             }
1064         }
1065     }
1066 
1067     /**
1068      * Must be called by the agent when the network's {@link LinkProperties} change.
1069      * @param linkProperties the new LinkProperties.
1070      */
sendLinkProperties(@onNull LinkProperties linkProperties)1071     public void sendLinkProperties(@NonNull LinkProperties linkProperties) {
1072         Objects.requireNonNull(linkProperties);
1073         // Copy the object because if the agent is running in the system server
1074         // then the same instance will be seen by the registry
1075         send(reg -> reg.sendLinkProperties(new LinkProperties(linkProperties)));
1076     }
1077 
1078     /**
1079      * Must be called by the agent when the network's underlying networks change.
1080      *
1081      * <p>{@code networks} is one of the following:
1082      * <ul>
1083      * <li><strong>a non-empty array</strong>: an array of one or more {@link Network}s, in
1084      * decreasing preference order. For example, if this VPN uses both wifi and mobile (cellular)
1085      * networks to carry app traffic, but prefers or uses wifi more than mobile, wifi should appear
1086      * first in the array.</li>
1087      * <li><strong>an empty array</strong>: a zero-element array, meaning that the VPN has no
1088      * underlying network connection, and thus, app traffic will not be sent or received.</li>
1089      * <li><strong>null</strong>: (default) signifies that the VPN uses whatever is the system's
1090      * default network. I.e., it doesn't use the {@code bindSocket} or {@code bindDatagramSocket}
1091      * APIs mentioned above to send traffic over specific channels.</li>
1092      * </ul>
1093      *
1094      * @param underlyingNetworks the new list of underlying networks.
1095      * @see {@link VpnService.Builder#setUnderlyingNetworks(Network[])}
1096      */
setUnderlyingNetworks( @uppressLint"NullableCollection") @ullable List<Network> underlyingNetworks)1097     public void setUnderlyingNetworks(
1098             @SuppressLint("NullableCollection") @Nullable List<Network> underlyingNetworks) {
1099         final ArrayList<Network> underlyingArray = (underlyingNetworks != null)
1100                 ? new ArrayList<>(underlyingNetworks) : null;
1101         send(reg -> reg.sendUnderlyingNetworks(underlyingArray));
1102     }
1103 
1104     /**
1105      * Inform ConnectivityService that this agent has now connected.
1106      * Call {@link #unregister} to disconnect.
1107      */
markConnected()1108     public void markConnected() {
1109         mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null /* reason */,
1110                 mNetworkInfo.getExtraInfo());
1111         sendNetworkInfo(mNetworkInfo);
1112     }
1113 
1114     /**
1115      * Unregister this network agent.
1116      *
1117      * This signals the network has disconnected and ends its lifecycle. After this is called,
1118      * the network is torn down and this agent can no longer be used.
1119      */
unregister()1120     public void unregister() {
1121         // When unregistering an agent nobody should use the extrainfo (or reason) any more.
1122         mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null /* reason */,
1123                 null /* extraInfo */);
1124         synchronized (mRegisterLock) {
1125             if (mState >= STATE_REGISTERED) {
1126                 sendNetworkInfo(mNetworkInfo);
1127             }
1128             mState = STATE_UNREGISTERED;
1129         }
1130     }
1131 
1132     /**
1133      * Sets the value of the teardown delay.
1134      *
1135      * The teardown delay is the time between when the network disconnects and when the native
1136      * network corresponding to this {@code NetworkAgent} is destroyed. By default, the native
1137      * network is destroyed immediately. If {@code teardownDelayMs} is non-zero, then when this
1138      * network disconnects, the system will instead immediately mark the network as restricted
1139      * and unavailable to unprivileged apps, but will defer destroying the native network until the
1140      * teardown delay timer expires.
1141      *
1142      * The interfaces in use by this network will remain in use until the native network is
1143      * destroyed and cannot be reused until {@link #onNetworkDestroyed()} is called.
1144      *
1145      * This method may be called at any time while the network is connected. It has no effect if
1146      * the network is already disconnected and the teardown delay timer is running.
1147      *
1148      * @param teardownDelayMillis the teardown delay to set, or 0 to disable teardown delay.
1149      */
setTeardownDelayMillis( @ntRangefrom = 0, to = MAX_TEARDOWN_DELAY_MS) int teardownDelayMillis)1150     public void setTeardownDelayMillis(
1151             @IntRange(from = 0, to = MAX_TEARDOWN_DELAY_MS) int teardownDelayMillis) {
1152         send(reg -> reg.sendTeardownDelayMs(teardownDelayMillis));
1153     }
1154 
1155     /**
1156      * Indicates that this agent will likely soon be replaced by another agent for a very similar
1157      * network (e.g., same Wi-Fi SSID).
1158      *
1159      * If the network is not currently satisfying any {@link NetworkRequest}s, it will be torn down.
1160      * If it is satisfying requests, then the native network corresponding to the agent will be
1161      * destroyed immediately, but the agent will remain registered and will continue to satisfy
1162      * requests until {@link #unregister} is called, the network is replaced by an equivalent or
1163      * better network, or the specified timeout expires. During this time:
1164      *
1165      * <ul>
1166      * <li>The agent may not send any further updates, for example by calling methods
1167      *    such as {@link #sendNetworkCapabilities}, {@link #sendLinkProperties},
1168      *    {@link #sendNetworkScore(NetworkScore)} and so on. Any such updates will be ignored.
1169      * <li>The network will remain connected and continue to satisfy any requests that it would
1170      *    otherwise satisfy (including, possibly, the default request).
1171      * <li>The validation state of the network will not change, and calls to
1172      *    {@link ConnectivityManager#reportNetworkConnectivity(Network, boolean)} will be ignored.
1173      * </ul>
1174      *
1175      * Once this method is called, it is not possible to restore the agent to a functioning state.
1176      * If a replacement network becomes available, then a new agent must be registered. When that
1177      * replacement network is fully capable of replacing this network (including, possibly, being
1178      * validated), this agent will no longer be needed and will be torn down. Otherwise, this agent
1179      * can be disconnected by calling {@link #unregister}. If {@link #unregister} is not called,
1180      * this agent will automatically be unregistered when the specified timeout expires. Any
1181      * teardown delay previously set using{@link #setTeardownDelayMillis} is ignored.
1182      *
1183      * <p>This method has no effect if {@link #markConnected} has not yet been called.
1184      * <p>This method may only be called once.
1185      *
1186      * @param timeoutMillis the timeout after which this network will be unregistered even if
1187      *                      {@link #unregister} was not called.
1188      */
unregisterAfterReplacement( @ntRangefrom = 0, to = MAX_TEARDOWN_DELAY_MS) int timeoutMillis)1189     public void unregisterAfterReplacement(
1190             @IntRange(from = 0, to = MAX_TEARDOWN_DELAY_MS) int timeoutMillis) {
1191         send(reg -> reg.sendUnregisterAfterReplacement(timeoutMillis));
1192     }
1193 
1194     /**
1195      * Change the legacy subtype of this network agent.
1196      *
1197      * This is only for backward compatibility and should not be used by non-legacy network agents,
1198      * or agents that did not use to set a subtype. As such, only TYPE_MOBILE type agents can use
1199      * this and others will be thrown an exception if they try.
1200      *
1201      * @deprecated this is for backward compatibility only.
1202      * @param legacySubtype the legacy subtype.
1203      * @hide
1204      */
1205     @Deprecated
1206     @SystemApi
setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName)1207     public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) {
1208         mNetworkInfo.setSubtype(legacySubtype, legacySubtypeName);
1209         sendNetworkInfo(mNetworkInfo);
1210     }
1211 
1212     /**
1213      * Set the ExtraInfo of this network agent.
1214      *
1215      * This sets the ExtraInfo field inside the NetworkInfo returned by legacy public API and the
1216      * broadcasts about the corresponding Network.
1217      * This is only for backward compatibility and should not be used by non-legacy network agents,
1218      * who will be thrown an exception if they try. The extra info should only be :
1219      * <ul>
1220      *   <li>For cellular agents, the APN name.</li>
1221      *   <li>For ethernet agents, the interface name.</li>
1222      * </ul>
1223      *
1224      * @deprecated this is for backward compatibility only.
1225      * @param extraInfo the ExtraInfo.
1226      * @hide
1227      */
1228     @Deprecated
setLegacyExtraInfo(@ullable final String extraInfo)1229     public void setLegacyExtraInfo(@Nullable final String extraInfo) {
1230         mNetworkInfo.setExtraInfo(extraInfo);
1231         sendNetworkInfo(mNetworkInfo);
1232     }
1233 
1234     /**
1235      * Must be called by the agent when it has a new NetworkInfo object.
1236      * @hide TODO: expose something better.
1237      */
1238     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
1239     // Note : this should be private, but is still called by some OEM network agents
1240     // linking against the full module. They should not do this, and it should be
1241     // forbidden, but as long as there are such devices this can't be made private
1242     // on pain of breaking them.
sendNetworkInfo(final NetworkInfo networkInfo)1243     public void sendNetworkInfo(final NetworkInfo networkInfo) {
1244         final NetworkInfo ni = new NetworkInfo(networkInfo);
1245         send(reg -> reg.sendNetworkInfo(ni));
1246     }
1247 
1248     /**
1249      * Must be called by the agent when the network's {@link NetworkCapabilities} change.
1250      * @param networkCapabilities the new NetworkCapabilities.
1251      */
sendNetworkCapabilities(@onNull NetworkCapabilities networkCapabilities)1252     public void sendNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
1253         Objects.requireNonNull(networkCapabilities);
1254         mBandwidthUpdatePending.set(false);
1255         mLastBwRefreshTime = System.currentTimeMillis();
1256         final NetworkCapabilities nc =
1257                 new NetworkCapabilities(networkCapabilities, NetworkCapabilities.REDACT_NONE);
1258         send(reg -> reg.sendNetworkCapabilities(nc));
1259     }
1260 
1261     /**
1262      * Must be called by the agent when the network's {@link LocalNetworkConfig} changes.
1263      * @param config the new LocalNetworkConfig
1264      * @hide
1265      */
sendLocalNetworkConfig(@onNull LocalNetworkConfig config)1266     public void sendLocalNetworkConfig(@NonNull LocalNetworkConfig config) {
1267         Objects.requireNonNull(config);
1268         // If the agent doesn't have NET_CAPABILITY_LOCAL_NETWORK, this will be ignored by
1269         // ConnectivityService with a Log.wtf.
1270         send(reg -> reg.sendLocalNetworkConfig(config));
1271     }
1272 
1273     /**
1274      * Must be called by the agent to update the score of this network.
1275      *
1276      * @param score the new score.
1277      */
sendNetworkScore(@onNull NetworkScore score)1278     public void sendNetworkScore(@NonNull NetworkScore score) {
1279         Objects.requireNonNull(score);
1280         send(reg -> reg.sendScore(score));
1281     }
1282 
1283     /**
1284      * Must be called by the agent to update the score of this network.
1285      *
1286      * @param score the new score, between 0 and 99.
1287      * deprecated use sendNetworkScore(NetworkScore) TODO : remove in S.
1288      */
sendNetworkScore(@ntRangefrom = 0, to = 99) int score)1289     public void sendNetworkScore(@IntRange(from = 0, to = 99) int score) {
1290         sendNetworkScore(new NetworkScore.Builder().setLegacyInt(score).build());
1291     }
1292 
1293     /**
1294      * Must be called by the agent to indicate this network was manually selected by the user.
1295      * This should be called before the NetworkInfo is marked CONNECTED so that this
1296      * Network can be given special treatment at that time. If {@code acceptUnvalidated} is
1297      * {@code true}, then the system will switch to this network. If it is {@code false} and the
1298      * network cannot be validated, the system will ask the user whether to switch to this network.
1299      * If the user confirms and selects "don't ask again", then the system will call
1300      * {@link #saveAcceptUnvalidated} to persist the user's choice. Thus, if the transport ever
1301      * calls this method with {@code acceptUnvalidated} set to {@code false}, it must also implement
1302      * {@link #saveAcceptUnvalidated} to respect the user's choice.
1303      * @hide should move to NetworkAgentConfig.
1304      */
explicitlySelected(boolean acceptUnvalidated)1305     public void explicitlySelected(boolean acceptUnvalidated) {
1306         explicitlySelected(true /* explicitlySelected */, acceptUnvalidated);
1307     }
1308 
1309     /**
1310      * Must be called by the agent to indicate whether the network was manually selected by the
1311      * user. This should be called before the network becomes connected, so it can be given
1312      * special treatment when it does.
1313      *
1314      * If {@code explicitlySelected} is {@code true}, and {@code acceptUnvalidated} is {@code true},
1315      * then the system will switch to this network. If {@code explicitlySelected} is {@code true}
1316      * and {@code acceptUnvalidated} is {@code false}, and the  network cannot be validated, the
1317      * system will ask the user whether to switch to this network.  If the user confirms and selects
1318      * "don't ask again", then the system will call {@link #saveAcceptUnvalidated} to persist the
1319      * user's choice. Thus, if the transport ever calls this method with {@code explicitlySelected}
1320      * set to {@code true} and {@code acceptUnvalidated} set to {@code false}, it must also
1321      * implement {@link #saveAcceptUnvalidated} to respect the user's choice.
1322      *
1323      * If  {@code explicitlySelected} is {@code false} and {@code acceptUnvalidated} is
1324      * {@code true}, the system will interpret this as the user having accepted partial connectivity
1325      * on this network. Thus, the system will switch to the network and consider it validated even
1326      * if it only provides partial connectivity, but the network is not otherwise treated specially.
1327      * @hide should move to NetworkAgentConfig.
1328      */
explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated)1329     public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) {
1330         send(reg -> reg.sendExplicitlySelected(explicitlySelected, acceptUnvalidated));
1331     }
1332 
1333     /**
1334      * Called when ConnectivityService has indicated they no longer want this network.
1335      * The parent factory should (previously) have received indication of the change
1336      * as well, either canceling NetworkRequests or altering their score such that this
1337      * network won't be immediately requested again.
1338      */
onNetworkUnwanted()1339     public void onNetworkUnwanted() {
1340         unwanted();
1341     }
1342     /** @hide TODO delete once subclasses have moved to onNetworkUnwanted. */
unwanted()1343     protected void unwanted() {
1344     }
1345 
1346     /**
1347      * Called when ConnectivityService request a bandwidth update. The parent factory
1348      * shall try to overwrite this method and produce a bandwidth update if capable.
1349      * @hide
1350      */
1351     @SystemApi
onBandwidthUpdateRequested()1352     public void onBandwidthUpdateRequested() {
1353         pollLceData();
1354     }
1355     /** @hide TODO delete once subclasses have moved to onBandwidthUpdateRequested. */
pollLceData()1356     protected void pollLceData() {
1357     }
1358 
1359     /**
1360      * Called when the system determines the usefulness of this network.
1361      *
1362      * The system attempts to validate Internet connectivity on networks that provide the
1363      * {@link NetworkCapabilities#NET_CAPABILITY_INTERNET} capability.
1364      *
1365      * Currently there are two possible values:
1366      * {@code VALIDATION_STATUS_VALID} if Internet connectivity was validated,
1367      * {@code VALIDATION_STATUS_NOT_VALID} if Internet connectivity was not validated.
1368      *
1369      * This is guaranteed to be called again when the network status changes, but the system
1370      * may also call this multiple times even if the status does not change.
1371      *
1372      * @param status one of {@code VALIDATION_STATUS_VALID} or {@code VALIDATION_STATUS_NOT_VALID}.
1373      * @param redirectUri If Internet connectivity is being redirected (e.g., on a captive portal),
1374      *        this is the destination the probes are being redirected to, otherwise {@code null}.
1375      */
onValidationStatus(@alidationStatus int status, @Nullable Uri redirectUri)1376     public void onValidationStatus(@ValidationStatus int status, @Nullable Uri redirectUri) {
1377         networkStatus(status, null == redirectUri ? "" : redirectUri.toString());
1378     }
1379     /** @hide TODO delete once subclasses have moved to onValidationStatus */
networkStatus(int status, String redirectUrl)1380     protected void networkStatus(int status, String redirectUrl) {
1381     }
1382 
1383 
1384     /**
1385      * Called when the user asks to remember the choice to use this network even if unvalidated.
1386      * The transport is responsible for remembering the choice, and the next time the user connects
1387      * to the network, should explicitlySelected with {@code acceptUnvalidated} set to {@code true}.
1388      * This method will only be called if {@link #explicitlySelected} was called with
1389      * {@code acceptUnvalidated} set to {@code false}.
1390      * @param accept whether the user wants to use the network even if unvalidated.
1391      */
onSaveAcceptUnvalidated(boolean accept)1392     public void onSaveAcceptUnvalidated(boolean accept) {
1393         saveAcceptUnvalidated(accept);
1394     }
1395     /** @hide TODO delete once subclasses have moved to onSaveAcceptUnvalidated */
saveAcceptUnvalidated(boolean accept)1396     protected void saveAcceptUnvalidated(boolean accept) {
1397     }
1398 
1399     /**
1400      * Called when ConnectivityService has successfully created this NetworkAgent's native network.
1401      */
onNetworkCreated()1402     public void onNetworkCreated() {}
1403 
1404 
1405     /**
1406      * Called when ConnectivityService has successfully destroy this NetworkAgent's native network.
1407      */
onNetworkDestroyed()1408     public void onNetworkDestroyed() {}
1409 
1410     /**
1411      * Called when when the DSCP Policy status has changed.
1412      */
onDscpPolicyStatusUpdated(int policyId, @DscpPolicyStatus int status)1413     public void onDscpPolicyStatusUpdated(int policyId, @DscpPolicyStatus int status) {}
1414 
1415     /**
1416      * Requests that the network hardware send the specified packet at the specified interval.
1417      *
1418      * @param slot the hardware slot on which to start the keepalive.
1419      * @param interval the interval between packets, between 10 and 3600. Note that this API
1420      *                 does not support sub-second precision and will round off the request.
1421      * @param packet the packet to send.
1422      */
1423     // seconds is from SocketKeepalive.MIN_INTERVAL_SEC to MAX_INTERVAL_SEC, but these should
1424     // not be exposed as constants because they may change in the future (API guideline 4.8)
1425     // and should have getters if exposed at all. Getters can't be used in the annotation,
1426     // so the values unfortunately need to be copied.
onStartSocketKeepalive(int slot, @NonNull Duration interval, @NonNull KeepalivePacketData packet)1427     public void onStartSocketKeepalive(int slot, @NonNull Duration interval,
1428             @NonNull KeepalivePacketData packet) {
1429         final long intervalSeconds = interval.getSeconds();
1430         if (intervalSeconds < SocketKeepalive.MIN_INTERVAL_SEC
1431                 || intervalSeconds > SocketKeepalive.MAX_INTERVAL_SEC) {
1432             throw new IllegalArgumentException("Interval needs to be comprised between "
1433                     + SocketKeepalive.MIN_INTERVAL_SEC + " and " + SocketKeepalive.MAX_INTERVAL_SEC
1434                     + " but was " + intervalSeconds);
1435         }
1436         final Message msg = mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, slot,
1437                 (int) intervalSeconds, packet);
1438         startSocketKeepalive(msg);
1439         msg.recycle();
1440     }
1441     /** @hide TODO delete once subclasses have moved to onStartSocketKeepalive */
startSocketKeepalive(Message msg)1442     protected void startSocketKeepalive(Message msg) {
1443         onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED);
1444     }
1445 
1446     /**
1447      * Requests that the network hardware stop a previously-started keepalive.
1448      *
1449      * @param slot the hardware slot on which to stop the keepalive.
1450      */
onStopSocketKeepalive(int slot)1451     public void onStopSocketKeepalive(int slot) {
1452         Message msg = mHandler.obtainMessage(CMD_STOP_SOCKET_KEEPALIVE, slot, 0, null);
1453         stopSocketKeepalive(msg);
1454         msg.recycle();
1455     }
1456     /** @hide TODO delete once subclasses have moved to onStopSocketKeepalive */
stopSocketKeepalive(Message msg)1457     protected void stopSocketKeepalive(Message msg) {
1458         onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED);
1459     }
1460 
1461     /**
1462      * Must be called by the agent when a socket keepalive event occurs.
1463      *
1464      * @param slot the hardware slot on which the event occurred.
1465      * @param event the event that occurred, as one of the SocketKeepalive.ERROR_*
1466      *              or SocketKeepalive.SUCCESS constants.
1467      */
sendSocketKeepaliveEvent(int slot, @SocketKeepalive.KeepaliveEvent int event)1468     public final void sendSocketKeepaliveEvent(int slot,
1469             @SocketKeepalive.KeepaliveEvent int event) {
1470         send(reg -> reg.sendSocketKeepaliveEvent(slot, event));
1471     }
1472     /** @hide TODO delete once callers have moved to sendSocketKeepaliveEvent */
onSocketKeepaliveEvent(int slot, int reason)1473     public void onSocketKeepaliveEvent(int slot, int reason) {
1474         sendSocketKeepaliveEvent(slot, reason);
1475     }
1476 
1477     /**
1478      * Called by ConnectivityService to add specific packet filter to network hardware to block
1479      * replies (e.g., TCP ACKs) matching the sent keepalive packets. Implementations that support
1480      * this feature must override this method.
1481      *
1482      * @param slot the hardware slot on which the keepalive should be sent.
1483      * @param packet the packet that is being sent.
1484      */
onAddKeepalivePacketFilter(int slot, @NonNull KeepalivePacketData packet)1485     public void onAddKeepalivePacketFilter(int slot, @NonNull KeepalivePacketData packet) {
1486         Message msg = mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0, packet);
1487         addKeepalivePacketFilter(msg);
1488         msg.recycle();
1489     }
1490     /** @hide TODO delete once subclasses have moved to onAddKeepalivePacketFilter */
addKeepalivePacketFilter(Message msg)1491     protected void addKeepalivePacketFilter(Message msg) {
1492     }
1493 
1494     /**
1495      * Called by ConnectivityService to remove a packet filter installed with
1496      * {@link #addKeepalivePacketFilter(Message)}. Implementations that support this feature
1497      * must override this method.
1498      *
1499      * @param slot the hardware slot on which the keepalive is being sent.
1500      */
onRemoveKeepalivePacketFilter(int slot)1501     public void onRemoveKeepalivePacketFilter(int slot) {
1502         Message msg = mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, slot, 0, null);
1503         removeKeepalivePacketFilter(msg);
1504         msg.recycle();
1505     }
1506     /** @hide TODO delete once subclasses have moved to onRemoveKeepalivePacketFilter */
removeKeepalivePacketFilter(Message msg)1507     protected void removeKeepalivePacketFilter(Message msg) {
1508     }
1509 
1510     /**
1511      * Called by ConnectivityService to inform this network agent of signal strength thresholds
1512      * that when crossed should trigger a system wakeup and a NetworkCapabilities update.
1513      *
1514      * When the system updates the list of thresholds that should wake up the CPU for a
1515      * given agent it will call this method on the agent. The agent that implement this
1516      * should implement it in hardware so as to ensure the CPU will be woken up on breach.
1517      * Agents are expected to react to a breach by sending an updated NetworkCapabilities
1518      * object with the appropriate signal strength to sendNetworkCapabilities.
1519      *
1520      * The specific units are bearer-dependent. See details on the units and requests in
1521      * {@link NetworkCapabilities.Builder#setSignalStrength}.
1522      *
1523      * @param thresholds the array of thresholds that should trigger wakeups.
1524      */
onSignalStrengthThresholdsUpdated(@onNull int[] thresholds)1525     public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) {
1526         setSignalStrengthThresholds(thresholds);
1527     }
1528     /** @hide TODO delete once subclasses have moved to onSetSignalStrengthThresholds */
setSignalStrengthThresholds(int[] thresholds)1529     protected void setSignalStrengthThresholds(int[] thresholds) {
1530     }
1531 
1532     /**
1533      * Called when the user asks to not stay connected to this network because it was found to not
1534      * provide Internet access.  Usually followed by call to {@code unwanted}.  The transport is
1535      * responsible for making sure the device does not automatically reconnect to the same network
1536      * after the {@code unwanted} call.
1537      */
onAutomaticReconnectDisabled()1538     public void onAutomaticReconnectDisabled() {
1539         preventAutomaticReconnect();
1540     }
1541     /** @hide TODO delete once subclasses have moved to onAutomaticReconnectDisabled */
preventAutomaticReconnect()1542     protected void preventAutomaticReconnect() {
1543     }
1544 
1545     /**
1546      * Called when a qos callback is registered with a filter.
1547      * @param qosCallbackId the id for the callback registered
1548      * @param filter the filter being registered
1549      */
onQosCallbackRegistered(final int qosCallbackId, final @NonNull QosFilter filter)1550     public void onQosCallbackRegistered(final int qosCallbackId, final @NonNull QosFilter filter) {
1551     }
1552 
1553     /**
1554      * Called when a qos callback is registered with a filter.
1555      * <p/>
1556      * Any QoS events that are sent with the same callback id after this method is called
1557      * are a no-op.
1558      *
1559      * @param qosCallbackId the id for the callback being unregistered
1560      */
onQosCallbackUnregistered(final int qosCallbackId)1561     public void onQosCallbackUnregistered(final int qosCallbackId) {
1562     }
1563 
1564 
1565     /**
1566      * Sends the attributes of Qos Session back to the Application
1567      *
1568      * @param qosCallbackId the callback id that the session belongs to
1569      * @param sessionId the unique session id across all Qos Sessions
1570      * @param attributes the attributes of the Qos Session
1571      */
sendQosSessionAvailable(final int qosCallbackId, final int sessionId, @NonNull final QosSessionAttributes attributes)1572     public final void sendQosSessionAvailable(final int qosCallbackId, final int sessionId,
1573             @NonNull final QosSessionAttributes attributes) {
1574         Objects.requireNonNull(attributes, "The attributes must be non-null");
1575         if (attributes instanceof EpsBearerQosSessionAttributes) {
1576             send(reg -> reg.sendEpsQosSessionAvailable(qosCallbackId,
1577                     new QosSession(sessionId, QosSession.TYPE_EPS_BEARER),
1578                     (EpsBearerQosSessionAttributes)attributes));
1579         } else if (attributes instanceof NrQosSessionAttributes) {
1580             send(reg -> reg.sendNrQosSessionAvailable(qosCallbackId,
1581                     new QosSession(sessionId, QosSession.TYPE_NR_BEARER),
1582                     (NrQosSessionAttributes)attributes));
1583         }
1584     }
1585 
1586     /**
1587      * Sends event that the Qos Session was lost.
1588      *
1589      * @param qosCallbackId the callback id that the session belongs to
1590      * @param sessionId the unique session id across all Qos Sessions
1591      * @param qosSessionType the session type {@code QosSesson#QosSessionType}
1592      */
sendQosSessionLost(final int qosCallbackId, final int sessionId, final int qosSessionType)1593     public final void sendQosSessionLost(final int qosCallbackId,
1594             final int sessionId, final int qosSessionType) {
1595         send(reg -> reg.sendQosSessionLost(qosCallbackId,
1596                 new QosSession(sessionId, qosSessionType)));
1597     }
1598 
1599     /**
1600      * Sends the exception type back to the application.
1601      *
1602      * The NetworkAgent should not send anymore messages with this id.
1603      *
1604      * @param qosCallbackId the callback id this exception belongs to
1605      * @param exceptionType the type of exception
1606      */
sendQosCallbackError(final int qosCallbackId, @QosCallbackException.ExceptionType final int exceptionType)1607     public final void sendQosCallbackError(final int qosCallbackId,
1608             @QosCallbackException.ExceptionType final int exceptionType) {
1609         send(reg -> reg.sendQosCallbackError(qosCallbackId, exceptionType));
1610     }
1611 
1612     /**
1613      * Set the linger duration for this network agent.
1614      * @param duration the delay between the moment the network becomes unneeded and the
1615      *                 moment the network is disconnected or moved into the background.
1616      *                 Note that If this duration has greater than millisecond precision, then
1617      *                 the internal implementation will drop any excess precision.
1618      */
setLingerDuration(@onNull final Duration duration)1619     public void setLingerDuration(@NonNull final Duration duration) {
1620         Objects.requireNonNull(duration);
1621         final long durationMs = duration.toMillis();
1622         if (durationMs < MIN_LINGER_TIMER_MS || durationMs > Integer.MAX_VALUE) {
1623             throw new IllegalArgumentException("Duration must be within ["
1624                     + MIN_LINGER_TIMER_MS + "," + Integer.MAX_VALUE + "]ms");
1625         }
1626         send(reg -> reg.sendLingerDuration((int) durationMs));
1627     }
1628 
1629     /**
1630      * Add a DSCP Policy.
1631      * @param policy the DSCP policy to be added.
1632      */
sendAddDscpPolicy(@onNull final DscpPolicy policy)1633     public void sendAddDscpPolicy(@NonNull final DscpPolicy policy) {
1634         Objects.requireNonNull(policy);
1635         send(reg -> reg.sendAddDscpPolicy(policy));
1636     }
1637 
1638     /**
1639      * Remove the specified DSCP policy.
1640      * @param policyId the ID corresponding to a specific DSCP Policy.
1641      */
sendRemoveDscpPolicy(final int policyId)1642     public void sendRemoveDscpPolicy(final int policyId) {
1643         send(reg -> reg.sendRemoveDscpPolicy(policyId));
1644     }
1645 
1646     /**
1647      * Remove all the DSCP policies on this network.
1648      */
sendRemoveAllDscpPolicies()1649     public void sendRemoveAllDscpPolicies() {
1650         send(reg -> reg.sendRemoveAllDscpPolicies());
1651     }
1652 
1653     /** @hide */
log(final String s)1654     protected void log(final String s) {
1655         Log.d(LOG_TAG, "NetworkAgent: " + s);
1656     }
1657 }
1658