Android 13 网络 Adb相关流程深入分析研究

2023-11-16

Android 13 网络 Adb 分析研究

文章目录

一、前言

通过代码分析发现Android13 上对 网络adb 进行了限制!
Android13原生代码要求:必现连接上某个wifi,才能进行adb ,并且切换wifi或者关闭wifi都是会停止adb。
并且Android13 上 wifi adb 端口号每次是变化的,这个也是很不方便的!

如果要做成Android11 或者之前一样,设备连接WiFi/有线网络后电脑可以直接进行adb连接,就要对系统代码进行适配修改。

之前以为设置端口号和persist.adb.tls_server.enable 属性就ok了,但是还是有些小bug,还是要完全研究一遍具体流程。

之前已经发过 adb默认端口号设置:
https://blog.csdn.net/wenzhi20102321/article/details/131056174

默认adb实现简单分析:

https://blog.csdn.net/wenzhi20102321/article/details/131774893

默认adb开启分析:
https://blog.csdn.net/wenzhi20102321/article/details/132382549

后面两个文章都是有进行了简单研究和参考价值,当时整个流程还是可以更深入了解一些,所以特意再写一篇。

这个也是全网第一个比较全面分析 Android12以上的wifi adb 代码的文章了,需要的可以点赞收藏。

下面几个分析到的Android13 的adb相关源码文件:

https://download.csdn.net/download/wenzhi20102321/88306366

二、默认adb 代码实现

关键:
1、mk 设置系统属性:persist.adb.tls_server.enable=1
2、写死端口号 5555
3、注释若干判断Wifi情况停止adb的代码

1、修改的目录:

packages\modules\adb\daemon\adb_wifi.cpp
framework\base\services\core\java\com\android\server\adb\AdbDebuggingManager.java

//修改前面两个文件就可以实现adb了,后面的文件试辅助分析的。

//虽然 SettingsProvider 也有加载 Settings属性 Settings.Global.ADB_WIFI_ENABLED ,
//但是 prop那个属性更优先,所以可以不用考虑这里默认情况
framework\base\packages\SettingsProvider\src\com\android\providers\settings\SettingsProvider.java

//增加分析定位文件,系统服务启动后会判断 属性persist.adb.tls_server.enable 进行相关操作
//如果属性设置不生效,可以在这里添加打印日志查看过程
framework\base\services\core\java\com\android\server\adb\AdbService.java

2、具体修改:

(1)在XXX_device.mk 添加属性
persist.adb.tls_server.enable = 1

手动添加,也是会记忆的!

//设置
setprop persist.adb.tls_server.enable  1
//查询
getprop persist.adb.tls_server.enable
//可以查看其他adb相关属性
getprop | grep adb 
(2)设置固定端口号
+++ b/release/packages/modules/adb/daemon/adb_wifi.cpp
@@ -160,7 +160,8 @@ static void enable_wifi_debugging() {
     if (sTlsServer != nullptr) {
         delete sTlsServer;
     }
-    sTlsServer = new TlsServer(0);
+    // default port 0 means random,change to 5555 ,by liwenzhi
+    sTlsServer = new TlsServer(5555);
     if (!sTlsServer->Start()) {
         LOG(ERROR) << "Failed to start TlsServer";
         delete sTlsServer;
         

固定端口号,必须是这里设置,使用service.adb.tls.port属性设置其实是没用的!

(3)去除判断网络后,设置 ADB_WIFI_ENABLED 为 0 的代码

去吃wifi网络判断,是能有线网adb和wifi 修改后还是正常adb 的关键。
一个是初始化的时候判断,另外一个是监听网络变化的时候判断,都去掉就行。

+++ b/release/frameworks/base/services/core/java/com/android/server/adb/AdbDebuggingManager.java
public class AdbDebuggingManager {


                case MSG_ADBDWIFI_ENABLE: {
                    if (mAdbWifiEnabled) {
                        break;
                    }

                    //not to check network state ,change by  liwenzhi //(1)去除下面一大段判断网络和监听网络的代码
                    /** AdbConnectionInfo currentInfo = getCurrentWifiApInfo();
                    if (currentInfo == null) {
                        Settings.Global.putInt(mContentResolver,
                                Settings.Global.ADB_WIFI_ENABLED, 0); //关闭 adb wifi
                        break;
                    }

                    if (!verifyWifiNetwork(currentInfo.getBSSID(),
                            currentInfo.getSSID())) {
                        // This means that the network is not in the list of trusted networks.
                        // We'll give user a prompt on whether to allow wireless debugging on
                        // the current wifi network.
                        Settings.Global.putInt(mContentResolver,
                                Settings.Global.ADB_WIFI_ENABLED, 0);
                        break;
                    }

                    setAdbConnectionInfo(currentInfo); **/
                    //no listener network change for disable adb_wifi,by  liwenzhi
                    /** IntentFilter intentFilter =
                            new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
                    intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
                    mContext.registerReceiver(mBroadcastReceiver, intentFilter); **/

                    SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "1");


                case MSG_ADBDWIFI_DISABLE:
                    if (!mAdbWifiEnabled) {
                        break;
                    }
                    mAdbWifiEnabled = false;
                    setAdbConnectionInfo(null);
                    //no need unregisterReceiver, because no listener network,chenge by liwenzhi,//(2)监听已经注释,不需要再注销监听
                    //mContext.unregisterReceiver(mBroadcastReceiver);


                case MSG_ADBWIFI_ALLOW:
                    if (mAdbWifiEnabled) {
                        break;
                    }
                    String bssid = (String) msg.obj;
                    boolean alwaysAllow = msg.arg1 == 1;
                    if (alwaysAllow) {
                        mAdbKeyStore.addTrustedNetwork(bssid);
                    }

                    // Let's check again to make sure we didn't switch networks while verifying
                    // the wifi bssid.
                    //no to check network ,change by  liwenzhi //(3)不需要判断网络
                    /** AdbConnectionInfo newInfo = getCurrentWifiApInfo();
                    if (newInfo == null || !bssid.equals(newInfo.getBSSID())) {
                        break;
                    }

                    setAdbConnectionInfo(newInfo); **/
                    Settings.Global.putInt(mContentResolver,
                            Settings.Global.ADB_WIFI_ENABLED, 1);
                    //no listener network change for disable adb_wifi,by  liwenzhi //(4)不需要要监听网络变化
                    /** IntentFilter intentFilter =
                            new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
                    intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
                    mContext.registerReceiver(mBroadcastReceiver, intentFilter); **/

                    SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "1");


从上面代码看到未连接wifi的情况,getCurrentWifiApInfo 获取为null,会执行关闭wifi adb!
并且还有很多网络开关变化和网络状态变化的判断。

三、日志分析查看

日志分析查看主要是:AdbService.java、AdbDebuggingManager.java、adb_wifi.cpp
AdbService 的日志默认是关闭模式的,需要设置成true,并且如果要看里面数据具体值,相关属性的日志需要自己添加打印出来。
AdbDebuggingManager 是有相关异常过程日志的
adb_wifi 该文件的打印,TAG 是adbd, 不管有没有打开adb,整个系统是一直有这个 adbd 的相关打印的,每秒大概有十几行日志!

这里查看打印相关日志多个关键字的信息命令:

可能每个系统的日志都不一样,这里因供参考:


logcat | grep -E "lwz|AdbService|changed to|adb wifi|AdbDebuggingManager"

lwz 是我自己加的关键字。

通过日志查看,正常开启的情况大概日志过程是:


01-01 08:00:22.756   496   511 I adbd    : Waiting for persist.adb.tls_server.enable=1
08-16 15:13:50.123   762   762 D SystemServerTiming: StartAdbService
08-16 15:13:51.528   762   762 D AdbService: systemReady //修改 DEBUG = true 才看到的日志
08-16 15:13:51.528   762   762 D AdbService: lwz systemReady= persist.adb.tls_server.enable = 1 //自己加的日志打印
08-16 15:13:51.528   762   762 D AdbService: lwz systemReady mIsAdbWifiEnabled= true //自己加的日志打印,确认查看服务启动是否打开 adb
08-16 15:13:58.993   762   799 D AdbService: setAdbEnabled(true), mIsAdbUsbEnabled=true, mIsAdbWifiEnabled=true, transportType=0
08-16 15:13:58.994   762   762 D AdbService: lwz onChange shouldEnable = true
08-16 15:13:58.995   762   799 D AdbService: setAdbEnabled(true), mIsAdbUsbEnabled=true, mIsAdbWifiEnabled=true, transportType=1
08-16 15:13:59.015   762   802 D ActivityManagerTiming: OnBootPhase_1000_com.android.server.adb.AdbService$Lifecycle
08-16 15:13:59.016   762   802 V ActivityManagerTiming: OnBootPhase_1000_com.android.server.adb.AdbService$Lifecycle took to complete: 1ms
08-16 15:13:59.016   762   799 D AdbService: boot completed
08-16 15:13:59.033   496   511 I adbd    : persist.adb.tls_server.enable changed to 1 //正常开启adb的日志
08-16 15:13:59.056   496   511 I adbd    : adb wifi started on port 5555
08-16 15:13:59.058   496   511 I adbd    : Waiting for persist.adb.tls_server.enable=0

如果未屏蔽网络判断,添加打印日志查看过程:

08-18 16:51:20.104   762   762 D SystemServerTiming: OnBootPhase_550_com.android.server.adb.AdbService$Lifecycle
08-18 16:51:20.104   762   762 D AdbService: systemReady
08-18 16:51:20.105   762   762 D AdbService: lwz systemReady mIsAdbWifiEnabled= true //这里说明,prop 属性已经设置了
08-18 16:51:26.248   762   798 I AdbDebuggingManager: Not connected to any wireless network. Not enabling adbwifi. //这里提示没网络,会执行关闭adb
08-18 16:51:26.586   762   762 D AdbService: lwz onChange shouldEnable = false
08-18 16:51:27.411   762   762 D AdbService: lwz onChange shouldEnable = false
08-18 16:51:27.971   762   798 D AdbService: setAdbEnabled(true), mIsAdbUsbEnabled=true, mIsAdbWifiEnabled=true, transportType=0
08-18 16:51:27.972   762   798 D AdbService: setAdbEnabled(false), mIsAdbUsbEnabled=true, mIsAdbWifiEnabled=true, transportType=1 //关闭adb
08-18 16:51:27.973   510   517 I adbd    : persist.adb.tls_server.enable changed to 0  //到这里 persist.adb.tls_server.enable 属性又变成了 0
08-18 16:51:27.973   510   517 I adbd    : adb wifi stopped
08-18 16:51:27.981   762   798 D AdbService: Broadcasting enable = false, type = 1

这个也是为啥配置了那个 persist.adb.tls_server.enable =1 属性后,系统启动发现获取属性还是0 ,并且wifi adb未打开。

如果打开日志开关,并且没添加自定义日志,是不会有上面这么多日志显示的。

如果代码和属性都适配了,但是还是没有默认adb ,那么就是要好好梳理代码或者多添加日志分析查看了。

四、代码流程

其实就是看 AdbService.java、AdbDebuggingManager.java、adb_wifi.cpp 这三个类之间的流程就差不多了。

adb_wifi.cpp 这类是Androi11以及之前的版本是没有的,其他的Java类是一直有的。
packages\modules\adb 这个目录也是Android12才开始有的

1、adb_wifi 底层启动

里面的日志是跑在比较前面的,比SystemServer 更早。
也是为啥设置了 persist.adb.tls_server.enable=1 能够直接使能网络adb的原因。
正常开启和关闭adb 是有相关日志的。
具体启动adb 还是靠上层调用了接口到底层才会进行开启的。

这里看一段最重要的代码


const char kWifiPortProp[] = "service.adb.tls.port"; //(1)adb 端口号属性

const char kWifiEnabledProp[] = "persist.adb.tls_server.enable"; //(2)adb prop 开关属性

//(3)底层开启adb 具体实现
static void enable_wifi_debugging() {
    start_mdnsd();

    if (sTlsServer != nullptr) {
        delete sTlsServer;
    }
    sTlsServer = new TlsServer(5555); //(4)写死端口号,不写死会随机生成
    if (!sTlsServer->Start()) {
        LOG(ERROR) << "Failed to start TlsServer";
        delete sTlsServer;
        sTlsServer = nullptr;
        return;
    }

    // Start mdns connect service for discovery
    register_adb_secure_connect_service(sTlsServer->port());
   //(5)开启 adb 后,这里是会有打印的,并且对端口号属性进行了赋值
   //所以代码中设置端口号的prop 数值是没啥意义的
    LOG(INFO) << "lwz adb wifi started on port " << sTlsServer->port();
    SetProperty(kWifiPortProp, std::to_string(sTlsServer->port()));
}

//(6)底层关闭adb 具体实现
static void disable_wifi_debugging() {
    if (sTlsServer != nullptr) {
        delete sTlsServer;
        sTlsServer = nullptr;
    }
    if (is_adb_secure_connect_service_registered()) {
        unregister_adb_secure_connect_service();
    }
    kick_all_tcp_tls_transports();
   //(7)关闭 adb 后,这里是会有打印的,并且对端口号属性进行了赋值
   //所以代码中设置端口号的prop 数值是没啥意义的
    LOG(INFO) << "adb wifi stopped";
    SetProperty(kWifiPortProp, "");
}

//(8)关键:这个逻辑不难,刚开始看懵了!!
// Watches for the #kWifiEnabledProp property to toggle the TlsServer
static void start_wifi_enabled_observer() {
    std::thread([]() {
        bool wifi_enabled = false;
        while (true) { // (9)这里不会阻塞,WaitForProperty 会等待属性设置,否则一直等待状态
            std::string toggled_val = wifi_enabled ? "0" : "1";
            LOG(INFO) << "lwz Waiting for " << kWifiEnabledProp << "=" << toggled_val; //(10)正常开机会打印这个,等待进入1,即等待开启状态
            if (WaitForProperty(kWifiEnabledProp, toggled_val)) { //底层的等待状态,等待某个属性变成某个值
                wifi_enabled = !wifi_enabled;
                // (11)prop 属性变化,这里会有打印
                //上面是while true,这里修改后,马上又进入了 “Waiting for”下一次属性变化的监听
                LOG(INFO) << kWifiEnabledProp << " changed to " << toggled_val;
                if (wifi_enabled) {
                    enable_wifi_debugging(); //(12)开启adb
                } else {
                    disable_wifi_debugging(); //(13)关闭adb
                }
            }
        }
    }).detach();
}


上面13 个主要的点就是,adb cpp里面的重要流程。
其他更具体和底层的这里不进行研究分析。

参考别人写的adb 的底层线程逻辑:

https://blog.csdn.net/qq_35970872/article/details/78912611

Android13 上也有相关的底层逻辑,代码路径:

packages\modules\adb\transport.cpp

里面有线程一直在读取数据,具体逻辑我也看不懂,就不分析研究了!

2、adb 上层启动

AdbService 是SystemServer 执行 startOtherServices 里面启动的服务。

AdbService extends IAdbManager.Stub //具体暴露接口可以看 IAdbManager

AdbDebuggingManager 是一个管理adbDebug的类,在 AdbService 里面实例化,其实就是分化了一下具体执行的代码。

很多无法进入adb wifi 的情况都是在AdbDebuggingManager 拒绝的,并且重新设置了 Global属性 和 Prop 属性为0

(1)SystemServce.java 启动AdbServices代码

framework\base\services\java\com\android\server\SystemServer.java

/**
 * Entry point to {@code system_server}.
 */
public final class SystemServer implements Dumpable {

    private static final String ADB_SERVICE_CLASS =
            "com.android.server.adb.AdbService$Lifecycle";

    /**
     * The main entry point from zygote.
     */
    public static void main(String[] args) { //(1)java 入口方法
        new SystemServer().run();
    }

    private void run() { //(2)启动上层系统相关服务
            t.traceBegin("StartServices");
            startBootstrapServices(t); //启动核心服务,电源管理、AMS、WMS、PMS等服务
            startCoreServices(t);  //启动关键服务,电池状态信息等服务
            startOtherServices(t); //(3)启动其他服务(最多),蓝牙,wifi,通知,adb等服务
            startApexServices(t); //启动app相关服务
    }

    private void startOtherServices(@NonNull TimingsTraceAndSlog t) { //(4)启动其他服务
        t.traceBegin("startOtherServices");
            // Start ADB Debugging Service
            t.traceBegin("StartAdbService");
            try {
                mSystemServiceManager.startService(ADB_SERVICE_CLASS); //启动蓝牙相关服务
            } catch (Throwable e) {
                Slog.e(TAG, "Failure starting AdbService");
            }
            t.traceEnd();
    }

}
(2)AdbServices.java 服务启动后关键代码

这个AdbService 不是具体的服务(不是四大组件里面的Service),而是通过AIDL绑定的服务,
别的类可以通过这个服务的接口对象IXXX/Manager调用里面的实现。

有个特殊的是这里有 继承了 SystemService 能监听系统启动完成。

framework\base\services\core\java\com\android\server\adb\AdbService.java

public class AdbService extends IAdbManager.Stub {  //(1)不是普通Service

    private static final boolean DEBUG = true; //打印默认为false,可以修改true 打开她

    private static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config";
    private static final String WIFI_PERSISTENT_CONFIG_PROPERTY = "persist.adb.tls_server.enable";

   private AdbService(Context context) {
        mContext = context;
        mContentResolver = context.getContentResolver();
        mDebuggingManager = new AdbDebuggingManager(context); //(2)从这里看就知道 AdbDebuggingManager 不是 AdbServices 的暴露Manager

        registerContentObservers(); //(3)监听 Settings.Global.ADB_WIFI_ENABLED 属性变化
        LocalServices.addService(AdbManagerInternal.class, new AdbManagerInternalImpl());
    }

    /**
     * Manages the service lifecycle for {@code AdbService} in {@code SystemServer}.
     */
    public static class Lifecycle extends SystemService { //(4)监听系统启动
        private AdbService mAdbService;

        public Lifecycle(Context context) {
            super(context);
        }

        @Override
        public void onStart() {
            mAdbService = new AdbService(getContext()); //(5)系统启动,创建对象
            publishBinderService(Context.ADB_SERVICE, mAdbService);
        }

        @Override
        public void onBootPhase(int phase) {
            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { //这个消息其实是SystemServer在启动OtherServie中间代码发出的。
                mAdbService.systemReady(); //(6)系统关键服务启动完成,调用。这里比开机广播早。
            } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { // 里面的 bootCompleted 方法也是重新调用了开关Wifi adb,不过不一定会跑这里。我这系统代码没看到跑这里。
                FgThread.getHandler().sendMessage(obtainMessage(
                        AdbService::bootCompleted, mAdbService));
            }
        }
    }

    /**
     * Called in response to {@code SystemService.PHASE_ACTIVITY_MANAGER_READY} from {@code
     * SystemServer}.
     */
    public void systemReady() { //(7)系统关键服务启动完成
        if (DEBUG) Slog.d(TAG, "systemReady");

        /*
         * Use the normal bootmode persistent prop to maintain state of adb across
         * all boot modes.
         */
        //(8)判断Usb调试 是否打开
        mIsAdbUsbEnabled = containsFunction(
                SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, ""), //USB_PERSISTENT_CONFIG_PROPERTY=sys.usb.config
                UsbManager.USB_FUNCTION_ADB); // USB_FUNCTION_ADB=adb
        boolean shouldEnableAdbUsb = mIsAdbUsbEnabled
                || SystemProperties.getBoolean(
                        TestHarnessModeService.TEST_HARNESS_MODE_PROPERTY, false); //属性: persist.sys.test_harness

        // 可以添加打印查看prop属性,
        Slog.d(TAG, "lwz systemReady= " + WIFI_PERSISTENT_CONFIG_PROPERTY + " = " + SystemProperties.get(WIFI_PERSISTENT_CONFIG_PROPERTY, "0"));
        // (9)判断Wifi adb 是否打开,persist.adb.tls_server.enable 属性是否为1
        mIsAdbWifiEnabled = "1".equals(SystemProperties.get(WIFI_PERSISTENT_CONFIG_PROPERTY, "0"));
        // 可以添加打印查看是否是打开wifiadb状态,
        Slog.d(TAG, "lwz systemReady mIsAdbWifiEnabled= " + mIsAdbWifiEnabled);

        // make sure the ADB_ENABLED setting value matches the current state
        try {

            //(10)保存Settings 属性后会有重新调用 setAdbEnabled,因为这里进行了监听
            Settings.Global.putInt(mContentResolver,
                    Settings.Global.ADB_ENABLED, shouldEnableAdbUsb ? 1 : 0);
            Settings.Global.putInt(mContentResolver,
                    Settings.Global.ADB_WIFI_ENABLED, mIsAdbWifiEnabled ? 1 : 0);
        } catch (SecurityException e) {
            // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't be changed.
            Slog.d(TAG, "ADB_ENABLED is restricted.");
        }
    }

    /**
     * Called in response to {@code SystemService.PHASE_BOOT_COMPLETED} from {@code SystemServer}.
     */
    public void bootCompleted() { //开机完成后,调用设置方法,这边不一定调用到!
        if (DEBUG) Slog.d(TAG, "boot completed + mIsAdbWifiEnabled" + mIsAdbWifiEnabled);
        if (mDebuggingManager != null) {
            mDebuggingManager.setAdbEnabled(mIsAdbUsbEnabled, AdbTransportType.USB);
            mDebuggingManager.setAdbEnabled(mIsAdbWifiEnabled, AdbTransportType.WIFI);
        }
    }

}

    // (11)监听Settings属性变化
    private void registerContentObservers() {
        try {
            // register observer to listen for settings changes
            mObserver = new AdbSettingsObserver();
            //(12)注册监听usb开关和wifi adb开关
            mContentResolver.registerContentObserver(
                    Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
                    false, mObserver);
            mContentResolver.registerContentObserver(
                    Settings.Global.getUriFor(Settings.Global.ADB_WIFI_ENABLED),
                    false, mObserver);
        } catch (Exception e) {
            Slog.e(TAG, "Error in registerContentObservers", e);
        }
    }

    // (13)Settings属性 内部监听类,这里说明代码中修改 ADB_WIFI_ENABLED 属性或者adb shell中动态修改属性,这里也是能收到的
    private class AdbSettingsObserver extends ContentObserver {
        private final Uri mAdbUsbUri = Settings.Global.getUriFor(Settings.Global.ADB_ENABLED);
        private final Uri mAdbWifiUri = Settings.Global.getUriFor(Settings.Global.ADB_WIFI_ENABLED);

        AdbSettingsObserver() {
            super(null);
        }

        @Override
        public void onChange(boolean selfChange, @NonNull Uri uri, @UserIdInt int userId) {
            if (mAdbUsbUri.equals(uri)) {
                boolean shouldEnable = (Settings.Global.getInt(mContentResolver,
                        Settings.Global.ADB_ENABLED, 0) > 0);
                FgThread.getHandler().sendMessage(obtainMessage(
                        AdbService::setAdbEnabled, AdbService.this, shouldEnable,
                            AdbTransportType.USB));
            } else if (mAdbWifiUri.equals(uri)) { // (14)ADB_WIFI_ENABLED 属性监听回调
                boolean shouldEnable = (Settings.Global.getInt(mContentResolver,
                        Settings.Global.ADB_WIFI_ENABLED, 0) > 0);
                 // (15)自己添加的打印,打印一下开关状态值
                Slog.d(TAG, "lwz onChange shouldEnable = " + shouldEnable);
                 // (16)系统属性值变化后,执行 AdbService.setAdbEnabled 方法
                FgThread.getHandler().sendMessage(obtainMessage(
                        AdbService::setAdbEnabled, AdbService.this, shouldEnable,
                            AdbTransportType.WIFI));
            }
        }
    }

    //(17) 执行usb 开关和adb开关的方法
    private void setAdbEnabled(boolean enable, byte transportType) { //transportType ,usb =1,wifi = 1
        if (DEBUG) {
            Slog.d(TAG, "setAdbEnabled(" + enable + "), mIsAdbUsbEnabled=" + mIsAdbUsbEnabled
                    + ", mIsAdbWifiEnabled=" + mIsAdbWifiEnabled + ", transportType="
                        + transportType);
        }

        if (transportType == AdbTransportType.USB && enable != mIsAdbUsbEnabled) {
            mIsAdbUsbEnabled = enable;
        } else if (transportType == AdbTransportType.WIFI && enable != mIsAdbWifiEnabled) {
            mIsAdbWifiEnabled = enable;
            if (mIsAdbWifiEnabled) {
                if (!AdbProperties.secure().orElse(false) && mDebuggingManager == null) {
                    // Start adbd. If this is secure adb, then we defer enabling adb over WiFi.
                    SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "1");
                    mConnectionPortPoller =
                            new AdbDebuggingManager.AdbConnectionPortPoller(mPortListener);
                    mConnectionPortPoller.start(); // (18) AdbConnectionPortPoller 是一个线程对象,不清楚为啥要启动这个线程,底层也有线程!里面没看到做非常重要的事情。
                }
            } else {
                // Stop adb over WiFi.
                SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "0");
                if (mConnectionPortPoller != null) {
                    mConnectionPortPoller.cancelAndWait(); //停止线程
                    mConnectionPortPoller = null;
                }
            }
        } else {
            // No change
            return;
        }

        if (enable) {
            startAdbd(); //这里的start 和 stop 无关紧要,不用关注
        } else {
            stopAdbd();
        }
        。。。。
        // (19)其实这里调用 DebuggingManager 方法才是最关键的,其他都是kalife
        if (mDebuggingManager != null) {
            mDebuggingManager.setAdbEnabled(enable, transportType);
        }
        
    }

    //这个的startAdbd 只设置了一个属性,没看到上层有判断使用,可能底层有读取这个属性
    private void startAdbd() {
        SystemProperties.set(CTL_START, ADBD);
    }

    //这个的stopAdbd 只设置了一个属性,
    private void stopAdbd() {
        if (!mIsAdbUsbEnabled && !mIsAdbWifiEnabled) {
            SystemProperties.set(CTL_STOP, ADBD);
        }
    }


下面就是关键代码,AdbDebuggingManager 的分析

framework\base\services\core\java\com\android\server\adb\AdbDebuggingManager.java


    private static final String TAG = "AdbDebuggingManager";
    private static final boolean DEBUG = false; //打印默认为false,调试可以修改为true,查看相关日志

    public void setAdbEnabled(boolean enabled, byte transportType) {
        if (transportType == AdbTransportType.USB) {
            mHandler.sendEmptyMessage(enabled ? AdbDebuggingHandler.MESSAGE_ADB_ENABLED
                                              : AdbDebuggingHandler.MESSAGE_ADB_DISABLED);
        } else if (transportType == AdbTransportType.WIFI) {
            mHandler.sendEmptyMessage(enabled ? AdbDebuggingHandler.MSG_ADBDWIFI_ENABLE
                                              : AdbDebuggingHandler.MSG_ADBDWIFI_DISABLE);
        }
    }

       public void handleMessage(Message msg) {
            initKeyStore();

            switch (msg.what) {
                case MESSAGE_ADB_ENABLED:
...

                case MESSAGE_ADB_DISABLED:
...
                case MSG_ADBDWIFI_ENABLE: { //(1)收到打开wifiadb 消息
                    if (mAdbWifiEnabled) { //(2) 已经打开的情况不用继续打开
                        break;
                    }
                    //not to check network state ,change by      liwenzhi
                    // (3) 注释未打开wifi和未连接wifi情况下,调用关闭adb wifi 的代码
                    /** AdbConnectionInfo currentInfo = getCurrentWifiApInfo(); //这里是校验当前网络是否连接wifi
                    if (currentInfo == null) {
                        Settings.Global.putInt(mContentResolver,
                                Settings.Global.ADB_WIFI_ENABLED, 0); //(4)未连接wifi,关闭wifi adb的情况
                        break;
                    }

                    if (!verifyWifiNetwork(currentInfo.getBSSID(),
                            currentInfo.getSSID())) { //这里是校验,当前连接的网络是否是上次连接的那个网络
                        // This means that the network is not in the list of trusted networks.
                        // We'll give user a prompt on whether to allow wireless debugging on
                        // the current wifi network.
                        Settings.Global.putInt(mContentResolver,
                                Settings.Global.ADB_WIFI_ENABLED, 0); //(5)切换到其他网络,关闭wifi adb的情况
                        break;
                    }

                    //这个是保存当前连接的wifi,就是为了区分下次连接的wifi是否和上次一致
                    setAdbConnectionInfo(currentInfo); **/
                    //no listener network change for disable adb_wifi,by      liwenzhi
                     // (6) 注释网络变化的监听,只要网络变化都会导致关闭wifi adb
                    /** IntentFilter intentFilter =
                            new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
                    intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
                    mContext.registerReceiver(mBroadcastReceiver, intentFilter); **/

                    SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "1");
                    mConnectionPortPoller =
                            new AdbDebuggingManager.AdbConnectionPortPoller(mPortListener);
                    mConnectionPortPoller.start();

                    startAdbDebuggingThread(); //这线程主要是为了一直监听获取outputStream和inputStream数据,这里好像会记录每一个连接的adb设备,
                    mAdbWifiEnabled = true;

                    if (DEBUG) Slog.i(TAG, "adb start wireless adb");
                    break;

                case MSG_ADBDWIFI_DISABLE: //关闭wifi adb
                    if (!mAdbWifiEnabled) { //已经关闭的情况不用管
                        break;
                    }
                    mAdbWifiEnabled = false;
                    setAdbConnectionInfo(null); //设置保存的连接wifi信息为null
                    mContext.unregisterReceiver(mBroadcastReceiver); //如果上面监听注释了,这里也要注释

                    if (mThread != null) {
                        mThread.sendResponse(MSG_DISABLE_ADBDWIFI);
                    }
                    onAdbdWifiServerDisconnected(-1); //这里主要是发送通知和发送广播
                    stopAdbDebuggingThread(); //停止相关线程
                    break;

            }
        }

    // (7)自定义handler内部类,内部包含接收网络变化自定义广播接收器
  class AdbDebuggingHandler extends Handler {
        private NotificationManager mNotificationManager;
        private boolean mAdbNotificationShown;

        private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                // We only care about when wifi is disabled, and when there is a wifi network
                // change.
                if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) { // (8)监听wifi开关变化
                    int state = intent.getIntExtra(
                            WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
                    if (state == WifiManager.WIFI_STATE_DISABLED) { // (9)wifi关闭的情况,关闭wifi adb
                        Slog.i(TAG, "Wifi disabled. Disabling adbwifi.");
                        Settings.Global.putInt(mContentResolver,
                                Settings.Global.ADB_WIFI_ENABLED, 0);
                    }
                } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) { // (10)监听wifi连接情况变化
                    // We only care about wifi type connections
                    NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(
                            WifiManager.EXTRA_NETWORK_INFO);
                    if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                        // Check for network disconnect
                        if (!networkInfo.isConnected()) { // (10)发生连接变化后,如果不是连接状态,就关闭wifi adb
                            Slog.i(TAG, "Network disconnected. Disabling adbwifi.");
                            Settings.Global.putInt(mContentResolver,
                                    Settings.Global.ADB_WIFI_ENABLED, 0);
                            return;
                        }

                        WifiManager wifiManager =
                                (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
                        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
                        if (wifiInfo == null || wifiInfo.getNetworkId() == -1) { // (11)发生连接变化后,如果信息状态不对,就关闭wifi adb
                            Slog.i(TAG, "Not connected to any wireless network."
                                    + " Not enabling adbwifi.");
                            Settings.Global.putInt(mContentResolver,
                                    Settings.Global.ADB_WIFI_ENABLED, 0);
                        }

                        // Check for network change
                        String bssid = wifiInfo.getBSSID();
                        if (bssid == null || bssid.isEmpty()) { // (12)发生连接变化后,如果信息ssid不对,就关闭wifi adb
                            Slog.e(TAG, "Unable to get the wifi ap's BSSID. Disabling adbwifi.");
                            Settings.Global.putInt(mContentResolver,
                                    Settings.Global.ADB_WIFI_ENABLED, 0);
                        }
                        synchronized (mAdbConnectionInfo) {
                            if (!bssid.equals(mAdbConnectionInfo.getBSSID())) { // (12)发生连接变化后,如果和上次连接的wifi不同,就关闭wifi adb
                                Slog.i(TAG, "Detected wifi network change. Disabling adbwifi.");
                                Settings.Global.putInt(mContentResolver,
                                        Settings.Global.ADB_WIFI_ENABLED, 0);
                            }
                        }
                    }
                }
            }
        };

从上面代码可以看到 很多情况都有设置了ADB_WIFI_ENABLED 关闭的行为。
如果没有强制的安全要求,是可以把这些关闭的,目前测试还未发现啥问题。

这里设置了 Settings.Global.ADB_WIFI_ENABLED 属性代码,那么哪里会处理?
再往上看一下发现 AdbService 里面是有监听这个属性变化的,
然后调用 setAdbEnabled 方法,里面有设置prop属性哦,
接着调用了 AdbDebuggingManager.setAdbEnabled ,进行很相关线程启动,属性判断,网络判断等操作!

3、上层adb 相关流程

系统prop属性:persist.adb.tls_server.enable 0/1
Settings.GLOBAL属性:adb_wifi_enabled 0/1

(1)系统刚启动的情况
1、adb_wifi.cpp 优先启动,start_wifi_enabled_observer方法进入等待 prop 属性改变状态
2、SystemServer 启动 AdbService
3、AdbService.systemReady方法判断prop属性,执行是否开启adb,设置Settings.GLOBAL值
4、因为 AdbService 已经监听了 Settings.GLOBAL值的变化,所以会调用监听到变化,先设置prop方法,再执行setAdbEnabled 方法
5、接着调用 AdbDebuggingManager.setAdbEnabled ,进行很相关线程启动,属性判断,网络判断等操作!
6、如果网络未开启或者未连接等情况,AdbDebuggingManager 会设置 Settings.GLOBAL.ADB_WIFI_ENABLED 为0
7、AdbService 监听监听到Settings属性变化,又调用了 setAdbEnabled 关闭wifi adb

所以未屏蔽 AdbDebuggingManager 判断网络情况的代码就会出现:

设置属性 persist.adb.tls_server.enable = 1,系统启动后,发现还是为0;
设置属性 Settings.GLOBAL.ADB_WIFI_ENABLED =1 ,系统启动后,发现还是为0;
adb或者代码中,手动设置 ADB_WIFI_ENABLED =1 属性后,等下看,属性还是 0 ;

(2)直接设置Settings属性的情况
1、AdbService 监听监听到Settings属性变化,设置prop属性值,调用了 setAdbEnabled 方法
2、接着调用 AdbDebuggingManager.setAdbEnabled ,进行很相关线程启动,属性判断,网络判断等操作!
3、未屏蔽网络变化的情况,可能会导致 设置 Settings.GLOBAL.ADB_WIFI_ENABLED 为0
AdbService 监听监听到Settings属性变化,重新设置prop属性值

注意这里即使未屏蔽网络判断的代码,设置Settings.GLOBAL.ADB_WIFI_ENABLED = 1,
系统是会先调用开启adb,但是又马上关闭adb的,这个在 adb_wifi.cpp 是可以看到相关日志的。

(3)直接设置prop属性的情况
1、adb_wifi.cpp 的 start_wifi_enabled_observer 方法接收到prop属性变化
2、如果是开启就创建对应Server,随机生成端口号,设置端口号prop属性 service.adb.tls.port 
3、如果关闭就删除Server,并且端口号属性设置空字符串

可以看到设置prop 属性是不经过java代码的;
如果未屏蔽网络相关判断,设置prop开启wifi adb,那么重启设备或者网络变化都是会导致wifi adb关闭的。
端口号是在开启adb的时候设置在系统的,只修改prop端口号属性是没有效果的。

默认流程所有有可能是:

1、系统默认启动,未设置prop属性,未屏蔽网络判断
SystemServer --> AdbService.systemReady --> 读取prop --> 设置GLOBAL值 --> 
onChange --> setAdbEnabled -- > 设置prop属性( -->adb_wifi.cpp 会收到属性变化) 并且调用 AdbDebuggingManager.setAdbEnabled(false)

2、系统启动:只设置prop属性,未屏蔽网络判断 
SystemServer --> AdbService.systemReady --> 读取prop --> 设置GLOBAL值 --> 
onChange --> setAdbEnabled -- > 设置prop属性( -->adb_wifi.cpp 会收到属性变化) 并且调用 AdbDebuggingManager.setAdbEnabled(true)
-- > 判断到网络未连接 --> 设置GLOBAL值 -->
onChange --> setAdbEnabled -- > 设置prop属性( -->adb_wifi.cpp 会收到属性变化) 并且调用 AdbDebuggingManager.setAdbEnabled(false)

3、系统启动:设置prop属性,并且屏蔽网络判断
SystemServer --> AdbService.systemReady --> 读取prop --> 设置GLOBAL值 --> 
onChange --> setAdbEnabled -- >设置prop属性( -->adb_wifi.cpp 会收到属性变化) 并且调用 AdbDebuggingManager.setAdbEnabled(true)

4、后期设置 Settings.GLOBAL.ADB_WIFI_ENABLED =1 属性值,未屏蔽网络判断

Settings.GLOBAL.ADB_WIFI_ENABLED = 1 -->
AdbService.onChange --> setAdbEnabled -- > 设置prop属性( -->adb_wifi.cpp 会收到属性变化) 并且调用 AdbDebuggingManager.setAdbEnabled(true)
-- > 判断到网络未连接 --> 设置GLOBAL值 -->
onChange --> setAdbEnabled -- > 设置prop属性( -->adb_wifi.cpp 会收到属性变化) 并且调用 AdbDebuggingManager.setAdbEnabled(false)



5、后期设置 Settings.GLOBAL.ADB_WIFI_ENABLED =1 属性值,屏蔽网络判断
Settings.GLOBAL.ADB_WIFI_ENABLED = 1 --> 
AdbService.onChange --> setAdbEnabled -- >设置prop属性( -->adb_wifi.cpp 会收到属性变化) 并且调用 AdbDebuggingManager.setAdbEnabled(true)


6、后期设置 persist.adb.tls_server.enable =1 属性值, 不管屏不屏蔽网络变化,都是一样的

设置prop属性( -->adb_wifi.cpp 会收到属性变化) --> 启动adb ,设置端口号

但是最后一种情况,如果没有屏蔽网络变化,就会很不稳定,因为网络变化,就会关闭 wifi adb。


7、未屏蔽网络判断,网络改变情况
AdbDebuggingManager 广播接收到网络变化 --> 设置GLOBAL值 -->
AdbService.onChange --> setAdbEnabled -- > 设置prop属性( -->adb_wifi.cpp 会收到属性变化) 并且调用 AdbDebuggingManager.setAdbEnabled(false)


这里也有个简单结论:

设置默认 Settings.GLOBAL.ADB_WIFI_ENABLED 的值是没用的,系统流程会给他重新设置 0

如果未屏蔽网络变化的代码,即使设置了prop属性和GLOBAL属性也是没有意义的,系统流程也是会给它设置成 0

五、如果修改后依然无法网络adb连接分析

(1)查看adb默认值

getprop persist.adb.tls_server.enable  //查看prop属性
settings get global adb_wifi_enabled  //查看Settings 属性

setprop persist.adb.tls_server.enable 1 //设置prop属性
settings put global adb_wifi_enabled  1 //设置Settings 属性

如果设置 adb_wifi_enabled 1 ,等下查询马上又变成0 ,那么就是未去除网络变化的监听和判断。

(2)查看是否去除了限制adb的网络判断代码

这个就要看 AdbDebuggingManager 里面的代码了。

1、查看是否去除了网络变化的监听
WifiManager.WIFI_STATE_CHANGED_ACTION
WifiManager.NETWORK_STATE_CHANGED_ACTION
2、查看是否对 getCurrentWifiApInfo() 的判断进行了屏蔽
3、查看是否去除了执行:Settings.Global.putInt(mContentResolver,Settings.Global.ADB_WIFI_ENABLED, 0);

(3)查看是否打印了底层具体执行adb_wifi.cpp adb 开关的处理

//开启wifi 的日志
LOG(INFO) << "adb wifi started on port " << sTlsServer->port();

//停止wifi adb的日志
LOG(INFO) << "adb wifi stopped";

所以查看关键字"adb wifi"可以看到日志。

logcat | grep "adb wifi"

日志如下:

console:/ # logcat | grep "adb wifi"                                           
09-05 21:09:31.755   668   712 I adbd    : adb wifi stopped //关闭日志
09-05 21:09:48.326   668   712 I adbd    : adb wifi started on port 5555 //开启日志,并且会打印 端口号

(4)还是有问题,只能在代码流程上添加日志了

1、打开 AdbService 和 AdbDebuggingManager 的日志开关
2、AdbService.systemReady()添加打印默认属性
Slog.d(TAG, "lwz systemReady= " + WIFI_PERSISTENT_CONFIG_PROPERTY + " = " + SystemProperties.get(WIFI_PERSISTENT_CONFIG_PROPERTY, "0"));
Slog.d(TAG, "lwz systemReady mIsAdbWifiEnabled= " + mIsAdbWifiEnabled); 
3、AdbSettingsObserver.onChange 打印Settings属性变化后的值
Slog.d(TAG, "lwz onChange shouldEnable = " + shouldEnable);

AdbDebuggingManager 也可以看情况添加一下日志,但是里面关闭 wifi adb的情况基本是有打印的。

这是通过命令logcat 打印多个关键字,就能看到问题原因了。


logcat | grep -E "AdbService|AdbDebuggingManager|adb wifi|XXX" //XXX 是自己定义的


(5)device offline

连接之后提示设备离线,那么可能是电脑的adb 版本和 Android设备不匹配,一般换成adb 高的版本就行,也有可能需要换成adb 低的版本。

六、其他

1、adb 相关属性

(1) prop属性:persist.adb.tls_server.enable

系统启动后,AdbService 会判断该属性决定后续是否执行开启adb。

(2)prop属性:service.adb.tls.port

该属性是 adb_wifi.cpp 使能adb的时候设置的. 后续让你知道它的端口号。
所以设置这个属性值是没有意义的。
在 adb_wifi.cpp,初始化 TlsServer 设置固定端口 5555,那么这个属性一直就是 5555. 如果未设置就是随机的5位数。

(3)Settings属性:Settings.Global.ADB_WIFI_ENABLED 具体名称是 “adb_wifi_enabled”

同时在 AdbService 是有监听 这个Global 属性的变化,关联上 AdbDebuggingManager ,设置 adb 使能。

查询和设置命令:


//查询属性;
setttings get global adb_wifi_enabled
//设置属性 0/1:
setttings put global adb_wifi_enabled 1

该属性是系统上层设置的一个值,原本主要用来记录adb wifi 的开关状态。
因为Android13 会判断当前wifi是否是信任的,切换wifi后设置这个属性是无效的。

但是如果修改了上面去除网络限制对策后,直接设置Global属性,是会正常开关adb的。

如果未去除网络限制对策,你会发现 adb_wifi_enabled 无法设置成1,
因为 AdbDebuggingManager 在开启的是会还会判断网络情况,如果没有网络会设置为 0 .

2、AdbService.java、AdbDebuggingManager.java、adb_wifi.cpp 的关系

(1) adb_wifi 是底层init/cpp 启动的服务

里面的日志是跑在比较前面的,比SystemServer 更早。
正常开启和关闭adb 是有相关日志的。

(2)AdbService启动时机

AdbService 是SystemServer 执行 startOtherServices 里面启动的服务。

AdbService extends IAdbManager.Stub //具体暴露接口可以看 IAdbManager

(3)AdbDebuggingManager 是一个管理adbDebug的类,

该类在 AdbService 里面实例化,其实就是分化了一下具体执行的代码。

很多无法进入adb wifi 的情况都是在AdbDebuggingManager 拒绝的,并且重新设置了 Global属性 和 Prop 属性为0

AdbDebuggingManager 并不是普通的暴露给其他类使用的SDK类,只是一个普通类,并且里面监听了网络变化广播,是可以收到网络变化的。

适配了去除网络限制上面代码后,就应用而言,使用 Settings.Global.ADB_WIFI_ENABLED 控制和或者当前 网络adb状态最合适的。
虽然使用prop 属性也能生效,但是系统应用Settings判断的是Settings.Global.ADB_WIFI_ENABLED的值是否为1,
会出现adb状态显示不同步的情况。

别人分析的user版本不能使用adb问题(版本不是最新的,写的比较复杂):
https://blog.csdn.net/kc58236582/article/details/53502177/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android 13 网络 Adb相关流程深入分析研究 的相关文章

  • 如何重试已消耗的 Observable?

    我正在尝试重新执行失败的已定义可观察对象 一起使用 Retrofit2 和 RxJava2 我想在单击按钮时重试特定请求及其订阅和行为 那可能吗 service excecuteLoginService url tokenModel Ret
  • 在 Android Studio 中,为什么我必须在模拟器中单击“运行应用程序”两次才能启动应用程序?

    在 Android Studio 中 当我按播放按钮在 Android 模拟器上安装并运行应用程序时 大约 5 10 秒后 我在屏幕底部收到一条消息 显示 安装成功 但应用程序实际上并未运行在模拟器上 我必须再次按下播放按钮 这是非常令人沮
  • CardView 圆角获得意想不到的白色

    When using rounded corner in CardView shows a white border in rounded area which is mostly visible in dark environment F
  • 如何以编程方式检查 AndroidManifest.xml 中是否声明了服务?

    我正在编写一个库 该库提供了一项服务 其他开发人员可以通过将其包含在他们的项目中来使用该服务 因此 我无法控制 AndroidManifest xml 我在文档中解释了要做什么 但一个常见的问题是人们忽略了将适当的 标记添加到其清单中 或者
  • android xamarin 中的 reCaptcha

    我想在 Xamarin android 应用程序中实现验证码 我抓住了这个在 Android 中集成 googles reCaptcha 验证 https www c sharpcorner com article how to integ
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • 带有 EditText 和 Spinner 的对话框

    我有一个按钮 单击后会弹出一个对话框 我希望对话框有一个EditText and a Spinner对话框内 我不知道如何设置它的视图 我有一个代码AlertDialog它有效 只是EditText and Spinner我需要将其放入其中
  • 尝试将相机切换回前面但出现异常

    尝试将相机切换回前面 但出现异常 找不到 问题请检查并帮助 error 01 27 11 49 00 376 E AndroidRuntime 30767 java lang RuntimeException Unable to start
  • 获取当前 android.intent.category.LAUNCHER 活动的实例

    我创建了一个库项目 并在多个应用程序之间共享 我实现了一个简单的会话过期功能 该功能将在一段时间后将用户踢回到登录屏幕 登录屏幕活动是我的主要活动 因此在清单中它看起来像这样
  • 如何使用 IF 检查 TextView 可见性

    我有一个 onCheckedChangeListener 来根据选择的单选按钮显示文本视图 我有 1 个疑问和 1 个难题 想知道是否有人可以帮助我 问题 您能否将单选组默认检查值设置为 否 单选按钮 以便一开始就不会检查任何内容 问题 如
  • 如何发布Android .aar源以使Android Studio自动找到它们?

    我正在将库发布到内部 Sonatype Nexus 存储库 Android Studio 有一个功能 可以自动查找通过 gradle 引用的库的正确源 我将 aar 的源代码作为单独的 jar 发布到 Nexus 但 Android Stu
  • Android 中麦克风的后台访问

    是否可以通过 Android 手机上的后台应用程序 服务 持续监控麦克风 我想做的一些想法 不断聆听背景中的声音信号 收到 有趣的 音频信号后 执行一些网络操作 如果前台应用程序需要的话 后台应用程序必须能够智能地放弃对麦克风的访问 除非可
  • Android向menuItem添加子菜单,addSubMenu()在哪里?

    我想根据我的参数以编程方式将 OptionsMenu 内的子菜单添加到 menuItem 中 我检查了android sdk中的 MenuItem 没有addSubMenu 方法 尽管你可以找到 hasSubMenu 和 getSubMen
  • Android 套接字和 asynctask

    我即将开始制作一个应该充当 tcp 聊天客户端的应用程序 我一直在阅读和阅读 我得出的结论是最好 如果不需要 将我的套接字和异步任务中的阅读器 问题是我不确定从哪里开始 因为我是 Android 新手 这至少对我来说是一项艰巨的任务 但据我
  • 如何确定对手机号码的呼叫是本地呼叫还是 STD 或 ISD

    我正在为 Android 开发某种应用程序 但不知道如何获取被叫号码是本地或 STD 的号码的数据 即手机号码检查器等应用程序从哪里获取数据 注意 我说的是手机号码 而不是固定电话 固定电话号码 你得到的数字是字符串类型 因此 您可以获取号
  • 实现滚动选择 ListView 中的项目

    我想使用 ListView 您可以在其中滚动列表来选择一个项目 它应该像一个 Seekbar 但拇指应该是固定的 并且您必须使用该栏来调整它 我面临的一个问题是 我不知道这种小部件是如何调用的 这使得我很难搜索 所以我制作了下面这张图片 以
  • 将 Intent 包装在 LabeledIntent 中以用于显示目的

    要求 我的应用程序中有一个 共享 按钮 我需要通过 Facebook 分享 我需要选择是否安装原生 Facebook 应用程序 我们的决定是 如果未安装该应用程序 则将用户发送到 facebook com 进行分享 当前状态 我可以检测何时
  • 将两个文本视图并排放置在布局中

    我有两个文本视图 需要在布局中并排放置 并且必须遵守两条规则 Textview2 始终需要完整显示 如果布局中没有足够的空间 则必须裁剪 Textview1 例子 文本视图1 文本视图2 Teeeeeeeeeeeeeeeeeextview1
  • 如何将 google+ 登录集成到我的 Android 应用程序中?

    大家好 实际上我需要通过我的应用程序从 google 登录人们 现在我阅读了 google 上的文档 其中指出 要允许用户登录 请将 Google Sign In 集成到您的应用中 初始化 GoogleApiClient 对象时 请求 PL
  • 节拍匹配算法

    我最近开始尝试创建一个移动应用程序 iOS Android 它将自动击败比赛 http en wikipedia org wiki Beatmatching http en wikipedia org wiki Beatmatching 两

随机推荐

  • uniApp中 nvue和vue开发 小结

    最近接手uniapp开发 对遇到的问题进行总结 什么是nvue nvue native vue 原生渲染 为何要用nvue开发 weex 有个很大的问题是它只是一个高性能的渲染器 没有足够的API能力 比如各种push sdk集成 蓝牙等能
  • 电梯调度算法-C++

    1 算法解析 扫描算法 SCAN 又称电梯调度算法 SCAN算法是磁头前进方向上的最短查找时间优先算法 它排除了磁头在盘面局部位置上的往复移动 SCAN算法在很大程度上消除了SSTF算法的不公平性 但仍有利于对中间磁道的请求 电梯调度算法是
  • 【图解】ThreadLocal底层实现原理

    1 ThreadLocal的底层原理图 说明 Thread中有threadLocals成员变量 threadLocal会在threadlocal首次set时进行赋值 这会在非main线程中复现 主线程启动即会进行赋值 ThreadLocal
  • git使用(由浅到深)

    目录流程图 1 分布式版本控制与集中式版本控制 1 1 集中式版本控制 集中式版本控制系统有 CVS和SVN 它们的主要特点是单一的集中管理的服务器 保存所有文件的修订版本 协同开发人员通过客户端连接到这台服务器 取出最新的文件或者提交更新
  • Java面试题及答案整理(2021最新版)

    Java面试题及答案整理 一 Java 基础 1 JDK 和 JRE 有什么区别 2 和 equals 的区别是什么 3 两个对象的 hashCode 相同 则 equals 也一定为 true 对吗 4 final 在 java 中有什么
  • C语言中C89与C99的区别

    1 增加restrict指针 C99中增加了公适用于指针的restrict类型修饰符 它是初始访问指针所指对象的惟一途径 因此只 有借助restrict指针表达式才能访问对象 restrict指针指针主要用做函数变元 或者指向由malloc
  • QT中json与数据转换

    QT中json与数据转换 一 json简介 二 json文件的写入与解析 1 简单的json对象 2 json数组 3 复杂的json对象 三 QT中配置文件应用json实现 1 需求 2 打开工程 3 保存工程 4 新建工程 一 json
  • java无法从静态上下文_ERROR无法从静态上下文中引用非静态变量

    什么是 static 学习过java C 或C的人都应该认识这个关键字 用这个关键字修饰的变量叫做静态变量 有其特殊的作用 在java中static也用来修饰静态方法和静态内部类 静态变量的特点 1 生存周期 静态局部变量的生存周期也是整个
  • 华为华三思科 配置arp IP地址和mac地址绑定

    华为
  • 微信小程序存在的风险_警惕,你的微信小程序可能面临着风险!

    小程序目前在移动互联网领域的流行 它有火 到6月底的数据告诉你 微信微型节目C端用户达到2 8亿 迷你程序达到100万 累计用户数达到6亿 即时访问 不需要下载 成为用户使用小程序的触发点 但在建立生态的小程序 其独特的安全风险也逐渐显示出
  • 四千个厂商默认账号密码 默认登录凭证

    Product Vendor Username Password Zyxel ssh zyfwp PrOw aN fXp APC UPS web apc apc Weblogic web system manager Weblogic we
  • 基于cubemx的stm32HAL库SPI通信写LCD显示屏

    之前学习了如何使用LCD 记录一下 关于spi部分是从野火的资料中截取 也会加入我自己的备注 便于理解 代码部分在后面 请耐心看完 一 SPI协议简介 SPI 协议是由摩托罗拉公司提出的通讯协议 Serial Peripheral Inte
  • STM32用SYSTICK实现的系统时钟和微秒级延时函数

    代码耗时法延时难以准确 比较过定时器法在10微秒内误差比较大 下面的代码片段使用SysTick实现系统时钟 以及不影响时钟的高精度微秒级延时 想法是SysTick实现每毫秒递增的系统时钟 而在不影响SysTick连续运行前提下 使用当前计数
  • driver org.postgresql.driver claims to not accept jdbcurl, jdbc:h2:mem:test

    driver org postgresql driver claims to not accept jdbcurl jdbc h2 mem test 背景 项目中使用了h2数据库 不想用h2 把配置改为PostgreSQL 出现此异常 原因
  • DuplexPipe二三事(五)——来自内网的呼唤

    穿越防火墙 你是否曾经尝试过去连接一台远程计算机 却因为被防火墙拦截或路由器没有转发而造成无法通信 这是主动式连接的一个弊端 它依赖服务器的状态 而对服务器有生杀大权的只有管理员 如果能让服务器主动尝试连接我们的计算机 那就没问题了 因为防
  • linux不能编译内核,linux – 内核编译时无法统计错误

    我试图按照here所述的方式在Ubuntu 14 04中编译内核版本4 10 1 它一直工作到4 9 x版本 当4 10 x出现时 我不断收到以下错误 install p o root g root m 644 CREDITS usr sr
  • OpenCV Python 系列教程4 - OpenCV 图像处理(上)

    import cv2 cv2 version 3 4 1 更改色彩空间 学习目标 改变色彩空间 B G R G r a
  • UnicodeEncodeError: 'gbk' codec can't encode character '\xa0' in position ... 问题解决办法之一

    使用Python写文件的时候 或者将网络数据流写入到本地文件的时候 大部分情况下会遇到 UnicodeEncodeError gbk codec can t encode character xa0 in position 这个问题 网络上
  • 不愧是美团内部 “接口自动化测试学习笔记” 这细节讲解,神了

    Lego 美团接口自动化测试实践 1 1接口自动化概述 众所周知 接口自动化测试有着如下特点 1 低投入 高产出 2 比较容 实现自动化 3 和UI自动化测试相比 加稳定 如何做好一个接口自动化测试项目呢 我认为 一个 好的 自动化测试项目
  • Android 13 网络 Adb相关流程深入分析研究

    Android 13 网络 Adb 分析研究 文章目录 Android 13 网络 Adb 分析研究 一 前言 二 默认adb 代码实现 关键 1 修改的目录 2 具体修改 1 在XXX device mk 添加属性 2 设置固定端口号 3