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 package android.net;
17 
18 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
19 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
20 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
21 
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.content.Context;
25 import android.net.dhcp.DhcpServingParamsParcel;
26 import android.net.dhcp.IDhcpServerCallbacks;
27 import android.net.ip.IIpClientCallbacks;
28 import android.net.util.SharedLog;
29 import android.os.Binder;
30 import android.os.IBinder;
31 import android.os.Process;
32 import android.os.RemoteException;
33 import android.os.ServiceManager;
34 import android.os.UserHandle;
35 import android.util.Slog;
36 
37 import com.android.internal.annotations.GuardedBy;
38 import com.android.internal.annotations.VisibleForTesting;
39 
40 import java.io.PrintWriter;
41 import java.util.ArrayList;
42 
43 /**
44  * Service used to communicate with the network stack, which is running in a separate module.
45  * @hide
46  */
47 public class NetworkStackClient {
48     private static final String TAG = NetworkStackClient.class.getSimpleName();
49 
50     private static final int NETWORKSTACK_TIMEOUT_MS = 10_000;
51 
52     private static NetworkStackClient sInstance;
53 
54     @NonNull
55     private final Dependencies mDependencies;
56 
57     @NonNull
58     @GuardedBy("mPendingNetStackRequests")
59     private final ArrayList<NetworkStackCallback> mPendingNetStackRequests = new ArrayList<>();
60     @Nullable
61     @GuardedBy("mPendingNetStackRequests")
62     private INetworkStackConnector mConnector;
63 
64     @GuardedBy("mLog")
65     private final SharedLog mLog = new SharedLog(TAG);
66 
67     private volatile boolean mWasSystemServerInitialized = false;
68 
69     private interface NetworkStackCallback {
onNetworkStackConnected(INetworkStackConnector connector)70         void onNetworkStackConnected(INetworkStackConnector connector);
71     }
72 
73     @VisibleForTesting
NetworkStackClient(@onNull Dependencies dependencies)74     protected NetworkStackClient(@NonNull Dependencies dependencies) {
75         mDependencies = dependencies;
76     }
77 
NetworkStackClient()78     private NetworkStackClient() {
79         this(new DependenciesImpl());
80     }
81 
82     @VisibleForTesting
83     protected interface Dependencies {
addToServiceManager(@onNull IBinder service)84         void addToServiceManager(@NonNull IBinder service);
checkCallerUid()85         void checkCallerUid();
getConnectivityModuleConnector()86         ConnectivityModuleConnector getConnectivityModuleConnector();
87     }
88 
89     private static class DependenciesImpl implements Dependencies {
90         @Override
addToServiceManager(@onNull IBinder service)91         public void addToServiceManager(@NonNull IBinder service) {
92             ServiceManager.addService(Context.NETWORK_STACK_SERVICE, service,
93                     false /* allowIsolated */, DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
94         }
95 
96         @Override
checkCallerUid()97         public void checkCallerUid() {
98             final int caller = Binder.getCallingUid();
99             // This is a client lib so "caller" is the current UID in most cases. The check is done
100             // here in the caller's process just to provide a nicer error message to clients; more
101             // generic checks are also done in NetworkStackService.
102             // See PermissionUtil in NetworkStack for the actual check on the service side - the
103             // checks here should be kept in sync with PermissionUtil.
104             if (caller != Process.SYSTEM_UID
105                     && caller != Process.NETWORK_STACK_UID
106                     && UserHandle.getAppId(caller) != Process.BLUETOOTH_UID) {
107                 throw new SecurityException(
108                         "Only the system server should try to bind to the network stack.");
109             }
110         }
111 
112         @Override
getConnectivityModuleConnector()113         public ConnectivityModuleConnector getConnectivityModuleConnector() {
114             return ConnectivityModuleConnector.getInstance();
115         }
116     }
117 
118     /**
119      * Get the NetworkStackClient singleton instance.
120      */
getInstance()121     public static synchronized NetworkStackClient getInstance() {
122         if (sInstance == null) {
123             sInstance = new NetworkStackClient();
124         }
125         return sInstance;
126     }
127 
128     /**
129      * Create a DHCP server according to the specified parameters.
130      *
131      * <p>The server will be returned asynchronously through the provided callbacks.
132      */
makeDhcpServer(final String ifName, final DhcpServingParamsParcel params, final IDhcpServerCallbacks cb)133     public void makeDhcpServer(final String ifName, final DhcpServingParamsParcel params,
134             final IDhcpServerCallbacks cb) {
135         requestConnector(connector -> {
136             try {
137                 connector.makeDhcpServer(ifName, params, cb);
138             } catch (RemoteException e) {
139                 e.rethrowFromSystemServer();
140             }
141         });
142     }
143 
144     /**
145      * Create an IpClient on the specified interface.
146      *
147      * <p>The IpClient will be returned asynchronously through the provided callbacks.
148      */
makeIpClient(String ifName, IIpClientCallbacks cb)149     public void makeIpClient(String ifName, IIpClientCallbacks cb) {
150         requestConnector(connector -> {
151             try {
152                 connector.makeIpClient(ifName, cb);
153             } catch (RemoteException e) {
154                 e.rethrowFromSystemServer();
155             }
156         });
157     }
158 
159     /**
160      * Create a NetworkMonitor.
161      *
162      * <p>The INetworkMonitor will be returned asynchronously through the provided callbacks.
163      */
makeNetworkMonitor(Network network, String name, INetworkMonitorCallbacks cb)164     public void makeNetworkMonitor(Network network, String name, INetworkMonitorCallbacks cb) {
165         requestConnector(connector -> {
166             try {
167                 connector.makeNetworkMonitor(network, name, cb);
168             } catch (RemoteException e) {
169                 e.rethrowFromSystemServer();
170             }
171         });
172     }
173 
174     /**
175      * Get an instance of the IpMemoryStore.
176      *
177      * <p>The IpMemoryStore will be returned asynchronously through the provided callbacks.
178      */
fetchIpMemoryStore(IIpMemoryStoreCallbacks cb)179     public void fetchIpMemoryStore(IIpMemoryStoreCallbacks cb) {
180         requestConnector(connector -> {
181             try {
182                 connector.fetchIpMemoryStore(cb);
183             } catch (RemoteException e) {
184                 e.rethrowFromSystemServer();
185             }
186         });
187     }
188 
189     private class NetworkStackConnection implements
190             ConnectivityModuleConnector.ModuleServiceCallback {
191         @Override
onModuleServiceConnected(IBinder service)192         public void onModuleServiceConnected(IBinder service) {
193             logi("Network stack service connected");
194             registerNetworkStackService(service);
195         }
196     }
197 
registerNetworkStackService(@onNull IBinder service)198     private void registerNetworkStackService(@NonNull IBinder service) {
199         final INetworkStackConnector connector = INetworkStackConnector.Stub.asInterface(service);
200         mDependencies.addToServiceManager(service);
201         log("Network stack service registered");
202 
203         final ArrayList<NetworkStackCallback> requests;
204         synchronized (mPendingNetStackRequests) {
205             requests = new ArrayList<>(mPendingNetStackRequests);
206             mPendingNetStackRequests.clear();
207             mConnector = connector;
208         }
209 
210         for (NetworkStackCallback r : requests) {
211             r.onNetworkStackConnected(connector);
212         }
213     }
214 
215     /**
216      * Initialize the network stack. Should be called only once on device startup, before any
217      * client attempts to use the network stack.
218      */
init()219     public void init() {
220         log("Network stack init");
221         mWasSystemServerInitialized = true;
222     }
223 
224     /**
225      * Start the network stack. Should be called only once on device startup.
226      *
227      * <p>This method will start the network stack either in the network stack process, or inside
228      * the system server on devices that do not support the network stack module. The network stack
229      * connector will then be delivered asynchronously to clients that requested it before it was
230      * started.
231      */
start()232     public void start() {
233         mDependencies.getConnectivityModuleConnector().startModuleService(
234                 INetworkStackConnector.class.getName(), PERMISSION_MAINLINE_NETWORK_STACK,
235                 new NetworkStackConnection());
236         log("Network stack service start requested");
237     }
238 
239     /**
240      * Log a message in the local log.
241      */
log(@onNull String message)242     private void log(@NonNull String message) {
243         synchronized (mLog) {
244             mLog.log(message);
245         }
246     }
247 
logWtf(@onNull String message, @Nullable Throwable e)248     private void logWtf(@NonNull String message, @Nullable Throwable e) {
249         Slog.wtf(TAG, message);
250         synchronized (mLog) {
251             mLog.e(message, e);
252         }
253     }
254 
loge(@onNull String message, @Nullable Throwable e)255     private void loge(@NonNull String message, @Nullable Throwable e) {
256         synchronized (mLog) {
257             mLog.e(message, e);
258         }
259     }
260 
261     /**
262      * Log a message in the local and system logs.
263      */
logi(@onNull String message)264     private void logi(@NonNull String message) {
265         synchronized (mLog) {
266             mLog.i(message);
267         }
268     }
269 
270     /**
271      * For non-system server clients, get the connector registered by the system server.
272      */
getRemoteConnector()273     private INetworkStackConnector getRemoteConnector() {
274         // Block until the NetworkStack connector is registered in ServiceManager.
275         // <p>This is only useful for non-system processes that do not have a way to be notified of
276         // registration completion. Adding a callback system would be too heavy weight considering
277         // that the connector is registered on boot, so it is unlikely that a client would request
278         // it before it is registered.
279         // TODO: consider blocking boot on registration and simplify much of the logic in this class
280         IBinder connector;
281         try {
282             final long before = System.currentTimeMillis();
283             while ((connector = ServiceManager.getService(Context.NETWORK_STACK_SERVICE)) == null) {
284                 Thread.sleep(20);
285                 if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
286                     loge("Timeout waiting for NetworkStack connector", null);
287                     return null;
288                 }
289             }
290         } catch (InterruptedException e) {
291             loge("Error waiting for NetworkStack connector", e);
292             return null;
293         }
294 
295         return INetworkStackConnector.Stub.asInterface(connector);
296     }
297 
requestConnector(@onNull NetworkStackCallback request)298     private void requestConnector(@NonNull NetworkStackCallback request) {
299         mDependencies.checkCallerUid();
300 
301         if (!mWasSystemServerInitialized) {
302             // The network stack is not being started in this process, e.g. this process is not
303             // the system server. Get a remote connector registered by the system server.
304             final INetworkStackConnector connector = getRemoteConnector();
305             synchronized (mPendingNetStackRequests) {
306                 mConnector = connector;
307             }
308             request.onNetworkStackConnected(connector);
309             return;
310         }
311 
312         final INetworkStackConnector connector;
313         synchronized (mPendingNetStackRequests) {
314             connector = mConnector;
315             if (connector == null) {
316                 mPendingNetStackRequests.add(request);
317                 return;
318             }
319         }
320 
321         request.onNetworkStackConnected(connector);
322     }
323 
324     /**
325      * Dump NetworkStackClient logs to the specified {@link PrintWriter}.
326      */
dump(PrintWriter pw)327     public void dump(PrintWriter pw) {
328         // dump is thread-safe on SharedLog
329         mLog.dump(null, pw, null);
330         // dump connectivity module connector logs.
331         ConnectivityModuleConnector.getInstance().dump(pw);
332 
333         final int requestsQueueLength;
334         synchronized (mPendingNetStackRequests) {
335             requestsQueueLength = mPendingNetStackRequests.size();
336         }
337 
338         pw.println();
339         pw.println("pendingNetStackRequests length: " + requestsQueueLength);
340     }
341 }
342