WIFI
模块 申屠家振

修改

1.2011119

2.2011127

android平台的WIFI模块进行已经有段时间了,现在做一总结,以便以后查阅与修正。

心得之作,如有异议,请斧正。


  1. 什么是WIFI

android 屏蔽WiFi 流量 安卓禁用wifi模块_android 屏蔽WiFi 流量

WIFI是一种无线连接技术,可用于PC,PDA,手机等终端。WIFI的目的是改善基于IEEE802.11标准的无线网络产品之间的互通性,也就是说WIFI是基于802.11标准的,但WIFI不等同无线网络。


  1. android平台下的WIFI模块

简单介绍一下,WIFI模块的基本功能:

  1. 开关WIFI

除了在WIFI设置界面可以开关WIFI,还有其他的入口可以开关,要查看这些开关状态是否一致。还有就是飞行模式对WIFI开关的影响,由于WIFI开和关都有一个时间过程,而飞行模式的开关瞬间完成,所以有时会出现冲突。

  1. 开关新可用网络提醒

新可用网络的定义是自WIFI模块开启后,从未发现过的,为加密的网络。只有满足了新可用网络的定义,才会有提醒。

  1. 连接断开网络

连接断开各种不同加密类型的网络(具体类型下文有详解)

  1. 手动添加网络

需要路由器关闭SIID广播。可手动输入SIID,网络加密类型,密码。对于OPAL手机来说,路由器隐藏了SSID,手动添加的网络是无法连接的。

  1. 搜索网络

手动点击搜索按钮可以搜索网络,也可以等待WIFI模块自动搜索网络。

  1. 休眠设置

由于WIFI模块是用电大户,所有为了省电,android的WIFI加了一个休眠策略,可以设置永远不断开,充电时不断开和锁屏时断开。要测试休眠设置是否有效,可以在路由器上PING手机的IP,PING通就是连接状态。OPAL手机的休眠策略属于完全失效,现在的情况是无论选哪个都会一直保持连接,锁屏后15分钟再休眠。

  1. 设置静态IP

Android系统里对IP设置的输入限制很有问题,我一直认为这是弱智的限制。正常IP的范围在0-255之间,android对IP输入的限制是整数0到整数255之间,也就是说0000.000200.001.001这样一个IP都能合法输入。


  1. WIFI模块深入了解一点点
  2. WIFI的基本运行流程

android 屏蔽WiFi 流量 安卓禁用wifi模块_android_02

【初始化】
1在SystemServer启动的时候,会生成一个ConnectivityService的实例

2ConnectivityService的构造函数会创建WifiService

3WifiStateTracker会创建WifiMonitor接收来自底层的事件,WifiService和WifiMonitor是整个模块的核心。WifiService负责启动关闭wpa_supplicant、启动关闭WifiMonitor监视线程和把命令下发给wpa_supplicant,而WifiMonitor则负责从wpa_supplicant接收事件通知。

【连接AP】

1WirelessSettings在初始化的时候配置了由WifiEnabler来处理Wifi按钮

2当用户按下Wifi按钮后,Android会调用WifiEnabler的onPreferenceChange,再由WifiEnabler调用WifiManager的setWifiEnabled接口函数,通过AIDL,实际调用的是WifiService的setWifiEnabled函数,WifiService接着向自身发送一条MESSAGE_ENABLE_WIFI消息,在处理该消息的代码中做真正的使能工作:首先装载WIFI内核模块(该模块的位置硬编码为"/system/lib/modules/wlan.ko"),然后 启 动wpa_supplicant(配置 文 件 硬 编 码 为"/data/misc/wifi/wpa_supplicant.conf")再通过WifiStateTracker来启动WifiMonitor中的监视线程

3当使能成功后,会广播发送WIFI_STATE_CHANGED_ACTION这个Intent通知外界WIFI已经 成 功 使 能 了 。WifiEnabler创建 的 时 候 就 会 向Android注册 接 收WIFI_STATE_CHANGED_ACTION,因此它会收到该Intent,从而开始扫描

【查找AP】

1扫描的入口函数是WifiService的startScan,它其实也就是往wpa_supplicant发送SCAN命令。

2当wpa_supplicant处理完SCAN命令后,它会向控制通道发送事件通知扫描完成,从而wifi_wait_for_event函数会接收到该事件,由此WifiMonitor中的MonitorThread会被执行来出来这个事件。

3WifiStateTracker则接着广播发送SCAN_RESULTS_AVAILABLE_ACTION这个Intent。

4WifiLayer注册了接收SCAN_RESULTS_AVAILABLE_ACTION这个Intent,所以它的相关处理函数handleScanResultsAvailable会被调用,在该函数中,先会去拿到SCAN的结果(最终是往wpa_supplicant发送SCAN_RESULT命令并读取返回值来实现的),List<ScanResult>list = mWifiManager.getScanResults();对每一个扫描返回的AP,WifiLayer会调用WifiSettings的onAccessPointSetChanged函数,从而最终把该AP加到GUI显示列表中。

【配置AP参数】

当用户在WifiSettings界面上选择了一个AP后,会显示配置AP参数的一个对话框。

showAccessPointDialog(state,AccessPointDialog.MODE_INFO);

【连接】

当用户在AcessPointDialog中选择好加密方式和输入密钥之后,再点击连接按钮,Android就会去连接这个AP。

1WifiLayer会先检测这个AP是不是之前被配置过,这个是通过向wpa_supplicant发送LIST_NETWORK命令并且比较返回值来实现的,

//NeedWifiConfiguration for the AP
WifiConfigurationconfig = findConfiguredNetwork(state);

如果wpa_supplicant没有这个AP的配置信息,则会向wpa_supplicant发送ADD_NETWORK命令来添加该AP

2ADD_NETWORK命令 会 返 回 一 个ID,WifiLayer再用 这 个 返 回 的ID作为参数向wpa_supplicant发送ENABLE_NETWORK命令,从而让wpa_supplicant去连接该AP。

【配置IP地址】

1当wpa_supplicant成功连接上AP之后,它会向控制通道发送事件通知连接上AP了,从而wifi_wait_for_event函数会接收到该事件,由此WifiMonitor中的MonitorThread会被执行来出来这个事件

2WifiMonitor再调用WifiStateTracker的notifyStateChange,WifiStateTracker则接着会往自身发送EVENT_DHCP_START消息来启动DHCP去获取IP地址

3然后再广播发送NETWORK_STATE_CHANGED_ACTION这个Intent

4WifiLayer注册了接收NETWORK_STATE_CHANGED_ACTION这个Intent,所以它的相关处理函数handleNetworkStateChanged会被调用,当DHCP拿到IP地址之后,会再发送EVENT_DHCP_SUCCEEDED消息

5WifiLayer处理EVENT_DHCP_SUCCEEDED消息,会再 次 广 播 发 送

至此为止,整个连接过程完成

2.wpa_supplicant

Android平台使用的WiFi控制框架是基于大名鼎鼎的wpa_supplicant,它是一个安全中间件,为各种无线网卡提供统一的安全机制,如下图所示:

android 屏蔽WiFi 流量 安卓禁用wifi模块_网络_03

对应上述结构,基于Android的手机中的WiFi控制分为三大组件:
1)客户端程序,包括wpa_cli命令行或java图形界面程序,通过unix本地socket与
wpa_supplicantdaemon服务通信,发送命令并接收结果;
2)wpa_supplicantdaemon服务,对应上述中间部分,功能是“上传下达”。所有客户端通过它控制硬件网卡,通过发送字符串命令控制是否扫描AP,提取扫描结果和是否关联AP等操作,同时将驱动的执行状态发送给用户。该服务是设计支持多种无线网卡芯片,因此各个厂商共同提供了一个通用接口给wpa_supplicant调用;
3)网卡驱动;


在手机内存的/etc/wpa_supplicant.conf中我们可以直接看到WIFI支持的网络类型,每种类型都有例子,比如:

#BothWPA-PSK and WPA-EAP is accepted. Only CCMP is accepted as pairwiseand
#group cipher.
#network={
# ssid="example"
# bssid=00:11:22:33:44:55
# proto=WPARSN
# key_mgmt=WPA-PSKWPA-EAP
# pairwise=CCMP
# group=CCMP
# psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb
#}

不同类型的网络,不同的参数等等,应有尽有。

  1. WIFI模块的LOG了解多一点点

我们在上面已经知道WIFI的启动过程,在功能运行中也会输出相应的日志信息,下面就来详细了解一下。(请注意,WIFI开启后会更改电池状态等其他状态。关闭WIFI时,android的策略是卸载驱动来省电。如有缺失就是问题。不过下文删去了与WIFI无关的LOG!)

1.开启WIFI&自动搜索

E/WifiHW (1201): ==JOHN DEBUG==: [WIFI] Load Driver
加载驱动
D/SettingsWifiEnabler(1321): Received wifi state changed from Disabled to Enabling
接收到广播:WIFI正在开启
D/WifiService(1201): ACTION_BATTERY_CHANGED pluggedType: 2
电池状态改变
E/WifiHW(1201):==JOHNDEBUG==:moduleaddress:4b938008filename:/system/lib/modules/dhd.koargs:firmware_path=/system/wlan/broadcom/rtecdc.binnvram_path=/system/wlan/broadcom/nvram.txt
WIFI硬件:加载内核模块
I/wpa_supplicant(2490): CTRL-EVENT-STATE-CHANGE id=-1 state=2
wpa_supplicant发出事件通知
V/WifiMonitor(1201): Event [CTRL-EVENT-STATE-CHANGE id=-1 state=2]
WifiMonitor从wpa_supplicant接收事件通知
I/wpa_supplicant(2490): CTRL-EVENT-SCAN-RESULTS Ready
wpa_supplicant发出事件通知:准备好开始搜索网络了
E/wpa_supplicant(2490): wpa_driver_priv_driver_cmd SCAN-ACTIVE len = 4096
wpa_supplicant发出事件通知:驱动命令行.主动搜索.LEN
E/wpa_supplicant(2490): wpa_driver_priv_driver_cmd SCAN-ACTIVE len = 0, 11
wpa_supplicant发出事件通知:驱动命令行.主动搜索.LEN
E/wpa_supplicant(2490): wpa_driver_priv_driver_cmd SCAN-PASSIVE len = 4096
wpa_supplicant发出事件通知:驱动命令行.被动搜索.LEN
E/wpa_supplicant(2490): wpa_driver_priv_driver_cmd SCAN-PASSIVE len = 0, 12
wpa_supplicant发出事件通知:驱动命令行.被动搜索.LEN=0.12
D/SettingsWifiEnabler(1321): Received wifi state changed from Enabling to Enabled
接收到广播:WIFI已经开启
E/wpa_supplicant(2490): wpa_driver_priv_driver_cmd RSSI len = 4096
wpa_supplicant发出事件通知:
E/wpa_supplicant(2490): wpa_driver_priv_driver_cmd RSSI len = 4, 4
wpa_supplicant发出事件通知:
E/wpa_supplicant(2490): wpa_driver_priv_driver_cmd LINKSPEED len = 4096
wpa_supplicant发出事件通知:
E/wpa_supplicant(2490): wpa_driver_priv_driver_cmd LinkSpeed 54 len = 12, 12
wpa_supplicant发出事件通知:
E/wpa_supplicant(2490): wpa_driver_priv_driver_cmd MACADDR len = 4096
wpa_supplicant发出事件通知:驱动命令行.MAC地址.LEN
E/wpa_supplicant(2490): wpa_driver_priv_driver_cmd Macaddr = 44:A4:2D:27:25:BE
wpa_supplicant发出事件通知:驱动命令行.MAC地址
E/wpa_supplicant(2490): len = 28, 28
wpa_supplicant发出事件通知:
V/WifiStateTracker(1201): Connection to supplicant established, state=SCANNING
WIFI状态跟踪:连接请求确认,状态=搜索
D/NetworkStateTracker(1201): setDetailed state, ld =IDLE and new state=SCANNING
网络状态跟踪:更新显示为搜索状态
V/WifiStateTracker(1201): Changing supplicant state: SCANNING ==> INACTIVE
WIFI状态跟踪:更改请求状态:搜索中->不活动


2.点击连接&获取状态

E/WifiHW (1201): ==JOHN DEBUG==: [WIFI] Load Driver
WIFI硬件:加载驱动
D/SettingsWifiEnabler(1321): Received wifi state changed from Disabled to Enabling
收到广播,WIFI状态正在开启
E/WifiHW(1201):==JOHNDEBUG==:moduleaddress:4b938008filename:/system/lib/modules/dhd.koargs:firmware_path=/system/wlan/broadcom/rtecdc.binnvram_path=/system/wlan/broadcom/nvram.txt
WIFI硬件:加载内核模块
E/WifiHW (1201): ==JOHN DEBUG==: return of insmod : ret = 0, Unknown error: 0
WIFI硬件:返回装载模块报告:返回指令0,未知错误0
……
I/wpa_supplicant(2490): Trying to associate with 1c:bd:b9:f6:a7:9f (SSID='LosAngeles'freq=2412 MHz)
wpa_supplicant发出事件通知:尝试连接,(SSID='LosAngeles'频段=2412MHz)
V/WifiMonitor(1201):Event[Trying to associate with 1c:bd:b9:f6:a7:9f(SSID='LosAngeles' freq=2412 MHz)]
WifiMonitor接收wpa_supplicant的事件
V/WifiMonitor(1201): Event [CTRL-EVENT-STATE-CHANGE id=-1 state=3]
WifiMonitor接收事件
V/WifiStateTracker(1201): Changing supplicant state: SCANNING ==> ASSOCIATING
WIFI状态跟踪:更改请求状态:搜索中->匹配中
D/NetworkStateTracker(1201): setDetailed state, ld =SCANNING and new state=CONNECTING
网络状态跟踪:更新显示为正在连接状态
D/ConnectivityService(1201): ConnectivityChange for WIFI: CONNECTING/CONNECTING
连接管理服务:改变WIFI连接状态:正在连接/正在连接
V/WifiStateTracker(1201): Changing supplicant state: ASSOCIATING ==> ASSOCIATED
WIFI状态跟踪:更改请求状态:匹配中->已匹配
D/NetworkStateTracker(1201): setDetailed state, ld =CONNECTING and new state=CONNECTING
网络状态跟踪:更新显示为正在连接状态
I/wpa_supplicant(2490): Associated with 1c:bd:b9:f6:a7:9f
wpa_supplicant发出事件通知:已和1c:bd:b9:f6:a7:9f匹配
V/WifiMonitor(1201): Event [Associated with 1c:bd:b9:f6:a7:9f]
WifiMonitor接收wpa_supplicant的事件
V/WifiStateTracker(1201): Changing supplicant state: ASSOCIATED ==>FOUR_WAY_HANDSHAKE
WIFI状态跟踪:更改请求状态:已匹配->TCP中断连接
D/NetworkStateTracker(1201): setDetailed state, ld =CONNECTING and newstate=AUTHENTICATING
网络状态跟踪:更新显示为鉴定中
D/ConnectivityService(1201): Dropping ConnectivityChange for WIFI:CONNECTING/AUTHENTICATING
连接管理服务:抛出WIFI连接状态改变:已连接/鉴定中
V/WifiStateTracker(1201): Changing supplicant state: FOUR_WAY_HANDSHAKE ==>GROUP_HANDSHAKE
WIFI状态跟踪:更改请求状态:TCP中断连接->确认标志位
D/NetworkStateTracker(1201): setDetailed state, ld =AUTHENTICATING and newstate=AUTHENTICATING
网络状态跟踪:更新显示为鉴定中
I/wpa_supplicant(2490): WPA: Key negotiation completed with 1c:bd:b9:f6:a7:9f[PTK=CCMP GTK=TKIP]
wpa_supplicant发出事件通知:WPA:与1c:bd:b9:f6:a7:9f确定标志位
I/wpa_supplicant(2490): CTRL-EVENT-STATE-CHANGE id=0 state=7
wpa_supplicant发出事件通知:
I/wpa_supplicant(2490): CTRL-EVENT-CONNECTED - Connection to 1c:bd:b9:f6:a7:9fcompleted (auth) [id=0 id_str=]
wpa_supplicant发出事件通知:连接完成
V/WifiMonitor(1201): Event [WPA: Key negotiation completed with 1c:bd:b9:f6:a7:9f[PTK=CCMP GTK=TKIP]]
WifiMonitor接收wpa_supplicant事件
V/WifiMonitor(1201): Event [CTRL-EVENT-STATE-CHANGE id=0 state=7]
WifiMonitor接收wpa_supplicant事件
V/WifiMonitor(1201): Event [CTRL-EVENT-CONNECTED - Connection to 1c:bd:b9:f6:a7:9fcompleted (auth) [id=0 id_str=]]
WifiMonitor接收wpa_supplicant事件
V/WifiStateTracker(1201): Changing supplicant state: GROUP_HANDSHAKE ==> COMPLETED
WIFI状态跟踪:更改请求状态:确认标志位->完成
V/WifiStateTracker(1201): New network state is CONNECTED
WIFI状态跟踪:新网络状态为已连接
D/NetworkStateTracker(1201): setDetailed state, ld =AUTHENTICATING and newstate=OBTAINING_IPADDR
网络状态跟踪:更新显示为获取IP地址
D/ConnectivityService(1201): Dropping ConnectivityChange for WIFI:CONNECTING/OBTAINING_IPADDR
连接管理服务:抛出WIFI





Android 下使用wpa_cli 连接 wifi


# cp /media/sd8686.bin /lib/firmware/sd8686.bin
 # cp /media/sd8686_helper.bin /lib/firmware/sd8686_helper.bin
 # dpkg -i kernel-smartq5-modules_2.6.24.7-smartq5-050509_all.deb 
# insmod sd8686.ko 
 
# ifconfig -a
 
# chmod 0660 /data/misc/wifi/wpa_supplicant.conf
 
* The content of wpa_supplicant.conf 
----
update_config=1
ctrl_interface=DIR=/data/system/wpa_supplicant GROUP=1010
----
 # /system/bin/wpa_supplicant -Dwext -iwlan0 -c /data/misc/wifi/wpa_supplicant.conf
# /system/bin/wpa_cli -i wlan0 -p /data/system/wpa_supplicant
  > status
  INACTIVE
  > help
  > add_network
  > set_network 0 ssid "NETGEAR"
  > set_network 0 key_mgmt NONE 
  > set_network 0 priority 0
  > list_network
  > save_config
  > enable_network 0
  
 bssid=00:24:b2:5b:5b:0a 
 ssid=NETGEAR 
 …. 
 wpa_state=COMPLETED



http://hi.baidu.com/xyp86/blog/item/d371a1d78d4162d7a144dfd3.html


Android平台上无线网卡自动扫描并关联AP的实现


2009-12-09 21:34

http://hi.baidu.com/xyp86/blog/item/d371a1d78d4162d7a144dfd3.html

最近为了验证一个算法的能耗,研究了在开源的Android平台上如何实现无线网卡的自动开启和基于wpa_supplicant的AP自动扫描和关联,记录且共享之。
目标:

自动打开无线网卡,扫描指定的信道列表,并在发现合适的AP时自动关联。

1. Android平台的WiFi框架

Android平台使用的WiFi控制框架是基于大名鼎鼎的wpa_supplicant,它是一个安全中间件,为各种无线网卡提供统一的安全机制,如下图所示:


图1:Android平台WiFi框架


对应上述结构,基于Android 的G1手机中的WiFi控制分为三大组件:

1)客户端程序,包括wpa_cli命令行或java图形界面程序,通过unix本地socket与

wpa_supplicant daemon服务通信,发送命令并接收结果;

2)wpa_supplicant daemon服务,对应上述中间部分,功能是“上传下达”。所有客户端通过它控制硬件网卡,通过发送字符串命令控制是否扫描AP,提取扫描结果和是否关联AP等操作,同时将驱动的执行状态发送给用户。该服务是设计支持多种无线网卡芯片,因此各个厂商共同提供了一个通用接口给wpa_supplicant调用,其中G1用的是TI的芯片;

3)网卡驱动,本文中可以不涉及。


2.    自动打开网卡并启动wpa_supplicant

图形界面可以正常启动网卡并开始AP扫描,但通过命令行wpa_cli无法启动,为此修改wpa_supplicant程序,输出所有argv参数,然后通过图形界面的设置来启动AP扫描,设置->无线接口->启动WiFi,输出如下参数:

1257946571.827087: /system/bin/wpa_supplicant
 1257946571.827453: -Dtiwlan0
 1257946571.827545: -itiwlan0
 1257946571.827636: -c/data/misc/wifi/wpa_supplicant.conf

手工输入 wpa_supplicant -Dtiwlan0 -itiwlan0 -c/data/misc/wifi/wpa_supplicant.conf 还是启动失败。通过跟踪图形界面的java代码,定位android/packages/apps/Settings/src/com/android/settings/wifi下的java文件,确定是WifiEnabler.java,调用路径为:WifiEnabler->WifiManager.setWifiEnabled 接口函数,通过AIDL->WifiServic.setWifiEnabled函数,它向自身发送一条 MESSAGE_ENABLE_WIFI 消息, 处理代码handleMessage中调用setWifiEnabledBlocking,该函数代码如下:

…
 if (enable) {
 if (!WifiNative.loadDriver()) {}
 if (!WifiNative.startSupplicant()) {}
 ..... } else {
 if (!WifiNative.stopSupplicant()) {}      
 if (!WifiNative.unloadDriver()) { }

 }
 }

WifiNative.java使用JNI机制,对应的c文件是android/hardware/libhardware_legacy/wifi/wifi.c, 其中包括以下核心函数:

int wifi_load_driver();
 int wifi_unload_driver();
 int wifi_start_supplicant();
 int wifi_stop_supplicant();


It’s great! 将该文件静态链接到我们的代码中就可以自动加载网卡和启动wpa_supplicant。

3.    自动扫描指定的信道,并关联给定的AP

现有的wpa_cli是一个交互式命令环境,在连接到wpa_supplicant服务后,通过请求-响应的方式工作。因此我们需要重写一个客户端wpa_myclient,并通过前述wifi.c代码自动打开网卡并启动wpa_supplicant,涉及代码文件包括:

1)    分析wpa_cli的工作原理,确定通过手工命令如何关联AP

android/external/wpa_supplicant/
 android/system/wlan/ti/wpa_supplicant_lib/:是由TI公司提供给wpa_supplicant的统一接口

术语networks是指由当前网卡已记忆的WLAN网络,与windows无线接口设置中的“首选网络”概念类似,该网络也可以通过wpa_supplicant.conf手工配置

术语scan_results是指当前网卡扫描发现的AP。

网卡通过需要使用下列命令序列来关联一个网络:

scan

scan_results %获得扫描结果,包括ssid和信号强度等信息

add_network %必须先创建一个网络,得到一个新的网络号id

set_network id ssid “***” %将网络与想关联AP的SSID对应

set_network id key_mgmt NONE %设置安全信息,这里是针对Open System

set_network id pairwise NONE

select_network id %激活该网络,此时开始关联过程


2)    分析wpa_cli与supplicant的通信协议,添加一个新的命令MYSCAN能按指定信道列表扫描,并修改核心数据结构struct wpa_supplicant加入一个成员保存待扫描的信道列表,主要修改文件包括:ctrl_iface.c和wpa_supplicant_i.h

3)    由wpa_supplicant.c的wpa_supplicant_scan()->driver_ti.c的wpa_driver_tista_scan-> ti_init_scan_params()初始化扫描参数,将pScanParams->channelEntry设置为指定的信道列表;

4)    扫描结束后,驱动程序通过driver_ti.c的wpa_driver_tista_receive_driver_event()通知调用程序,该事件通过逐级传递到events.c 的wpa_supplicant_event()事件分发接口, 并通过wpa_supplicant_event_scan_results()通知wpa_cli客户端,指示用户可以使用scan_results命令获取扫描结果;此外在该处理函数中如果发现扫描结果包括用户的首选网络networks,则会自动启动关联过程(windows也是这种方式)。

5)    修改events.c 的wpa_supplicant_event_scan_results()来模拟用户首选网络,首先利用    wpa_config_remove_network方法删除wpa_s->conf->ssid 中的所有首选网络,并根据一个规则从wpa_s->scan_results[]中选择一个最合适的,然后通过wpa_config_add_network和wpa_config_set按照上述手工命令格式设置该network,然后它将自动按照正常流程关联。


Hints and Tips:

1)    在android根目录执行命令,. build/envsetup.sh,然后就可以使用mm TARGET_PRODUCT=htc_dream命令加速编译

2)    实现命令set_network id ssid “***”,不能少了SSID的双引号

3)    为了实现将输出调试信息到文件,需要在.config中打开编译开关CONFIG_DEBUG_FILE,同时在main.c中初始化params.wpa_debug_file_path为一个文件(我的是/sdcard/wpadbg),最后自定义一个wpa_printf的消息优先级,并打开wpa_debug_print_timestamp,输出时戳