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