Android13 Wifi启动流程分析

Android13 Wifi启动流程分析

文章目录

  • Android13 Wifi启动流程分析
    • 一、正常开关wifi 启动流程
      • 1、WifiManager
      • 2、WifiServiceImpl
      • 3、ActiveModeWarden
      • 4、ConcreteClientModeManager
      • 5、WifiNative
      • 6、WifiVendorHal
      • 7、HalDeviceManager
      • 8、wifi.cpp
    • 二、重启设备时自动开启wifi流程
      • 1、系统服务启动 SystemServer
      • 2、WifiService
      • 3、WifiServiceImpl
      • 4、ActiveModeWarden
    • 三、其他
      • 1、Android13 Wifi启动 完整流程:
      • 2、日志查看
        • 关键字和可以查看到的关键信息
        • 正常开启wifi日志:
        • 正常关闭wifi日志:
        • 缺少wifi硬件模组是开启wifi日志:
      • 3、wifi开关状态值
      • 4、之前写的一些wifi相关的知识

本文对Android13 wifi 开启流程进行梳理,有需要的可以看看。

如果遇到wifi 打不开问题,可以依照这个流程进行分析,看看具体是哪个流程出现问题。

如果后续需要分析比Android13 更新的代码可以对比参考,毕竟Android11的代码变动比较大。

本文最后有流程总结,代码分析过程还有最大一个亮点,每个类的流程分析都标志了数字,避免读着读着就迷路了。

最后还有wifi开关相关日志过程分析。

一、正常开关wifi 启动流程

1、WifiManager

WifiManager 是给应用暴露的api接口类

packages\modules\Wifi\framework\java\android\net\wifi\WifiManager.java

@SystemService(Context.WIFI_SERVICE)
public class WifiManager {

    public boolean setWifiEnabled(boolean enabled) {
        try {
        	// (1)调用 Service 的 setWifiEnabled 方法
            return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}

2、WifiServiceImpl

WifiServiceImpl 是Manager接口具体实现类

packages\modules\Wifi\service\java\com\android\server\wifi\WifiServiceImpl.java

public class WifiServiceImpl extends BaseWifiService {

    private static final String TAG = "WifiService";
    
    // (1) setWifiEnabled 方法
    public synchronized boolean setWifiEnabled(String packageName, boolean enable) {

        // If Airplane mode is enabled, only privileged apps are allowed to toggle Wifi
        if (mSettingsStore.isAirplaneModeOn() && !isPrivileged) {
            mLog.err("setWifiEnabled in Airplane mode: only Settings can toggle wifi").flush(); //异常日志
            return false;
        }
...
		 // (2)  继续追踪setWifiEnabledInternal 方法
        setWifiEnabledInternal(packageName, enable, callingUid, callingPid, isPrivileged);
        return true;
    }

	// (3)  查看 setWifiEnabledInternal 方法实现
    private void setWifiEnabledInternal(String packageName, boolean enable,
            int callingUid, int callingPid, boolean isPrivileged) {
        // (4) 这里有打印哦,打印哪个应用打开还是关闭wifi 的日志 
        mLog.info("setWifiEnabled package=% uid=% enable=% isPrivileged=%").c(packageName)
                .c(callingUid).c(enable).c(isPrivileged).flush(); //wifi 打开日志
 。。。
        // (5) 继续追踪 ActiveModeWarden.wifiToggled
        mActiveModeWarden.wifiToggled(new WorkSource(callingUid, packageName));
        mLastCallerInfoManager.put(WifiManager.API_WIFI_ENABLED, Process.myTid(),
		callingUid, callingPid, packageName, enable); //一些属性的保存,可以不用管
    }
	
}

WifiServiceImpl 的打印TAG 是 WifiService,wifi 开关有比较多相关日志,主要是看出开关日志和哪个应用调用的开关。

3、ActiveModeWarden

里面有一些关键日志,调试可以查看该日志。

packages\modules\Wifi\service\java\com\android\server\wifi\ActiveModeWarden.java

public class ActiveModeWarden {

	private static final String TAG = "WifiActiveModeWarden";

	//(1) wifi打开消息发送方法
    public void wifiToggled(WorkSource requestorWs) {
        mWifiController.sendMessage(WifiController.CMD_WIFI_TOGGLED, requestorWs);
    }

		//(2) wifi打开消息的接收
		//内部类,wifi执行打开是Disable 的状态
        class DisabledState extends BaseState {
            @Override
            public void enter() {
                log("DisabledState.enter()");
                super.enter();
                if (hasAnyModeManager()) {
                    Log.e(TAG, "Entered DisabledState, but has active mode managers");
                }
            }

            @Override
            public boolean processMessageFiltered(Message msg) {
                switch (msg.what) {
               		 //(3) wifi打开消息处理
                    case CMD_WIFI_TOGGLED:
                    case CMD_SCAN_ALWAYS_MODE_CHANGED:
                        handleStaToggleChangeInDisabledState((WorkSource) msg.obj);
                        break;
						}
                    default:
                        return NOT_HANDLED;
				}
			return HANDLED;
			}

		
		 //(4) 内部类的处理方法 handleStaToggleChangeInDisabledState
        private void handleStaToggleChangeInDisabledState(WorkSource requestorWs) {
            if (shouldEnableSta()) {
                startPrimaryOrScanOnlyClientModeManager(requestorWs);
                transitionTo(mEnabledState);
            }
        }
	}
	
	//(4) 具体的处理方法 startPrimaryOrScanOnlyClientModeManager
    private boolean startPrimaryOrScanOnlyClientModeManager(WorkSource requestorWs) {
        //(5)这里其实是判断了wifi_on那个Settings属性
        ActiveModeManager.ClientRole role = getRoleForPrimaryOrScanOnlyClientModeManager();
        if (role == ROLE_CLIENT_PRIMARY) { //(6)wifi 打开是进这里
            return startPrimaryClientModeManager(requestorWs);
        } else if (role == ROLE_CLIENT_SCAN_ONLY) {
            return startScanOnlyClientModeManager(requestorWs);
        } else {
            return false;
        }
    }

	
	// (7)继续追踪方法
    private boolean startPrimaryClientModeManager(WorkSource requestorWs) {
        Log.d(TAG, "Starting primary ClientModeManager in connect mode");
        //(8)这里创建了 ConcreteClientModeManager 对象,看起来没做啥,其实创建对象会做事情
		ConcreteClientModeManager manager = mWifiInjector.makeClientModeManager(
                new ClientListener(), requestorWs, ROLE_CLIENT_PRIMARY, mVerboseLoggingEnabled);
				mClientModeManagers.add(manager); //连接对象被接入队列管理,可以不用关注,断开会被移除
        mLastPrimaryClientModeManagerRequestorWs = requestorWs;
        return true;
    }

	
}

ActiveModeWarden 的日志 TAG 是 WifiActiveModeWarden,该文件的日志有打印目前wifi是从哪个状态进入进行操作的日志。

往下走的 ConcreteClientModeManager 对象 比较特殊,你只要创建它,它就会默认执行开启wifi,往下看它的代码实现就可以看到,所以这里manager 未调用方法,只是加入到队列管理中,很多人可能会看懵,但是继续往下看它的构造方法就明白了。

4、ConcreteClientModeManager

ConcreteClientModeManager 相关一个系统层的wifi Manager,系统内部使用;

Android11 中没有 ConcreteClientModeManager ,只有 ClientModeManager。

packages\modules\Wifi\service\java\com\android\server\wifi\ConcreteClientModeManager.java

public class ConcreteClientModeManager implements ClientModeManager {
    private static final String TAG = "WifiClientModeManager";

	//(1) ConcreteClientModeManager 构造方法
    ConcreteClientModeManager(Context context,...) {
        mContext = context;
        mWifiNative = wifiNative;
...
		//(2)构造方法中,发送wifi开启
        mStateMachine.sendMessage(ClientModeStateMachine.CMD_START, mTargetRoleChangeInfo);
    }

		//(3)内部状态类,接收消息
		//内部类,未开启wifi前是IdleState状态
        private class IdleState extends State {
            @Override
            public void enter() {
                Log.d(getTag(), "entering IdleState");
                mClientInterfaceName = null;
                mIfaceIsUp = false;
            }
			
            @Override
            public boolean processMessage(Message message) {
                switch (message.what) {
               		 //(3)接收消息
                    case CMD_START:
                        // Always start in scan mode first.
                        RoleChangeInfo roleChangeInfo = (RoleChangeInfo) message.obj;
						// (4) native 方法调用,拉起节点,一般是wlan0
                        mClientInterfaceName = mWifiNative.setupInterfaceForClientInScanMode(
                                mWifiNativeInterfaceCallback, roleChangeInfo.requestorWs);
                        if (TextUtils.isEmpty(mClientInterfaceName)) {
                            Log.e(getTag(), "Failed to create ClientInterface. Sit in Idle");
                            takeBugReportInterfaceFailureIfNeeded(
                                    "Wi-Fi scan STA interface HAL failure");
                            mModeListener.onStartFailure(ConcreteClientModeManager.this);
                            break;
                        }
                        if (roleChangeInfo.role instanceof ClientConnectivityRole) { //默认是进入这里
                            sendMessage(CMD_SWITCH_TO_CONNECT_MODE, roleChangeInfo);
                            transitionTo(mStartedState);
                        } else {
                            mScanRoleChangeInfoToSetOnTransition = roleChangeInfo;
                            transitionTo(mScanOnlyModeState);
                        }
                        break;
                    default:
                        Log.d(getTag(), "received an invalid message: " + message);
                        return NOT_HANDLED;
                }
                return HANDLED;
            }
		}

		
}

ConcreteClientModeManager 的日志 TAG 是 WifiClientModeManager,

该文件的日志有也是包含了一些状态下的操作信息。

Android11 中 ClientModeManager 的日志 TAG 是 WifiClientModeManager。

5、WifiNative

WifiNative 是一个统筹调用底层接口的类,这个类往下的逻辑看起来好像没有太大修改。

packages\modules\Wifi\service\java\com\android\server\wifi\WifiNative.java

public class WifiNative {
    private static final String TAG = "WifiNative";

    private final WifiVendorHal mWifiVendorHal;
    private final IfaceManager mIfaceMgr = new IfaceManager(); //内部类,调用的Iface

    public String setupInterfaceForClientInScanMode(
            @NonNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs) {
        synchronized (mLock) {
            if (!startHal()) { //(1) 初始化驱动和vendor hal
                Log.e(TAG, "Failed to start Hal");
                mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
                return null;
            }
			// (2) 初始化interface
            Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_SCAN);
            if (iface == null) {
                Log.e(TAG, "Failed to allocate new STA iface");
                return null;
            }
            iface.externalListener = interfaceCallback;
            iface.name = createStaIface(iface, requestorWs);
            if (TextUtils.isEmpty(iface.name)) {
                Log.e(TAG, "Failed to create iface in vendor HAL");
                mIfaceMgr.removeIface(iface.id);
                mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
                return null;
            }
			// (3)初始化wificond
            if (!mWifiCondManager.setupInterfaceForClientMode(iface.name, Runnable::run,
                    new NormalScanEventCallback(iface.name),
                    new PnoScanEventCallback(iface.name))) {
                Log.e(TAG, "Failed to setup iface in wificond=" + iface.name);
                teardownInterface(iface.name);
                mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
                return null;
            }
            iface.networkObserver = new NetworkObserverInternal(iface.id);
			//(4)监听interface的down/up
            if (!registerNetworkObserver(iface.networkObserver)) {
                Log.e(TAG, "Failed to register network observer for iface=" + iface.name);
                teardownInterface(iface.name);
                return null;
            }
			//(5)启动supplicant监听(但是此时supplicant进程还未启动)
            mWifiMonitor.startMonitoring(iface.name);
            // Just to avoid any race conditions with interface state change callbacks,
            // update the interface state before we exit.
            onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
            mWifiVendorHal.enableLinkLayerStats(iface.name);
            Log.i(TAG, "Successfully setup " + iface); //成功启动wifi节点

			//(6)获取芯片支持的wifi feature
            iface.featureSet = getSupportedFeatureSetInternal(iface.name);
            return iface.name;
        }
    }

	//(7) 继续分析:初始化驱动
    private boolean startHal() {
        synchronized (mLock) {
            if (!mIfaceMgr.hasAnyIface()) { //(8) 判断节点是否存在
                if (mWifiVendorHal.isVendorHalSupported()) { //(9) 判断底层是否支持
                    if (!mWifiVendorHal.startVendorHal()) { //(10) **重点:判断是否可以正常启动节点
                        Log.e(TAG, "Failed to start vendor HAL");
                        return false;
                    }
                    if (SdkLevel.isAtLeastS()) {
                        mWifiVendorHal.setCoexUnsafeChannels(mCachedCoexUnsafeChannels, mCachedCoexRestrictions);
                    }
                } else {
                    Log.i(TAG, "Vendor Hal not supported, ignoring start.");
                }
            }
            registerWificondListenerIfNecessary();
            return true;
        }
    }
	
}

6、WifiVendorHal

packages\modules\Wifi\service\java\com\android\server\wifi\WifiVendorHal.java

/**
 * Vendor HAL via HIDL
 */
public class WifiVendorHal {

    private final HalDeviceManager mHalDeviceManager;
    
    // (1)追踪 startVendorHal
    public boolean startVendorHal() {
        synchronized (sLock) {
        	//(2) 关键 mHalDeviceManager.start
            if (!mHalDeviceManager.start()) {
                mLog.err("Failed to start vendor HAL").flush();
                return false;
            }
            mLog.info("Vendor Hal started successfully").flush();
            return true;
        }
    }
}

7、HalDeviceManager

import android.hardware.wifi.V1_0.IWifi;

/**
 * Handles device management through the HAL (HIDL) interface.
 */
public class HalDeviceManager {
    private static final String TAG = "HalDevMgr";

    private IWifi mWifi;
	
	//(1) 继续追踪 HalDeviceManager.start
	public boolean start() {
        return startWifi();
    }

	//(2) startWifi 实现
    private boolean startWifi() {
        if (VDBG) Log.d(TAG, "startWifi");
        initIWifiIfNecessary();
        synchronized (mLock) {
            try {
                if (mWifi == null) {
                    Log.w(TAG, "startWifi called but mWifi is null!?");
                    return false;
                } else {
                    int triedCount = 0;
                    while (triedCount <= START_HAL_RETRY_TIMES) { //最多启动start三次
                        WifiStatus status = mWifi.start();
                        if (status.code == WifiStatusCode.SUCCESS) {
                            initIWifiChipDebugListeners();
                            managerStatusListenerDispatch();
                            if (triedCount != 0) { //(3)启动慢,一次没有启动成功的情况,这里才会有日志!
                                Log.d(TAG, "start IWifi succeeded after trying " + triedCount + " times");
                            }
                            WifiChipInfo[] wifiChipInfos = getAllChipInfo();
                            if (wifiChipInfos != null) {
                                mCachedStaticChipInfos =
                                        convertWifiChipInfoToStaticChipInfos(getAllChipInfo());
                                saveStaticChipInfoToStore(mCachedStaticChipInfos);
                            } else {
                                Log.e(TAG, "Started wifi but could not get current chip info.");
                            }
                            return true;
                        } else if (status.code == WifiStatusCode.ERROR_NOT_AVAILABLE) {
                            // Should retry. Hal might still be stopping. the registered event
                            // callback will not be cleared.
                            Log.e(TAG, "Cannot start IWifi: " + statusString(status)
                                    + ", Retrying...");
                            try {
                                Thread.sleep(START_HAL_RETRY_INTERVAL_MS);
                            } catch (InterruptedException ignore) {
                                // no-op
                            }
                            triedCount++;
                        } else {
                            // Should not retry on other failures.
                            // Will be handled in the onFailure event.
                            Log.e(TAG, "Cannot start IWifi: " + statusString(status));
                            return false;
                        }
                    }
                    Log.e(TAG, "Cannot start IWifi after trying " + triedCount + " times");
                    return false;
                }
            } catch (RemoteException e) {
                Log.e(TAG, "startWifi exception: " + e);
                return false;
            }
        }
    }
	
}

WifiNative往下大致流程:

WifiNative -> WifiVendorHal -> HalDeviceManager

WifiNative.startHal() -> 
WifiVendorHal.startVendorHal() ->
HalDeviceManager.start() -> 
HalDeviceManager.startWifi()

HalDeviceManager 往下的 Hal 层代码是直接调用硬件接口的了。
并且 IWifi 这些 接口类是系统编译生成的,没有具体的IWifi.java 文件,只有相关的class文件。

8、wifi.cpp

Hal 层代码

hardware\interfaces\wifi\1.6\default\wifi.cpp

Return<void> Wifi::start(start_cb hidl_status_cb) {
    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::startInternal,
                           hidl_status_cb);
}


WifiStatus Wifi::startInternal() {
    if (run_state_ == RunState::STARTED) {
        return createWifiStatus(WifiStatusCode::SUCCESS);
    } else if (run_state_ == RunState::STOPPING) {
        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, "HAL is stopping");
    }
    WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
    if (wifi_status.code == WifiStatusCode::SUCCESS) {
        // Register the callback for subsystem restart
        const auto& on_subsystem_restart_callback = [this](const std::string& error) {
            WifiStatus wifi_status = createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, error);
            for (const auto& callback : event_cb_handler_.getCallbacks()) {
                LOG(INFO) << "Attempting to invoke onSubsystemRestart "
                             "callback";
                if (!callback->onSubsystemRestart(wifi_status).isOk()) {
                    LOG(ERROR) << "Failed to invoke onSubsystemRestart callback";
                } else {
                    LOG(INFO) << "Succeeded to invoke onSubsystemRestart "
                                 "callback";
                }
            }
        };

        // Create the chip instance once the HAL is started.
        android::hardware::wifi::V1_0::ChipId chipId = kPrimaryChipId;
        for (auto& hal : legacy_hals_) {
            chips_.push_back(
                    new WifiChip(chipId, chipId == kPrimaryChipId, hal, mode_controller_,
                                 std::make_shared<iface_util::WifiIfaceUtil>(iface_tool_, hal),
                                 feature_flags_, on_subsystem_restart_callback));
            chipId++;
        }
        run_state_ = RunState::STARTED;
        for (const auto& callback : event_cb_handler_.getCallbacks()) {
            if (!callback->onStart().isOk()) {
                LOG(ERROR) << "Failed to invoke onStart callback";
            };
        }
        LOG(INFO) << "Wifi HAL started";
    } else {
        for (const auto& callback : event_cb_handler_.getCallbacks()) {
            if (!callback->onFailure(wifi_status).isOk()) {
                LOG(ERROR) << "Failed to invoke onFailure callback";
            }
        }
        LOG(ERROR) << "Wifi HAL start failed";
        // Clear the event callback objects since the HAL start failed.
        event_cb_handler_.invalidate();
    }
    return wifi_status;
}

WifiStatus Wifi::initializeModeControllerAndLegacyHal() {
    // ... ...
    mode_controller_->initialize();				// 加载驱动 driver_tool_->LoadDriver()
    
    legacy_hals_ = legacy_hal_factory_->getHals();
    for (auto& hal : legacy_hals_) {
        legacy_hal::wifi_error legacy_status = hal->initialize();
        // ... ...
    }
    // ... ...
}

std::vector<std::shared_ptr<WifiLegacyHal>> WifiLegacyHalFactory::getHals() {
    if (legacy_hals_.empty()) {
        // 先从已链接的so库中初始化vendor hal的接口(函数指针赋值)
        // 如果失败,证明是多wifi芯片的设备,需要从descriptor.xml初始化
        if (!initVendorHalDescriptorFromLinked()) initVendorHalsDescriptorList();
        for (auto& desc : descs_) {
            std::shared_ptr<WifiLegacyHal> hal =
                    std::make_shared<WifiLegacyHal>(iface_tool_, desc.fn, desc.primary);
            legacy_hals_.push_back(hal);
        }
    }

    return legacy_hals_;
}


wifi.cpp 主要工作:

通过wifi_mode_controller加载驱动
初始化所有的HAL接口(legacy_hal_factory_->getHals())
initVendorHalDescriptorFromLinked
initVendorHalsDescriptorList

wifi.cpp 已经是底层硬件实现了,这块代码其实我也不怎么了解,再往下不做具体分析了。

这篇文章对底层逻辑讲得详细一下:
https://blog.csdn.net/weixin_40588186/article/details/132837372

二、重启设备时自动开启wifi流程

系统启动时,其实就多了startServer的过程,并且在startOtherService中打开wifi。

init.rc那些就不说了,直接从Java部分说起。

1、系统服务启动 SystemServer

SystemServer 是包含Java入口的类,并且启动了很多Android 关键服务。

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

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

private static final String WIFI_SERVICE_CLASS =        "com.android.server.wifi.WifiService";

    /**
     * The main entry point from zygote.
     */
     //(1)Java 端启动入口
    public static void main(String[] args) {
        new SystemServer().run();
    }

	//(2)启动系统服务
    private void run() {
        // Start services.
        try {
            t.traceBegin("StartServices");
            startBootstrapServices(t);//设备启动服务,电源管理和设备管理服务
            startCoreServices(t); //核心服务
            startOtherServices(t);//(3)其他服务,AMS、WIFI、蓝牙那些
            startApexServices(t);//启动app相关服务,这个是Android13 才有的。
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            t.traceEnd(); // StartServices
        }

    }

	//(4)other服务启动
    private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
            //(5)wifi服务启动
            if (context.getPackageManager().hasSystemFeature(
                    PackageManager.FEATURE_WIFI)) {
                // Wifi Service must be started first for wifi-related services.
                t.traceBegin("StartWifi");  //(6)刚开机可以看到这些日志
                mSystemServiceManager.startServiceFromJar(
                        WIFI_SERVICE_CLASS, WIFI_APEX_SERVICE_JAR_PATH);
                t.traceEnd();
                t.traceBegin("StartWifiScanning");
                mSystemServiceManager.startServiceFromJar(
                        WIFI_SCANNING_SERVICE_CLASS, WIFI_APEX_SERVICE_JAR_PATH);
                t.traceEnd();
            }
            。。。
    }

}

2、WifiService

wifi服务类,并不是对外暴露的,对接的是SystemServer

packages\modules\Wifi\service\java\com\android\server\wifi\WifiService.java

public final class WifiService extends SystemService {
    
    private final WifiServiceImpl mImpl;
	@Override
    public void onBootPhase(int phase) {
        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
            mImpl.checkAndStartWifi(); // (1)检查是否需要启动wifi
        } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
            mImpl.handleBootCompleted();
        }
    }
}

3、WifiServiceImpl

wifi 启动的具体实现类,对接的是WifiManager 接口方法。

packages\modules\Wifi\service\java\com\android\server\wifi\WifiServiceImpl.java

public class WifiServiceImpl extends BaseWifiService {
    private static final String TAG = "WifiService";
	
	// (1)检查是否需要启动wifi
	public void checkAndStartWifi() {
        mWifiThreadRunner.post(() -> {
    
    		//这里有打印wifi是否需要启动,具体实现是判断Settings.Global.WIFI_ON
    		//但是这个方法内并未使用这个属性
            // Check if wi-fi needs to be enabled
            boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled();
            Log.i(TAG,"WifiService starting up with Wi-Fi " + (wifiEnabled ? "enabled" : "disabled"));

...
            mActiveModeWarden.start(); //(2)在这里判断是否开启
            registerForCarrierConfigChange();
            mWifiInjector.getAdaptiveConnectivityEnabledSettingObserver().initialize();
            mIsWifiServiceStarted = true;
        });

    }
}

4、ActiveModeWarden

wifi 状态处理,比较中间的

packages\modules\Wifi\service\java\com\android\server\wifi\ActiveModeWarden.java

public class ActiveModeWarden {
	private static final String TAG = "WifiActiveModeWarden";

    private final WifiController mWifiController;
    
    /** Begin listening to broadcasts and start the internal state machine. */
    //(1)ActiveModeWarden.start
    public void start() {
    ...
    	//(2) 调用Controller 状态机 start
		mWifiController.start();
    }

    private class WifiController extends StateMachine {
        private static final String TAG = "WifiController";

		@Override
        public void start() {
            boolean isAirplaneModeOn = mSettingsStore.isAirplaneModeOn();
            boolean isWifiEnabled = mSettingsStore.isWifiToggleEnabled();
            boolean isScanningAlwaysAvailable = mSettingsStore.isScanAlwaysAvailable();
            boolean isLocationModeActive = mWifiPermissionsUtil.isLocationModeEnabled();
			
			//(3) 这里也有打开wifi 是否需要开启wifi的日志
            log("isAirplaneModeOn = " + isAirplaneModeOn
                    + ", isWifiEnabled = " + isWifiEnabled
                    + ", isScanningAvailable = " + isScanningAlwaysAvailable
                    + ", isLocationModeActive = " + isLocationModeActive);
                    
            ActiveModeManager.ClientRole role = getRoleForPrimaryOrScanOnlyClientModeManager();
            if (role == ROLE_CLIENT_PRIMARY) { //**(4)这个比较隐蔽,wifi开启是开启就是进入这里
                 startPrimaryClientModeManager(mLastPrimaryClientModeManagerRequestorWs);
                setInitialState(mEnabledState);
            } else if (role == ROLE_CLIENT_SCAN_ONLY) {
                startScanOnlyClientModeManager(mLastScanOnlyClientModeManagerRequestorWs);
                setInitialState(mEnabledState);
            } else { //如果是不需要开启wifi,就是默认进入Disabled状态
                setInitialState(mDisabledState);
            }
            mWifiMetrics.noteWifiEnabledDuringBoot(mSettingsStore.isWifiToggleEnabled());

            // Initialize the lower layers before we start.
            mWifiNative.initialize();
            super.start();
        }
    }
    	//(5) 具体的处理方法 startPrimaryOrScanOnlyClientModeManager
    private boolean startPrimaryOrScanOnlyClientModeManager(WorkSource requestorWs) {
        //(6)这里其实是判断了wifi_on那个Settings属性
        ActiveModeManager.ClientRole role = getRoleForPrimaryOrScanOnlyClientModeManager();
        if (role == ROLE_CLIENT_PRIMARY) { //(7)wifi 打开是进这里
            return startPrimaryClientModeManager(requestorWs);
        } else if (role == ROLE_CLIENT_SCAN_ONLY) {
            return startScanOnlyClientModeManager(requestorWs);
        } else {
            return false;
        }
    }

	
	// (8)继续追踪方法
    private boolean startPrimaryClientModeManager(WorkSource requestorWs) {
        Log.d(TAG, "Starting primary ClientModeManager in connect mode");
        //(9)这里创建了 ConcreteClientModeManager 对象,看起来没做啥,其实创建对象会做事情
		ConcreteClientModeManager manager = mWifiInjector.makeClientModeManager(
                new ClientListener(), requestorWs, ROLE_CLIENT_PRIMARY, mVerboseLoggingEnabled);
				mClientModeManagers.add(manager); //连接对象被接入队列管理,可以不用关注,断开会被移除
        mLastPrimaryClientModeManagerRequestorWs = requestorWs;
        return true;
    }

}

上面第4点看到,wifi开启是调用到 startPrimaryClientModeManager 方法和上面正常开启wifi调用到的第3步的ActiveModeWarden.wifiToggled里面后面调用到的方法是一个方法。

所以往后的流程接着往ConcreteClientModeManager看就可以看到了。

三、其他

1、Android13 Wifi启动 完整流程:

(1) WifiManager.java
(2) WifiServiceImpl.java
(3) ActivityModenWarden.java
(4) ConcreteClientModeManager.java
(5) WifiNative.java
(6) WIfiVendorHar.java
(7) HalDeviceManager.java
(8) wifi.cpp //HAl层
(9) HAl 往下

Android11 完整流程图:

在这里插入图片描述

Android13 完整流程图:

在这里插入图片描述

不同Android11 部分用黄色标记出来了。

其实正常情况,流程大多是没啥用处的,除非有特殊需求要需要改,但是wifi异常分析是经常遇到的,这种情况就要查看日志,需要找到关键时间点,进一步确定异常原因了,下面的日志可能会有一些帮助。

2、日志查看

关键字和可以查看到的关键信息
关键字 : 关键信息
WifiService:查看WifiServiceImpl调用信息,一些api调用日志和wifi 开关日志
WifiController:ActiveModeWarden 内部状态机的一些信息
WifiActiveModeWarden:ActiveModeWarden 过程日志
WifiClientModeManager:ConcreteClientModeManager的过程日志
WifiNative:底层调用情况日志,异常情况会有明显日志
(底层)
HalDevMgr:HalDeviceManager 过程日志,和异常提示
WifiVendorHal:Hal过程日志和异常日志
android.hardware.wifi:底层hardware包相关日志

一般情况关键日志主要看 WifiService 和 WifiNative , 根据发生问题时间点再仔细研究即可。

多个日志打印的命令:

logcat | grep -E "WifiService|WifiController|WifiActiveModeWarden|WifiClientModeManager|WifiNative"

测试打印部分日志如下:

正常开启wifi日志:
//(1)清除一下日志
bsp:/ $ logcat -c

//(2)过滤关键字日志
bsp:/ $logcat | grep -E "WifiService|WifiController|WifiActiveModeWarden|WifiClientModeManager|WifiNative" 

//(3)打开wifi 的应用包名和uid, uid =1000 表示普通的系统应用, enable=true 表示打开
12-21 16:57:37.448   979  1393 I WifiService: setWifiEnabled package=com.skg.settings uid=1000 enable=true isPrivileged=true

//(4)其他一下状态信息
12-21 16:57:37.453   979  1275 D WifiActiveModeWarden: Starting primary ClientModeManager in connect mode
12-21 16:57:37.453   979  1275 D WifiController: DisabledState.exit()
12-21 16:57:37.453   979  1275 D WifiController: EnabledState.enter()

//(5) wlan0 节点开始打开
12-21 16:57:37.582   979  1275 I WifiNative: Successfully setup Iface:{Name=wlan0,Id=13,Type=STA_SCAN}
12-21 16:57:37.585   979  1275 D WifiClientModeManager[wlan0]: entering StartedState
12-21 16:57:37.599   979  1275 D WifiActiveModeWarden: setting wifi state to: 2

//(6)系统发送wifi 开关状态广播, 说明系统发出wifi 开关状态变化的广播 WIFI_STATE_CHANGED_ACTION 是 ConcreteClientModeManager 发出的
12-21 16:57:37.600   979  1275 D WifiClientModeManager[wlan0]: Sending broadcast=WIFI_STATE_CHANGED_ACTION EXTRA_WIFI_STATE=2 EXTRA_PREVIOUS_WIFI_STATE=1

//(7) 应用查询wifi状态日志, uid=1000 是uid系统apk
12-21 16:57:37.610   979  9543 I WifiService: getWifiEnabledState uid=10097
12-21 16:57:37.637   979 24139 I WifiService: getWifiEnabledState uid=1000
12-21 16:57:37.641   979 24139 I WifiService: getWifiEnabledState uid=1000

//(8) wlan0 节点成功打开
12-21 16:57:37.674   979  1275 I WifiNative: Successfully switched to connectivity mode on iface=Iface:{Name=wlan0,Id=13,Type=STA_CONNECTIVITY}

//(9)中间一些信息
12-21 16:57:37.674   979  1275 D WifiClientModeManager[wlan0]: entering ConnectModeState, starting ClientModeImpl
12-21 16:57:37.679   979  1275 V WifiClientModeManager[wlan0]: ClientModeManager started in role: Role: ROLE_CLIENT_PRIMARY, RequestorWs: WorkSource{1000 com.skg.settings}, ModeListener: com.android.server.wifi.ActiveModeWarden$ClientListener@ded9fb6
12-21 16:57:37.685   979  1275 V WifiActiveModeWarden: ModeManager added ConcreteClientModeManager{id=10580945 iface=wlan0 role=ROLE_CLIENT_PRIMARY}

//(11)设置  CountryCode ,00 应该是无效的,CN,US 那些才有用的,不过wifi 开启对CountryCode 没有要求,热点才有要求
12-21 16:57:37.695   979  1275 D WifiNative: onSetCountryCodeSucceeded: 00
12-21 16:57:37.699   979  1275 V WifiActiveModeWarden: Primary ClientModeManager changed from null to ConcreteClientModeManager{id=10580945 iface=wlan0 role=ROLE_CLIENT_PRIMARY}

//(12) wifi 完成打开的状态
12-21 16:57:37.699   979  1275 D WifiActiveModeWarden: setting wifi state to: 3

这里看到wifi 从打开标识 setWifiEnabled 开始,到完成打开一般只用一秒不到。

重点可以关注:WifiService 和 WifiNative 相关的日志,其中 WifiService 在后续扫描过程也是会有一些日志。

正常关闭wifi日志:
bsp:/ $logcat | grep -E "WifiService|WifiController|WifiActiveModeWarden|WifiClientModeManager|WifiNative"

//(1)关闭 wifi 的应用包名和uid, uid =1000 表示普通的系统应用, enable=false 表示关闭
12-21 18:24:01.039   967  1554 I WifiService: setWifiEnabled package=com.skg.settings uid=1000 enable=false isPrivileged=true

//(2)状态机那些准备关闭wifi
12-21 18:24:01.044   967  1212 D WifiActiveModeWarden: Shutting down all client mode managers
12-21 18:24:01.051   967  1212 D WifiClientModeManager[wlan0]:  currentstate: ConnectModeState

//(3)进入正在关闭wifi状态0
12-21 18:24:01.055   967  1212 D WifiActiveModeWarden: setting wifi state to: 0

//(4)发送广播 正在关闭WiFi,EXTRA_WIFI_STATE=0 当前状态是正在关闭, EXTRA_PREVIOUS_WIFI_STATE=3 之前状态是打开
12-21 18:24:01.059   967  1212 D WifiClientModeManager[wlan0]: Sending broadcast=WIFI_STATE_CHANGED_ACTION EXTRA_WIFI_STATE=0 EXTRA_PREVIOUS_WIFI_STATE=3
12-21 18:24:01.065   967  1212 D WifiClientModeManager[wlan0]: The target role change info null
12-21 18:24:01.065   967  1212 D WifiClientModeManager[wlan0]: Continue to stop wifi

//(5)进入已关闭wifi状态1
12-21 18:24:01.065   967  1212 D WifiActiveModeWarden: setting wifi state to: 1
//发送广播 正在已WiFi,EXTRA_WIFI_STATE=1 是当前进入已关闭wifi状态,EXTRA_PREVIOUS_WIFI_STATE=0 表示上一个状态是正在关闭wifi状态
12-21 18:24:01.066   967  1212 D WifiClientModeManager[wlan0]: Sending broadcast=WIFI_STATE_CHANGED_ACTION EXTRA_WIFI_STATE=1 EXTRA_PREVIOUS_WIFI_STATE=0


//(6)移除节点信息
12-21 18:24:01.094   967  1212 D WifiNative: IfaceManager#removeIface: id=1, pre-map={1=Iface:{Name=wlan0,Id=1,Type=STA_CONNECTIVITY}}
12-21 18:24:01.127   967  1212 D WifiClientModeManager[wlan0]: STA iface wlan0 was destroyed, stopping client mode
12-21 18:24:01.127   967  1212 W WifiClientModeManager[wlan0]: Received mWifiNativeInterfaceCallback.onDestroyed callback when no ClientModeImpl instance is active.

//(7)完成节点关闭
12-21 18:24:01.127   967  1212 I WifiNative: Successfully torn down Iface:{Name=wlan0,Id=1,Type=STA_CONNECTIVITY}
12-21 18:24:01.128   967  1212 I WifiNative: Successfully initiated teardown for iface=wlan0

缺少wifi硬件模组是开启wifi日志:
bsp:/ $logcat | grep -E "WifiService|WifiController|WifiActiveModeWarden|WifiClientModeManager|WifiNative"

//(1)打开wifi 的应用包名和uid, uid =1000 表示普通的系统应用, enable=true 表示打开
12-21 18:56:50.905   967  2954 I WifiService: setWifiEnabled package=com.skg.settings uid=1000 enable=true isPrivileged=true

//(2)准备打开 wifi
12-21 18:56:50.907   967  1212 D WifiActiveModeWarden: Starting primary ClientModeManager in connect mode
12-21 18:56:50.908   967  1212 D WifiController: DisabledState.exit()
12-21 18:56:50.908   967  1212 D WifiController: EnabledState.enter()

//(3)无法打开,进入闲置状态
12-21 18:56:50.908   967  1212 D WifiClientModeManager[unknown]: entering IdleState
12-21 18:56:50.966   967  1212 D WifiNative: IfaceManager#allocateIface: type=2, pre-map={}

//(4)Hal 层有异常 died
12-21 18:56:50.969   967  1212 I WifiNative: Vendor HAL died. Cleaning up internal state.

//(5)Hal 层无法创建节点
12-21 18:56:50.970   967  1212 E WifiNative: Failed to create iface in vendor HAL

//(6)移除节点
12-21 18:56:50.970   967  1212 D WifiNative: IfaceManager#removeIface: id=2, pre-map={2=Iface:{Name=null,Id=2,Type=STA_SCAN}}
12-21 18:56:50.970   967  1212 E WifiClientModeManager[unknown]: Failed to create ClientInterface. Sit in Idle
12-21 18:56:50.970   967  1212 E WifiActiveModeWarden: ClientModeManager start failed!ConcreteClientModeManager{id=6808585 iface=null role=null}
12-21 18:56:50.970   967  1212 V WifiActiveModeWarden: ModeManager removed ConcreteClientModeManager{id=6808585 iface=null role=null}
12-21 18:56:50.978   967  1212 E WifiActiveModeWarden: One of the native daemons died. Triggering recovery
12-21 18:56:50.979   967  1212 E WifiSelfRecovery: Triggering recovery for reason: WifiNative Failure
12-21 18:56:50.979   967  1212 E WifiSelfRecovery: Restarting wifi for reason: WifiNative Failure
12-21 18:56:50.979   967  1212 D WifiController: STA disabled, return to DisabledState.

//(7)有可能多次循环该异常日志
12-21 18:56:50.979   967  1212 D WifiController: EnabledState.exit()
12-21 18:56:50.979   967  1212 D WifiController: DisabledState.enter()
12-21 18:56:50.979   967  1212 D WifiController: Recovery triggered, already in disabled state
12-21 18:56:50.995   967  1212 I WifiNative: Vendor HAL died. Cleaning up internal state.
12-21 18:56:50.995   967  1212 E WifiActiveModeWarden: One of the native daemons died. Triggering recovery
12-21 18:56:50.995   967  1212 E WifiSelfRecovery: Triggering recovery for reason: WifiNative Failure
12-21 18:56:50.995   967  1212 E WifiSelfRecovery: Restarting wifi for reason: WifiNative Failure
12-21 18:56:50.995   967  1212 D WifiController: Recovery triggered, already in disabled state
12-21 18:56:52.981   967  1212 D WifiController: Recovery in progress, start wifi
12-21 18:56:52.984   967  1212 D WifiActiveModeWarden: Starting primary ClientModeManager in connect mode
12-21 18:56:52.985   967  1212 D WifiController: DisabledState.exit()
12-21 18:56:52.985   967  1212 D WifiController: EnabledState.enter()
12-21 18:56:52.985   967  1212 D WifiClientModeManager[unknown]: entering IdleState
。。。

重新测试看从(2)准备打开到(3)异常情况,查看整个logcat日志,发现还有部分底层的打印:

12-21 19:14:26.660   967  1212 D HalDevMgr: initIWifiIfNecessary
12-21 19:14:26.664   967  1212 I android_os_HwBinder: HwBinder: Starting thread pool for getting: android.hardware.wifi@1.0::IWifi/default
12-21 19:14:26.666   442   442 I android.hardware.wifi@1.0-service-lazy: Wifi HAL stopped
12-21 19:14:26.667   967  1212 I WifiVendorHal: Device Manager onStatusChanged. isReady(): false, isStarted(): false
12-21 19:14:26.667   967  1212 I WifiNative: Vendor HAL died. Cleaning up internal state.

3、wifi开关状态值

从WifiManager.java 代码看wifi 开关、关闭是有过程状态的:

    /**
     * The lookup key for an int that indicates whether Wi-Fi is enabled,
     * disabled, enabling, disabling, or unknown.  Retrieve it with
     * {@link android.content.Intent#getIntExtra(String,int)}.
     *
     * @see #WIFI_STATE_DISABLED //1
     * @see #WIFI_STATE_DISABLING //0 
     * @see #WIFI_STATE_ENABLED //3
     * @see #WIFI_STATE_ENABLING //2
     * @see #WIFI_STATE_UNKNOWN //4
     */
    public static final String EXTRA_WIFI_STATE = "wifi_state";
    
     /**
     * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
     * enabling, disabling, or unknown. One extra provides this state as an int.
     * Another extra provides the previous state, if available.  No network-related
     * permissions are required to subscribe to this broadcast.
     *
     * <p class="note">This broadcast is not delivered to manifest receivers in
     * applications that target API version 26 or later.
     *
     * @see #EXTRA_WIFI_STATE //广播的wifi状态值数据
     * @see #EXTRA_PREVIOUS_WIFI_STATE
     */
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String WIFI_STATE_CHANGED_ACTION =
        "android.net.wifi.WIFI_STATE_CHANGED";

这里可以看到从wifi开关状态广播变化中的额外信息可以看到:

1 是关闭状态,3是打开状态,0 是正在关闭,2是正在打开;

这几个状态变化的过程,正常都是有广播的。

4、之前写的一些wifi相关的知识

汇总:

https://so.csdn.net/so/search?q=wifi&t=blog&u=wenzhi20102321

Android10 系统应用wifi连接和静态ip代理设置:

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

Android adb shell svc 知识详解:

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

Android无线Wifi开发:

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

Android13 wifi状态问题分析:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/262877.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

结构型模式 | 适配器模式

一、适配器模式 1、原理 适配器模式&#xff08;Adapter&#xff09;&#xff0c;将一个类的接口转换成客户希望的另外一个接口&#xff0c;使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。适配器模式主要分为三类&#xff1a;类适配器模式、对象适配器模式、接口…

智能优化算法应用:基于冠状病毒群体免疫算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于冠状病毒群体免疫算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于冠状病毒群体免疫算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.冠状病毒群体免疫算法4.…

程序员的自我修养:链接、装载与库-3 目标文件里有什么

1 目标文件的格式 2 目标文件是什么样的 3 挖掘SimpleSection.o 3.1 代码段 3.2 数据段和只读数据段 3.3 BSS段 3.4 其他段 4 ELF文件结构描述 4.1 文件头 4.2 段表 4.3 重定位表 4.4 字符串表 5 链接的接口-符号 待补充 107

MySQL数据库 索引

目录 索引概述 索引结构 二叉树 B-Tree BTree Hash 索引分类 索引语法 慢查询日志 索引概述 索引 (index&#xff09;是帮助MySQL高效获取数据的数据结构(有序)。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种…

【银行测试】银行金融测试+金融项目测试点汇总...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、银行金融测试是…

Pycharm报的一些Python语法错误

Pycharm报的一些Python语法错误 1、PEP8:Expected 2 blank less:found 1 意思是&#xff1a;类和上面的行要间隔两行&#xff0c;现在只有一行 解决办法&#xff1a; 间隔2行 2、Remove redundant parentheses 意思是&#xff1a;删除多余的括号 解决&#xff1a;删掉外面括…

两种经典的现货白银假突破类型

假突破是现货白银市场中一种具有反大众性的市场行为。它通常和一种强势的市场行为突破联系在一起&#xff0c;但是它的方向是和突破完全相反的&#xff0c;识别假突破的类型&#xff0c;有助于降低我们亏损的风险&#xff0c;那如何识别呢&#xff1f;下面我们来介绍两种假突破…

redis 从0到1完整学习 (四):字符串 SDS 数据结构

文章目录 1. 引言2. redis 源码下载3. 字符串数据结构4. 参考 1. 引言 前情提要&#xff1a; 《redis 从0到1完整学习 &#xff08;一&#xff09;&#xff1a;安装&初识 redis》 《redis 从0到1完整学习 &#xff08;二&#xff09;&#xff1a;redis 常用命令》 《redis…

JSON Wizard for Mac - 解析你的 JSON 数据

JSON Wizard for Mac 是一款强大的工具&#xff0c;旨在帮助你处理和解析 JSON 数据。无论你是开发人员、数据分析师还是对 JSON 数据感兴趣的用户&#xff0c;这个工具都能方便地处理和编辑 JSON 文件。 ✨主要功能包括&#xff1a; 1️⃣ JSON 格式验证&#xff1a;JSON Wi…

【论文笔记】NeuRAD: Neural Rendering for Autonomous Driving

原文链接&#xff1a;https://arxiv.org/abs/2311.15260 1. 引言 神经辐射场&#xff08;NeRF&#xff09;应用在自动驾驶中&#xff0c;可以创建可编辑的场景数字克隆&#xff08;可自由编辑视角和场景物体&#xff09;&#xff0c;以进行仿真。但目前的方法或者需要大量的训…

【AI美图】第09期效果图,AI人工智能汽车+摩托车系列图集

期待中的未来AI汽车 欢迎来到未来的世界&#xff0c;一个充满创新和无限可能的世界&#xff0c;这里有你从未见过的科技奇迹——AI汽车。 想象一下&#xff0c;你站在十字路口&#xff0c;繁忙的交通信号灯在你的视线中闪烁&#xff0c;汽车如潮水般涌来&#xff0c;但是&…

建构伦敦银交易策略可遵循的三个原则

构建交易策略&#xff0c;我们应该遵循什么原则呢&#xff1f;有的人说可以盈利就行了&#xff0c;确实盈利是很关键的&#xff0c;没有人想使用一个导致自己亏损的策略。但构建伦敦银策略的时候可不能简单地以一个可以盈利带过&#xff0c;下面我们就来介绍构建策略时所需的三…

鹦鹉目标检测数据集VOC+YOLO格式2000张

鹦鹉是一种非常受欢迎的鸟类&#xff0c;它们通常生活在热带和亚热带地区的森林和草原中。鹦鹉是一种非常聪明、有趣和亲密的动物&#xff0c;也是一种受到广泛关注和保护的物种。 鹦鹉的身体结构非常适应于它们的生活方式。它们的身体非常修长&#xff0c;有着漂亮的羽毛和强…

鸿蒙应用开发初体验 HelloWorld

9 月 25 日&#xff0c;华为常务董事、终端 BG CEO、智能汽车解决方案 BU 董事长余承东华为秋季全场景新品发布会上介绍了鸿蒙系统的最新进展&#xff1a;HarmonyOS 4 发布后&#xff0c;短短一个多月升级用户已经超过 6000 万&#xff0c;成为史上升级速度最快的 HarmonyOS 版…

众和策略证券开户首选:股票增持是好还是坏?大股东增持规定?

股票增持是好仍是坏&#xff1f; 股东增持在一定程度上反映股东对个股比较看好&#xff0c;大量的买单&#xff0c;增加了市场上的多方力气&#xff0c;会推动股价上涨&#xff0c;是一种利好消息。 一般大股东会增持可能是上市公司运营成绩较好&#xff0c;具有较大的发展前…

java 项目日记实现两种方式:拦截器方式实现日记与定义日记注解方式实现日记

通常只要是java web项目基本都离不开项目日记&#xff0c;项目日记存在的意义很多&#xff0c;例如&#xff1a;安全审计&#xff0c;问题追踪都离不开项目日记。下面我们说一下项目日记实现最常用的两种方式 。 一 拉截器实现项目日记 1 实现一个拦截器基类&#xff0c;用于事…

在做题中学习(37):复写零

1089. 复写零 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a;双指针法 1.因为是就地修改不能用新数组&#xff0c;但可以试试看看结果是什么&#xff08;结尾数是4&#xff09; &#xff08;cur遍历数组&#xff09;&#xff08;当cur&#xff01;0时替换一个 当c…

FFmpeg windows安装与使用

FFmpeg下载&#xff1a; 1、进入ffmpeg官网&#xff0c;点击“Download”。官网地址&#xff1a;FFmpeg 2、选择对应环境的编译工具&#xff0c;如下载windows环境下的ffmpeg编译工具 3、点击下载编译好的ffmpeg工具 FFmpeg使用&#xff1a; 1、将ffmpeg编译的bin文件复制出来…

【大模型】1、LoRA | 大模型高效微调技术

文章目录 一、背景1.1 什么是秩1.2 为什么要用低秩 二、方法三、效果 论文&#xff1a;LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS 代码&#xff1a;https://github.com/microsoft/LoRA 出处&#xff1a;微软 一、背景 1.1 什么是秩 矩阵的秩是指其行&#xff0…

Tomcat转SpringBoot、tomcat升级到springboot、springmvc改造springboot

Tomcat转SpringBoot、tomcat升级到springboot、springmvc改造springboot 起因&#xff1a;我接手tomcat-springmvc-hibernate项目&#xff0c;使用tomcat时问题不大。自从信创开始&#xff0c;部分市场使用国产中间件&#xff0c;例如第一次听说的宝兰德、东方通&#xff0c;还…