1 /* 2 * Copyright (C) 2020 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.vcn; 18 19 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; 20 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; 21 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; 22 import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; 23 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 24 25 import static com.android.server.VcnManagementService.VDBG; 26 27 import android.annotation.NonNull; 28 import android.content.Context; 29 import android.net.ConnectivityManager; 30 import android.net.NetworkCapabilities; 31 import android.net.NetworkProvider; 32 import android.net.NetworkRequest; 33 import android.net.NetworkScore; 34 import android.net.vcn.VcnGatewayConnectionConfig; 35 import android.os.Handler; 36 import android.os.HandlerExecutor; 37 import android.os.Looper; 38 import android.util.ArraySet; 39 import android.util.Slog; 40 41 import com.android.internal.annotations.VisibleForTesting; 42 import com.android.internal.annotations.VisibleForTesting.Visibility; 43 import com.android.internal.util.IndentingPrintWriter; 44 45 import java.util.Objects; 46 import java.util.Set; 47 import java.util.concurrent.Executor; 48 49 /** 50 * VCN Network Provider routes NetworkRequests to listeners to bring up tunnels as needed. 51 * 52 * <p>The VcnNetworkProvider provides a caching layer to ensure that all listeners receive all 53 * active NetworkRequest(s), including ones that were filed prior to listener registration. 54 * 55 * @hide 56 */ 57 public class VcnNetworkProvider extends NetworkProvider { 58 private static final String TAG = VcnNetworkProvider.class.getSimpleName(); 59 60 private final Set<NetworkRequestListener> mListeners = new ArraySet<>(); 61 62 private final Context mContext; 63 private final Handler mHandler; 64 private final Dependencies mDeps; 65 66 /** 67 * Cache of NetworkRequest(s). 68 * 69 * <p>NetworkRequests are immutable once created, and therefore can be used as stable keys. 70 */ 71 private final Set<NetworkRequest> mRequests = new ArraySet<>(); 72 VcnNetworkProvider(@onNull Context context, @NonNull Looper looper)73 public VcnNetworkProvider(@NonNull Context context, @NonNull Looper looper) { 74 this(context, looper, new Dependencies()); 75 } 76 77 @VisibleForTesting(visibility = Visibility.PRIVATE) VcnNetworkProvider( @onNull Context context, @NonNull Looper looper, @NonNull Dependencies dependencies)78 public VcnNetworkProvider( 79 @NonNull Context context, @NonNull Looper looper, @NonNull Dependencies dependencies) { 80 super( 81 Objects.requireNonNull(context, "Missing context"), 82 Objects.requireNonNull(looper, "Missing looper"), 83 TAG); 84 85 mContext = context; 86 mHandler = new Handler(looper); 87 mDeps = Objects.requireNonNull(dependencies, "Missing dependencies"); 88 } 89 90 /** Registers this VcnNetworkProvider and a generic network offer with ConnectivityService. */ register()91 public void register() { 92 mContext.getSystemService(ConnectivityManager.class).registerNetworkProvider(this); 93 mDeps.registerNetworkOffer( 94 this, 95 Vcn.getNetworkScore(), // score filter 96 buildCapabilityFilter(), 97 new HandlerExecutor(mHandler), 98 new NetworkOfferCallback() { 99 @Override 100 public void onNetworkNeeded(@NonNull NetworkRequest request) { 101 handleNetworkRequested(request); 102 } 103 104 @Override 105 public void onNetworkUnneeded(@NonNull NetworkRequest request) { 106 handleNetworkRequestWithdrawn(request); 107 } 108 }); 109 } 110 111 /** Builds the filter for NetworkRequests that can be served by the VcnNetworkProvider. */ buildCapabilityFilter()112 private NetworkCapabilities buildCapabilityFilter() { 113 final NetworkCapabilities.Builder builder = 114 new NetworkCapabilities.Builder() 115 .addTransportType(TRANSPORT_CELLULAR) 116 .addCapability(NET_CAPABILITY_TRUSTED) 117 .addCapability(NET_CAPABILITY_NOT_RESTRICTED) 118 .addCapability(NET_CAPABILITY_NOT_VPN) 119 .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); 120 121 for (int cap : VcnGatewayConnectionConfig.ALLOWED_CAPABILITIES) { 122 builder.addCapability(cap); 123 } 124 125 return builder.build(); 126 } 127 128 /** 129 * Registers a NetworkRequestListener with this NetworkProvider. 130 * 131 * <p>Upon registering, the provided listener will receive all cached requests. 132 */ 133 @VisibleForTesting(visibility = Visibility.PACKAGE) registerListener(@onNull NetworkRequestListener listener)134 public void registerListener(@NonNull NetworkRequestListener listener) { 135 mListeners.add(listener); 136 137 // Send listener all cached requests 138 resendAllRequests(listener); 139 } 140 141 /** Unregisters the specified listener from receiving future NetworkRequests. */ 142 @VisibleForTesting(visibility = Visibility.PACKAGE) unregisterListener(@onNull NetworkRequestListener listener)143 public void unregisterListener(@NonNull NetworkRequestListener listener) { 144 mListeners.remove(listener); 145 } 146 147 /** Sends all cached NetworkRequest(s) to the specified listener. */ 148 @VisibleForTesting(visibility = Visibility.PACKAGE) resendAllRequests(@onNull NetworkRequestListener listener)149 public void resendAllRequests(@NonNull NetworkRequestListener listener) { 150 for (NetworkRequest request : mRequests) { 151 notifyListenerForEvent(listener, request); 152 } 153 } 154 notifyListenerForEvent( @onNull NetworkRequestListener listener, @NonNull NetworkRequest request)155 private void notifyListenerForEvent( 156 @NonNull NetworkRequestListener listener, @NonNull NetworkRequest request) { 157 listener.onNetworkRequested(request); 158 } 159 handleNetworkRequested(@onNull NetworkRequest request)160 private void handleNetworkRequested(@NonNull NetworkRequest request) { 161 if (VDBG) { 162 Slog.v(TAG, "Network requested: Request = " + request); 163 } 164 165 mRequests.add(request); 166 167 // TODO(b/176939047): Intelligently route requests to prioritized VcnInstances (based on 168 // Default Data Sub, or similar) 169 for (NetworkRequestListener listener : mListeners) { 170 notifyListenerForEvent(listener, request); 171 } 172 } 173 handleNetworkRequestWithdrawn(@onNull NetworkRequest request)174 private void handleNetworkRequestWithdrawn(@NonNull NetworkRequest request) { 175 if (VDBG) { 176 Slog.v(TAG, "Network request withdrawn: Request = " + request); 177 } 178 179 mRequests.remove(request); 180 } 181 182 // package-private 183 interface NetworkRequestListener { onNetworkRequested(@onNull NetworkRequest request)184 void onNetworkRequested(@NonNull NetworkRequest request); 185 } 186 187 /** 188 * Dumps the state of this VcnNetworkProvider for logging and debugging purposes. 189 * 190 * <p>PII and credentials MUST NEVER be dumped here. 191 */ dump(IndentingPrintWriter pw)192 public void dump(IndentingPrintWriter pw) { 193 pw.println("VcnNetworkProvider:"); 194 pw.increaseIndent(); 195 196 pw.println("mListeners:"); 197 pw.increaseIndent(); 198 for (NetworkRequestListener listener : mListeners) { 199 pw.println(listener); 200 } 201 pw.decreaseIndent(); 202 pw.println(); 203 204 pw.println("mRequests:"); 205 pw.increaseIndent(); 206 for (NetworkRequest request : mRequests) { 207 pw.println(request); 208 } 209 pw.decreaseIndent(); 210 pw.println(); 211 212 pw.decreaseIndent(); 213 } 214 215 /** Proxy class for dependencies used for testing. */ 216 @VisibleForTesting(visibility = Visibility.PRIVATE) 217 public static class Dependencies { 218 /** Registers a given network offer for the given provider. */ registerNetworkOffer( @onNull VcnNetworkProvider provider, @NonNull NetworkScore score, @NonNull NetworkCapabilities capabilitiesFilter, @NonNull Executor executor, @NonNull NetworkOfferCallback callback)219 public void registerNetworkOffer( 220 @NonNull VcnNetworkProvider provider, 221 @NonNull NetworkScore score, 222 @NonNull NetworkCapabilities capabilitiesFilter, 223 @NonNull Executor executor, 224 @NonNull NetworkOfferCallback callback) { 225 provider.registerNetworkOffer(score, capabilitiesFilter, executor, callback); 226 } 227 } 228 } 229