一次UsageStatsManager在UTC零点清零数据的Debug

在之前的项目里,我做过一款统计用户每天使用不同App的时长的app。然而因为一个UsageStatsManager里一个undocumented behavior导致大量的app usage丢失。


对于Lolipop之前的设备,这个app使用的是ActivityManager.getRecentTasks() 来获得前台app,每隔几秒就进行一次检测,一旦发现前台app改变,就产生一个session。对于Lolipop之后的设备,因为ActivityManager.getRecentTasks() 被deprecated了,所以转而使用UsageStatsManager.queryEvents(),每隔三个小时调用这个方法,计算session,然后上传给服务器。


在Google Play的review里,我们一直看到有用户抱怨自己上了两个小时facebook,结果到app里一看,什么数据都没记录。但是在实际测试中,从来未能reproduce这个bug,只有非常偶尔的日常使用中会出现,通过观察数据库里存储的event事件,发现只记录到该app的MOVE_TO_FOREGROUND事件,却没有相应的MOVE_TO_BACKGROUND,导致session长度为0。当时我们的猜想是,在后台记录app使用情况的service被系统kill了,然后内存中存储的events没来得及存进database就被关闭了。


根据这个猜想,数据丢失的情况应该只出现在Lolipop以下的系统,因为在Lolipop以上,这些events都被系统保存随时可以读取,而且时间分布应该比较平均,因为可以认为service被kill是一个随机事件。


然而当我们从数据库里调取这些数据来验证猜想的时候,发现情况并非如此。当我们调取一天中每个小时用户发送的session的数目并且绘制成图标的时候,发现Lolipop以下的设备的曲线图,和iOS的曲线图几乎一致,这意味着iOS用户和Android用户一天不同时段使用app的频率大致相同,白天多晚上少,休息时间多工作时间少。而Lolipop之后的用户在下午3点之前的三个小时有着显著的降低,而且越靠近3点,发送的session越少,3点之后迅速恢复正常。


当时我所在的城市是旧金山,下午3点正好是UTC的零点。等到过了Daytime Saving之后,整个图的趋势向右移了一个小时,从3点变成了4点。于是我们确定,这个问题和服务器无关,和手机有关,只发生在使用UsageStatsManager的设备上,而且在UTC零点的时候发生了一些事情导致session的丢失。


为了验证这个猜想,我们做了一个实验。从下午1点开始,到下午5点,每个小时开始后5分钟,使用10个app,每个app使用5分钟,然后读取log,看一共记录了多少个session,以及能从UsageStatsManager读到多少events。如果是UsageStatsManager在靠近UTC零点的时候因为某些原因无法正常工作记录events的话,我们应该能够从session和event的数量上看出一些问题。


结果出来了,session数一切正常,并没有发生靠近UTC零点的时候,session数目显著减少的情况。正当组里人叹气,认为方法不对导致没能重现这个bug的时候,我看了一眼4点钟从UsageStatsManager里读到的events,发现读到的第一个event的开始时间居然是当天的下午4:05。


然后这个谜题就解开了,原来是UsageStatsManager会在每天的UTC零点清除所有的events。我们的app每隔3个小时读取events,并且上传给服务器,如果这个读取上传的时机正好在UTC零点之后的话,那么因为无法读取UTC零点之前的events,导致session数目急剧减少,越靠近UTC零点的session有越高的概率丢失。


之所以我们的测试未能够reproduce这个bug,也是因为我们严格执行的测试计划,完美的绕开了这个坑,在下午3:55的时候打开了app,导致events都被flush进database而且sessions都被计算出来了。如果我们是4:00之后打开这个app的话,我们就能观测到3点到4点之间使用的所有的app都没有被记录。


看一眼Google的官方文档对UsageStatsManager.queryEvents()的描述:

“Query for events in the given time range. Events are only kept by the system for a few days.”

然而实际上events最多被保存一天,而且还不是从现在往前数的24小时,而是只保存现在到上一个UTC零点的events。


明白了这个道理,修复起来就简单了,要么在UTC零点之前的一两分钟wake up一下,计算一下sessions,要么提高计算sessions的频率。考虑到这个behavior并没有在官方文档上记载,我们选择了后者。发布了这个修复之后,Lolipop的app使用曲线和iOS完美重合了,证明这个修复确实有效。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值