1 /*
2  * Copyright (C) 2023 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.routeselection;
18 
19 import static com.android.server.VcnManagementService.LOCAL_LOG;
20 import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
21 
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.net.IpSecTransform;
25 import android.net.IpSecTransformState;
26 import android.net.Network;
27 import android.os.OutcomeReceiver;
28 import android.util.CloseGuard;
29 import android.util.Slog;
30 
31 import com.android.internal.annotations.VisibleForTesting;
32 import com.android.internal.annotations.VisibleForTesting.Visibility;
33 import com.android.server.vcn.VcnContext;
34 
35 import java.util.Objects;
36 import java.util.concurrent.Executor;
37 
38 /**
39  * NetworkMetricMonitor is responsible for managing metric monitoring and tracking validation
40  * results.
41  *
42  * <p>This class is flag gated by "network_metric_monitor"
43  */
44 public abstract class NetworkMetricMonitor implements AutoCloseable {
45     private static final String TAG = NetworkMetricMonitor.class.getSimpleName();
46 
47     private static final boolean VDBG = false; // STOPSHIP: if true
48 
49     @NonNull private final CloseGuard mCloseGuard = new CloseGuard();
50 
51     @NonNull private final VcnContext mVcnContext;
52     @NonNull private final Network mNetwork;
53     @NonNull private final NetworkMetricMonitorCallback mCallback;
54 
55     private boolean mIsSelectedUnderlyingNetwork;
56     private boolean mIsStarted;
57     private boolean mIsValidationFailed;
58 
NetworkMetricMonitor( @onNull VcnContext vcnContext, @NonNull Network network, @Nullable PersistableBundleWrapper carrierConfig, @NonNull NetworkMetricMonitorCallback callback)59     protected NetworkMetricMonitor(
60             @NonNull VcnContext vcnContext,
61             @NonNull Network network,
62             @Nullable PersistableBundleWrapper carrierConfig,
63             @NonNull NetworkMetricMonitorCallback callback)
64             throws IllegalAccessException {
65         if (!vcnContext.isFlagNetworkMetricMonitorEnabled()) {
66             // Caller error
67             logWtf("networkMetricMonitor flag disabled");
68             throw new IllegalAccessException("networkMetricMonitor flag disabled");
69         }
70 
71         mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext");
72         mNetwork = Objects.requireNonNull(network, "Missing network");
73         mCallback = Objects.requireNonNull(callback, "Missing callback");
74 
75         mIsSelectedUnderlyingNetwork = false;
76         mIsStarted = false;
77         mIsValidationFailed = false;
78     }
79 
80     /** Callback to notify caller of the validation result */
81     public interface NetworkMetricMonitorCallback {
82         /** Called when there is a validation result is ready */
onValidationResultReceived()83         void onValidationResultReceived();
84     }
85 
86     /**
87      * Start monitoring
88      *
89      * <p>This method might be called on a an already started monitor for updating monitor
90      * properties (e.g. IpSecTransform, carrier config)
91      *
92      * <p>Subclasses MUST call super.start() when overriding this method
93      */
start()94     protected void start() {
95         mIsStarted = true;
96     }
97 
98     /**
99      * Stop monitoring
100      *
101      * <p>Subclasses MUST call super.stop() when overriding this method
102      */
stop()103     public void stop() {
104         mIsValidationFailed = false;
105         mIsStarted = false;
106     }
107 
108     /** Called by the subclasses when the validation result is ready */
onValidationResultReceivedInternal(boolean isFailed)109     protected void onValidationResultReceivedInternal(boolean isFailed) {
110         mIsValidationFailed = isFailed;
111         mCallback.onValidationResultReceived();
112     }
113 
114     /** Called when the underlying network changes to selected or unselected */
onSelectedUnderlyingNetworkChanged()115     protected abstract void onSelectedUnderlyingNetworkChanged();
116 
117     /**
118      * Mark the network being monitored selected or unselected
119      *
120      * <p>Subclasses MUST call super when overriding this method
121      */
setIsSelectedUnderlyingNetwork(boolean isSelectedUnderlyingNetwork)122     public void setIsSelectedUnderlyingNetwork(boolean isSelectedUnderlyingNetwork) {
123         if (mIsSelectedUnderlyingNetwork == isSelectedUnderlyingNetwork) {
124             return;
125         }
126 
127         mIsSelectedUnderlyingNetwork = isSelectedUnderlyingNetwork;
128         onSelectedUnderlyingNetworkChanged();
129     }
130 
131     /** Wrapper that allows injection for testing purposes */
132     @VisibleForTesting(visibility = Visibility.PROTECTED)
133     public static class IpSecTransformWrapper {
134         @NonNull public final IpSecTransform ipSecTransform;
135 
IpSecTransformWrapper(@onNull IpSecTransform ipSecTransform)136         public IpSecTransformWrapper(@NonNull IpSecTransform ipSecTransform) {
137             this.ipSecTransform = ipSecTransform;
138         }
139 
140         /** Poll an IpSecTransformState */
requestIpSecTransformState( @onNull Executor executor, @NonNull OutcomeReceiver<IpSecTransformState, RuntimeException> callback)141         public void requestIpSecTransformState(
142                 @NonNull Executor executor,
143                 @NonNull OutcomeReceiver<IpSecTransformState, RuntimeException> callback) {
144             ipSecTransform.requestIpSecTransformState(executor, callback);
145         }
146 
147         /** Close this instance and release the underlying resources */
close()148         public void close() {
149             ipSecTransform.close();
150         }
151 
152         @Override
hashCode()153         public int hashCode() {
154             return Objects.hash(ipSecTransform);
155         }
156 
157         @Override
equals(Object o)158         public boolean equals(Object o) {
159             if (!(o instanceof IpSecTransformWrapper)) {
160                 return false;
161             }
162 
163             final IpSecTransformWrapper other = (IpSecTransformWrapper) o;
164 
165             return Objects.equals(ipSecTransform, other.ipSecTransform);
166         }
167     }
168 
169     /** Set the IpSecTransform that applied to the Network being monitored */
setInboundTransform(@onNull IpSecTransform inTransform)170     public void setInboundTransform(@NonNull IpSecTransform inTransform) {
171         setInboundTransformInternal(new IpSecTransformWrapper(inTransform));
172     }
173 
174     /**
175      * Set the IpSecTransform that applied to the Network being monitored *
176      *
177      * <p>Subclasses MUST call super when overriding this method
178      */
179     @VisibleForTesting(visibility = Visibility.PRIVATE)
setInboundTransformInternal(@onNull IpSecTransformWrapper inTransform)180     public void setInboundTransformInternal(@NonNull IpSecTransformWrapper inTransform) {
181         // Subclasses MUST override it if they care
182     }
183 
184     /** Update the carrierconfig */
setCarrierConfig(@ullable PersistableBundleWrapper carrierConfig)185     public void setCarrierConfig(@Nullable PersistableBundleWrapper carrierConfig) {
186         // Subclasses MUST override it if they care
187     }
188 
189     /** Called when LinkProperties or NetworkCapabilities have changed */
onLinkPropertiesOrCapabilitiesChanged()190     public void onLinkPropertiesOrCapabilitiesChanged() {
191         // Subclasses MUST override it if they care
192     }
193 
isValidationFailed()194     public boolean isValidationFailed() {
195         return mIsValidationFailed;
196     }
197 
isSelectedUnderlyingNetwork()198     public boolean isSelectedUnderlyingNetwork() {
199         return mIsSelectedUnderlyingNetwork;
200     }
201 
isStarted()202     public boolean isStarted() {
203         return mIsStarted;
204     }
205 
206     @NonNull
getVcnContext()207     public VcnContext getVcnContext() {
208         return mVcnContext;
209     }
210 
211     @NonNull
getNetwork()212     public Network getNetwork() {
213         return mNetwork;
214     }
215 
216     // Override methods for AutoCloseable. Subclasses MUST call super when overriding this method
217     @Override
close()218     public void close() {
219         mCloseGuard.close();
220 
221         stop();
222     }
223 
224     // Override #finalize() to use closeGuard for flagging that #close() was not called
225     @SuppressWarnings("Finalize")
226     @Override
finalize()227     protected void finalize() throws Throwable {
228         try {
229             if (mCloseGuard != null) {
230                 mCloseGuard.warnIfOpen();
231             }
232             close();
233         } finally {
234             super.finalize();
235         }
236     }
237 
getClassName()238     private String getClassName() {
239         return this.getClass().getSimpleName();
240     }
241 
getLogPrefix()242     protected String getLogPrefix() {
243         return " [Network " + mNetwork + "] ";
244     }
245 
logV(String msg)246     protected void logV(String msg) {
247         if (VDBG) {
248             Slog.v(getClassName(), getLogPrefix() + msg);
249             LOCAL_LOG.log("[VERBOSE ] " + getClassName() + getLogPrefix() + msg);
250         }
251     }
252 
logInfo(String msg)253     protected void logInfo(String msg) {
254         Slog.i(getClassName(), getLogPrefix() + msg);
255         LOCAL_LOG.log("[INFO ] " + getClassName() + getLogPrefix() + msg);
256     }
257 
logW(String msg)258     protected void logW(String msg) {
259         Slog.w(getClassName(), getLogPrefix() + msg);
260         LOCAL_LOG.log("[WARN ] " + getClassName() + getLogPrefix() + msg);
261     }
262 
logWtf(String msg)263     protected void logWtf(String msg) {
264         Slog.wtf(getClassName(), getLogPrefix() + msg);
265         LOCAL_LOG.log("[WTF ] " + getClassName() + getLogPrefix() + msg);
266     }
267 
logV(String className, String msgWithPrefix)268     protected static void logV(String className, String msgWithPrefix) {
269         if (VDBG) {
270             Slog.wtf(className, msgWithPrefix);
271             LOCAL_LOG.log("[VERBOSE ] " + className + msgWithPrefix);
272         }
273     }
274 
logE(String className, String msgWithPrefix)275     protected static void logE(String className, String msgWithPrefix) {
276         Slog.w(className, msgWithPrefix);
277         LOCAL_LOG.log("[ERROR ] " + className + msgWithPrefix);
278     }
279 
logWtf(String className, String msgWithPrefix)280     protected static void logWtf(String className, String msgWithPrefix) {
281         Slog.wtf(className, msgWithPrefix);
282         LOCAL_LOG.log("[WTF ] " + className + msgWithPrefix);
283     }
284 }
285