Android Package的使用情况统计



In developing PhoneLab Conductor, I need to get various statistics about a installed package to determine if a app is actively used by participant. For example, for interactive apps, I’d like to know how many times the user launches the app, and how long user actively interact with the app. For background apps (e.g., data collection), I’d like to know how long the background service has been running.

There is this dumpsys tool in Android which will provide various information about the status of the system, including package statistics.

Here is the sample output.

root@android:/ # dumpsys usagestats
Date: 20140402
  com.android.launcher: 2 times, 43748 ms
    com.android.launcher2.Launcher: 2 starts
  com.tencent.mm: 1 times, 167750 ms
    com.tencent.mm.ui.chatting.ChattingUI: 4 starts, 1000-1500ms=2, 4000-5000ms=1
    com.tencent.mm.ui.tools.ImageGalleryUI: 1 starts, 250-500ms=1
    com.tencent.mm.ui.LauncherUI: 4 starts, 2000-3000ms=1
    com.tencent.mm.ui.friend.FMessageConversationUI: 1 starts, 250-500ms=1
  com.android.settings: 2 times, 93065 ms
    com.android.settings.Settings: 2 starts
    com.android.settings.SubSettings: 2 starts, 250-500ms=1, 500-750ms=2
  com.google.android.gm: 1 times, 11396 ms
    com.google.android.

 
 

At first glance, this is a perfect fit for my purpose. But there’re two problems.

  • This command needs to be run in shell. How can I get these information programatically using Java code? I definitely don’t want to execute this shell command and then parse its output.
  • Only interactive apps’ statistics are included. What about background apps which may don’t have an activity?

IUsageStats Service

After poking around Android Settings app’s source code, I found there is one internal interface called IUsageStats. It’s defined in framework/base/core/java/com/android/internal/app/IUsageStats.aidl inside AOSP tree. You can find it here

package com.android.internal.app;

import android.content.ComponentName;
import com.android.internal.os.PkgUsageStats;

interface IUsageStats {
    void noteResumeComponent(in ComponentName componentName);
    void notePauseComponent(in ComponentName componentName);
    void noteLaunchTime(in ComponentName componentName, int millis);
    PkgUsageStats getPkgUsageStats(in ComponentName componentName);
    PkgUsageStats[] getAllPkgUsageStats();
}

 
 

Where PkgUsageStats class is defined in framework/base/core/java/com/android/internal/os/PkgUsageStats.java link.

public class PkgUsageStats implements Parcelable {
    public String packageName;
    public int launchCount;
    public long usageTime;
    public Map<String, Long> componentResumeTimes;

    // other stuff...
}

 
 

It contains all the information I need about foreground apps!

Now is the problem of how to access the internal class and interface of Android. There’s plenty way to do this. Since I have aosp source tree at hand, I just copy those two files into my project. For PkgUsageStats, I also need to copy the aidl file (framework/base/core/java/com/android/internal/os/PkgUsageStats.aidl).

Here is the final directory structure of my src folder.

 
src/
|-- com
|   `-- android
|       `-- internal
|           |-- app
|           |   `-- IUsageStats.aidl
|           `-- os
|               |-- PkgUsageStats.aidl
|               `-- PkgUsageStats.java
`-- other stuff

Here is the code snippet that get the IUsageStats service.

 
private static final String SERVICE_MANAGER_CLASS = "android.os.ServiceManager";

try {
    Class serviceManager = Class.forName(SERVICE_MANAGER_CLASS);
    Method getService = serviceManager.getDeclaredMethod("getService", new Class[]{String.class});
    mUsageStatsService = IUsageStats.Stub.asInterface((IBinder)getService.invoke(null, "usagestats"));
}
catch (Exception e) {
    Log.e(TAG, "Failed to get service manager class: " + e);
    mUsageStatsService = null;
}

Here I use Java reflection to get the class of android.os.ServiceManager, which is also internal interface.

After that, you just get all the package statistics like so:

 
HashMap<String, PkgUsageStats> stats = new HashMap<String, PkgUsageStats>();
if (mUsageStatsService != null) {
    try {
        PkgUsageStats[] pkgUsageStats = mUsageStatsService.getAllPkgUsageStats();
        for (PkgUsageStats s : pkgUsageStats) {
            stats.put(s.packageName, s);
        }
    }
    catch (Exception e) {
        Log.e(TAG, "Failed to get package usage stats: " + e);
    }
}

Background Service Running Time

It seems that Settings->Apps->Running Apps are already showing the information that how long a process or service has been running.

After inspecting the source code of Settings app, I found that information is coming from ActivityManager.RunningServiceInfo. There is a field named activeSince, which is the time when the service was first made active.

=== UPDATE ===

It seems the reflection need system permission (I haven’t tested yet). Since we build our own platform, it’s not a problem–we just sign our apk with the platform key and declare our app’s user as system in AndroidManifest.xml.

转自:http://jhshi.me/2014/04/02/get-package-usage-statistics-in-android/

1
android:sharedUserId="android.uid.system"

But if you don’t have the platform key, then this approach probably won’t work. The other way I can think of is you run the dumpsys command and parse the output, but it still requites root permission.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值