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.connectivity; 18 19 import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET; 20 import static android.net.SocketKeepalive.MIN_INTERVAL_SEC; 21 import static android.net.SocketKeepalive.SUCCESS; 22 import static android.net.SocketKeepalive.SUCCESS_PAUSED; 23 import static android.system.OsConstants.AF_INET; 24 import static android.system.OsConstants.AF_INET6; 25 import static android.system.OsConstants.SOL_SOCKET; 26 import static android.system.OsConstants.SO_SNDTIMEO; 27 28 import static com.android.net.module.util.HandlerUtils.ensureRunningOnHandlerThread; 29 import static com.android.net.module.util.netlink.NetlinkUtils.IO_TIMEOUT_MS; 30 31 import android.annotation.IntDef; 32 import android.annotation.NonNull; 33 import android.annotation.Nullable; 34 import android.app.AlarmManager; 35 import android.content.Context; 36 import android.net.INetd; 37 import android.net.ISocketKeepaliveCallback; 38 import android.net.MarkMaskParcel; 39 import android.net.Network; 40 import android.net.SocketKeepalive.InvalidSocketException; 41 import android.os.FileUtils; 42 import android.os.Handler; 43 import android.os.IBinder; 44 import android.os.Message; 45 import android.os.RemoteException; 46 import android.os.SystemClock; 47 import android.system.ErrnoException; 48 import android.system.Os; 49 import android.system.OsConstants; 50 import android.system.StructTimeval; 51 import android.util.LocalLog; 52 import android.util.Log; 53 import android.util.Pair; 54 import android.util.SparseArray; 55 56 import com.android.internal.annotations.VisibleForTesting; 57 import com.android.internal.util.IndentingPrintWriter; 58 import com.android.net.module.util.BinderUtils; 59 import com.android.net.module.util.CollectionUtils; 60 import com.android.net.module.util.DeviceConfigUtils; 61 import com.android.net.module.util.HexDump; 62 import com.android.net.module.util.SocketUtils; 63 import com.android.net.module.util.netlink.InetDiagMessage; 64 import com.android.net.module.util.netlink.NetlinkMessage; 65 import com.android.net.module.util.netlink.NetlinkUtils; 66 import com.android.net.module.util.netlink.StructNlAttr; 67 68 import java.io.FileDescriptor; 69 import java.io.InterruptedIOException; 70 import java.lang.annotation.Retention; 71 import java.lang.annotation.RetentionPolicy; 72 import java.net.SocketException; 73 import java.nio.BufferUnderflowException; 74 import java.nio.ByteBuffer; 75 import java.util.ArrayList; 76 import java.util.List; 77 import java.util.Objects; 78 79 /** 80 * Manages automatic on/off socket keepalive requests. 81 * 82 * Provides methods to stop and start automatic keepalive requests, and keeps track of keepalives 83 * across all networks. This class is tightly coupled to ConnectivityService. It is not 84 * thread-safe and its handle* methods must be called only from the ConnectivityService handler 85 * thread. 86 */ 87 public class AutomaticOnOffKeepaliveTracker { 88 private static final String TAG = "AutomaticOnOffKeepaliveTracker"; 89 private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); 90 private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET6, AF_INET}; 91 private static final long LOW_TCP_POLLING_INTERVAL_MS = 1_000L; 92 private static final int ADJUST_TCP_POLLING_DELAY_MS = 2000; 93 private static final String AUTOMATIC_ON_OFF_KEEPALIVE_DISABLE_FLAG = 94 "automatic_on_off_keepalive_disable_flag"; 95 public static final long METRICS_COLLECTION_DURATION_MS = 24 * 60 * 60 * 1_000L; 96 97 // ConnectivityService parses message constants from itself and AutomaticOnOffKeepaliveTracker 98 // with MessageUtils for debugging purposes, and crashes if some messages have the same values. 99 private static final int BASE = 2000; 100 /** 101 * Sent by AutomaticOnOffKeepaliveTracker periodically (when relevant) to trigger monitor 102 * automatic keepalive request. 103 * 104 * NATT keepalives have an automatic mode where the system only sends keepalive packets when 105 * TCP sockets are open over a VPN. The system will check periodically for presence of 106 * such open sockets, and this message is what triggers the re-evaluation. 107 * 108 * obj = A Binder object associated with the keepalive. 109 */ 110 public static final int CMD_MONITOR_AUTOMATIC_KEEPALIVE = BASE + 1; 111 112 /** 113 * Sent by AutomaticOnOffKeepaliveTracker to ConnectivityService to start a keepalive. 114 * 115 * obj = AutomaticKeepaliveInfo object 116 */ 117 public static final int CMD_REQUEST_START_KEEPALIVE = BASE + 2; 118 119 /** 120 * States for {@code #AutomaticOnOffKeepalive}. 121 * 122 * If automatic mode is off for this keepalive, the state is STATE_ALWAYS_ON and it stays 123 * so for the entire lifetime of this object. 124 * 125 * If enabled, a new AutomaticOnOffKeepalive starts with STATE_ENABLED. The system will monitor 126 * the TCP sockets on VPN networks running on top of the specified network, and turn off 127 * keepalive if there is no TCP socket any of the VPN networks. Conversely, it will turn 128 * keepalive back on if any TCP socket is open on any of the VPN networks. 129 * 130 * When there is no TCP socket on any of the VPN networks, the state becomes STATE_SUSPENDED. 131 * The {@link KeepaliveTracker.KeepaliveInfo} object is kept to remember the parameters so it 132 * is possible to resume keepalive later with the same parameters. 133 * 134 * When the system detects some TCP socket is open on one of the VPNs while in STATE_SUSPENDED, 135 * this AutomaticOnOffKeepalive goes to STATE_ENABLED again. 136 * 137 * When finishing keepalive, this object is deleted. 138 */ 139 private static final int STATE_ENABLED = 0; 140 private static final int STATE_SUSPENDED = 1; 141 private static final int STATE_ALWAYS_ON = 2; 142 @Retention(RetentionPolicy.SOURCE) 143 @IntDef(prefix = { "STATE_" }, value = { 144 STATE_ENABLED, 145 STATE_SUSPENDED, 146 STATE_ALWAYS_ON 147 }) 148 private @interface AutomaticOnOffState {} 149 150 @NonNull 151 private final Handler mConnectivityServiceHandler; 152 @NonNull 153 private final KeepaliveTracker mKeepaliveTracker; 154 @NonNull 155 private final Context mContext; 156 @NonNull 157 private final AlarmManager mAlarmManager; 158 159 /** 160 * The {@code inetDiagReqV2} messages for different IP family. 161 * 162 * Key: Ip family type. 163 * Value: Bytes array represent the {@code inetDiagReqV2}. 164 * 165 * This should only be accessed in the connectivity service handler thread. 166 */ 167 private final SparseArray<byte[]> mSockDiagMsg = new SparseArray<>(); 168 private final Dependencies mDependencies; 169 private final INetd mNetd; 170 /** 171 * Keeps track of automatic on/off keepalive requests. 172 * This should be only updated in ConnectivityService handler thread. 173 */ 174 private final ArrayList<AutomaticOnOffKeepalive> mAutomaticOnOffKeepalives = new ArrayList<>(); 175 // TODO: Remove this when TCP polling design is replaced with callback. 176 private long mTestLowTcpPollingTimerUntilMs = 0; 177 178 private static final int MAX_EVENTS_LOGS = 40; 179 private final LocalLog mEventLog = new LocalLog(MAX_EVENTS_LOGS); 180 181 private final KeepaliveStatsTracker mKeepaliveStatsTracker; 182 183 private final long mMetricsWriteTimeBase; 184 185 /** 186 * Information about a managed keepalive. 187 * 188 * The keepalive in mKi is managed by this object. This object can be in one of three states 189 * (in mAutomatiOnOffState) : 190 * • STATE_ALWAYS_ON : this keepalive is always on 191 * • STATE_ENABLED : this keepalive is currently on, and monitored for possibly being turned 192 * off if no TCP socket is open on the VPN. 193 * • STATE_SUSPENDED : this keepalive is currently off, and monitored for possibly being 194 * resumed if a TCP socket is open on the VPN. 195 * See the documentation for the states for more detail. 196 */ 197 public class AutomaticOnOffKeepalive implements IBinder.DeathRecipient { 198 @NonNull 199 private final KeepaliveTracker.KeepaliveInfo mKi; 200 @NonNull 201 private final ISocketKeepaliveCallback mCallback; 202 @Nullable 203 private final FileDescriptor mFd; 204 @Nullable 205 private final AlarmManager.OnAlarmListener mAlarmListener; 206 @AutomaticOnOffState 207 private int mAutomaticOnOffState; 208 @Nullable 209 private final Network mUnderpinnedNetwork; 210 AutomaticOnOffKeepalive(@onNull final KeepaliveTracker.KeepaliveInfo ki, final boolean autoOnOff, @Nullable Network underpinnedNetwork)211 AutomaticOnOffKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki, 212 final boolean autoOnOff, @Nullable Network underpinnedNetwork) 213 throws InvalidSocketException { 214 this.mKi = Objects.requireNonNull(ki); 215 mCallback = ki.mCallback; 216 mUnderpinnedNetwork = underpinnedNetwork; 217 // Reading DeviceConfig will check if the calling uid and calling package name are the 218 // same. Clear calling identity to align the calling uid and package 219 final boolean enabled = BinderUtils.withCleanCallingIdentity( 220 () -> mDependencies.isTetheringFeatureNotChickenedOut( 221 AUTOMATIC_ON_OFF_KEEPALIVE_DISABLE_FLAG)); 222 if (autoOnOff && enabled) { 223 mAutomaticOnOffState = STATE_ENABLED; 224 if (null == ki.mFd) { 225 throw new IllegalArgumentException("fd can't be null with automatic " 226 + "on/off keepalives"); 227 } 228 mAlarmListener = () -> mConnectivityServiceHandler.obtainMessage( 229 CMD_MONITOR_AUTOMATIC_KEEPALIVE, mCallback.asBinder()) 230 .sendToTarget(); 231 } else { 232 mAutomaticOnOffState = STATE_ALWAYS_ON; 233 mAlarmListener = null; 234 } 235 236 // A null fd is acceptable in KeepaliveInfo for backward compatibility of 237 // PacketKeepalive API, but it must never happen with automatic keepalives. 238 // TODO : remove mFd from KeepaliveInfo. 239 mFd = dupFd(ki.mFd); 240 } 241 dupFd(FileDescriptor fd)242 private FileDescriptor dupFd(FileDescriptor fd) throws InvalidSocketException { 243 try { 244 if (fd == null) return null; 245 return Os.dup(fd); 246 } catch (ErrnoException e) { 247 Log.e(TAG, "Cannot dup fd: ", e); 248 throw new InvalidSocketException(ERROR_INVALID_SOCKET, e); 249 } 250 } 251 252 @VisibleForTesting getCallback()253 public ISocketKeepaliveCallback getCallback() { 254 return mCallback; 255 } 256 getNetwork()257 public Network getNetwork() { 258 return mKi.getNai().network(); 259 } 260 261 @Nullable getUnderpinnedNetwork()262 public Network getUnderpinnedNetwork() { 263 return mUnderpinnedNetwork; 264 } 265 match(Network network, int slot)266 public boolean match(Network network, int slot) { 267 return mKi.getNai().network().equals(network) && mKi.getSlot() == slot; 268 } 269 270 @Override binderDied()271 public void binderDied() { 272 mEventLog.log("Binder died : " + mCallback); 273 mConnectivityServiceHandler.post(() -> cleanupAutoOnOffKeepalive(this)); 274 } 275 276 /** Close this automatic on/off keepalive */ close()277 public void close() { 278 // Close the duplicated fd that maintains the lifecycle of socket. If this fd was 279 // not duplicated this is a no-op. 280 FileUtils.closeQuietly(mFd); 281 } 282 getAutomaticOnOffStateName(int state)283 private String getAutomaticOnOffStateName(int state) { 284 switch (state) { 285 case STATE_ENABLED: 286 return "STATE_ENABLED"; 287 case STATE_SUSPENDED: 288 return "STATE_SUSPENDED"; 289 case STATE_ALWAYS_ON: 290 return "STATE_ALWAYS_ON"; 291 default: 292 Log.e(TAG, "Get unexpected state:" + state); 293 return Integer.toString(state); 294 } 295 } 296 297 /** 298 * Construct a new AutomaticOnOffKeepalive from existing AutomaticOnOffKeepalive with a 299 * new KeepaliveInfo. 300 */ withKeepaliveInfo(KeepaliveTracker.KeepaliveInfo ki)301 public AutomaticOnOffKeepalive withKeepaliveInfo(KeepaliveTracker.KeepaliveInfo ki) 302 throws InvalidSocketException { 303 return new AutomaticOnOffKeepalive( 304 ki, 305 mAutomaticOnOffState != STATE_ALWAYS_ON /* autoOnOff */, 306 mUnderpinnedNetwork); 307 } 308 309 @Override toString()310 public String toString() { 311 return "AutomaticOnOffKeepalive [ " 312 + mKi 313 + ", state=" + getAutomaticOnOffStateName(mAutomaticOnOffState) 314 + " ]"; 315 } 316 } 317 AutomaticOnOffKeepaliveTracker(@onNull Context context, @NonNull Handler handler)318 public AutomaticOnOffKeepaliveTracker(@NonNull Context context, @NonNull Handler handler) { 319 this(context, handler, new Dependencies(context)); 320 } 321 322 @VisibleForTesting AutomaticOnOffKeepaliveTracker(@onNull Context context, @NonNull Handler handler, @NonNull Dependencies dependencies)323 public AutomaticOnOffKeepaliveTracker(@NonNull Context context, @NonNull Handler handler, 324 @NonNull Dependencies dependencies) { 325 mContext = Objects.requireNonNull(context); 326 mDependencies = Objects.requireNonNull(dependencies); 327 mConnectivityServiceHandler = Objects.requireNonNull(handler); 328 mNetd = mDependencies.getNetd(); 329 mKeepaliveTracker = mDependencies.newKeepaliveTracker( 330 mContext, mConnectivityServiceHandler); 331 332 mAlarmManager = mDependencies.getAlarmManager(context); 333 mKeepaliveStatsTracker = 334 mDependencies.newKeepaliveStatsTracker(context, handler); 335 336 final long time = mDependencies.getElapsedRealtime(); 337 mMetricsWriteTimeBase = time % METRICS_COLLECTION_DURATION_MS; 338 if (mKeepaliveStatsTracker.isEnabled()) { 339 final long triggerAtMillis = mMetricsWriteTimeBase + METRICS_COLLECTION_DURATION_MS; 340 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtMillis, TAG, 341 this::writeMetricsAndRescheduleAlarm, handler); 342 } 343 } 344 writeMetricsAndRescheduleAlarm()345 private void writeMetricsAndRescheduleAlarm() { 346 // If the metrics is disabled, skip writing and scheduling the next alarm. 347 if (!mKeepaliveStatsTracker.isEnabled()) { 348 return; 349 } 350 mKeepaliveStatsTracker.writeAndResetMetrics(); 351 352 final long time = mDependencies.getElapsedRealtime(); 353 final long triggerAtMillis = 354 mMetricsWriteTimeBase 355 + (time - time % METRICS_COLLECTION_DURATION_MS) 356 + METRICS_COLLECTION_DURATION_MS; 357 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtMillis, TAG, 358 this::writeMetricsAndRescheduleAlarm, mConnectivityServiceHandler); 359 } 360 startTcpPollingAlarm(@onNull AutomaticOnOffKeepalive ki)361 private void startTcpPollingAlarm(@NonNull AutomaticOnOffKeepalive ki) { 362 if (ki.mAlarmListener == null) return; 363 364 final long triggerAtMillis = 365 mDependencies.getElapsedRealtime() + getTcpPollingIntervalMs(ki); 366 // Setup a non-wake up alarm. 367 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, triggerAtMillis, null /* tag */, 368 ki.mAlarmListener, mConnectivityServiceHandler); 369 } 370 371 /** 372 * Determine if any state transition is needed for the specific automatic keepalive. 373 */ handleMonitorAutomaticKeepalive(@onNull final AutomaticOnOffKeepalive ki, final int vpnNetId)374 public void handleMonitorAutomaticKeepalive(@NonNull final AutomaticOnOffKeepalive ki, 375 final int vpnNetId) { 376 // Might happen if the automatic keepalive was removed by the app just as the alarm fires. 377 if (!mAutomaticOnOffKeepalives.contains(ki)) return; 378 if (STATE_ALWAYS_ON == ki.mAutomaticOnOffState) { 379 throw new IllegalStateException("Should not monitor non-auto keepalive"); 380 } 381 382 handleMonitorTcpConnections(ki, vpnNetId); 383 } 384 385 /** 386 * Determine if disable or re-enable keepalive is needed or not based on TCP sockets status. 387 */ handleMonitorTcpConnections(@onNull AutomaticOnOffKeepalive ki, int vpnNetId)388 private void handleMonitorTcpConnections(@NonNull AutomaticOnOffKeepalive ki, int vpnNetId) { 389 // Might happen if the automatic keepalive was removed by the app just as the alarm fires. 390 if (!mAutomaticOnOffKeepalives.contains(ki)) return; 391 if (STATE_ALWAYS_ON == ki.mAutomaticOnOffState) { 392 throw new IllegalStateException("Should not monitor non-auto keepalive"); 393 } 394 if (!isAnyTcpSocketConnected(vpnNetId)) { 395 // No TCP socket exists. Stop keepalive if ENABLED, and remain SUSPENDED if currently 396 // SUSPENDED. 397 if (ki.mAutomaticOnOffState == STATE_ENABLED) { 398 ki.mAutomaticOnOffState = STATE_SUSPENDED; 399 handlePauseKeepalive(ki.mKi); 400 } 401 } else { 402 handleMaybeResumeKeepalive(ki); 403 } 404 // TODO: listen to socket status instead of periodically check. 405 startTcpPollingAlarm(ki); 406 } 407 408 /** 409 * Resume an auto on/off keepalive, unless it's already resumed 410 * @param autoKi the keepalive to resume 411 */ handleMaybeResumeKeepalive(@onNull AutomaticOnOffKeepalive autoKi)412 public void handleMaybeResumeKeepalive(@NonNull AutomaticOnOffKeepalive autoKi) { 413 mEventLog.log("Resume keepalive " + autoKi.mCallback + " on " + autoKi.getNetwork()); 414 // Might happen if the automatic keepalive was removed by the app just as the alarm fires. 415 if (!mAutomaticOnOffKeepalives.contains(autoKi)) return; 416 if (STATE_ALWAYS_ON == autoKi.mAutomaticOnOffState) { 417 throw new IllegalStateException("Should not resume non-auto keepalive"); 418 } 419 if (autoKi.mAutomaticOnOffState == STATE_ENABLED) return; 420 KeepaliveTracker.KeepaliveInfo newKi; 421 try { 422 // Get fd from AutomaticOnOffKeepalive since the fd in the original 423 // KeepaliveInfo should be closed. 424 newKi = autoKi.mKi.withFd(autoKi.mFd); 425 } catch (InvalidSocketException | IllegalArgumentException | SecurityException e) { 426 Log.e(TAG, "Fail to construct keepalive", e); 427 mKeepaliveTracker.notifyErrorCallback(autoKi.mCallback, ERROR_INVALID_SOCKET); 428 return; 429 } 430 autoKi.mAutomaticOnOffState = STATE_ENABLED; 431 final int error = handleResumeKeepalive(newKi); 432 if (error != SUCCESS) { 433 // Failed to start the keepalive 434 cleanupAutoOnOffKeepalive(autoKi); 435 } 436 } 437 438 /** 439 * Find the AutomaticOnOffKeepalive associated with a given callback. 440 * @return the keepalive associated with this callback, or null if none 441 */ 442 @Nullable getKeepaliveForBinder(@onNull final IBinder token)443 public AutomaticOnOffKeepalive getKeepaliveForBinder(@NonNull final IBinder token) { 444 ensureRunningOnHandlerThread(mConnectivityServiceHandler); 445 446 return CollectionUtils.findFirst(mAutomaticOnOffKeepalives, 447 it -> it.mCallback.asBinder().equals(token)); 448 } 449 450 /** 451 * Handle keepalive events from lower layer. 452 * 453 * Forward to KeepaliveTracker. 454 */ handleEventSocketKeepalive(@onNull NetworkAgentInfo nai, int slot, int reason)455 public void handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai, int slot, int reason) { 456 if (mKeepaliveTracker.handleEventSocketKeepalive(nai, slot, reason)) return; 457 458 // The keepalive was stopped and so the autoKi should be cleaned up. 459 final AutomaticOnOffKeepalive autoKi = 460 CollectionUtils.findFirst( 461 mAutomaticOnOffKeepalives, it -> it.match(nai.network(), slot)); 462 if (autoKi == null) { 463 // This may occur when the autoKi gets cleaned up elsewhere (i.e 464 // handleCheckKeepalivesStillValid) while waiting for the network agent to 465 // start the keepalive and the network agent returns an error event. 466 Log.e(TAG, "Attempt cleanup on unknown network, slot"); 467 return; 468 } 469 cleanupAutoOnOffKeepalive(autoKi); 470 } 471 472 /** 473 * Handle stop all keepalives on the specific network. 474 */ handleStopAllKeepalives(NetworkAgentInfo nai, int reason)475 public void handleStopAllKeepalives(NetworkAgentInfo nai, int reason) { 476 mEventLog.log("Stop all keepalives on " + nai.network + " because " + reason); 477 mKeepaliveTracker.handleStopAllKeepalives(nai, reason); 478 final List<AutomaticOnOffKeepalive> matches = 479 CollectionUtils.filter(mAutomaticOnOffKeepalives, it -> it.mKi.getNai() == nai); 480 for (final AutomaticOnOffKeepalive ki : matches) { 481 if (ki.mAutomaticOnOffState == STATE_SUSPENDED) { 482 mKeepaliveTracker.finalizePausedKeepalive(ki.mKi, reason); 483 } 484 cleanupAutoOnOffKeepalive(ki); 485 } 486 } 487 488 /** 489 * Handle start keepalive contained within a message. 490 * 491 * The message is expected to contain a KeepaliveTracker.KeepaliveInfo. 492 */ handleStartKeepalive(Message message)493 public void handleStartKeepalive(Message message) { 494 final AutomaticOnOffKeepalive target = (AutomaticOnOffKeepalive) message.obj; 495 final Pair<Integer, KeepaliveTracker.KeepaliveInfo> res = 496 mKeepaliveTracker.handleStartKeepalive(target.mKi); 497 final int error = res.first; 498 if (error != SUCCESS) { 499 mEventLog.log("Failed to start keepalive " + target.mCallback + " on " 500 + target.getNetwork() + " with error " + error); 501 return; 502 } 503 // Generate a new auto ki with the started keepalive info. 504 final AutomaticOnOffKeepalive autoKi; 505 try { 506 autoKi = target.withKeepaliveInfo(res.second); 507 target.close(); 508 } catch (InvalidSocketException e) { 509 Log.wtf(TAG, "Fail to create AutomaticOnOffKeepalive", e); 510 return; 511 } 512 513 mEventLog.log("Start keepalive " + autoKi.mCallback + " on " + autoKi.getNetwork()); 514 mKeepaliveStatsTracker.onStartKeepalive( 515 autoKi.getNetwork(), 516 autoKi.mKi.getSlot(), 517 autoKi.mKi.getNai().networkCapabilities, 518 autoKi.mKi.getKeepaliveIntervalSec(), 519 autoKi.mKi.getUid(), 520 STATE_ALWAYS_ON != autoKi.mAutomaticOnOffState); 521 522 // Add automatic on/off request into list to track its life cycle. 523 try { 524 autoKi.mKi.mCallback.asBinder().linkToDeath(autoKi, 0); 525 } catch (RemoteException e) { 526 // The underlying keepalive performs its own cleanup 527 autoKi.binderDied(); 528 return; 529 } 530 mAutomaticOnOffKeepalives.add(autoKi); 531 if (STATE_ALWAYS_ON != autoKi.mAutomaticOnOffState) { 532 startTcpPollingAlarm(autoKi); 533 } 534 } 535 536 /** 537 * Handle resume keepalive with the given KeepaliveInfo 538 * 539 * @return SUCCESS if the keepalive is successfully starting and the error reason otherwise. 540 */ handleResumeKeepalive(@onNull final KeepaliveTracker.KeepaliveInfo ki)541 private int handleResumeKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki) { 542 final Pair<Integer, KeepaliveTracker.KeepaliveInfo> res = 543 mKeepaliveTracker.handleStartKeepalive(ki); 544 final KeepaliveTracker.KeepaliveInfo startedKi = res.second; 545 final int error = res.first; 546 if (error != SUCCESS) { 547 mEventLog.log("Failed to resume keepalive " + startedKi.mCallback + " on " 548 + startedKi.mNai + " with error " + error); 549 return error; 550 } 551 552 mKeepaliveStatsTracker.onResumeKeepalive(startedKi.getNai().network(), startedKi.getSlot()); 553 mEventLog.log("Resumed successfully keepalive " + startedKi.mCallback 554 + " on " + startedKi.mNai); 555 556 return SUCCESS; 557 } 558 handlePauseKeepalive(@onNull final KeepaliveTracker.KeepaliveInfo ki)559 private void handlePauseKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki) { 560 mEventLog.log("Suspend keepalive " + ki.mCallback + " on " + ki.mNai); 561 mKeepaliveStatsTracker.onPauseKeepalive(ki.getNai().network(), ki.getSlot()); 562 // TODO : mKT.handleStopKeepalive should take a KeepaliveInfo instead 563 mKeepaliveTracker.handleStopKeepalive(ki.getNai(), ki.getSlot(), SUCCESS_PAUSED); 564 } 565 566 /** 567 * Handle stop keepalives on the specific network with given slot. 568 */ handleStopKeepalive(@onNull final AutomaticOnOffKeepalive autoKi, int reason)569 public void handleStopKeepalive(@NonNull final AutomaticOnOffKeepalive autoKi, int reason) { 570 mEventLog.log("Stop keepalive " + autoKi.mCallback + " because " + reason); 571 // Stop the keepalive unless it was suspended. This includes the case where it's managed 572 // but enabled, and the case where it's always on. 573 if (autoKi.mAutomaticOnOffState != STATE_SUSPENDED) { 574 final KeepaliveTracker.KeepaliveInfo ki = autoKi.mKi; 575 mKeepaliveTracker.handleStopKeepalive(ki.getNai(), ki.getSlot(), reason); 576 } else { 577 mKeepaliveTracker.finalizePausedKeepalive(autoKi.mKi, reason); 578 } 579 580 cleanupAutoOnOffKeepalive(autoKi); 581 } 582 cleanupAutoOnOffKeepalive(@onNull final AutomaticOnOffKeepalive autoKi)583 private void cleanupAutoOnOffKeepalive(@NonNull final AutomaticOnOffKeepalive autoKi) { 584 ensureRunningOnHandlerThread(mConnectivityServiceHandler); 585 mKeepaliveStatsTracker.onStopKeepalive(autoKi.getNetwork(), autoKi.mKi.getSlot()); 586 autoKi.close(); 587 if (null != autoKi.mAlarmListener) mAlarmManager.cancel(autoKi.mAlarmListener); 588 589 // If the KI is not in the array, it's because it was already removed, or it was never 590 // added ; the only ways this can happen is if the keepalive is stopped by the app and the 591 // app dies immediately, or if the app died before the link to death could be registered. 592 if (!mAutomaticOnOffKeepalives.remove(autoKi)) return; 593 594 autoKi.mKi.mCallback.asBinder().unlinkToDeath(autoKi, 0); 595 } 596 597 /** 598 * Called when requesting that keepalives be started on a IPsec NAT-T socket. See 599 * {@link android.net.SocketKeepalive}. 600 * 601 * Forward to KeepaliveTracker. 602 **/ startNattKeepalive(@ullable NetworkAgentInfo nai, @Nullable FileDescriptor fd, int intervalSeconds, @NonNull ISocketKeepaliveCallback cb, @NonNull String srcAddrString, int srcPort, @NonNull String dstAddrString, int dstPort, boolean automaticOnOffKeepalives, @Nullable Network underpinnedNetwork)603 public void startNattKeepalive(@Nullable NetworkAgentInfo nai, 604 @Nullable FileDescriptor fd, 605 int intervalSeconds, 606 @NonNull ISocketKeepaliveCallback cb, 607 @NonNull String srcAddrString, 608 int srcPort, 609 @NonNull String dstAddrString, 610 int dstPort, boolean automaticOnOffKeepalives, @Nullable Network underpinnedNetwork) { 611 final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeNattKeepaliveInfo(nai, fd, 612 intervalSeconds, cb, srcAddrString, srcPort, dstAddrString, dstPort); 613 if (null == ki) return; 614 try { 615 final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki, 616 automaticOnOffKeepalives, underpinnedNetwork); 617 mEventLog.log("Start natt keepalive " + cb + " on " + nai.network 618 + " " + srcAddrString + ":" + srcPort 619 + " → " + dstAddrString + ":" + dstPort 620 + " auto=" + autoKi 621 + " underpinned=" + underpinnedNetwork); 622 mConnectivityServiceHandler.obtainMessage(CMD_REQUEST_START_KEEPALIVE, autoKi) 623 .sendToTarget(); 624 } catch (InvalidSocketException e) { 625 mKeepaliveTracker.notifyErrorCallback(cb, e.error); 626 } 627 } 628 629 /** 630 * Called when requesting that keepalives be started on a IPsec NAT-T socket. See 631 * {@link android.net.SocketKeepalive}. 632 * 633 * Forward to KeepaliveTracker. 634 **/ startNattKeepalive(@ullable NetworkAgentInfo nai, @Nullable FileDescriptor fd, int resourceId, int intervalSeconds, @NonNull ISocketKeepaliveCallback cb, @NonNull String srcAddrString, @NonNull String dstAddrString, int dstPort, boolean automaticOnOffKeepalives, @Nullable Network underpinnedNetwork)635 public void startNattKeepalive(@Nullable NetworkAgentInfo nai, 636 @Nullable FileDescriptor fd, 637 int resourceId, 638 int intervalSeconds, 639 @NonNull ISocketKeepaliveCallback cb, 640 @NonNull String srcAddrString, 641 @NonNull String dstAddrString, 642 int dstPort, 643 boolean automaticOnOffKeepalives, 644 @Nullable Network underpinnedNetwork) { 645 final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeNattKeepaliveInfo(nai, fd, 646 resourceId, intervalSeconds, cb, srcAddrString, dstAddrString, dstPort); 647 if (null == ki) return; 648 try { 649 final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki, 650 automaticOnOffKeepalives, underpinnedNetwork); 651 mEventLog.log("Start natt keepalive " + cb + " on " + nai.network 652 + " " + srcAddrString 653 + " → " + dstAddrString + ":" + dstPort 654 + " auto=" + autoKi 655 + " underpinned=" + underpinnedNetwork); 656 mConnectivityServiceHandler.obtainMessage(CMD_REQUEST_START_KEEPALIVE, autoKi) 657 .sendToTarget(); 658 } catch (InvalidSocketException e) { 659 mKeepaliveTracker.notifyErrorCallback(cb, e.error); 660 } 661 } 662 663 /** 664 * Called by ConnectivityService to start TCP keepalive on a file descriptor. 665 * 666 * In order to offload keepalive for application correctly, sequence number, ack number and 667 * other fields are needed to form the keepalive packet. Thus, this function synchronously 668 * puts the socket into repair mode to get the necessary information. After the socket has been 669 * put into repair mode, the application cannot access the socket until reverted to normal. 670 * See {@link android.net.SocketKeepalive}. 671 * 672 * Forward to KeepaliveTracker. 673 **/ startTcpKeepalive(@ullable NetworkAgentInfo nai, @NonNull FileDescriptor fd, int intervalSeconds, @NonNull ISocketKeepaliveCallback cb)674 public void startTcpKeepalive(@Nullable NetworkAgentInfo nai, 675 @NonNull FileDescriptor fd, 676 int intervalSeconds, 677 @NonNull ISocketKeepaliveCallback cb) { 678 final KeepaliveTracker.KeepaliveInfo ki = mKeepaliveTracker.makeTcpKeepaliveInfo(nai, fd, 679 intervalSeconds, cb); 680 if (null == ki) return; 681 try { 682 final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki, 683 false /* autoOnOff, tcp keepalives are never auto on/off */, 684 null /* underpinnedNetwork, tcp keepalives do not refer to this */); 685 mConnectivityServiceHandler.obtainMessage(CMD_REQUEST_START_KEEPALIVE, autoKi) 686 .sendToTarget(); 687 } catch (InvalidSocketException e) { 688 mKeepaliveTracker.notifyErrorCallback(cb, e.error); 689 } 690 } 691 692 /** 693 * Dump AutomaticOnOffKeepaliveTracker state. 694 * This should be only be called in ConnectivityService handler thread. 695 */ dump(IndentingPrintWriter pw)696 public void dump(IndentingPrintWriter pw) { 697 ensureRunningOnHandlerThread(mConnectivityServiceHandler); 698 mKeepaliveTracker.dump(pw); 699 // Reading DeviceConfig will check if the calling uid and calling package name are the same. 700 // Clear calling identity to align the calling uid and package so that it won't fail if cts 701 // would like to call dump() 702 final boolean featureEnabled = BinderUtils.withCleanCallingIdentity( 703 () -> mDependencies.isTetheringFeatureNotChickenedOut( 704 AUTOMATIC_ON_OFF_KEEPALIVE_DISABLE_FLAG)); 705 pw.println("AutomaticOnOff enabled: " + featureEnabled); 706 pw.increaseIndent(); 707 for (AutomaticOnOffKeepalive autoKi : mAutomaticOnOffKeepalives) { 708 pw.println(autoKi.toString()); 709 } 710 pw.decreaseIndent(); 711 712 pw.println("Events (most recent first):"); 713 pw.increaseIndent(); 714 mEventLog.reverseDump(pw); 715 pw.decreaseIndent(); 716 717 pw.println(); 718 mKeepaliveStatsTracker.dump(pw); 719 } 720 721 /** 722 * Check all keepalives on the network are still valid. 723 * 724 * Forward to KeepaliveTracker. 725 */ handleCheckKeepalivesStillValid(NetworkAgentInfo nai)726 public void handleCheckKeepalivesStillValid(NetworkAgentInfo nai) { 727 ArrayList<Pair<AutomaticOnOffKeepalive, Integer>> invalidKeepalives = null; 728 729 for (final AutomaticOnOffKeepalive autoKi : mAutomaticOnOffKeepalives) { 730 if (!nai.equals(autoKi.mKi.mNai)) continue; 731 final int error = autoKi.mKi.isValid(); 732 if (error != SUCCESS) { 733 if (invalidKeepalives == null) { 734 invalidKeepalives = new ArrayList<>(); 735 } 736 invalidKeepalives.add(Pair.create(autoKi, error)); 737 } 738 } 739 if (invalidKeepalives == null) return; 740 for (final Pair<AutomaticOnOffKeepalive, Integer> keepaliveAndError : invalidKeepalives) { 741 handleStopKeepalive(keepaliveAndError.first, keepaliveAndError.second); 742 } 743 } 744 745 @VisibleForTesting isAnyTcpSocketConnected(int netId)746 boolean isAnyTcpSocketConnected(int netId) { 747 FileDescriptor fd = null; 748 749 try { 750 fd = mDependencies.createConnectedNetlinkSocket(); 751 752 // Get network mask 753 final MarkMaskParcel parcel = mNetd.getFwmarkForNetwork(netId); 754 final int networkMark = (parcel != null) ? parcel.mark : NetlinkUtils.UNKNOWN_MARK; 755 final int networkMask = (parcel != null) ? parcel.mask : NetlinkUtils.NULL_MASK; 756 757 // Send request for each IP family 758 for (final int family : ADDRESS_FAMILIES) { 759 if (isAnyTcpSocketConnectedForFamily(fd, family, networkMark, networkMask)) { 760 return true; 761 } 762 } 763 } catch (ErrnoException | SocketException | InterruptedIOException | RemoteException e) { 764 Log.e(TAG, "Fail to get socket info via netlink.", e); 765 } finally { 766 SocketUtils.closeSocketQuietly(fd); 767 } 768 769 return false; 770 } 771 isAnyTcpSocketConnectedForFamily(FileDescriptor fd, int family, int networkMark, int networkMask)772 private boolean isAnyTcpSocketConnectedForFamily(FileDescriptor fd, int family, int networkMark, 773 int networkMask) 774 throws ErrnoException, InterruptedIOException { 775 ensureRunningOnHandlerThread(mConnectivityServiceHandler); 776 // Build SocketDiag messages and cache it. 777 if (mSockDiagMsg.get(family) == null) { 778 mSockDiagMsg.put(family, InetDiagMessage.buildInetDiagReqForAliveTcpSockets(family)); 779 } 780 mDependencies.sendRequest(fd, mSockDiagMsg.get(family)); 781 782 // Iteration limitation as a protection to avoid possible infinite loops. 783 // DEFAULT_RECV_BUFSIZE could read more than 20 sockets per time. Max iteration 784 // should be enough to go through reasonable TCP sockets in the device. 785 final int maxIteration = 100; 786 int parsingIteration = 0; 787 while (parsingIteration < maxIteration) { 788 final ByteBuffer bytes = mDependencies.recvSockDiagResponse(fd); 789 790 try { 791 while (NetlinkUtils.enoughBytesRemainForValidNlMsg(bytes)) { 792 // NetlinkMessage.parse() will move the byte buffer position. 793 // TODO: Parse dst address information to filter socket. 794 final NetlinkMessage nlMsg = NetlinkMessage.parse( 795 bytes, OsConstants.NETLINK_INET_DIAG); 796 if (!(nlMsg instanceof InetDiagMessage)) { 797 if (DBG) Log.e(TAG, "Not a SOCK_DIAG_BY_FAMILY msg"); 798 return false; 799 } 800 801 final InetDiagMessage diagMsg = (InetDiagMessage) nlMsg; 802 if (isTargetTcpSocket(diagMsg, networkMark, networkMask)) { 803 if (DBG) { 804 Log.d(TAG, String.format("Found open TCP connection by uid %d to %s" 805 + " cookie %d", 806 diagMsg.inetDiagMsg.idiag_uid, 807 diagMsg.inetDiagMsg.id.remSocketAddress, 808 diagMsg.inetDiagMsg.id.cookie)); 809 } 810 return true; 811 } 812 } 813 } catch (BufferUnderflowException e) { 814 // The exception happens in random place in either header position or any data 815 // position. Partial bytes from the middle of the byte buffer may not be enough to 816 // clarify, so print out the content before the error to possibly prevent printing 817 // the whole 8K buffer. 818 final int exceptionPos = bytes.position(); 819 final String hex = HexDump.dumpHexString(bytes.array(), 0, exceptionPos); 820 Log.e(TAG, "Unexpected socket info parsing: " + hex, e); 821 } 822 823 parsingIteration++; 824 } 825 return false; 826 } 827 isTargetTcpSocket(@onNull InetDiagMessage diagMsg, int networkMark, int networkMask)828 private boolean isTargetTcpSocket(@NonNull InetDiagMessage diagMsg, 829 int networkMark, int networkMask) { 830 final int mark = readSocketDataAndReturnMark(diagMsg); 831 return (mark & networkMask) == networkMark; 832 } 833 readSocketDataAndReturnMark(@onNull InetDiagMessage diagMsg)834 private int readSocketDataAndReturnMark(@NonNull InetDiagMessage diagMsg) { 835 int mark = NetlinkUtils.INIT_MARK_VALUE; 836 // Get socket mark 837 for (StructNlAttr attr : diagMsg.nlAttrs) { 838 if (attr.nla_type == NetlinkUtils.INET_DIAG_MARK) { 839 // The netlink attributes should contain only one INET_DIAG_MARK for each socket. 840 mark = attr.getValueAsInteger(); 841 break; 842 } 843 } 844 return mark; 845 } 846 getTcpPollingIntervalMs(@onNull AutomaticOnOffKeepalive ki)847 private long getTcpPollingIntervalMs(@NonNull AutomaticOnOffKeepalive ki) { 848 final boolean useLowTimer = mTestLowTcpPollingTimerUntilMs > System.currentTimeMillis(); 849 // Adjust the polling interval to be smaller than the keepalive delay to preserve 850 // some time for the system to restart the keepalive. 851 final int timer = ki.mKi.getKeepaliveIntervalSec() * 1000 - ADJUST_TCP_POLLING_DELAY_MS; 852 if (timer < MIN_INTERVAL_SEC) { 853 Log.wtf(TAG, "Unreasonably low keepalive delay: " + ki.mKi.getKeepaliveIntervalSec()); 854 } 855 return useLowTimer ? LOW_TCP_POLLING_INTERVAL_MS : Math.max(timer, MIN_INTERVAL_SEC); 856 } 857 858 /** 859 * Temporarily use low TCP polling timer for testing. 860 * The value works when the time set is more than {@link System.currentTimeMillis()}. 861 */ handleSetTestLowTcpPollingTimer(long timeMs)862 public void handleSetTestLowTcpPollingTimer(long timeMs) { 863 Log.d(TAG, "handleSetTestLowTcpPollingTimer: " + timeMs); 864 mTestLowTcpPollingTimerUntilMs = timeMs; 865 } 866 867 /** 868 * Dependencies class for testing. 869 */ 870 @VisibleForTesting 871 public static class Dependencies { 872 private final Context mContext; 873 Dependencies(final Context context)874 public Dependencies(final Context context) { 875 mContext = context; 876 } 877 878 /** 879 * Create a netlink socket connected to the kernel. 880 * 881 * @return fd the fileDescriptor of the socket. 882 */ createConnectedNetlinkSocket()883 public FileDescriptor createConnectedNetlinkSocket() 884 throws ErrnoException, SocketException { 885 final FileDescriptor fd = NetlinkUtils.createNetLinkInetDiagSocket(); 886 NetlinkUtils.connectToKernel(fd); 887 Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, 888 StructTimeval.fromMillis(IO_TIMEOUT_MS)); 889 return fd; 890 } 891 892 /** 893 * Send composed message request to kernel. 894 * 895 * The given FileDescriptor is expected to be created by 896 * {@link #createConnectedNetlinkSocket} or equivalent way. 897 * 898 * @param fd a netlink socket {@code FileDescriptor} connected to the kernel. 899 * @param msg the byte array representing the request message to write to kernel. 900 */ sendRequest(@onNull final FileDescriptor fd, @NonNull final byte[] msg)901 public void sendRequest(@NonNull final FileDescriptor fd, 902 @NonNull final byte[] msg) 903 throws ErrnoException, InterruptedIOException { 904 Os.write(fd, msg, 0 /* byteOffset */, msg.length); 905 } 906 907 /** 908 * Get an INetd connector. 909 */ getNetd()910 public INetd getNetd() { 911 return INetd.Stub.asInterface( 912 (IBinder) mContext.getSystemService(Context.NETD_SERVICE)); 913 } 914 915 /** 916 * Get an instance of AlarmManager 917 */ getAlarmManager(@onNull final Context ctx)918 public AlarmManager getAlarmManager(@NonNull final Context ctx) { 919 return ctx.getSystemService(AlarmManager.class); 920 } 921 922 /** 923 * Receive the response message from kernel via given {@code FileDescriptor}. 924 * The usage should follow the {@code #sendRequest} call with the same 925 * FileDescriptor. 926 * 927 * The overall response may be large but the individual messages should not be 928 * excessively large(8-16kB) because trying to get the kernel to return 929 * everything in one big buffer is inefficient as it forces the kernel to allocate 930 * large chunks of linearly physically contiguous memory. The usage should iterate the 931 * call of this method until the end of the overall message. 932 * 933 * The default receiving buffer size should be small enough that it is always 934 * processed within the {@link NetlinkUtils#IO_TIMEOUT_MS} timeout. 935 */ recvSockDiagResponse(@onNull final FileDescriptor fd)936 public ByteBuffer recvSockDiagResponse(@NonNull final FileDescriptor fd) 937 throws ErrnoException, InterruptedIOException { 938 return NetlinkUtils.recvMessage( 939 fd, NetlinkUtils.DEFAULT_RECV_BUFSIZE, NetlinkUtils.IO_TIMEOUT_MS); 940 } 941 942 /** 943 * Construct a new KeepaliveTracker. 944 */ newKeepaliveTracker(@onNull Context context, @NonNull Handler connectivityserviceHander)945 public KeepaliveTracker newKeepaliveTracker(@NonNull Context context, 946 @NonNull Handler connectivityserviceHander) { 947 return new KeepaliveTracker(mContext, connectivityserviceHander); 948 } 949 950 /** 951 * Construct a new KeepaliveStatsTracker. 952 */ newKeepaliveStatsTracker(@onNull Context context, @NonNull Handler connectivityserviceHander)953 public KeepaliveStatsTracker newKeepaliveStatsTracker(@NonNull Context context, 954 @NonNull Handler connectivityserviceHander) { 955 return new KeepaliveStatsTracker(context, connectivityserviceHander); 956 } 957 958 /** 959 * Find out if a feature is not disabled from DeviceConfig. 960 * 961 * @param name The name of the property to look up. 962 * @return whether the feature is enabled 963 */ isTetheringFeatureNotChickenedOut(@onNull final String name)964 public boolean isTetheringFeatureNotChickenedOut(@NonNull final String name) { 965 return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(mContext, name); 966 } 967 968 /** 969 * Returns milliseconds since boot, including time spent in sleep. 970 * 971 * @return elapsed milliseconds since boot. 972 */ getElapsedRealtime()973 public long getElapsedRealtime() { 974 return SystemClock.elapsedRealtime(); 975 } 976 } 977 } 978