当前位置: 首页 > news >正文

手机网站制作公司/网络营销学什么内容

手机网站制作公司,网络营销学什么内容,web proxy online,手机网站建设机构前言在 Android 开发中合理利用网络不浪费用户流量是每个良心 APP 的目标,收集 APP 的流量使用数据是重要的一环,毕竟没有数据支撑做的优化都是纸上谈兵.一般用户查看流量统计特别都是针对 3G/4G ,会去下载比如 360*** 之类的第三方软件来进行监控,其实 Android 系统提供了一个…

前言

在 Android 开发中合理利用网络不浪费用户流量是每个良心 APP 的目标,收集 APP 的流量使用数据是重要的一环,毕竟没有数据支撑做的优化都是纸上谈兵.一般用户查看流量统计特别都是针对 3G/4G ,会去下载比如 360*** 之类的第三方软件来进行监控,其实 Android 系统提供了一个类给开发者使用,它就是 TrafficStats.

本文的目标是以简单快捷地介绍 TrafficStats 读取本地文件获取应用流量统计的过程,关于其他详细方法和系统服务的相关内容都不做详细解读.

TrafficStats

类注解

/**

* Class that provides network traffic statistics. These statistics include

* bytes transmitted and received and network packets transmitted and received,

* over all interfaces, over the mobile interface, and on a per-UID basis.

*

* These statistics may not be available on all platforms. If the statistics are

* not supported by this device, {@link #UNSUPPORTED} will be returned.

*

* Note that the statistics returned by this class reset and start from zero

* after every reboot. To access more robust historical network statistics data,

* use {@link NetworkStatsManager} instead.

*/

TrafficStats 提供网络流量统计.这些统计包括字节的上传/接收和数据包的上传/接收,

流量统计在 Android2.2 之前是不可用的,如果系统版本过低会返回 UNSUPPORTED (-1).

数据统计会在每次手机启动后从零开始算,如果要访问更多详细的网络状态数据就使用 NetworkStatsManager.

TrafficStats 提供的方法有很多,可以通过阅读官方文档了解,我们统计应用流量使用情况通常使用的是 getUidRxBytes().

下面从一个例子开始了解 TrafficStats 如何读取 APP 流量使用情况的,该例子主要通过调用 TrafficStats.getUidRxBytes() 根据应用的 Uid 获取该应用接收字节数.

long uidRxBytes = TrafficStats.getUidRxBytes(android.os.Process.myUid());

while (true) {

try {

Thread.sleep(10000);

} catch (InterruptedException e) {

e.printStackTrace();

}

Log.d("uidRxBytes", "当前进程流量:"+ (TrafficStats.getUidRxBytes(

android.os.Process.myUid()) - uidRxBytes));

}

getUidRxBytes()

统计的字节包括 TCP 和 UDP.

// TrafficStats.java

public static long getUidRxBytes(int uid) {

// This isn't actually enforcing any security; it just returns the

// unsupported value. The real filtering is done at the kernel level.

// 获取当前调用所在进程的 UID

final int callingUid = android.os.Process.myUid();

if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {

try {

return getStatsService().getUidStats(uid, TYPE_RX_BYTES);

} catch (RemoteException e) {

throw e.rethrowFromSystemServer();

}

} else {

return UNSUPPORTED;

}

}

// NOTE: keep these in sync with android_net_TrafficStats.cpp

private static final int TYPE_RX_BYTES = 0;

private static final int TYPE_RX_PACKETS = 1;

private static final int TYPE_TX_BYTES = 2;

private static final int TYPE_TX_PACKETS = 3;

private static final int TYPE_TCP_RX_PACKETS = 4;

private static final int TYPE_TCP_TX_PACKETS = 5;

首先调用 getStatsService() 获取 INetworkStatsService 实现类的实例.

然后调用 INetworkStatsService.getUidStats() 获取接收的字节数.

注意 getUidStats() 中参数 TYPE_RX_BYTES 表示获取的统计数据类型,具体类型根据字节和数据包分为 6 个如上面代码所示,根据注释这些类型的值要与 android_net_TrafficStats.cpp 即与 C++ 层同步.

首先看 getStatsService().

getStatsService()

// TrafficStats.java

private synchronized static INetworkStatsService getStatsService() {

if (sStatsService == null) {

sStatsService = INetworkStatsService.Stub.asInterface(

ServiceManager.getService(Context.NETWORK_STATS_SERVICE));

}

return sStatsService;

}

很明显这里是通过 AIDL 的方式跨进程与系统服务 NetworkStatsService 进行通信,下面看下 AIDL 文件的定义,下面截取部分 AIDL 常用方法.

INetworkStatsService.aidl

// INetworkStatsService.aidl

// /frameworks/base/core/java/android/net/INetworkStatsService.aidl

interface INetworkStatsService {

// ...

long getUidStats(int uid, int type);

long getIfaceStats(String iface, int type);

long getTotalStats(int type);

}

接着我们查看系统服务 NetworkStatsService.

NetworkStatsService

NetworkStatsService 源码路径为 /frameworks/base/services/core/java/com/android/server/net/NetworkStatsService.java

下面截取 getUidStats() 相关代码.

// NetworkStatsService.java

public class NetworkStatsService extends INetworkStatsService.Stub {

private final boolean mUseBpfTrafficStats;

@VisibleForTesting

NetworkStatsService(Context context, INetworkManagementService networkManager,

AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock,

TelephonyManager teleManager, NetworkStatsSettings settings,

NetworkStatsObservers statsObservers, File systemDir, File baseDir) {

// ...

mUseBpfTrafficStats = new File("/sys/fs/bpf/traffic_uid_stats_map").exists();

// ...

}

// ...

@Override

public long getUidStats(int uid, int type) {

return nativeGetUidStat(uid, type, checkBpfStatsEnable());

}

private boolean checkBpfStatsEnable() {

return mUseBpfTrafficStats;

}

// ...

private static native long nativeGetUidStat(int uid, int type, boolean useBpfStats);

}

NetworkStatsService.getUidStats() 内部调用了本地方法 nativeGetUidStat().对应的类是 com_android_server_net_NetworkStatsService.cpp ,源码路径是

/frameworks/base/services/core/jni/com_android_server_net_NetworkStatsService.cpp

注意到调用 nativeGetUidStat() 时第二个参数是 checkBpfStatsEnable() 返回的 boolean 值.该方法的返回值是 mUseBpfTrafficStats ,且 mUseBpfTrafficStats 是在 NetworkStatsService 初始化的时候通过判断文件 /sys/fs/bpf/traffic_uid_stats_map 是否存在来初始化的.这个参数与 eBPF 流量监控有关,可以在 Android 开源项目 AOSP 官方文档eBPF 流量监控了解.

com_android_server_net_NetworkStatsService.cpp

首先看常量 QTAGUID_UID_STATS,由于我们是根据 Uid 查看流量的,所以本地方法会通过解析在系统路径 /proc/net/xt_qtaguid/ 下的 stats 文件来读取流量.

static const char* QTAGUID_UID_STATS = "/proc/net/xt_qtaguid/stats";

接着看 NetworkStatsService 本地方法 nativeGetUidStat 在 com_android_server_net_NetworkStatsService.cpp 中对应方法 getUidStat()

getUidStat()

// com_android_server_net_NetworkStatsService.cpp

static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type, jboolean useBpfStats) {

struct Stats stats;

// 初始化 stats

memset(&stats, 0, sizeof(Stats));

if (useBpfStats) {

if (bpfGetUidStats(uid, &stats) == 0) {

return getStatsType(&stats, (StatsType) type);

} else {

return UNKNOWN;

}

}

if (parseUidStats(uid, &stats) == 0) {

return getStatsType(&stats, (StatsType) type);

} else {

return UNKNOWN;

}

}

getUidStat() 首先根据 useBpfStats 决定调用 bpfGetUidStats() 还是 parseUidStats() 来获取流量统计数据并写入结构体 Stats 中,关于 BPF 的内容本文暂不关注,首先看结构体 Stats 的内容然后看 parseUidStats().

结构体 Stats

结构体 Stats 在头文件 BpfUtils 中, BpfUtils 在源码路径为

/system/netd/libbpf/include/bpf/BpfUtils.h

// BpfUtils.h

struct Stats {

uint64_t rxBytes;

uint64_t rxPackets;

uint64_t txBytes;

uint64_t txPackets;

uint64_t tcpRxPackets;

uint64_t tcpTxPackets;

};

parseUidStats()

// com_android_server_net_NetworkStatsService.cpp

static int parseUidStats(const uint32_t uid, struct Stats* stats) {

// proc/net/xt_qtaguid/stats

FILE *fp = fopen(QTAGUID_UID_STATS, "r");

if (fp == NULL) {

return -1;

}

char buffer[384];

char iface[32];

uint32_t idx, cur_uid, set;

uint64_t tag, rxBytes, rxPackets, txBytes, txPackets;

while (fgets(buffer, sizeof(buffer), fp) != NULL) {

if (sscanf(buffer,

"%" SCNu32 " %31s 0x%" SCNx64 " %u %u %" SCNu64 " %" SCNu64

" %" SCNu64 " %" SCNu64 "",

&idx, iface, &tag, &cur_uid, &set, &rxBytes, &rxPackets,

&txBytes, &txPackets) == 9) {

if (uid == cur_uid && tag == 0L) {

stats->rxBytes += rxBytes;

stats->rxPackets += rxPackets;

stats->txBytes += txBytes;

stats->txPackets += txPackets;

}

}

}

if (fclose(fp) != 0) {

return -1;

}

return 0;

}

首先通过 fopen 打开文件 /proc/net/xt_qtaguid/stats 获取 FILE 指针 *fp

然后从 *fp 中读取数据放到 buffer 中

调用 sscanf 读取 buffer 中的数据并写入结构体 stats

最后调用 fclose 关闭读取文件 stats 的流

我们先来看下 stats 文件的数据结构:

idx : 序号

iface : 代表流量类型(rmnet表示2G/3G, wlan表示Wifi流量,lo表示本地流量)

acct_tag_hex :线程标记(用于区分单个应用内不同模块/线程的流量)

uid_tag_int : 应用uid,据此判断是否是某应用统计的流量数据

cnt_set : 应用前后标志位:1:前台, 0:后台

rx_btyes : receive bytes 接受到的字节数

rx_packets : 接收到的任务包数

tx_bytes : transmit bytes 发送的总字节数

tx_packets : 发送的总包数

rx_tcp_types : 接收到的tcp字节数

rx_tcp_packets : 接收到的tcp包数

rx_udp_bytes : 接收到的udp字节数

rx_udp_packets : 接收到的udp包数

rx_other_bytes : 接收到的其他类型字节数

rx_other_packets : 接收到的其他类型包数

tx_tcp_bytes : 发送的tcp字节数

tx_tcp_packets : 发送的tcp包数

tx_udp_bytes : 发送的udp字节数

tx_udp_packets : 发送的udp包数

tx_other_bytes : 发送的其他类型字节数

tx_other_packets : 发送的其他类型包数

文件 stats 记录的数据类型还是挺多的,但从刚才第二步我们看到 parseUidStats() 只读前面九个类型,下面我用真机测试了一下并打印出 stats 文件并只截取我的测试 APP 即 UID 为 10279 的部分数据.

86 wlan0 0x0 10279 0 111013243 96471 4123723 64450 111007355 96447 5888 24 0 0 4119051 64426 4672 24 0 0

87 wlan0 0x0 10279 1 925202712 785236 32010086 529023 925186713 785149 13021 53 2978 34 31956732 528426 53354 597 0 0

92 wlan0 0xa00400000000 10279 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

93 wlan0 0xa00400000000 10279 1 1366 10 2264 8 1366 10 0 0 0 0 2264 8 0 0 0 0

94 wlan0 0xa00500000000 10279 0 96009 791 100452 798 96009 791 0 0 0 0 100452 798 0 0 0 0

95 wlan0 0xa00500000000 10279 1 217521 1791 228940 1828 217521 1791 0 0 0 0 228940 1828 0 0 0 0

214 lo 0x0 10279 0 4136 47 0 0 0 0 0 0 4136 47 0 0 0 0 0 0

215 lo 0x0 10279 1 3908 44 156 2 0 0 0 0 3908 44 0 0 156 2 0 0

218 lo 0xa00500000000 10279 0 88 1 0 0 0 0 0 0 88 1 0 0 0 0 0 0

219 lo 0xa00500000000 10279 1 352 4 0 0 0 0 0 0 352 4 0 0 0 0 0 0

从 stats 的数据结构可以看出一个 UID 记录流量区分主要通过流量类型iface、线程标记acct_tag_hex、前台或后台cnt_set来区分,其中 acct_tag_hex 为 0x0 时是记录该应用从上次开机以来所有接收的流量字节数.由于 parseUidStats() 是不需要区分前后端或者流量类型的,所以直接通过累加的方式把 acct_tag_hex 为 0x0 的所有数据都对应添加到结构体 stats 中即可.

现在阅读完 parseUidStats() 回到 getUidStat() 中.把数据写到结构体 Stats 后调用 getStatsType().

getStatsType()

// com_android_server_net_NetworkStatsService.cpp

static uint64_t getStatsType(struct Stats* stats, StatsType type) {

switch (type) {

case RX_BYTES:

return stats->rxBytes;

case RX_PACKETS:

return stats->rxPackets;

case TX_BYTES:

return stats->txBytes;

case TX_PACKETS:

return stats->txPackets;

case TCP_RX_PACKETS:

return stats->tcpRxPackets;

case TCP_TX_PACKETS:

return stats->tcpTxPackets;

default:

return UNKNOWN;

}

}

enum StatsType {

RX_BYTES = 0,

RX_PACKETS = 1,

TX_BYTES = 2,

TX_PACKETS = 3,

TCP_RX_PACKETS = 4,

TCP_TX_PACKETS = 5

};

getStatsType() 跟简单就是根据枚举 StatsType 的类型返回对应的值, StatsType 对应的就是上文 TrafficStats 的类型.

到这里我们简单了解 TrafficStats 如何读取系统文件得到应用的流量统计,对我们实现或者优化我们自己的流量监控机制有一个基本的概念.

参考资料

http://www.jmfq.cn/news/5068819.html

相关文章:

  • 网站制作公司信科网络/做网站建设优化的公司排名
  • 网站推广如何做/色盲色弱测试
  • 芜湖公司做网站/网上店铺的推广方法有哪些
  • wordpress推荐插件/最专业的seo公司
  • 广州有专做网站/域名信息查询网站
  • 如何制作网站后台/2022年明星百度指数排行
  • b站直播4000观看人数/外贸接单平台网站
  • 大城网站建设/seo投放是什么意思
  • 网站推广明细报价表/广东省各城市疫情搜索高峰进度
  • 建网站需要多久/长春seo整站优化
  • 网站开发设计素材/1个百度指数代表多少搜索
  • 静态网站如何做优化/百度app
  • 杭州手机网站制作电脑公司/怎么做关键词优化排名
  • 重庆便宜网站建设/中央新闻联播
  • 百度搜不到我的网站/网络营销专业是学什么的
  • 怎么用ps做网站ui/互联网营销方式有哪些
  • 网站做浏览器兼容/百度投流运营
  • 企业网站的作用/如何弄一个自己的网站
  • 青岛建设银行股份有限公司网站/百度seo工作室
  • 博物馆网站建设公司/郑州seo排名扣费
  • 胶南做网站/找客户的软件有哪些
  • 珠海响应式网站建设/网络营销推广活动有哪些
  • 香港主机做福彩网站/销售管理
  • 做网站网页的人是不是思维/竹子建站官网
  • 做网站公司多少钱/有没有购买链接
  • 网站后台图片滚动效果怎么做/网站建设制作过程
  • 做网站要营业执照吗/竞价托管公司
  • 织梦手机网站怎么安装/百度统计代码安装位置
  • 新闻网站建设意义/seo网站排名优化价格
  • 网站出现的问题/百度seo指南