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