Android7.0 获取其他应用数据流量

1.背景
客户开发的第三方APP统计各个应用的数据流量,发现使用TraffficStats.getUidRxBytes(uid)和TraffficStats.getUidRxBytes(uid)结果值一直是0.

2.分析
首先看一下源码TraffficStats.java,位置/frameworks/base/core/java/android/net/

 /**
     * Return number of bytes received by the given UID since device boot.
     * Counts packets across all network interfaces, and always increases
     * monotonically since device boot. Statistics are measured at the network
     * layer, so they include both TCP and UDP usage.
     * <p>
     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return
     * {@link #UNSUPPORTED} on devices where statistics aren't available.
     * <p>
     * Starting in {@link android.os.Build.VERSION_CODES#N} this will only
     * report traffic statistics for the calling UID. It will return
     * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access
     * historical network statistics belonging to other UIDs, use
     * {@link NetworkStatsManager}.
     *
     * @see android.os.Process#myUid()
     * @see android.content.pm.ApplicationInfo#uid
     */
    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.
        final int callingUid = android.os.Process.myUid();
        if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
            return nativeGetUidStat(uid, TYPE_RX_BYTES);
        } else {
            return UNSUPPORTED;
        }
    }
  • 1

先看注释:To access historical network statistics belonging to other UIDs, use NetworkStatsManager
意思是如果要获取其他的UID的statistics,请时使用NetworkStatsManager(注意这是一个大坑,跟着注释就走到了NetworkStatsManager里面去了,于是给客户回应TraffficStats.getUidRxBytes只能获取自己应用本身的流量数据,结果。。。。)

  • 2

在分析代码,代码很简单。
a.先获取当前进程(UID),不是系统进程或者当前进程和要查询的UID不同的话就直接返回 UNSUPPORTED(-1)了,否则进进入nativeGetUidStat()方法.
b. nativeGetUidStat方法在android_net_TrafficStats.cpp中,此文件在frameworks\base\core\jni\下 ,为方便分析,我直接在代码里面加注释

static int parseUidStats(const uint32_t uid, struct Stats* stats) {
    FILE *fp = fopen(QTAGUID_UID_STATS, "r");
    //QTAGUID_UID_STATS="/proc/net/xt_qtaguid/stats"
    //这里直接打开/proc/net/xt_qtaguid/stats文件
    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) {
                //通过UID、tag过滤读的结果值
                stats->rxBytes += rxBytes;
                stats->rxPackets += rxPackets;
                stats->txBytes += txBytes;
                stats->txPackets += txPackets;
            }
        }
    }
    if (fclose(fp) != 0) {
        return -1;
    }
    return 0;
}

上面代码就是去读取/proc/net/xt_qtaguid/stats文件,然后根据条件过滤输出结果,那么这个文件到底有什么了?
这里写图片描述
我们看到第4、6、8列数据分别是uid,rx和tx,这里面的数据正是我们想要的

  • 3

代码分析完了,整个代码很清晰明了(除了那个注释),但这么简单的功能客户为什么说有问题了,起初怀疑客户应用不是系统应用,在TrafficStats.java中被直接拦截了,返回了UNSUPPORTED,后面看UNSUPPORTED结果值是-1而不是0,不信邪的我又写了一个系统app(什么是系统APP自行度娘)亲自测试,结果真的和客户说的一样,全部为0。难道真的如google所说需要NetworkStatsManager获取结果。

  • 4

不到长城非好汉,不撞南墙誓不回,我辈程序员的精神所在,在被这个问题折磨了半天,猛然间想起Android/linux下对文件的权限管理很严格,stats是一个文件,肯定存在权限管理的,于是 ls -ll
这里写图片描述
stats文件是属于net_bw_stats组,那只有添加net_bw_stats组的应用才能读取此文件。事情终于有一点转机了,那么我们怎么使我们的应用有net_bw_stats组的权限了,请看这篇博客这里写链接内容,写很详细,具体就是在/frameworks/base/data/etc/platform.xml 找到net_bw_stats组的权限

 <!-- Group that can read detailed network usage statistics -->
    <permission name="android.permission.READ_NETWORK_USAGE_HISTORY">
        <group gid="net_bw_stats" />
    </permission>

然后在manifest.xml文件中添加对应的permission权限,验证ok。

总结:这个问题分析完了,感觉很简单,就是缺个权限,但是google API上都没有说明,就需要自己去发现了,也说明API文档不是万能的(又在黑google了)。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值