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