1 /* 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 */ 16 17 package com.android.server; 18 19 import static android.net.dhcp.IDhcpServer.STATUS_INVALID_ARGUMENT; 20 import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; 21 import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR; 22 23 import static com.android.net.module.util.DeviceConfigUtils.getResBooleanConfig; 24 import static com.android.net.module.util.FeatureVersions.FEATURE_IS_UID_NETWORKING_BLOCKED; 25 import static com.android.networkstack.util.NetworkStackUtils.IGNORE_TCP_INFO_FOR_BLOCKED_UIDS; 26 import static com.android.networkstack.util.NetworkStackUtils.SKIP_TCP_POLL_IN_LIGHT_DOZE; 27 import static com.android.server.util.PermissionUtil.checkDumpPermission; 28 29 import android.app.Service; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.net.ConnectivityManager; 33 import android.net.IIpMemoryStore; 34 import android.net.IIpMemoryStoreCallbacks; 35 import android.net.INetd; 36 import android.net.INetworkMonitor; 37 import android.net.INetworkMonitorCallbacks; 38 import android.net.INetworkStackConnector; 39 import android.net.INetworkStackStatusCallback; 40 import android.net.LinkProperties; 41 import android.net.Network; 42 import android.net.NetworkCapabilities; 43 import android.net.PrivateDnsConfigParcel; 44 import android.net.dhcp.DhcpServer; 45 import android.net.dhcp.DhcpServingParams; 46 import android.net.dhcp.DhcpServingParamsParcel; 47 import android.net.dhcp.IDhcpServerCallbacks; 48 import android.net.ip.IIpClientCallbacks; 49 import android.net.ip.IpClient; 50 import android.net.networkstack.aidl.NetworkMonitorParameters; 51 import android.net.shared.PrivateDnsConfig; 52 import android.os.Build; 53 import android.os.HandlerThread; 54 import android.os.IBinder; 55 import android.os.Looper; 56 import android.os.ParcelFileDescriptor; 57 import android.os.RemoteException; 58 import android.text.TextUtils; 59 import android.util.ArraySet; 60 61 import androidx.annotation.NonNull; 62 import androidx.annotation.Nullable; 63 import androidx.annotation.VisibleForTesting; 64 65 import com.android.internal.annotations.GuardedBy; 66 import com.android.internal.util.IndentingPrintWriter; 67 import com.android.modules.utils.BasicShellCommandHandler; 68 import com.android.net.module.util.DeviceConfigUtils; 69 import com.android.net.module.util.SharedLog; 70 import com.android.networkstack.NetworkStackNotifier; 71 import com.android.networkstack.R; 72 import com.android.networkstack.apishim.common.ShimUtils; 73 import com.android.networkstack.ipmemorystore.IpMemoryStoreService; 74 import com.android.server.connectivity.NetworkMonitor; 75 import com.android.server.util.PermissionUtil; 76 77 import java.io.FileDescriptor; 78 import java.io.PrintWriter; 79 import java.lang.ref.WeakReference; 80 import java.util.ArrayDeque; 81 import java.util.ArrayList; 82 import java.util.Collection; 83 import java.util.Collections; 84 import java.util.Comparator; 85 import java.util.HashSet; 86 import java.util.Iterator; 87 import java.util.List; 88 import java.util.ListIterator; 89 import java.util.Objects; 90 import java.util.SortedSet; 91 import java.util.TreeSet; 92 93 /** 94 * Android service used to start the network stack when bound to via an intent. 95 * 96 * <p>The service returns a binder for the system server to communicate with the network stack. 97 */ 98 public class NetworkStackService extends Service { 99 private static final String TAG = NetworkStackService.class.getSimpleName(); 100 private static NetworkStackConnector sConnector; 101 102 /** 103 * Create a binder connector for the system server to communicate with the network stack. 104 * 105 * <p>On platforms where the network stack runs in the system server process, this method may 106 * be called directly instead of obtaining the connector by binding to the service. 107 */ makeConnector(Context context)108 public static synchronized IBinder makeConnector(Context context) { 109 if (sConnector == null) { 110 sConnector = new NetworkStackConnector(context); 111 } 112 return sConnector; 113 } 114 115 @NonNull 116 @Override onBind(Intent intent)117 public IBinder onBind(Intent intent) { 118 return makeConnector(this); 119 } 120 121 /** 122 * An interface for internal clients of the network stack service that can return 123 * or create inline instances of the service it manages. 124 */ 125 public interface NetworkStackServiceManager { 126 /** 127 * Get an instance of the IpMemoryStoreService. 128 */ getIpMemoryStoreService()129 IIpMemoryStore getIpMemoryStoreService(); 130 131 /** 132 * Get an instance of the NetworkNotifier. 133 */ getNotifier()134 NetworkStackNotifier getNotifier(); 135 } 136 137 /** 138 * Permission checking dependency of the connector, useful for testing. 139 */ 140 public static class PermissionChecker { 141 /** 142 * @see PermissionUtil#enforceNetworkStackCallingPermission() 143 */ enforceNetworkStackCallingPermission()144 public void enforceNetworkStackCallingPermission() { 145 PermissionUtil.enforceNetworkStackCallingPermission(); 146 } 147 } 148 149 /** 150 * Dependencies of {@link NetworkStackConnector}, useful for testing. 151 */ 152 public static class Dependencies { 153 /** @see IpMemoryStoreService */ 154 @NonNull makeIpMemoryStoreService(@onNull Context context)155 public IpMemoryStoreService makeIpMemoryStoreService(@NonNull Context context) { 156 return new IpMemoryStoreService(context); 157 } 158 159 /** @see NetworkStackNotifier */ 160 @NonNull makeNotifier(@onNull Context context, @NonNull Looper looper)161 public NetworkStackNotifier makeNotifier(@NonNull Context context, @NonNull Looper looper) { 162 return new NetworkStackNotifier(context, looper); 163 } 164 165 /** @see DhcpServer */ 166 @NonNull makeDhcpServer(@onNull Context context, @NonNull String ifName, @NonNull DhcpServingParams params, @NonNull SharedLog log)167 public DhcpServer makeDhcpServer(@NonNull Context context, @NonNull String ifName, 168 @NonNull DhcpServingParams params, @NonNull SharedLog log) { 169 return new DhcpServer(context, ifName, params, log); 170 } 171 172 /** @see NetworkMonitor */ 173 @NonNull makeNetworkMonitor(@onNull Context context, @NonNull INetworkMonitorCallbacks cb, @NonNull Network network, @NonNull SharedLog log, @NonNull NetworkStackServiceManager nsServiceManager)174 public NetworkMonitor makeNetworkMonitor(@NonNull Context context, 175 @NonNull INetworkMonitorCallbacks cb, @NonNull Network network, 176 @NonNull SharedLog log, @NonNull NetworkStackServiceManager nsServiceManager) { 177 return new NetworkMonitor(context, cb, network, log, nsServiceManager); 178 } 179 180 /** @see IpClient */ 181 @NonNull makeIpClient(@onNull Context context, @NonNull String ifName, @NonNull IIpClientCallbacks cb, @NonNull NetworkStackServiceManager nsServiceManager)182 public IpClient makeIpClient(@NonNull Context context, @NonNull String ifName, 183 @NonNull IIpClientCallbacks cb, 184 @NonNull NetworkStackServiceManager nsServiceManager) { 185 return new IpClient(context, ifName, cb, nsServiceManager); 186 } 187 } 188 189 /** 190 * Connector implementing INetworkStackConnector for clients. 191 */ 192 @VisibleForTesting 193 public static class NetworkStackConnector extends INetworkStackConnector.Stub 194 implements NetworkStackServiceManager { 195 private static final int NUM_VALIDATION_LOG_LINES = 20; 196 private final Context mContext; 197 private final PermissionChecker mPermChecker; 198 private final Dependencies mDeps; 199 private final INetd mNetd; 200 @GuardedBy("mIpClients") 201 private final ArrayList<WeakReference<IpClient>> mIpClients = new ArrayList<>(); 202 private final IpMemoryStoreService mIpMemoryStoreService; 203 @Nullable 204 private final NetworkStackNotifier mNotifier; 205 206 private static final int MAX_VALIDATION_LOGS = 10; 207 @GuardedBy("mValidationLogs") 208 private final ArrayDeque<SharedLog> mValidationLogs = new ArrayDeque<>(MAX_VALIDATION_LOGS); 209 210 private static final String DUMPSYS_ARG_VERSION = "version"; 211 212 private static final String AIDL_KEY_NETWORKSTACK = "networkstack"; 213 private static final String AIDL_KEY_IPMEMORYSTORE = "ipmemorystore"; 214 private static final String AIDL_KEY_NETD = "netd"; 215 216 private static final int VERSION_UNKNOWN = -1; 217 private static final String HASH_UNKNOWN = "unknown"; 218 219 /** 220 * Versions of the AIDL interfaces observed by the network stack, in other words versions 221 * that the framework and other modules communicating with the network stack are using. 222 * The map may hold multiple values as the interface is used by modules with different 223 * versions. 224 */ 225 @GuardedBy("mFrameworkAidlVersions") 226 private final ArraySet<AidlVersion> mAidlVersions = new ArraySet<>(); 227 228 private static final class AidlVersion implements Comparable<AidlVersion> { 229 @NonNull 230 final String mKey; 231 final int mVersion; 232 @NonNull 233 final String mHash; 234 235 private static final Comparator<AidlVersion> COMPARATOR = 236 Comparator.comparing((AidlVersion v) -> v.mKey) 237 .thenComparingInt(v -> v.mVersion) 238 .thenComparing(v -> v.mHash, String::compareTo); 239 AidlVersion(@onNull String key, int version, @NonNull String hash)240 AidlVersion(@NonNull String key, int version, @NonNull String hash) { 241 mKey = key; 242 mVersion = version; 243 mHash = hash; 244 } 245 246 @Override hashCode()247 public int hashCode() { 248 return Objects.hash(mVersion, mHash); 249 } 250 251 @Override equals(@ullable Object obj)252 public boolean equals(@Nullable Object obj) { 253 if (!(obj instanceof AidlVersion)) return false; 254 final AidlVersion other = (AidlVersion) obj; 255 return Objects.equals(mKey, other.mKey) 256 && Objects.equals(mVersion, other.mVersion) 257 && Objects.equals(mHash, other.mHash); 258 } 259 260 @NonNull 261 @Override toString()262 public String toString() { 263 // Use a format that can be easily parsed by tests for the version 264 return String.format("%s:%s:%s", mKey, mVersion, mHash); 265 } 266 267 @Override compareTo(AidlVersion o)268 public int compareTo(AidlVersion o) { 269 return COMPARATOR.compare(this, o); 270 } 271 } 272 addValidationLogs(Network network, String name)273 private SharedLog addValidationLogs(Network network, String name) { 274 final SharedLog log = new SharedLog(NUM_VALIDATION_LOG_LINES, network + " - " + name); 275 synchronized (mValidationLogs) { 276 while (mValidationLogs.size() >= MAX_VALIDATION_LOGS) { 277 mValidationLogs.removeLast(); 278 } 279 mValidationLogs.addFirst(log); 280 } 281 return log; 282 } 283 NetworkStackConnector(@onNull Context context)284 NetworkStackConnector(@NonNull Context context) { 285 this(context, new PermissionChecker(), new Dependencies()); 286 } 287 288 @VisibleForTesting NetworkStackConnector( @onNull Context context, @NonNull PermissionChecker permChecker, @NonNull Dependencies deps)289 public NetworkStackConnector( 290 @NonNull Context context, @NonNull PermissionChecker permChecker, 291 @NonNull Dependencies deps) { 292 mContext = context; 293 mPermChecker = permChecker; 294 mDeps = deps; 295 mNetd = INetd.Stub.asInterface( 296 (IBinder) context.getSystemService(Context.NETD_SERVICE)); 297 mIpMemoryStoreService = mDeps.makeIpMemoryStoreService(context); 298 // NetworkStackNotifier only shows notifications relevant for API level > Q 299 if (ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q)) { 300 final HandlerThread notifierThread = new HandlerThread( 301 NetworkStackNotifier.class.getSimpleName()); 302 notifierThread.start(); 303 mNotifier = mDeps.makeNotifier(context, notifierThread.getLooper()); 304 } else { 305 mNotifier = null; 306 } 307 308 int netdVersion; 309 String netdHash; 310 try { 311 netdVersion = mNetd.getInterfaceVersion(); 312 netdHash = mNetd.getInterfaceHash(); 313 } catch (RemoteException e) { 314 mLog.e("Error obtaining INetd version", e); 315 netdVersion = VERSION_UNKNOWN; 316 netdHash = HASH_UNKNOWN; 317 } 318 updateNetdAidlVersion(netdVersion, netdHash); 319 } 320 updateNetdAidlVersion(final int version, final String hash)321 private void updateNetdAidlVersion(final int version, final String hash) { 322 synchronized (mAidlVersions) { 323 mAidlVersions.add(new AidlVersion(AIDL_KEY_NETD, version, hash)); 324 } 325 } 326 updateNetworkStackAidlVersion(final int version, final String hash)327 private void updateNetworkStackAidlVersion(final int version, final String hash) { 328 synchronized (mAidlVersions) { 329 mAidlVersions.add(new AidlVersion(AIDL_KEY_NETWORKSTACK, version, hash)); 330 } 331 } 332 updateIpMemoryStoreAidlVersion(final int version, final String hash)333 private void updateIpMemoryStoreAidlVersion(final int version, final String hash) { 334 synchronized (mAidlVersions) { 335 mAidlVersions.add(new AidlVersion(AIDL_KEY_IPMEMORYSTORE, version, hash)); 336 } 337 } 338 339 @NonNull 340 private final SharedLog mLog = new SharedLog(TAG); 341 342 @Override makeDhcpServer(@onNull String ifName, @NonNull DhcpServingParamsParcel params, @NonNull IDhcpServerCallbacks cb)343 public void makeDhcpServer(@NonNull String ifName, @NonNull DhcpServingParamsParcel params, 344 @NonNull IDhcpServerCallbacks cb) throws RemoteException { 345 mPermChecker.enforceNetworkStackCallingPermission(); 346 updateNetworkStackAidlVersion(cb.getInterfaceVersion(), cb.getInterfaceHash()); 347 final DhcpServer server; 348 try { 349 server = mDeps.makeDhcpServer( 350 mContext, 351 ifName, 352 DhcpServingParams.fromParcelableObject(params), 353 mLog.forSubComponent(ifName + ".DHCP")); 354 } catch (DhcpServingParams.InvalidParameterException e) { 355 mLog.e("Invalid DhcpServingParams", e); 356 cb.onDhcpServerCreated(STATUS_INVALID_ARGUMENT, null); 357 return; 358 } catch (Exception e) { 359 mLog.e("Unknown error starting DhcpServer", e); 360 cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null); 361 return; 362 } 363 cb.onDhcpServerCreated(STATUS_SUCCESS, server.makeConnector()); 364 } 365 366 @Override makeNetworkMonitor(Network network, String name, INetworkMonitorCallbacks cb)367 public void makeNetworkMonitor(Network network, String name, INetworkMonitorCallbacks cb) 368 throws RemoteException { 369 mPermChecker.enforceNetworkStackCallingPermission(); 370 updateNetworkStackAidlVersion(cb.getInterfaceVersion(), cb.getInterfaceHash()); 371 final SharedLog log = addValidationLogs(network, name); 372 final NetworkMonitor nm = mDeps.makeNetworkMonitor(mContext, cb, network, log, this); 373 cb.onNetworkMonitorCreated(new NetworkMonitorConnector(nm, mPermChecker)); 374 } 375 376 @Override makeIpClient(String ifName, IIpClientCallbacks cb)377 public void makeIpClient(String ifName, IIpClientCallbacks cb) throws RemoteException { 378 mPermChecker.enforceNetworkStackCallingPermission(); 379 updateNetworkStackAidlVersion(cb.getInterfaceVersion(), cb.getInterfaceHash()); 380 final IpClient ipClient = mDeps.makeIpClient( 381 mContext, ifName, cb, this); 382 383 synchronized (mIpClients) { 384 final Iterator<WeakReference<IpClient>> it = mIpClients.iterator(); 385 while (it.hasNext()) { 386 final IpClient ipc = it.next().get(); 387 if (ipc == null) { 388 it.remove(); 389 } 390 } 391 mIpClients.add(new WeakReference<>(ipClient)); 392 } 393 394 cb.onIpClientCreated(ipClient.makeConnector()); 395 } 396 397 @Override getIpMemoryStoreService()398 public IIpMemoryStore getIpMemoryStoreService() { 399 return mIpMemoryStoreService; 400 } 401 402 @Override getNotifier()403 public NetworkStackNotifier getNotifier() { 404 return mNotifier; 405 } 406 407 @Override fetchIpMemoryStore(@onNull final IIpMemoryStoreCallbacks cb)408 public void fetchIpMemoryStore(@NonNull final IIpMemoryStoreCallbacks cb) 409 throws RemoteException { 410 mPermChecker.enforceNetworkStackCallingPermission(); 411 updateIpMemoryStoreAidlVersion(cb.getInterfaceVersion(), cb.getInterfaceHash()); 412 cb.onIpMemoryStoreFetched(mIpMemoryStoreService); 413 } 414 415 @Override allowTestUid(int uid, @Nullable INetworkStackStatusCallback cb)416 public void allowTestUid(int uid, @Nullable INetworkStackStatusCallback cb) 417 throws RemoteException { 418 // setTestUid does its own permission checks 419 PermissionUtil.setTestUid(mContext, uid); 420 mLog.i("Allowing test uid " + uid); 421 if (cb != null) cb.onStatusAvailable(0); 422 } 423 424 @Override @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) dump(@onNull FileDescriptor fd, @NonNull PrintWriter fout, @Nullable String[] args)425 public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout, 426 @Nullable String[] args) { 427 checkDumpPermission(); 428 429 final IndentingPrintWriter pw = new IndentingPrintWriter(fout, " "); 430 pw.println("NetworkStack version:"); 431 dumpVersion(pw); 432 pw.println(); 433 434 if (args != null && args.length >= 1 && DUMPSYS_ARG_VERSION.equals(args[0])) { 435 return; 436 } 437 438 pw.println("Device Configs:"); 439 pw.increaseIndent(); 440 pw.println("SKIP_TCP_POLL_IN_LIGHT_DOZE=" 441 + DeviceConfigUtils.isNetworkStackFeatureNotChickenedOut( 442 mContext, SKIP_TCP_POLL_IN_LIGHT_DOZE)); 443 pw.println("FEATURE_IS_UID_NETWORKING_BLOCKED=" + DeviceConfigUtils.isFeatureSupported( 444 mContext, FEATURE_IS_UID_NETWORKING_BLOCKED)); 445 pw.println("IGNORE_TCP_INFO_FOR_BLOCKED_UIDS=" 446 + DeviceConfigUtils.isNetworkStackFeatureNotChickenedOut(mContext, 447 IGNORE_TCP_INFO_FOR_BLOCKED_UIDS)); 448 pw.decreaseIndent(); 449 pw.println(); 450 451 452 pw.println("NetworkStack logs:"); 453 mLog.dump(fd, pw, args); 454 455 // Dump full IpClient logs for non-GCed clients 456 pw.println(); 457 pw.println("Recently active IpClient logs:"); 458 final ArrayList<IpClient> ipClients = new ArrayList<>(); 459 final HashSet<String> dumpedIpClientIfaces = new HashSet<>(); 460 synchronized (mIpClients) { 461 for (WeakReference<IpClient> ipcRef : mIpClients) { 462 final IpClient ipc = ipcRef.get(); 463 if (ipc != null) { 464 ipClients.add(ipc); 465 } 466 } 467 } 468 469 for (IpClient ipc : ipClients) { 470 pw.println(ipc.getName()); 471 pw.increaseIndent(); 472 ipc.dump(fd, pw, args); 473 pw.decreaseIndent(); 474 dumpedIpClientIfaces.add(ipc.getInterfaceName()); 475 } 476 477 // State machine and connectivity metrics logs are kept for GCed IpClients 478 pw.println(); 479 pw.println("Other IpClient logs:"); 480 IpClient.dumpAllLogs(fout, dumpedIpClientIfaces); 481 482 pw.println(); 483 pw.println("Validation logs (most recent first):"); 484 synchronized (mValidationLogs) { 485 for (SharedLog p : mValidationLogs) { 486 pw.println(p.getTag()); 487 pw.increaseIndent(); 488 p.dump(fd, pw, args); 489 pw.decreaseIndent(); 490 } 491 } 492 493 pw.println(); 494 pw.print("useNeighborResource: "); 495 pw.println(getResBooleanConfig(mContext, 496 R.bool.config_no_sim_card_uses_neighbor_mcc, false)); 497 } 498 499 @Override handleShellCommand(@onNull ParcelFileDescriptor in, @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args)500 public int handleShellCommand(@NonNull ParcelFileDescriptor in, 501 @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, 502 @NonNull String[] args) { 503 return new ShellCmd().exec(this, in.getFileDescriptor(), out.getFileDescriptor(), 504 err.getFileDescriptor(), args); 505 } 506 apfShellCommand(String iface, String cmd, @Nullable String optarg)507 private String apfShellCommand(String iface, String cmd, @Nullable String optarg) { 508 synchronized (mIpClients) { 509 // HACK: An old IpClient serving the given interface name might not have been 510 // garbage collected. Since new IpClients are always appended to the list, iterate 511 // through it in reverse order to get the most up-to-date IpClient instance. 512 // Create a ListIterator at the end of the list. 513 final ListIterator it = mIpClients.listIterator(mIpClients.size()); 514 while (it.hasPrevious()) { 515 final IpClient ipClient = ((WeakReference<IpClient>) it.previous()).get(); 516 if (ipClient != null && ipClient.getInterfaceName().equals(iface)) { 517 return ipClient.apfShellCommand(cmd, optarg); 518 } 519 } 520 } 521 throw new IllegalArgumentException("No active IpClient found for interface " + iface); 522 } 523 524 private class ShellCmd extends BasicShellCommandHandler { 525 @Override onCommand(String cmd)526 public int onCommand(String cmd) { 527 if (cmd == null) { 528 return handleDefaultCommands(cmd); 529 } 530 final PrintWriter pw = getOutPrintWriter(); 531 switch (cmd) { 532 case "is-uid-networking-blocked": 533 if (!DeviceConfigUtils.isFeatureSupported(mContext, 534 FEATURE_IS_UID_NETWORKING_BLOCKED)) { 535 throw new IllegalStateException("API is unsupported"); 536 } 537 538 // Usage : cmd network_stack is-uid-networking-blocked <uid> <metered> 539 // If no argument, get and display the usage help. 540 if (getRemainingArgsCount() != 2) { 541 onHelp(); 542 throw new IllegalArgumentException("Incorrect number of arguments"); 543 } 544 final int uid; 545 final boolean metered; 546 uid = Integer.parseInt(getNextArg()); 547 metered = Boolean.parseBoolean(getNextArg()); 548 final ConnectivityManager cm = 549 mContext.getSystemService(ConnectivityManager.class); 550 pw.println(cm.isUidNetworkingBlocked(uid, metered /* isNetworkMetered */)); 551 return 0; 552 case "apf": 553 // Usage: cmd network_stack apf <iface> <cmd> 554 final String iface = getNextArg(); 555 if (iface == null) { 556 throw new IllegalArgumentException("No <iface> specified"); 557 } 558 559 final String subcmd = getNextArg(); 560 if (subcmd == null) { 561 throw new IllegalArgumentException("No <cmd> specified"); 562 } 563 564 final String optarg = getNextArg(); 565 if (getRemainingArgsCount() != 0) { 566 throw new IllegalArgumentException("Too many arguments passed"); 567 } 568 569 final String result = apfShellCommand(iface, subcmd, optarg); 570 pw.println(result); 571 return 0; 572 573 default: 574 return handleDefaultCommands(cmd); 575 } 576 } 577 578 @Override onHelp()579 public void onHelp() { 580 PrintWriter pw = getOutPrintWriter(); 581 pw.println("NetworkStack service commands:"); 582 pw.println(" help"); 583 pw.println(" Print this help text."); 584 pw.println(" is-uid-networking-blocked <uid> <metered>"); 585 pw.println(" Get whether the networking is blocked for given uid and metered."); 586 pw.println(" <uid>: The target uid."); 587 pw.println(" <metered>: [true|false], Whether the target network is metered."); 588 pw.println(" apf <iface> <cmd>"); 589 pw.println(" APF utility commands for integration tests."); 590 pw.println(" <iface>: the network interface the provided command operates on."); 591 pw.println(" <cmd>: [status]"); 592 pw.println(" status"); 593 pw.println(" returns whether the APF filter is \"running\" or \"paused\"."); 594 pw.println(" pause"); 595 pw.println(" pause APF filter generation."); 596 pw.println(" resume"); 597 pw.println(" resume APF filter generation."); 598 pw.println(" install <program-hex-string>"); 599 pw.println(" install the APF program contained in <program-hex-string>."); 600 pw.println(" The filter must be paused before installing a new program."); 601 pw.println(" capabilities"); 602 pw.println(" return the reported APF capabilities."); 603 pw.println(" Format: <apfVersion>,<maxProgramSize>,<packetFormat>"); 604 pw.println(" read"); 605 pw.println(" reads and returns the current state of APF memory."); 606 } 607 } 608 609 /** 610 * Dump version information of the module and detected system version. 611 */ dumpVersion(@onNull PrintWriter fout)612 private void dumpVersion(@NonNull PrintWriter fout) { 613 if (!ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q)) { 614 dumpVersionNumberOnly(fout); 615 return; 616 } 617 618 fout.println("LocalInterface:" + this.VERSION + ":" + this.HASH); 619 synchronized (mAidlVersions) { 620 // Sort versions for deterministic order in output 621 for (AidlVersion version : sortVersions(mAidlVersions)) { 622 fout.println(version); 623 } 624 } 625 } 626 sortVersions(Collection<AidlVersion> versions)627 private List<AidlVersion> sortVersions(Collection<AidlVersion> versions) { 628 final List<AidlVersion> sorted = new ArrayList<>(versions); 629 Collections.sort(sorted); 630 return sorted; 631 } 632 633 /** 634 * Legacy version of dumpVersion, only used for Q, as only the interface version number 635 * was used in Q. 636 * 637 * <p>Q behavior needs to be preserved as conformance tests for Q still expect this format. 638 * Once all conformance test suites are updated to expect the new format even on Q devices, 639 * this can be removed. 640 */ dumpVersionNumberOnly(@onNull PrintWriter fout)641 private void dumpVersionNumberOnly(@NonNull PrintWriter fout) { 642 fout.println("NetworkStackConnector: " + this.VERSION); 643 final SortedSet<Integer> systemServerVersions = new TreeSet<>(); 644 int netdVersion = VERSION_UNKNOWN; 645 synchronized (mAidlVersions) { 646 for (AidlVersion version : mAidlVersions) { 647 switch (version.mKey) { 648 case AIDL_KEY_IPMEMORYSTORE: 649 case AIDL_KEY_NETWORKSTACK: 650 systemServerVersions.add(version.mVersion); 651 break; 652 case AIDL_KEY_NETD: 653 netdVersion = version.mVersion; 654 break; 655 default: 656 break; 657 } 658 } 659 } 660 // TreeSet.toString is formatted as [a, b], but Q used ArraySet.toString formatted as 661 // {a, b}. ArraySet does not have guaranteed ordering, which was not a problem in Q 662 // when only one interface number was expected (and there was no unit test relying on 663 // the ordering). 664 fout.println("SystemServer: {" + TextUtils.join(", ", systemServerVersions) + "}"); 665 fout.println("Netd: " + netdVersion); 666 } 667 668 /** 669 * Get the version of the AIDL interface. 670 */ 671 @Override getInterfaceVersion()672 public int getInterfaceVersion() { 673 return this.VERSION; 674 } 675 676 @Override getInterfaceHash()677 public String getInterfaceHash() { 678 return this.HASH; 679 } 680 } 681 682 /** 683 * Proxy for {@link NetworkMonitor} that implements {@link INetworkMonitor}. 684 */ 685 @VisibleForTesting 686 public static class NetworkMonitorConnector extends INetworkMonitor.Stub { 687 @NonNull 688 private final NetworkMonitor mNm; 689 @NonNull 690 private final PermissionChecker mPermChecker; 691 NetworkMonitorConnector(@onNull NetworkMonitor nm, @NonNull PermissionChecker permChecker)692 public NetworkMonitorConnector(@NonNull NetworkMonitor nm, 693 @NonNull PermissionChecker permChecker) { 694 mNm = nm; 695 mPermChecker = permChecker; 696 } 697 698 @Override start()699 public void start() { 700 mPermChecker.enforceNetworkStackCallingPermission(); 701 mNm.start(); 702 } 703 704 @Override launchCaptivePortalApp()705 public void launchCaptivePortalApp() { 706 mPermChecker.enforceNetworkStackCallingPermission(); 707 mNm.launchCaptivePortalApp(); 708 } 709 710 @Override notifyCaptivePortalAppFinished(int response)711 public void notifyCaptivePortalAppFinished(int response) { 712 mPermChecker.enforceNetworkStackCallingPermission(); 713 mNm.notifyCaptivePortalAppFinished(response); 714 } 715 716 @Override setAcceptPartialConnectivity()717 public void setAcceptPartialConnectivity() { 718 mPermChecker.enforceNetworkStackCallingPermission(); 719 mNm.setAcceptPartialConnectivity(); 720 } 721 722 @Override forceReevaluation(int uid)723 public void forceReevaluation(int uid) { 724 mPermChecker.enforceNetworkStackCallingPermission(); 725 mNm.forceReevaluation(uid); 726 } 727 728 @Override notifyPrivateDnsChanged(PrivateDnsConfigParcel config)729 public void notifyPrivateDnsChanged(PrivateDnsConfigParcel config) { 730 mPermChecker.enforceNetworkStackCallingPermission(); 731 mNm.notifyPrivateDnsSettingsChanged(PrivateDnsConfig.fromParcel(config)); 732 } 733 734 @Override notifyDnsResponse(int returnCode)735 public void notifyDnsResponse(int returnCode) { 736 mPermChecker.enforceNetworkStackCallingPermission(); 737 mNm.notifyDnsResponse(returnCode); 738 } 739 740 /** 741 * Send a notification to NetworkMonitor indicating that the network is now connected. 742 * @Deprecated use notifyNetworkConnectedParcel, which also passes the NetworkAgentConfig. 743 */ 744 @Override notifyNetworkConnected(LinkProperties lp, NetworkCapabilities nc)745 public void notifyNetworkConnected(LinkProperties lp, NetworkCapabilities nc) { 746 mPermChecker.enforceNetworkStackCallingPermission(); 747 mNm.notifyNetworkConnected(lp, nc); 748 } 749 750 /** 751 * Send a notification to NetworkMonitor indicating that the network is now connected. 752 */ 753 @Override notifyNetworkConnectedParcel(NetworkMonitorParameters params)754 public void notifyNetworkConnectedParcel(NetworkMonitorParameters params) { 755 mPermChecker.enforceNetworkStackCallingPermission(); 756 mNm.notifyNetworkConnectedParcel(params); 757 } 758 759 @Override notifyNetworkDisconnected()760 public void notifyNetworkDisconnected() { 761 mPermChecker.enforceNetworkStackCallingPermission(); 762 mNm.notifyNetworkDisconnected(); 763 } 764 765 @Override notifyLinkPropertiesChanged(LinkProperties lp)766 public void notifyLinkPropertiesChanged(LinkProperties lp) { 767 mPermChecker.enforceNetworkStackCallingPermission(); 768 mNm.notifyLinkPropertiesChanged(lp); 769 } 770 771 @Override notifyNetworkCapabilitiesChanged(NetworkCapabilities nc)772 public void notifyNetworkCapabilitiesChanged(NetworkCapabilities nc) { 773 mPermChecker.enforceNetworkStackCallingPermission(); 774 mNm.notifyNetworkCapabilitiesChanged(nc); 775 } 776 777 @Override getInterfaceVersion()778 public int getInterfaceVersion() { 779 return this.VERSION; 780 } 781 782 @Override getInterfaceHash()783 public String getInterfaceHash() { 784 return this.HASH; 785 } 786 } 787 } 788