zl程序教程

您现在的位置是:首页 >  其他

当前栏目

瑞芯微RK3128-微信Airkiss2.0配网功能调试及实现

调试微信 实现 功能
2023-09-14 09:16:13 时间

原址

越来越多的智能硬件设备实现了简易的配网功能,微信硬件平台推出了Airkiss技术,详细的关于Airkiss的介绍可以参考微信硬件平台开发者心:微信硬件平台Airkiss

关于AirKiss的实现,基于的WiFi芯片是BroadCom AP6212,基于的CPU还是瑞芯微RK3128,Android系统。

其实很多WiFI厂商都和微信有了合作,实现了其Airkiss、AirSync等功能。比如我拿到的是正基科技(AMPAK)AP6212的

EasySetupTarget.zip,其实现了微信的Airkiss功能,同时也支持几个其它厂商的智能配网功能,具体如下:

Usage: (type setup -h)
# setup -h
-h: show help message
-d: show debug message
-k <v>: set 16-char key for all protocols
-p <v>: bitmask of protocols to enable
  0x0001 - bcast
  0x0002 - neeze
  0x0004 - akiss
  0x0010 - changhong
  0x0020 - changhong
  0x0040 - jd JoyLink

本文中我们只介绍Airkiss的测试过程,Airkiss的实现需要一下几个模块支持:wifi固件、服务端(EasySetupTarget)、

客户端(APP or微信公众号发送ssid和password)。


wifi固件


Airkiss服务实现模块



可以编译为可执行文件或so库,源码在jni文件夹中,可以通过Androi JNI调用。详细的说明在readme文档。

这里主要记录一下我遇到的问题,编译jni目录为可执行文件,push到开发板运行正常,可以获取到ssid和password。

但是为了更加方便操作,我是通过上层APP的JNI调用easysetup接口,开启airkiss,然后走到easy_setup_start()接口,

看日志已经进入该函数,但是在ioctrl操作时失败了,具体日志如下:

[ 01-01 12:45:27.541  7172: 7275 I/         ]Lucien:entere easySetupEnabbleAirkiss  
[ 01-01 12:45:27.541  7172: 7275 I/         ]Lucien: Easy setup target library v3.7.0
[ 01-01 12:45:27.541  7172: 7275 I/         ]easy setup iovar !
[ 01-01 12:45:27.541  7172: 7275 I/         ] easy setup ioctl(cmd=263) failed: 1(Operation not permitted)
[ 01-01 12:45:27.541  7172: 7275 I/         ]easy setup iovar:easy_setup_ioctl return:-1
[ 01-01 12:45:27.541  7172: 7275 I/         ] easy setup start failed: 1(Operation not permitted)
 
对应执行代码位置如下标红:
int  easy_setup_ioctl(int cmd, int set, void* param, int size) {
     。。。。。。
     if ((ret = ioctl(g_ioc_fd, SIOCDEVPRIVATE, &ifr)) < 0) {
        /* log if not WLC_SCAN_RESULTS(51) */
        if (cmd != 51) {
            LOGD("easy setup ioctl(cmd=%d) failed: %d(%s)\n", 
                    cmd, errno, strerror(errno));
        }
        return -1;
    }
    return 0;
}

刚开始百思不得其解,为什么会权限失败,apk是放在/system/app中、设置platform签名凭证、以及设置shareUid,

相应的so权限及用户组也没什么问题,纠结了半天,还是怪自己对Android权限管理了解到不够清楚,刚开始怀疑是selinux权限没加,

但是又没有相应的avc日志。还尝试app中调用可执行文件,也是失败的。看了这位同仁的博客才明白(参考博客),

其实是apk的操作权限没有加够。

原来函数dev_ioctl中,会检查CAP_NET_ADMIN权限,进入这个函数,发现检查的是进程是否在group AID_NET_ADMIN中:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. if (cap == CAP_NET_ADMIN && in_egroup_p(AID_NET_ADMIN))  
  2.   return 0;  

android权限定义
在system/core/include/private/android_filesystem_config.h中,android定义了一组uid和gid,如AID_ROOT, 
AID_SYSTEM,AID_NET_ADMIN。每一个id对应有字符串,如root, system, net_admin。当用户程序需要访问受限资源是,
需要保证自己加入到对应的Group中。在frameworks中platform.xml存放有AndroidManifest.xml中权限与底层权限的对应关系,
之所以一直报权限问题,原来是我在apk中没有申请NET_ADMIN权限,而这个权限是系统app才可以申请的,在 AndroidManifest.xml添加了权限申请后,终于不报ioctl的错误 了,终于看到了avc日志。

com.mydale.iot: type=1400 audit(0.0:4): avc: denied { net_admin } for capability=12 scontext=u:r:platform_app:s0 tcontext=u:r:

platform_app:s0tclass=capability permissive=1

添加权限:

allow platform_app self:capability { net_admin };

但是编译会报错,原来在app.te中声明了net_admin在app domain是不被允许的。

neverallow { appdomain -bluetooth } self:capability *;

这里需要修改下,其它就OK了。以上只是自己理解,可能有不准确的地方,谅解。


补充;

设备获取到wifi ssid和password后,也会同时获取一个随机数,在设备联网后,要发送不少于20次udp广播到端口10000,告诉微信公众号或app端,信息全部被正确接收了。

Java端的udp广播发送代码参考如下:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private void sendUdpBroadcast(byte[] data){  
  2.     Log.i(Tag,"start to sendUdpBroadcast");  
  3.     DatagramSocket udpSocket;  
  4.     String address = getLocalIPAddress();  
  5.     DatagramPacket dataPacket = new DatagramPacket(buffer, MAX_DATA_PACKET_LENGTH);  
  6.     InetAddress broadcastAddr;  
  7.     if (address != null) {  
  8.         Log.i(Tag,"Can not get IP address");  
  9.     }  
  10.     try {  
  11.         udpSocket = new DatagramSocket(DEFAULT_PORT);  
  12.         dataPacket.setData(data);  
  13.         dataPacket.setLength(data.length);  
  14.         dataPacket.setPort(DEFAULT_PORT);  
  15.         broadcastAddr = InetAddress.getByName("255.255.255.255");  
  16.         dataPacket.setAddress(broadcastAddr);  
  17.         for(int i=0; i<30; i++) {  
  18.             udpSocket.send(dataPacket);  
  19.             sleep(10);  
  20.         }  
  21.         udpSocket.close();  
  22.     } catch (Exception e) {  
  23.         e.printStackTrace();  
  24.     }  
  25. }