1 /*
2  * Copyright (C) 2020 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.networkstack;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.net.IIpMemoryStoreCallbacks;
22 import android.net.INetworkMonitorCallbacks;
23 import android.net.INetworkStackConnector;
24 import android.net.Network;
25 import android.net.dhcp.DhcpServingParamsParcel;
26 import android.net.dhcp.IDhcpServerCallbacks;
27 import android.net.ip.IIpClientCallbacks;
28 import android.os.RemoteException;
29 
30 import com.android.internal.annotations.GuardedBy;
31 
32 import java.util.ArrayList;
33 import java.util.function.Consumer;
34 
35 /**
36  * Utility class to obtain and communicate with the NetworkStack module.
37  */
38 public abstract class NetworkStackClientBase {
39     @NonNull
40     @GuardedBy("mPendingNetStackRequests")
41     private final ArrayList<Consumer<INetworkStackConnector>> mPendingNetStackRequests =
42             new ArrayList<>();
43 
44     @Nullable
45     @GuardedBy("mPendingNetStackRequests")
46     private INetworkStackConnector mConnector;
47 
48     /**
49      * Create a DHCP server according to the specified parameters.
50      *
51      * <p>The server will be returned asynchronously through the provided callbacks.
52      */
makeDhcpServer(final String ifName, final DhcpServingParamsParcel params, final IDhcpServerCallbacks cb)53     public void makeDhcpServer(final String ifName, final DhcpServingParamsParcel params,
54             final IDhcpServerCallbacks cb) {
55         requestConnector(connector -> {
56             try {
57                 connector.makeDhcpServer(ifName, params, cb);
58             } catch (RemoteException e) {
59                 throw new IllegalStateException("Could not create DhcpServer", e);
60             }
61         });
62     }
63 
64     /**
65      * Create an IpClient on the specified interface.
66      *
67      * <p>The IpClient will be returned asynchronously through the provided callbacks.
68      */
makeIpClient(String ifName, IIpClientCallbacks cb)69     public void makeIpClient(String ifName, IIpClientCallbacks cb) {
70         requestConnector(connector -> {
71             try {
72                 connector.makeIpClient(ifName, cb);
73             } catch (RemoteException e) {
74                 throw new IllegalStateException("Could not create IpClient", e);
75             }
76         });
77     }
78 
79     /**
80      * Create a NetworkMonitor.
81      *
82      * <p>The INetworkMonitor will be returned asynchronously through the provided callbacks.
83      */
makeNetworkMonitor(Network network, String name, INetworkMonitorCallbacks cb)84     public void makeNetworkMonitor(Network network, String name, INetworkMonitorCallbacks cb) {
85         requestConnector(connector -> {
86             try {
87                 connector.makeNetworkMonitor(network, name, cb);
88             } catch (RemoteException e) {
89                 throw new IllegalStateException("Could not create NetworkMonitor", e);
90             }
91         });
92     }
93 
94     /**
95      * Get an instance of the IpMemoryStore.
96      *
97      * <p>The IpMemoryStore will be returned asynchronously through the provided callbacks.
98      */
fetchIpMemoryStore(IIpMemoryStoreCallbacks cb)99     public void fetchIpMemoryStore(IIpMemoryStoreCallbacks cb) {
100         requestConnector(connector -> {
101             try {
102                 connector.fetchIpMemoryStore(cb);
103             } catch (RemoteException e) {
104                 throw new IllegalStateException("Could not fetch IpMemoryStore", e);
105             }
106         });
107     }
108 
requestConnector(@onNull Consumer<INetworkStackConnector> request)109     protected void requestConnector(@NonNull Consumer<INetworkStackConnector> request) {
110         final INetworkStackConnector connector;
111         synchronized (mPendingNetStackRequests) {
112             connector = mConnector;
113             if (connector == null) {
114                 mPendingNetStackRequests.add(request);
115                 return;
116             }
117         }
118 
119         request.accept(connector);
120     }
121 
122     /**
123      * Call this method once the NetworkStack is connected.
124      *
125      * <p>This method will cause pending oneway Binder calls for the NetworkStack to be processed on
126      * the calling thread.
127      */
onNetworkStackConnected(@onNull INetworkStackConnector connector)128     protected void onNetworkStackConnected(@NonNull INetworkStackConnector connector) {
129         // Process the connector wait queue in order, including any items that are added
130         // while processing.
131         while (true) {
132             final ArrayList<Consumer<INetworkStackConnector>> requests;
133             synchronized (mPendingNetStackRequests) {
134                 requests = new ArrayList<>(mPendingNetStackRequests);
135                 mPendingNetStackRequests.clear();
136             }
137 
138             for (Consumer<INetworkStackConnector> consumer : requests) {
139                 consumer.accept(connector);
140             }
141 
142             synchronized (mPendingNetStackRequests) {
143                 if (mPendingNetStackRequests.size() == 0) {
144                     // Once mConnector is non-null, no more tasks will be queued.
145                     mConnector = connector;
146                     return;
147                 }
148             }
149         }
150     }
151 
152     /**
153      * Used in subclasses for diagnostics (dumpsys) purposes.
154      * @return How many requests for the network stack are currently pending.
155      */
getQueueLength()156     protected int getQueueLength() {
157         synchronized (mPendingNetStackRequests) {
158             return mPendingNetStackRequests.size();
159         }
160     }
161 }
162