RKAndroid11-WIFI白名单功能实现

实现WIFI白名单功能


前言

针对定制案子有客户需求是要有一个WIFI白名单功能

WIFI白名单解释-需求理解: 设置

  • 客户指定的SSID 才能够在WIFI列表中显示出来;
  • 默认情况下所有WIFI列表可以显示
  • 客户可以编辑白名单SSID,实现白名单可控
    如下,应用界面需求:
    在这里插入图片描述

一、参考资料

android 11.0 设置wifi白名单

具体需要大家自己实验,实际会遇到各种问题,参考资料只是给一个思路而已。

按照上面思路,可以实现Framework 层思路,具体还会遇到如下问题,这里给一个参考,实际需要自己解决。

  • 源码继承后无法编译,方法存在错误,需要自己修复,对齐
  • 无法编译,修改了系统的api,修改了aidl 文件和service 里面新增了对应的方法,需要更新系统编译的api .
make update-api

二、涉及修改的文件

/frameworks/base/wifi/java/android/net/wifi/IWifiManager.aidl
/frameworks/base/wifi/java/android/net/wifi/WifiManager.java
/frameworks/opt/net/wifi/service/java/com/android/server/wifi/BaseWifiService.java
/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java

实现思路

初看需求的时候,其实还不知道实现方案的,查阅资料修改起来也是云里雾里。 功能实现后,我发现思路其实特别重要。 如上需求已经很明确了,如何实现呢? 这里的思路其实就是:WIFI 获取WIFI列表这个步骤、方法中进行拦截。 默认情况下返回所有的WIFI列表、如果白名单不为空则在所有WIFI列表和白名单列表进行匹配,只返回白名单里面的且实际扫码到的WIFI列表页存在的 SSID 才会显示出来。

三、源码文件修改

AIDL文件IWifiManager.aidl 新增方法

路径:/frameworks/base/wifi/java/android/net/wifi/IWifiManager.aidl
修改内容如下,添加设置和获取白名单方法,新增的方法


/**
 * Interface that allows controlling and querying Wi-Fi connectivity.
 *
 * {@hide}
 */
interface IWifiManager
{
。。。。。。。。。。

	void setWiFiWhiteList(in List<String> whiteList);  
	
    List<String> getWiFiWhiteList();

}

服务 WifiManager.java 实现方法

路径:/frameworks/base/wifi/java/android/net/wifi/WifiManager.java
修改内容如下,实现aidl 文件中添加的方法


@SystemService(Context.WIFI_SERVICE)
public class WifiManager {
。。。。。。。。。。

 @NonNull
	  public void setWiFiWhiteList(@Nullable  List<String> blackList){

          try {
          Log.v(TAG," setWiFiWhiteList ");
          mService.setWiFiWhiteList(blackList); 
 
           } catch (RemoteException e) {

            throw e.rethrowFromSystemServer();

        }

      }
	  
	 @NonNull 
     public List<String> getWiFiWhiteList(){
          try {
			
			Log.v(TAG," getWiFiWhiteList ");
            return mService.getWiFiWhiteList();
          } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
         }
       }
}

备注:这里的方法可不是 overide 方法,这里不做延伸说明 。
看看 我们在这里其实是一个服务,这个Service 里面最终调用的是 mService 方法,这个mService 变量是什么? 且看如下:它其实就是一个Binder
在这里插入图片描述

AIDL实现类 BaseWifiService.java 新增实现方法

路径:/frameworks/opt/net/wifi/service/java/com/android/server/wifi/BaseWifiService.java
修改内容如下,实现添加设置和获取白名单方法,新增的方法


/**
 * Empty concrete class implementing IWifiManager with stub methods throwing runtime exceptions.
 *
 * This class is meant to be extended by real implementations of IWifiManager in order to facilitate
 * cross-repo changes to WiFi internal APIs, including the introduction of new APIs, the removal of
 * deprecated APIs, or the migration of existing API signatures.
 *
 * When an existing API is scheduled for removal, it can be removed from IWifiManager.aidl
 * immediately and marked as @Deprecated first in this class. Children inheriting this class are
 * then given a short grace period to update themselves before the @Deprecated stub is removed for
 * good. If the API scheduled for removal has a replacement or an overload (signature change),
 * these should be introduced before the stub is removed to allow children to migrate.
 *
 * When a new API is added to IWifiManager.aidl, a stub should be added in BaseWifiService as
 * well otherwise compilation will fail.
 */
public class BaseWifiService extends IWifiManager.Stub {

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

       。。。。。。。。。。。。。。。。。。。。

	
	 @Override
        public void setWiFiWhiteList( List<String> blackList){
                 throw new UnsupportedOperationException();
                
        };
        @Override
        public List<String> getWiFiWhiteList(){
                 throw new UnsupportedOperationException();
                
        };

}

这里看注释其实就一目了然了,知道在这里要实现aidl 接口方法

WifiServiceImpl.java 继承 BaseWifiService

路径:/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
在 父类BaseWifiService 已经讲了,它是aidl对应的实现类, 这里WifiServiceImpl 作为子类,是功能的补充或者实现吧,处理逻辑和业务。
我们看看类声明,其实很有感觉的,如下:处理remote 端wifi 的操作请求,通过实现IWifiManager 接口。

/**
 * WifiService handles remote WiFi operation requests by implementing
 * the IWifiManager interface.
 */
public class WifiServiceImpl extends BaseWifiService {
    private static final String TAG = "WifiServiceImpl";

这里我们重点关注的 getScanResults 请求wifi 扫码列表就在这个文件里面。如上面分析思路,最终拦截就在这个方法里面去匹配WIFI列表,同步对比自己的白名单。

解决需求思路就是在这个类中去维护一个白名单列表。 对应的源码如下:


   // modeify add 
       private List<String> ssid_whiteList=new ArrayList<>();
	   
       
       public void setWiFiWhiteList(List<String> whiteList){
               this.ssid_whiteList=whiteList;
               
       }
	   
        
       public List<String> getWiFiWhiteList(){
               return this.ssid_whiteList;
               
       }
   // modeify end 


    /**
     * Return the results of the most recent access point scan, in the form of
     * a list of {@link ScanResult} objects.
     * @return the list of results
     */
    @Override
    public List<ScanResult> getScanResults(String callingPackage, String callingFeatureId) {
        enforceAccessPermission();
        int uid = Binder.getCallingUid();
        long ident = Binder.clearCallingIdentity();
        if (mVerboseLoggingEnabled) {
            mLog.info("getScanResults uid=%").c(uid).flush();
        }
        try {
            mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, callingFeatureId,
                    uid, null);
            List<ScanResult> scanResults = mWifiThreadRunner.call(
                    mScanRequestProxy::getScanResults, Collections.emptyList());
					
					   // modeify add   
					Log.d(TAG,"getScanResults result size:"+scanResults.size());
					for (String whiteSSID : this.ssid_whiteList) {
                      //System.out.println(item);
					 
					   Log.e(TAG, "getScanResults  whiteSSID:"+whiteSSID);

                      }
					
				if(this.ssid_whiteList!=null && this.ssid_whiteList.size()!=0){   // zhi you white list caihui pipei 
      
			        List<ScanResult> result1 =new ArrayList<>();
                    for (ScanResult resultbean : scanResults){
				   
				         Log.e(TAG, "getScanResults  ssid_whiteList:"+ssid_whiteList+"      resultbean.SSID:"+resultbean.SSID  );
						// zhiyou zai baimingdan limian de  ssid caihui xianshi chulai 
                        if(!this.ssid_whiteList.contains(resultbean.SSID)){             // pipei gongzuo 
					      Log.e(TAG, "getScanResults  not in whiteList  no add to show      resultbean.SSID:"+resultbean.SSID);
                          continue;
                       }
                      result1.add(resultbean);
                   }
				   Log.e(TAG," there is whitelist so to return filter results result1:"+result1);
                    return  result1;
              }   
                // modeify end 
                Log.e(TAG, "getScanResults  final to return scanResults:"+scanResults);
					
            return scanResults;
        } catch (SecurityException e) {
            Log.e(TAG, "Permission violation - getScanResults not allowed for uid="
                    + uid + ", packageName=" + callingPackage + ", reason=" + e);
            return new ArrayList<>();
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

小结

这里设计到framework层wifi 相关的四个类的修改,这里暂不延伸源码和业务分析,本身大家日常开发对WIFI 应该不陌生的。结合实现需求的思路,应该很容易理解并找到源码对应的位置。

四、测试验证

既然思路和Framework 层的逻辑已经写好了的,那么总要验证一下吧,这样app同事好对接,自己也要验证下功能是否OK吧。

获取framework.jar 包

我自己在实现了 Framework层功能后,自己写个app 验证,功能是否实现了需求。 自己想法就是 自己改了那么文件,固件也编译到了主板机器上了,系统都跑起来了。但是应用如何调用呢?

按照自己以往的经验,自己在项目开发时候 直接拿 系统的framwork.jar ,然后直接调用、引用系统的类,进行系统类进行直接调用。 如下 常用的 framework.jar 引用和framework 层类的调用。

在这里插入图片描述

所以自己在应用层调用刚才在framework层的wifi 相关接口方法,第一反应就是去找framework.jar 文件。 那就在系统里面找framework.jar 文件。

这里 用find 命令找路径:

fise4@ubuntu-PowerEdge-R730:~/Android/rk/Rockchip_RK356X_Android11_CloudDesk_SDK_RELEASE$ find . -name framework.jar
./out/soong/rk3566_r/dex_bootjars_input/framework.jar
./out/soong/.intermediates/frameworks/base/framework/android_common/turbine-combined/framework.jar
./out/target/product/rk3566_r/obj/PACKAGING/target_files_intermediates/rk3566_r-target_files-eng.fise4/SYSTEM/framework/framework.jar
./out/target/product/rk3566_r/system/framework/framework.jar
fise4@ubuntu-PowerEdge-R730:~/Android/rk/Rockchip_RK356X_Android11_CloudDesk_SDK_RELEASE$ 

这里发现有好几个,那么就具体确定具体是哪一个吧:实际发现并不是每个framework.jar 里面都一样的,我们就是要找到具体是哪一个framework.jar 是 系统编译出来的,包含所有的源码文件。

那就解析jar 包,查看 是否含有WifiManager 相关类来查找:

jar tf framework.jar | grep WifiManager

在这里插入图片描述

最终确认路径如下: 居然和网上说的都不一样,所以需要自己实际操作才有相关的经验和感受的,找到正确的 framework.jar

\out\soong\.intermediates\frameworks\base\framework\android_common\turbine-combined\framework.jar

在这里插入图片描述

这里拿到jar 包去验证自己的猜想,解析jar 看看,里面是不是有自己修改过的文件:
在这里插入图片描述

哈哈,这里我们基本上确认,我们引用的jar 是没问题的。

引用framework.jar 实现功能

当你把自己需要的jar 包引用到AS 项目里面,满心欢喜准备直接调用的时候,沉重的一击是 发现根本没有自己写的方法。 自己尝试好多遍验证是不是自己framework.jar 引用错误了,实际发现没有的,在项目里面应用jar 就是无法加载自己修改类,添加的方法! 【这里暂不扩展,机制问题】
在这里插入图片描述

反射调用WIFI 扩展的相关方法

当上面两个历程走完后,一脸懵逼。 如果不行就直接发射调用呗,系统framework层已经也一定有相关的实现,其实就是自己应用层如何调用framework层问题。那就直接发射呗。

问题:反射什么? 反射调用设置和获取白名单方法功能。

在这里插入图片描述

反射实现设置白名单 setWiFiWhiteList

  fun setWifiWhiteList(  whiteList: List<String>): Boolean {
        return try {
            val wifiManager = ContextProvider.get().context.getSystemService(Context.WIFI_SERVICE) as WifiManager

            // 通过反射获取 setWiFiWhiteList 方法
            val method: Method = wifiManager.javaClass.getMethod(
                "setWiFiWhiteList",
                List::class.java
            )

            // 调用方法设置白名单
            method.invoke(wifiManager, whiteList)

            true // 操作成功
        } catch (e: Exception) {
            e.printStackTrace()
            false // 操作失败
        }
    }
实际调用反射
 val wifiManager = getSystemService(WIFI_SERVICE) as WifiManager
            if (wifiManager.isWifiEnabled()) {
                // WiFi 已启用
                Log.d(TAG,"  WiFi 已启用")
                // 设置 WiFi 白名单
                val success = setWifiWhiteList(
                    listOf("HomeWiFi", "OfficeWiFi", "TrustedNetwork","fiseGMS","FiseTest_5G","FiseTest")
                )
                if (success) {
                    Log.d("WifiConfig", "WiFi 白名单设置成功")
                } else {
                    Log.e("WifiConfig", "WiFi 白名单设置失败")
                }
            } else {
                Log.d(TAG,"  WiFi 未启用")
            }

反射实现获取白名单 getWiFiWhiteList

  fun getWifiWhiteList(): List<String>? {
        return try {
            val wifiManager =ContextProvider.get().context.getSystemService(Context.WIFI_SERVICE) as WifiManager

            // 通过反射获取 getWiFiWhiteList 方法
            val method: Method = wifiManager.javaClass.getMethod("getWiFiWhiteList")

            // 调用方法并获取结果
            val result = method.invoke(wifiManager)

            // 转换为 List<String>
            result as? List<String>
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }

实际调用反射
viewBinding.getWifiwhitelist.setOnClickListener {
            Log.d(TAG, "get_Wifiwhitelist   WIFI 白名单获取")
            val wifiManager = getSystemService(WIFI_SERVICE) as WifiManager
            if (wifiManager.isWifiEnabled()) {
                // WiFi 已启用
                Log.d(TAG,"  WiFi 已启用")

                val whiteWifiList=getWifiWhiteList()
                Log.d(TAG,"white_WifiList:${whiteWifiList}")

              //  wifiManager
            } else {

                Log.d(TAG,"  WiFi 未启用")

            }

        }

效果

这里给出实际 效果如吐下

默认的WIFI列表

在这里插入图片描述

设置白名单后的wifi 列表

在这里插入图片描述

一些日志打印

默认获取 wifi 白名单

在这里插入图片描述

设置一次白名单

在这里插入图片描述

获取白名单-设置白名单后

在这里插入图片描述

总结

  • 假使你已经对WIIF相关基础有一定的了解,这边文章和推荐资料能帮你实现需求,很容易理解,和定制相关WIFI功能
  • 实际经验来看,framework.jar 就是无法调用到自己修改的文件方法,不妨换个思路,反射。
  • 这里只是在服务类里面维护了一个内存结合List 类型的白名单。实际开发中 维护本地存储就可以了。 这样方便保存 满足实际开发需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野火少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值