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