Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Retrieving Application Launch Statistics and Usage Data on Android

Tech 1

The com.android.internal.os.PkgUsageStats class provides access to application launch counts and runtime statistics. Since this class is not part of the public SDK, direct usage requires either source-level access or reflection techniques.

For native Android development, the following approach demonstrates how to retrieve usage data:

import com.android.internal.app.IUsageStats;
import com.android.internal.os.PkgUsageStats;

public int compare(ApplicationInfo firstApp, ApplicationInfo secondApp) {
    ComponentName firstComponent = firstApp.intent.getComponent();
    ComponentName secondComponent = secondApp.intent.getComponent();
    int comparisonResult = 0;
    
    IUsageStats usageService = IUsageStats.Stub.asInterface(
        ServiceManager.getService("usagestats"));
    
    try {
        PkgUsageStats firstStats = usageService.getPkgUsageStats(firstComponent);
        PkgUsageStats secondStats = usageService.getPkgUsageStats(secondComponent);
        
        if (firstStats != null && secondStats != null) {
            if ((firstStats.launchCount > secondStats.launchCount) ||
                ((firstStats.launchCount == secondStats.launchCount) && 
                 (firstStats.usageTime > secondStats.usageTime))) {
                comparisonResult = -1;
            } else if ((firstStats.launchCount < secondStats.launchCount) ||
                      ((firstStats.launchCount == secondStats.launchCount) && 
                       (firstStats.usageTime < secondStats.usageTime))) {
                comparisonResult = 1;
            } else {
                comparisonResult = 0;
            }
        } else if (firstStats != null && secondStats == null) {
            comparisonResult = -1;
        } else if (firstStats == null && secondStats != null) {
            comparisonResult = 1;
        }
    } catch (RemoteException e) {
        Log.i("TAG", "Failed to retrieve usage statistics");
    }
    
    return comparisonResult;
}

When working within the SDK environment, reflection can be used to access these internal APIs:

public int compare(ApplicationInfo firstApp, ApplicationInfo secondApp) {
    ComponentName firstComponent = firstApp.intent.getComponent();
    ComponentName secondComponent = secondApp.intent.getComponent();
    int firstLaunchCount, secondLaunchCount;
    long firstUsageTime, secondUsageTime;
    int comparisonResult = 0;
    
    try {
        Class<?> serviceManager = Class.forName("android.os.ServiceManager");
        Method getService = serviceManager.getMethod("getService", String.class);
        Object remoteService = getService.invoke(null, "usagestats");
        
        Class<?> stubClass = Class.forName("com.android.internal.app.IUsageStats$Stub");
        Method asInterface = stubClass.getMethod("asInterface", IBinder.class);
        Object usageStatsInterface = asInterface.invoke(null, remoteService);
        
        Method getPkgUsageStats = usageStatsInterface.getClass().getMethod(
            "getPkgUsageStats", ComponentName.class);
        Object firstStats = getPkgUsageStats.invoke(usageStatsInterface, firstComponent);
        Object secondStats = getPkgUsageStats.invoke(usageStatsInterface, secondComponent);
        
        Class<?> pkgStatsClass = Class.forName("com.android.internal.os.PkgUsageStats");
        
        firstLaunchCount = pkgStatsClass.getDeclaredField("launchCount").getInt(firstStats);
        secondLaunchCount = pkgStatsClass.getDeclaredField("launchCount").getInt(secondStats);
        firstUsageTime = pkgStatsClass.getDeclaredField("usageTime").getLong(firstStats);
        secondUsageTime = pkgStatsClass.getDeclaredField("usageTime").getLong(secondStats);
        
        if ((firstLaunchCount > secondLaunchCount) ||
            ((firstLaunchCount == secondLaunchCount) && (firstUsageTime > secondUsageTime))) {
            comparisonResult = 1;
        } else if ((firstLaunchCount < secondLaunchCount) ||
                  ((firstLaunchCount == secondLaunchCount) && (firstUsageTime < secondUsageTime))) {
            comparisonResult = -1;
        } else {
            comparisonResult = 0;
        }
    } catch (Exception e) {
        Log.e("###", e.toString(), e);
    }
    
    return comparisonResult;
}

For end users seeking their own device usage analytics, Android provides built-in tools through engineering mode. On devices running Android 4.0, enter the dialer and input "##4636##" to access diagnostic menus. Within the menu, select "Usage statistics" to view application usage metrics including launch frequency and time spent.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.