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.

[email protected]:/ # dumpsys usagestatsDate: 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 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.

Android Package的使用情况统计_第1张图片

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.



更多相关文章

  1. android 图片处理
  2. android 安卓 开发 图片库获得图片的绝对路径
  3. TableRow 背景问题以及修改对话框标题高度或者图片
  4. Android 把从网络获取的图片缓存到内存中
  5. Android 的网络编程(17)-android显示网络图片
  6. androidSDK下的图片资源
  7. 自定义RadioButton 文字在下,图片在上
  8. 自定义progressbar使用图片
  9. Shape实现圆形图片

随机推荐

  1. Linearlayout和relativeLayout的属性的一
  2. Android中的单元测试
  3. Android2.2 API 中文文档系列(3) —— Acce
  4. android 邮件开发(javax.mail)
  5. Android SDK Android NDK Android Studio
  6. Android(安卓)init.rc文件简单介绍
  7. Android 初级(待续)
  8. android 环境搭建
  9. android中ListView拖动时背景黑色的问题
  10. Android夜间模式实现