• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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