blob: b6cd6359384affaf58a095921455a96dcdf91803 [file] [log] [blame]
Remi NGUYEN VANc094a542018-12-07 16:52:24 +09001/*
2 * Copyright (C) 2018 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 */
16package android.net;
17
18import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
19import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
20
21import android.annotation.NonNull;
22import android.annotation.Nullable;
Remi NGUYEN VANd8c75a02019-01-30 21:45:56 +090023import android.annotation.SystemApi;
Remi NGUYEN VANc094a542018-12-07 16:52:24 +090024import android.annotation.SystemService;
Remi NGUYEN VANd8c75a02019-01-30 21:45:56 +090025import android.annotation.TestApi;
Remi NGUYEN VANc094a542018-12-07 16:52:24 +090026import android.content.ComponentName;
27import android.content.Context;
28import android.content.Intent;
29import android.content.ServiceConnection;
Remi NGUYEN VAN0e3d09232018-12-04 12:13:09 +090030import android.net.dhcp.DhcpServingParamsParcel;
31import android.net.dhcp.IDhcpServerCallbacks;
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +090032import android.net.ip.IIpClientCallbacks;
Remi NGUYEN VANc094a542018-12-07 16:52:24 +090033import android.os.Binder;
34import android.os.IBinder;
35import android.os.Process;
Remi NGUYEN VAN0e3d09232018-12-04 12:13:09 +090036import android.os.RemoteException;
Remi NGUYEN VANc094a542018-12-07 16:52:24 +090037import android.os.ServiceManager;
38import android.os.UserHandle;
39import android.util.Slog;
40
41import com.android.internal.annotations.GuardedBy;
42
43import java.lang.reflect.InvocationTargetException;
44import java.util.ArrayList;
45
46/**
47 * Service used to communicate with the network stack, which is running in a separate module.
48 * @hide
49 */
50@SystemService(Context.NETWORK_STACK_SERVICE)
Remi NGUYEN VANd8c75a02019-01-30 21:45:56 +090051@SystemApi
52@TestApi
Remi NGUYEN VANc094a542018-12-07 16:52:24 +090053public class NetworkStack {
54 private static final String TAG = NetworkStack.class.getSimpleName();
55
Remi NGUYEN VANd8c75a02019-01-30 21:45:56 +090056 /**
57 * Permission granted only to the NetworkStack APK, defined in NetworkStackStub with signature
58 * protection level.
59 * @hide
60 */
61 @SystemApi
62 @TestApi
63 public static final String PERMISSION_MAINLINE_NETWORK_STACK =
64 "android.permission.MAINLINE_NETWORK_STACK";
65
66 /** @hide */
Remi NGUYEN VANe67b0c32018-12-27 16:43:56 +090067 public static final String NETWORKSTACK_PACKAGE_NAME = "com.android.mainline.networkstack";
68
Remi NGUYEN VAN69b967f2019-01-13 03:10:49 +090069 private static final int NETWORKSTACK_TIMEOUT_MS = 10_000;
70
Remi NGUYEN VANc094a542018-12-07 16:52:24 +090071 @NonNull
72 @GuardedBy("mPendingNetStackRequests")
Remi NGUYEN VANe67b0c32018-12-27 16:43:56 +090073 private final ArrayList<NetworkStackCallback> mPendingNetStackRequests = new ArrayList<>();
Remi NGUYEN VANc094a542018-12-07 16:52:24 +090074 @Nullable
75 @GuardedBy("mPendingNetStackRequests")
76 private INetworkStackConnector mConnector;
77
Remi NGUYEN VAN69b967f2019-01-13 03:10:49 +090078 private volatile boolean mNetworkStackStartRequested = false;
79
Remi NGUYEN VANe67b0c32018-12-27 16:43:56 +090080 private interface NetworkStackCallback {
Remi NGUYEN VANc094a542018-12-07 16:52:24 +090081 void onNetworkStackConnected(INetworkStackConnector connector);
82 }
83
Remi NGUYEN VANd8c75a02019-01-30 21:45:56 +090084 /** @hide */
Remi NGUYEN VANc094a542018-12-07 16:52:24 +090085 public NetworkStack() { }
86
Remi NGUYEN VAN0e3d09232018-12-04 12:13:09 +090087 /**
88 * Create a DHCP server according to the specified parameters.
89 *
90 * <p>The server will be returned asynchronously through the provided callbacks.
Remi NGUYEN VANd8c75a02019-01-30 21:45:56 +090091 * @hide
Remi NGUYEN VAN0e3d09232018-12-04 12:13:09 +090092 */
93 public void makeDhcpServer(final String ifName, final DhcpServingParamsParcel params,
94 final IDhcpServerCallbacks cb) {
95 requestConnector(connector -> {
96 try {
97 connector.makeDhcpServer(ifName, params, cb);
98 } catch (RemoteException e) {
99 e.rethrowFromSystemServer();
100 }
101 });
102 }
103
Remi NGUYEN VANe67b0c32018-12-27 16:43:56 +0900104 /**
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +0900105 * Create an IpClient on the specified interface.
106 *
107 * <p>The IpClient will be returned asynchronously through the provided callbacks.
Remi NGUYEN VANd8c75a02019-01-30 21:45:56 +0900108 * @hide
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +0900109 */
110 public void makeIpClient(String ifName, IIpClientCallbacks cb) {
111 requestConnector(connector -> {
112 try {
113 connector.makeIpClient(ifName, cb);
114 } catch (RemoteException e) {
115 e.rethrowFromSystemServer();
116 }
117 });
118 }
119
120 /**
Remi NGUYEN VANe67b0c32018-12-27 16:43:56 +0900121 * Create a NetworkMonitor.
122 *
123 * <p>The INetworkMonitor will be returned asynchronously through the provided callbacks.
Remi NGUYEN VANd8c75a02019-01-30 21:45:56 +0900124 * @hide
Remi NGUYEN VANe67b0c32018-12-27 16:43:56 +0900125 */
Remi NGUYEN VAN231b52b2019-01-29 15:38:52 +0900126 public void makeNetworkMonitor(
127 NetworkParcelable network, String name, INetworkMonitorCallbacks cb) {
Remi NGUYEN VANe67b0c32018-12-27 16:43:56 +0900128 requestConnector(connector -> {
129 try {
Remi NGUYEN VAN231b52b2019-01-29 15:38:52 +0900130 connector.makeNetworkMonitor(network, name, cb);
Remi NGUYEN VANe67b0c32018-12-27 16:43:56 +0900131 } catch (RemoteException e) {
132 e.rethrowFromSystemServer();
133 }
134 });
135 }
136
Remi NGUYEN VANc094a542018-12-07 16:52:24 +0900137 private class NetworkStackConnection implements ServiceConnection {
138 @Override
139 public void onServiceConnected(ComponentName name, IBinder service) {
140 registerNetworkStackService(service);
141 }
142
143 @Override
144 public void onServiceDisconnected(ComponentName name) {
145 // TODO: crash/reboot the system ?
146 Slog.wtf(TAG, "Lost network stack connector");
147 }
148 };
149
150 private void registerNetworkStackService(@NonNull IBinder service) {
151 final INetworkStackConnector connector = INetworkStackConnector.Stub.asInterface(service);
152
153 ServiceManager.addService(Context.NETWORK_STACK_SERVICE, service, false /* allowIsolated */,
154 DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
155
Remi NGUYEN VANe67b0c32018-12-27 16:43:56 +0900156 final ArrayList<NetworkStackCallback> requests;
Remi NGUYEN VANc094a542018-12-07 16:52:24 +0900157 synchronized (mPendingNetStackRequests) {
158 requests = new ArrayList<>(mPendingNetStackRequests);
159 mPendingNetStackRequests.clear();
160 mConnector = connector;
161 }
162
Remi NGUYEN VANe67b0c32018-12-27 16:43:56 +0900163 for (NetworkStackCallback r : requests) {
Remi NGUYEN VANc094a542018-12-07 16:52:24 +0900164 r.onNetworkStackConnected(connector);
165 }
166 }
167
168 /**
169 * Start the network stack. Should be called only once on device startup.
170 *
171 * <p>This method will start the network stack either in the network stack process, or inside
172 * the system server on devices that do not support the network stack module. The network stack
173 * connector will then be delivered asynchronously to clients that requested it before it was
174 * started.
Remi NGUYEN VANd8c75a02019-01-30 21:45:56 +0900175 * @hide
Remi NGUYEN VANc094a542018-12-07 16:52:24 +0900176 */
177 public void start(Context context) {
Remi NGUYEN VAN69b967f2019-01-13 03:10:49 +0900178 mNetworkStackStartRequested = true;
Remi NGUYEN VANc094a542018-12-07 16:52:24 +0900179 // Try to bind in-process if the library is available
180 IBinder connector = null;
181 try {
182 final Class service = Class.forName(
183 "com.android.server.NetworkStackService",
184 true /* initialize */,
185 context.getClassLoader());
Remi NGUYEN VANe67b0c32018-12-27 16:43:56 +0900186 connector = (IBinder) service.getMethod("makeConnector", Context.class)
187 .invoke(null, context);
Remi NGUYEN VANc094a542018-12-07 16:52:24 +0900188 } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
189 Slog.wtf(TAG, "Could not create network stack connector from NetworkStackService");
190 // TODO: crash/reboot system here ?
191 return;
192 } catch (ClassNotFoundException e) {
193 // Normal behavior if stack is provided by the app: fall through
194 }
195
196 // In-process network stack. Add the service to the service manager here.
197 if (connector != null) {
198 registerNetworkStackService(connector);
199 return;
200 }
201 // Start the network stack process. The service will be added to the service manager in
202 // NetworkStackConnection.onServiceConnected().
203 final Intent intent = new Intent(INetworkStackConnector.class.getName());
204 final ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
205 intent.setComponent(comp);
206
207 if (comp == null || !context.bindServiceAsUser(intent, new NetworkStackConnection(),
208 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
209 Slog.wtf(TAG,
210 "Could not bind to network stack in-process, or in app with " + intent);
211 // TODO: crash/reboot system server if no network stack after a timeout ?
212 }
213 }
214
Remi NGUYEN VAN69b967f2019-01-13 03:10:49 +0900215 /**
216 * For non-system server clients, get the connector registered by the system server.
217 */
218 private INetworkStackConnector getRemoteConnector() {
219 // Block until the NetworkStack connector is registered in ServiceManager.
220 // <p>This is only useful for non-system processes that do not have a way to be notified of
221 // registration completion. Adding a callback system would be too heavy weight considering
222 // that the connector is registered on boot, so it is unlikely that a client would request
223 // it before it is registered.
224 // TODO: consider blocking boot on registration and simplify much of the logic in this class
225 IBinder connector;
226 try {
227 final long before = System.currentTimeMillis();
228 while ((connector = ServiceManager.getService(Context.NETWORK_STACK_SERVICE)) == null) {
229 Thread.sleep(20);
230 if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
231 Slog.e(TAG, "Timeout waiting for NetworkStack connector");
232 return null;
233 }
234 }
235 } catch (InterruptedException e) {
236 Slog.e(TAG, "Error waiting for NetworkStack connector", e);
237 return null;
238 }
239
Remi NGUYEN VAN800e8432019-01-21 20:57:05 +0900240 return INetworkStackConnector.Stub.asInterface(connector);
Remi NGUYEN VAN69b967f2019-01-13 03:10:49 +0900241 }
242
Remi NGUYEN VANe67b0c32018-12-27 16:43:56 +0900243 private void requestConnector(@NonNull NetworkStackCallback request) {
Remi NGUYEN VANc094a542018-12-07 16:52:24 +0900244 // TODO: PID check.
Remi NGUYEN VAN69b967f2019-01-13 03:10:49 +0900245 final int caller = Binder.getCallingUid();
Remi NGUYEN VAN3b906872019-01-31 08:46:36 +0900246 if (caller != Process.SYSTEM_UID && !UserHandle.isSameApp(caller, Process.BLUETOOTH_UID)) {
Remi NGUYEN VANc094a542018-12-07 16:52:24 +0900247 // Don't even attempt to obtain the connector and give a nice error message
248 throw new SecurityException(
249 "Only the system server should try to bind to the network stack.");
250 }
251
Remi NGUYEN VAN69b967f2019-01-13 03:10:49 +0900252 if (!mNetworkStackStartRequested) {
253 // The network stack is not being started in this process, e.g. this process is not
254 // the system server. Get a remote connector registered by the system server.
Remi NGUYEN VAN800e8432019-01-21 20:57:05 +0900255 final INetworkStackConnector connector = getRemoteConnector();
256 synchronized (mPendingNetStackRequests) {
257 mConnector = connector;
258 }
259 request.onNetworkStackConnected(connector);
Remi NGUYEN VAN69b967f2019-01-13 03:10:49 +0900260 return;
261 }
262
Remi NGUYEN VANc094a542018-12-07 16:52:24 +0900263 final INetworkStackConnector connector;
264 synchronized (mPendingNetStackRequests) {
265 connector = mConnector;
266 if (connector == null) {
267 mPendingNetStackRequests.add(request);
268 return;
269 }
270 }
271
272 request.onNetworkStackConnected(connector);
273 }
274}