[android]获取各应用的启动次数和运行时间

来源:互联网 发布:uc聊天软件 编辑:程序博客网 时间:2024/05/18 03:53
android本身有PkgUsageStats等相关类来统计应用使用情况,但这些类在SDK不公开,只能通过反射或者在源码环境下才能访问到。所以,针对这一特点,如果需要获取应用使用信息,可以采取反射或者源码下开发这两种方式。


1、在源码环境下(源码环境下可以访问一些标记为hide的方法),代码如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private void getPkgUsageStats()  
  2.     {  
  3.         IUsageStats statsService = (IUsageStats) IUsageStats.Stub.  
  4.                 asInterface(ServiceManager.getService("usagestats"));  
  5.           
  6.         PkgUsageStats[] pkgStats = null;  
  7.         try {  
  8.             pkgStats = statsService.getAllPkgUsageStats();  
  9.         } catch (RemoteException e) {  
  10.             // TODO Auto-generated catch block  
  11.             e.printStackTrace();  
  12.         }  
  13.           
  14.         if(pkgStats != null)  
  15.         {  
  16.             StringBuffer sb = new StringBuffer();  
  17.             sb.append("nerver used : ");  
  18.             for(PkgUsageStats usageStats : pkgStats)  
  19.             {  
  20.                 String packageName = usageStats.packageName;  
  21.                 int launchCount = usageStats.launchCount;  
  22.                 long usageTime = usageStats.usageTime;  
  23.                 if(launchCount > 0)  
  24.                     Log.v("getPkgUsageStats",packageName + "  count: " + launchCount + "  time:  "  
  25.                         + usageTime);  
  26.                 else{  
  27.                     sb.append(packageName+" ");  
  28.                 }  
  29.             }  
  30.   
  31.             Log.v("getPkgUsageStats",sb.toString());  
  32.         }  
  33.     }  






2、通过反射来调用,代码如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Use reflect to get Package Usage Statistics data.<br> 
  3.  */  
  4. public static void getPkgUsageStats() {  
  5.     LogUtils.d(TAG, "[getPkgUsageStats]");  
  6.     try {  
  7.         Class<?> cServiceManager = Class  
  8.                 .forName("android.os.ServiceManager");  
  9.         Method mGetService = cServiceManager.getMethod("getService",  
  10.                 java.lang.String.class);  
  11.         Object oRemoteService = mGetService.invoke(null"usagestats");  
  12.   
  13.         // IUsageStats oIUsageStats =  
  14.         // IUsageStats.Stub.asInterface(oRemoteService)  
  15.         Class<?> cStub = Class  
  16.                 .forName("com.android.internal.app.IUsageStats$Stub");  
  17.         Method mUsageStatsService = cStub.getMethod("asInterface",  
  18.                 android.os.IBinder.class);  
  19.         Object oIUsageStats = mUsageStatsService.invoke(null,  
  20.                 oRemoteService);  
  21.   
  22.         // PkgUsageStats[] oPkgUsageStatsArray =  
  23.         // mUsageStatsService.getAllPkgUsageStats();  
  24.         Class<?> cIUsageStatus = Class  
  25.                 .forName("com.android.internal.app.IUsageStats");  
  26.         Method mGetAllPkgUsageStats = cIUsageStatus.getMethod(  
  27.                 "getAllPkgUsageStats", (Class[]) null);  
  28.         Object[] oPkgUsageStatsArray = (Object[]) mGetAllPkgUsageStats  
  29.                 .invoke(oIUsageStats, (Object[]) null);  
  30.         LogUtils.d(TAG, "[getPkgUsageStats] oPkgUsageStatsArray = "+oPkgUsageStatsArray);  
  31.   
  32.         Class<?> cPkgUsageStats = Class  
  33.                 .forName("com.android.internal.os.PkgUsageStats");  
  34.   
  35.         StringBuffer sb = new StringBuffer();  
  36.         sb.append("nerver used : ");  
  37.         for (Object pkgUsageStats : oPkgUsageStatsArray) {  
  38.             // get pkgUsageStats.packageName, pkgUsageStats.launchCount,  
  39.             // pkgUsageStats.usageTime  
  40.             String packageName = (String) cPkgUsageStats.getDeclaredField(  
  41.                     "packageName").get(pkgUsageStats);  
  42.             int launchCount = cPkgUsageStats  
  43.                     .getDeclaredField("launchCount").getInt(pkgUsageStats);  
  44.             long usageTime = cPkgUsageStats.getDeclaredField("usageTime")  
  45.                     .getLong(pkgUsageStats);  
  46.             if (launchCount > 0)  
  47.                 LogUtils.d(TAG, "[getPkgUsageStats] "+ packageName + "  count: "  
  48.                         + launchCount + "  time:  " + usageTime);  
  49.             else {  
  50.                 sb.append(packageName + "; ");  
  51.             }  
  52.         }  
  53.         LogUtils.d(TAG, "[getPkgUsageStats] " + sb.toString());  
  54.     } catch (IllegalArgumentException e) {  
  55.         e.printStackTrace();  
  56.     } catch (IllegalAccessException e) {  
  57.         e.printStackTrace();  
  58.     } catch (InvocationTargetException e) {  
  59.         e.printStackTrace();  
  60.     } catch (NoSuchFieldException e) {  
  61.         e.printStackTrace();  
  62.     } catch (ClassNotFoundException e) {  
  63.         e.printStackTrace();  
  64.     } catch (NoSuchMethodException e) {  
  65.         e.printStackTrace();  
  66.     }  
  67. }  




这是获取信息的两种实现方式,另外,要想让程序能够正常运行并成功获取到数据,我们还需要做如下的配置:
1、在AndroidManifest.xml中增加android:sharedUserId="android.uid.system"
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.xxx"
    android:versionCode="1"
    android:versionName="1.0"
    android:sharedUserId="android.uid.system" >
还有权限的声明
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />


2、对apk进行系统签名,在源码中取platform.pk8、platform.x509.pem、signapk.jar文件并通过如下命令实现apk的签名
java -jar signapk.jar platform.x509.pem platform.pk8 unsigned.apk signed.apk

unsigned.apk为签名之前的apk,signed.apk为通过命令签名成功的apk


补充:

UsageStats信息通过UsageStatsService保存在路径data/system/usagestats目录下,在系统启动后,UsageStatsService服务开启,在该Service的构造函数中调用readStatsFromFile()方法从本地获取UsageStats信息,并保存到mStats成员变量中。(见源码UsageStatsService.java

我们通过getAllPkgUsageStats()方法来获取信息,但是该方法所返回的信息并非从文件中读取的全部数据,而是开机后启动过的apk集合,代码如下:

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public PkgUsageStats[] getAllPkgUsageStats() {  
  2.         mContext.enforceCallingOrSelfPermission(  
  3.                 android.Manifest.permission.PACKAGE_USAGE_STATS, null);  
  4.         synchronized (mStatsLock) {  
  5.             int size = mLastResumeTimes.size();  
  6.             if (size <= 0) {  
  7.                 return null;  
  8.             }  
  9.             PkgUsageStats retArr[] = new PkgUsageStats[size];  
  10.             int i = 0;  
  11.             for (Map.Entry<String, Map<String, Long>> entry : mLastResumeTimes.entrySet()) {  
  12.                 String pkg = entry.getKey();  
  13.                 long usageTime = 0;  
  14.                 int launchCount = 0;  
  15.    
  16.                 PkgUsageStatsExtended pus = mStats.get(pkg);  
  17.                 if (pus != null) {  
  18.                     usageTime = pus.mUsageTime;  
  19.                     launchCount = pus.mLaunchCount;  
  20.                 }  
  21.                 retArr[i] = new PkgUsageStats(pkg, launchCount, usageTime, entry.getValue());  
  22.                 i++;  
  23.             }  
  24.             return retArr;  
  25.         }  
  26.     }  

 

所以根据以上方法仅能获取开机后被启动过的apk信息集合,那如何获取所有apk的信息集合呢?该Service提供有另一个方法:

public PkgUsageStats getPkgUsageStats(ComponentName componentName) 

我们可以先获取当前系统所有安装包包名,再根据包名逐个通过此方法去获取对应包名的启动次数和运行时间。

0 0