Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b2c1d50 authored by Sherif Eid's avatar Sherif Eid
Browse files

Automatically enable ADB Wifi on trusted networks

This change enables ADB over Wi-Fi automatically when the device
connects to a previously authorized, trusted network. It disables it
otherwise. Network trust is established when the user selects the
"Always allow" option for that network.

Test: AdbWifiNetworkMonitorTest
Bug: 423809120
Flag: com.android.server.adb.allow_adb_wifi_reconnect
Change-Id: I625758ea3f58d3cb9650c1d6ac214b52cc73f836
parent c4d43324
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -223,6 +223,7 @@ java_library_static {
        "securebox",
        "securebox",
        "apache-commons-math",
        "apache-commons-math",
        "apache-commons-compress",
        "apache-commons-compress",
        "adb_flags_lib",
        "battery_saver_flag_lib",
        "battery_saver_flag_lib",
        "notification_flags_lib",
        "notification_flags_lib",
        "power_hint_flags_lib",
        "power_hint_flags_lib",
+19 −5
Original line number Original line Diff line number Diff line
/*
/*
 * Copyright (C) 2012 The Android Open Source Project
 * Copyright (C) 2025 The Android Open Source Project
 *
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * you may not use this file except in compliance with the License.
@@ -29,14 +29,18 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.Slog;
import android.util.Slog;


/** Monitors device Wifi and Network status in order to enable/disable ADB Wifi accordingly. */
/**
public class AdbBroadcastReceiver extends BroadcastReceiver {
 * Monitors Wi-Fi state changes to automatically disable ADB over Wi-Fi when the device disconnects
 * from Wi-Fi.
 */
public class AdbBroadcastReceiver extends BroadcastReceiver implements AdbNetworkMonitor {


    private static final String TAG = AdbBroadcastReceiver.class.getSimpleName();
    private static final String TAG = AdbBroadcastReceiver.class.getSimpleName();


    private final ContentResolver mContentResolver;
    private final ContentResolver mContentResolver;
    private final Context mContext;
    private final Context mContext;
    private final AdbConnectionInfo mAdbConnectionInfo;
    private final AdbConnectionInfo mAdbConnectionInfo;
    private boolean mStarted = false;


    AdbBroadcastReceiver(@NonNull Context context, @NonNull AdbConnectionInfo info) {
    AdbBroadcastReceiver(@NonNull Context context, @NonNull AdbConnectionInfo info) {
        mContext = context;
        mContext = context;
@@ -44,14 +48,24 @@ public class AdbBroadcastReceiver extends BroadcastReceiver {
        mAdbConnectionInfo = info;
        mAdbConnectionInfo = info;
    }
    }


    void register() {
    @Override
    public void register() {
        if (mStarted) {
            return;
        }
        IntentFilter intentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
        IntentFilter intentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
        intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        mContext.registerReceiver(this, intentFilter);
        mContext.registerReceiver(this, intentFilter);
        mStarted = true;
    }
    }


    void unregister() {
    @Override
    public void unregister() {
        if (!mStarted) {
            return;
        }
        mContext.unregisterReceiver(this);
        mContext.unregisterReceiver(this);
        mStarted = false;
    }
    }


    private void disableWifi(String reason) {
    private void disableWifi(String reason) {
+10 −6
Original line number Original line Diff line number Diff line
@@ -474,8 +474,7 @@ public class AdbDebuggingManager {
        private NotificationManager mNotificationManager;
        private NotificationManager mNotificationManager;
        private boolean mAdbNotificationShown;
        private boolean mAdbNotificationShown;


        private final AdbBroadcastReceiver mBroadcastReceiver =
        private final AdbNetworkMonitor mAdbNetworkMonitor;
                new AdbBroadcastReceiver(mContext, mAdbConnectionInfo);


        private static final String ADB_NOTIFICATION_CHANNEL_ID_TV = "usbdevicemanager.adb.tv";
        private static final String ADB_NOTIFICATION_CHANNEL_ID_TV = "usbdevicemanager.adb.tv";


@@ -605,6 +604,12 @@ public class AdbDebuggingManager {
                thread.setHandler(this);
                thread.setHandler(this);
            }
            }
            mThread = thread;
            mThread = thread;
            if (com.android.server.adb.Flags.allowAdbWifiReconnect()) {
                mAdbNetworkMonitor =
                        new AdbWifiNetworkMonitor(mContext, mAdbKeyStore::isTrustedNetwork);
            } else {
                mAdbNetworkMonitor = new AdbBroadcastReceiver(mContext, mAdbConnectionInfo);
            }
        }
        }


        // Show when at least one device is connected.
        // Show when at least one device is connected.
@@ -827,8 +832,7 @@ public class AdbDebuggingManager {
                    }
                    }


                    mAdbConnectionInfo.copy(currentInfo);
                    mAdbConnectionInfo.copy(currentInfo);
                    mBroadcastReceiver.register();
                    mAdbNetworkMonitor.register();

                    ensureAdbDebuggingThreadAlive();
                    ensureAdbDebuggingThreadAlive();
                    startTLSPortPoller();
                    startTLSPortPoller();
                    startAdbdWifi();
                    startAdbdWifi();
@@ -842,7 +846,7 @@ public class AdbDebuggingManager {
                    }
                    }
                    mAdbWifiEnabled = false;
                    mAdbWifiEnabled = false;
                    mAdbConnectionInfo.clear();
                    mAdbConnectionInfo.clear();
                    mBroadcastReceiver.unregister();
                    mAdbNetworkMonitor.unregister();
                    stopAdbdWifi();
                    stopAdbdWifi();
                    onAdbdWifiServerDisconnected(-1);
                    onAdbdWifiServerDisconnected(-1);
                }
                }
@@ -864,7 +868,7 @@ public class AdbDebuggingManager {
                    }
                    }
                    mAdbConnectionInfo.copy(newInfo);
                    mAdbConnectionInfo.copy(newInfo);
                    Settings.Global.putInt(mContentResolver, Settings.Global.ADB_WIFI_ENABLED, 1);
                    Settings.Global.putInt(mContentResolver, Settings.Global.ADB_WIFI_ENABLED, 1);
                    mBroadcastReceiver.register();
                    mAdbNetworkMonitor.register();
                    ensureAdbDebuggingThreadAlive();
                    ensureAdbDebuggingThreadAlive();
                    startTLSPortPoller();
                    startTLSPortPoller();
                    startAdbdWifi();
                    startAdbdWifi();
+41 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.server.adb;

/**
 * Interface for monitoring network connectivity to enable/disable ADB over Wi-Fi.
 *
 * <p>Implementations of this interface are responsible for registering and unregistering network
 * monitoring processes.
 */
public interface AdbNetworkMonitor {

    /**
     * Registers the network monitoring process.
     *
     * <p>It is safe to call this method multiple times; implementations should handle this without
     * side effects.
     */
    void register();

    /**
     * Unregisters the network monitoring process.
     *
     * <p>It is safe to call this method multiple times, even if the monitor was not previously
     * registered.
     */
    void unregister();
}
+141 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.server.adb;

import android.content.ContentResolver;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.wifi.WifiInfo;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Slog;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.internal.annotations.VisibleForTesting;

/**
 * Monitors Wi-Fi state changes to automatically enable ADB over Wi-Fi when the device connects to a
 * trusted network and disable it otherwise.
 */
public class AdbWifiNetworkMonitor extends ConnectivityManager.NetworkCallback
        implements AdbNetworkMonitor {

    private static final String TAG = AdbWifiNetworkMonitor.class.getSimpleName();

    private final Context mContext;
    private final ContentResolver mContentResolver;
    private final IsTrustedNetworkChecker mIsTrustedNetworkChecker;

    /**
     * Stores the BSSID of the most recently processed network.
     *
     * <p>This is used to deduplicate callbacks, which may fire multiple times for the same network
     * change event. By comparing against the last known BSSID, we can ensure we only react to a
     * given network update once.
     */
    @Nullable private String mLastBSSID;

    private boolean mStarted = false;

    @VisibleForTesting
    interface IsTrustedNetworkChecker {
        boolean isTrusted(String bssid);
    }

    AdbWifiNetworkMonitor(
            @NonNull Context context, @NonNull IsTrustedNetworkChecker isTrustedNetworkChecker) {
        // Flag is required to receive BSSID info in the callback.
        super(ConnectivityManager.NetworkCallback.FLAG_INCLUDE_LOCATION_INFO);

        mContext = context;
        mContentResolver = mContext.getContentResolver();
        mIsTrustedNetworkChecker = isTrustedNetworkChecker;
        register();
    }

    @Override
    public final void register() {
        if (mStarted) {
            return;
        }
        ConnectivityManager connectivityManager =
                mContext.getSystemService(ConnectivityManager.class);
        NetworkRequest request =
                new NetworkRequest.Builder()
                        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                        .build();
        connectivityManager.registerNetworkCallback(request, this);
        mStarted = true;
    }

    @Override
    public final void unregister() {
        // This NetworkMonitor must remain registered even when ADB over Wi-Fi is disabled.
        // This allows it to automatically re-enable ADB over Wi-Fi when the device connects
        // to a trusted network.
    }

    @Override
    public final void onCapabilitiesChanged(
            @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
        if (networkCapabilities.getTransportInfo() instanceof WifiInfo wifiInfo) {
            Slog.i(TAG, "Wi-Fi network available");
            processWifiConnection(wifiInfo);
        } else {
            setAdbWifiState(false, "Wi-Fi network not available. Disabling adb over Wi-Fi.");
        }
    }

    @Override
    public final void onLost(@NonNull Network network) {
        mLastBSSID = null;
        setAdbWifiState(false, "Wi-Fi network lost. Disabling adb over Wi-Fi.");
    }

    private void processWifiConnection(WifiInfo wifiInfo) {
        if (wifiInfo == null
                || wifiInfo.getNetworkId() == -1
                || TextUtils.isEmpty(wifiInfo.getBSSID())) {
            setAdbWifiState(false, "Wi-Fi connection info is invalid. Disabling adb over Wi-Fi.");
            return;
        }

        if (TextUtils.equals(wifiInfo.getBSSID(), mLastBSSID)) {
            Slog.i(TAG, "Received the same Wi-Fi BSSID. Ignoring.");
            return;
        }
        mLastBSSID = wifiInfo.getBSSID();

        boolean isTrusted = mIsTrustedNetworkChecker.isTrusted(wifiInfo.getBSSID());
        if (isTrusted) {
            setAdbWifiState(true, "Connected to a trusted Wi-Fi network. Enabling adb over Wi-Fi.");
        } else {
            setAdbWifiState(
                    false, "Connected to a non-trusted Wi-Fi network. Disabling adb over Wi-Fi.");
        }
    }

    @VisibleForTesting
    protected void setAdbWifiState(boolean enabled, String reason) {
        Slog.i(TAG, reason);
        Settings.Global.putInt(mContentResolver, Settings.Global.ADB_WIFI_ENABLED, enabled ? 1 : 0);
    }
}
Loading