Android10.0(Q) MTK平臺增加以太網靜態IP功能

前言

朋友們,網卡功能真的是太太太太常用了,這次我又帶着 10.0 的以太網靜態IP功能來了,相比 9.0 而言,

framework 沒啥大變化,可以直接對比移植。Settings 部分也沒啥大變化,preference 對應的包由 v7

變成 androidx,這個導報的時候注意下就行。

效果圖

效果圖就不貼了,和 9.0 一樣都是橫屏,差別不大。

上代碼

app層

Settins 源碼和9.0無差別,完整代碼資源鏈接

這裏列下差異地方。

vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\ethernet\EthernetStaticIP.java

9.0 導包

import android.support.v7.preference.Preference;
import android.preference.PreferenceActivity;
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.CheckBoxPreference;
import android.support.v7.preference.EditTextPreference;
import android.support.v14.preference.SwitchPreference;

10.0 導包

import androidx.preference.Preference;
import android.preference.PreferenceActivity;
import androidx.preference.PreferenceScreen;
import androidx.preference.CheckBoxPreference;
import androidx.preference.EditTextPreference;
import androidx.preference.SwitchPreference;

framework 層

修改文件清單

 alps/frameworks/base/api/current.txt                                                                              
 alps/frameworks/base/core/java/android/provider/Settings.java                                                      
 alps/frameworks/base/proto/src/metrics_constants/metrics_constants.proto                                           
 alps/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetServiceImpl.java                        
 alps/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetTracker.java

完整代碼資源鏈接

幾個注意點

Settings.java 新增字段編譯

10.0 之前通過執行命令 make update-api,將新增字段保存到 frameworks/base/api/current.txt 文件中,

這樣 java 類引用編譯時不報錯。10.0 編譯命令修改爲 make api-stubs-docs-update-current-api

不插網線設置靜態IP保存後顯示網卡圖標bug

不知道你的版本是否也存在這樣的bug,不插網線的情況下,設置完靜態 ip 各項參數保存後

你驚奇發現狀態欄網卡圖標出來了。來看下問題日誌

2020-05-29 10:07:59.537 1078-1416/system_process D/MtkConnectivityService: registerNetworkAgent NetworkAgentInfo{ ni{[type: Ethernet[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: e8:11:ca:03:da:07, failover: false, available: true, roaming: false]}  network{101}  nethandle{437197393933}  lp{{InterfaceName: eth0 LinkAddresses: [ 192.168.40.30/24 ] DnsAddresses: [ /8.8.8.8 ] Domains: 192.168.40.1 MTU: 0 TcpBufferSizes: 524288,1048576,3145728,524288,1048576,2097152 Routes: [ 192.168.40.0/24 -> 0.0.0.0 eth0,255.255.255.255/32 -> 0.0.0.0 eth0,0.0.0.0/0 -> 255.255.255.255 eth0 ]}}  nc{[ Transports: ETHERNET Capabilities: NOT_METERED&INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN&NOT_ROAMING&FOREGROUND&NOT_CONGESTED&NOT_SUSPENDED LinkUpBandwidth>=100000Kbps LinkDnBandwidth>=100000Kbps]}  Score{0}  everValidated{false}  lastValidated{false}  created{false} lingering{false} explicitlySelected{false} acceptUnvalidated{false} everCaptivePortalDetected{false} lastCaptivePortalDetected{false} captivePortalValidationPending{false} partialConnectivity{false} acceptPartialConnectivity{false} clat{mBaseIface: null, mIface: null, mState: IDLE} }
2020-05-29 10:07:59.545 1078-1373/system_process D/MtkConnectivityService: NetworkAgentInfo [Ethernet () - 101] EVENT_NETWORK_INFO_CHANGED, going from initial to CONNECTED
2020-05-29 10:07:59.550 1078-1373/system_process D/MtkConnectivityService: Setting DNS servers for network 101 to [/8.8.8.8]
2020-05-29 10:07:59.555 1078-1373/system_process D/MtkConnectivityService: Adding iface eth0 to network 101
2020-05-29 10:07:59.570 1078-1373/system_process D/MtkConnectivityService: Setting DNS servers for network 101 to [/8.8.8.8]
2020-05-29 10:07:59.594 1078-1373/system_process D/MtkConnectivityService: Switching to new default network: NetworkAgentInfo{ ni{[type: Ethernet[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: e8:11:ca:03:da:07, failover: false, available: true, roaming: false]}  network{101}  nethandle{437197393933}  lp{{InterfaceName: eth0 LinkAddresses: [ 192.168.40.30/24 ] DnsAddresses: [ /8.8.8.8 ] Domains: 192.168.40.1 MTU: 0 TcpBufferSizes: 524288,1048576,3145728,524288,1048576,2097152 Routes: [ 192.168.40.0/24 -> 0.0.0.0 eth0,255.255.255.255/32 -> 0.0.0.0 eth0,0.0.0.0/0 -> 255.255.255.255 eth0 ]}}  nc{[ Transports: ETHERNET Capabilities: NOT_METERED&INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN&NOT_ROAMING&FOREGROUND&NOT_CONGESTED&NOT_SUSPENDED LinkUpBandwidth>=100000Kbps LinkDnBandwidth>=100000Kbps]}  Score{0}  everValidated{false}  lastValidated{false}  created{true} lingering{false} explicitlySelected{false} acceptUnvalidated{false} everCaptivePortalDetected{false} lastCaptivePortalDetected{false} captivePortalValidationPending{false} partialConnectivity{false} acceptPartialConnectivity{false} clat{mBaseIface: null, mIface: null, mState: IDLE} }
2020-05-29 10:07:59.624 1078-1373/system_process D/MtkConnectivityService: Sending CONNECTED broadcast for type 9 NetworkAgentInfo [Ethernet () - 101] isDefaultNetwork=true

理解下大意爲你保存了一個默認網絡配置信息(new default network)後,發送 connected 通知出去,所以圖標就顯示出來了。

這是什麼騷操作,一看日誌tag就知道是 mkt 自己加的,搜索去看下源碼

vendor\mediatek\proprietary\frameworks\opt\net\services\core\java\com\android\server\MtkConnectivityService.java

 /** Adds the given network to the specified legacy type list. */
        public void add(int type, NetworkAgentInfo nai) {
            if (!isTypeSupported(type)) {
                return;  // Invalid network type.
            }
            if (VDBG) log("Adding agent " + nai + " for legacy network type " + type);

            ArrayList<NetworkAgentInfo> list = mTypeLists[type];
            if (list.contains(nai)) {
                return;
            }
            synchronized (mTypeLists) {
                list.add(nai);
            }

            // Send a broadcast if this is the first network of its type or if it's the default.
            final boolean isDefaultNetwork = mService.isDefaultNetwork(nai);
            if ((list.size() == 1) || isDefaultNetwork) {
                maybeLogBroadcast(nai, DetailedState.CONNECTED, type, isDefaultNetwork);
                mService.sendLegacyNetworkBroadcast(nai, DetailedState.CONNECTED, type);
            }
        }

可以看到當網絡列表集合只有一個配置,或是默認網絡時,發送 CONNECTED 通知。開始我以爲把這裏加入網線狀態判斷後再發送

通知,後來嘗試後發現並不行,那就轉戰應用層去處理這個bug吧。

解決思路

找到網卡圖標顯示的邏輯,當收到 CONNECTED 通知時同時判斷網線是否已經插入,未插入則無效消息,不顯示圖標

那麼問題來了,怎麼知道網線是否已經插入或撥出呢。一般來講這都需要驅動通過gpio口控制監聽發送按鍵消息或

其它通知給上層。分析網線插入撥出相關日誌,我發現在 framework 層中就能幹這個活,EthernetTracker 中

就已經監聽了網口狀態。來看下日誌

拔出
2020-05-29 09:03:55.847 1104-1131/? I/EthernetTracker: interfaceLinkStateChanged, iface: wlan0, up: false
2020-05-29 09:03:55.848 1104-1447/? E/EthernetTracker: updateInterfaceState up==false modified=false
2020-05-29 09:03:55.847 1104-1131/? I/EthernetTracker: interfaceLinkStateChanged, iface: eth0, up: false
2020-05-29 09:03:55.848 1104-1447/? E/EthernetTracker: updateInterfaceState up==false modified=false

插入

2020-05-29 09:04:55.847 1104-1131/? I/EthernetTracker: interfaceLinkStateChanged, iface: eth0, up: true
2020-05-29 09:04:55.848 1104-1447/? E/EthernetTracker: updateInterfaceState up==true modified=false


主要通過 NetworkManagementService 註冊 InterfaceObserver,當網絡狀態改變時收到實時響應。

frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetTracker.java

private class InterfaceObserver extends BaseNetworkObserver {

        @Override
        public void interfaceLinkStateChanged(String iface, boolean up) {
            if (DBG) {
                Log.i(TAG, "interfaceLinkStateChanged, iface: " + iface + ", up: " + up);
            }
            mHandler.post(() -> updateInterfaceState(iface, up));
        }

        @Override
        public void interfaceAdded(String iface) {
            mHandler.post(() -> maybeTrackInterface(iface));
        }

        @Override
        public void interfaceRemoved(String iface) {
            mHandler.post(() -> removeInterface(iface));
        }
    }


	private void updateInterfaceState(String iface, boolean up) {
        boolean modified = mFactory.updateInterfaceLinkState(iface, up);
        Log.e(TAG, "updateInterfaceState up==" + up + " modified="+modified);
        //cczheng add sys.ethernet.up for listen netline in or out 
        if ("eth0".equals(iface)) {
            android.os.SystemProperties.set("sys.ethernet.up", String.valueOf(up));
        }//E
        if (modified) {
            boolean restricted = isRestrictedInterface(iface);
            int n = mListeners.beginBroadcast();
            for (int i = 0; i < n; i++) {
                try {
                    if (restricted) {
                        ListenerInfo listenerInfo = (ListenerInfo) mListeners.getBroadcastCookie(i);
                        if (!listenerInfo.canUseRestrictedNetworks) {
                            continue;
                        }
                    }
                    mListeners.getBroadcastItem(i).onAvailabilityChanged(iface, up);
                } catch (RemoteException e) {
                    // Do nothing here.
                }
            }
            mListeners.finishBroadcast();
        }
    }

可以看到我在 updateInterfaceState() 中增加了 prop 保存網線插拔狀態,爲啥選用 prop 保存呢?因爲網卡圖標顯示在

SystemUI 中,算是跨應用通訊吧,prop 簡單方便,就不用 Settings.System/Global 之類的了。接下來修改 SystemUI

網卡圖標顯示監聽在 EthernetSignalController 中

vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\statusbar\policy\EthernetSignalController.java

 @Override
    public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) {
        mCurrentState.connected = connectedTransports.get(mTransportType);
        super.updateConnectivity(connectedTransports, validatedTransports);
    }

    @Override
    public void notifyListeners(SignalCallback callback) {
        boolean ethernetVisible = mCurrentState.connected;
        String contentDescription = getStringIfExists(getContentDescription());

        ////cczheng add visible for fix ethernet staticip set don't inset netline show bug
        android.util.Log.e("MtkConnectivityService", " systemui ethernetVisible="+ethernetVisible + " contentDescription="+contentDescription);
        boolean netLineIn = android.os.SystemProperties.getBoolean("sys.ethernet.up", false);
        android.util.Log.e("MtkConnectivityService", " systemui EthernetSignalController netline state ="+netLineIn);

        if (ethernetVisible){
            ethernetVisible = netLineIn;
            android.util.Log.e("MtkConnectivityService", "new ethernetVisible="+ethernetVisible);
        }//E
        
        // TODO: wire up data transfer using WifiSignalPoller.
        callback.setEthernetIndicators(new IconState(ethernetVisible, getCurrentIconId(),
                contentDescription));
        
    }

網線未插入情況,點擊設置靜態ip收到的日誌
2020-05-30 09:19:29.089 1456-1676/com.android.systemui E/MtkConnectivityService:  systemui ethernetVisible=true contentDescription=以太網已斷開連接。
2020-05-30 09:19:29.089 1456-1676/com.android.systemui E/MtkConnectivityService:  systemui EthernetSignalController netline state =false

網線插入,點擊設置靜態ip收到的日誌
2020-05-30 09:19:29.089 1456-1676/com.android.systemui E/MtkConnectivityService:  systemui ethernetVisible=true contentDescription=以太網已斷開連接。
2020-05-30 09:19:29.089 1456-1676/com.android.systemui E/MtkConnectivityService:  systemui EthernetSignalController netline state =true

可以看到我們需要過濾網線未插入收到的無效消息,讀取網線狀態 sys.ethernet.up 布爾值,當 ethernetVisible 爲 true 時,校驗狀態

這樣改完後測試發現還有坑,坑在真正 setIconVisibility 地方,也就是 StatusBarSignalPolicy

vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\statusbar\phone\StatusBarSignalPolicy.java

	@Override
    public void setEthernetIndicators(IconState state) {
        boolean visible = state.visible && !mBlockEthernet;
        int resId = state.icon;
        String description = state.contentDescription;

        //cczheng add visible for fix ethernet staticip set don't inset netline show bug
        if (visible && resId > 0) {
        //if (resId > 0) {
            mIconController.setIcon(mSlotEthernet, resId, description);
            mIconController.setIconVisibility(mSlotEthernet, true);
        } else {
            mIconController.setIconVisibility(mSlotEthernet, false);
        }
    }

發現了嗎,傳遞進來的 visible 根本就沒用上,這是什麼大坑啊,將 visible 作爲判斷依據即可。

好了,這樣 bug 就解決了,收工。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章