android本身有PkgUsageStats等相关类来统计应用使用情况,但这些类在SDK不公开,只能通过反射或者在源码环境下才能访问到。所以,针对这一特点,如果需要获取应用使用信息,可以采取反射或者源码下开发这两种方式。


1、在源码环境下(源码环境下可以访问一些标记为hide的方法),代码如下:
private void getPkgUsageStats()    {IUsageStats statsService = (IUsageStats) IUsageStats.Stub.asInterface(ServiceManager.getService("usagestats"));PkgUsageStats[] pkgStats = null;try {pkgStats = statsService.getAllPkgUsageStats();} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}if(pkgStats != null){StringBuffer sb = new StringBuffer();sb.append("nerver used : ");for(PkgUsageStats usageStats : pkgStats){String packageName = usageStats.packageName;int launchCount = usageStats.launchCount;long usageTime = usageStats.usageTime;if(launchCount > 0)Log.v("getPkgUsageStats",packageName + "  count: " + launchCount + "  time:  "+ usageTime);else{sb.append(packageName+" ");}}Log.v("getPkgUsageStats",sb.toString());}    }






2、通过反射来调用,代码如下:
/** * Use reflect to get Package Usage Statistics data.
*/public static void getPkgUsageStats() {LogUtils.d(TAG, "[getPkgUsageStats]");try {Class<?> cServiceManager = Class.forName("android.os.ServiceManager");Method mGetService = cServiceManager.getMethod("getService",java.lang.String.class);Object oRemoteService = mGetService.invoke(null, "usagestats");// IUsageStats oIUsageStats =// IUsageStats.Stub.asInterface(oRemoteService)Class<?> cStub = Class.forName("com.android.internal.app.IUsageStats$Stub");Method mUsageStatsService = cStub.getMethod("asInterface",android.os.IBinder.class);Object oIUsageStats = mUsageStatsService.invoke(null,oRemoteService);// PkgUsageStats[] oPkgUsageStatsArray =// mUsageStatsService.getAllPkgUsageStats();Class<?> cIUsageStatus = Class.forName("com.android.internal.app.IUsageStats");Method mGetAllPkgUsageStats = cIUsageStatus.getMethod("getAllPkgUsageStats", (Class[]) null);Object[] oPkgUsageStatsArray = (Object[]) mGetAllPkgUsageStats.invoke(oIUsageStats, (Object[]) null);LogUtils.d(TAG, "[getPkgUsageStats] oPkgUsageStatsArray = "+oPkgUsageStatsArray);Class<?> cPkgUsageStats = Class.forName("com.android.internal.os.PkgUsageStats");StringBuffer sb = new StringBuffer();sb.append("nerver used : ");for (Object pkgUsageStats : oPkgUsageStatsArray) {// get pkgUsageStats.packageName, pkgUsageStats.launchCount,// pkgUsageStats.usageTimeString packageName = (String) cPkgUsageStats.getDeclaredField("packageName").get(pkgUsageStats);int launchCount = cPkgUsageStats.getDeclaredField("launchCount").getInt(pkgUsageStats);long usageTime = cPkgUsageStats.getDeclaredField("usageTime").getLong(pkgUsageStats);if (launchCount > 0)LogUtils.d(TAG, "[getPkgUsageStats] "+ packageName + " count: "+ launchCount + " time: " + usageTime);else {sb.append(packageName + "; ");}}LogUtils.d(TAG, "[getPkgUsageStats] " + sb.toString());} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();}}




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



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集合,代码如下:

 

public PkgUsageStats[] getAllPkgUsageStats() {        mContext.enforceCallingOrSelfPermission(                android.Manifest.permission.PACKAGE_USAGE_STATS, null);        synchronized (mStatsLock) {            int size = mLastResumeTimes.size();            if (size <= 0) {                return null;            }            PkgUsageStats retArr[] = new PkgUsageStats[size];            int i = 0;            for (Map.Entry> entry : mLastResumeTimes.entrySet()) {                String pkg = entry.getKey();                long usageTime = 0;                int launchCount = 0;                 PkgUsageStatsExtended pus = mStats.get(pkg);                if (pus != null) {                    usageTime = pus.mUsageTime;                    launchCount = pus.mLaunchCount;                }                retArr[i] = new PkgUsageStats(pkg, launchCount, usageTime, entry.getValue());                i++;            }            return retArr;        }    }

 

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

public PkgUsageStats getPkgUsageStats(ComponentName componentName) 

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


更多相关文章

  1. 【Android】安卓AVD无法上网解决方案
  2. Android(安卓)从入门到资深学习路线
  3. android事件拦截处理机制图解
  4. android TIPS小结
  5. 浅谈Android程序与JavaScript脚本的交互
  6. 海神平台Crash监控SDK(Android)开发经验总结
  7. 斐波那契函数的优化
  8. Android(安卓)显示Intent和隐示Intent
  9. Android(安卓)AIDL远程调用

随机推荐

  1. android开发指南
  2. Android(安卓)Studio系列教程与技巧目录
  3. android驱动学习---led实验
  4. stagefright与opencore对比
  5. Theme(主题) Style(风格)
  6. Android的碎片fragment和activity之前的
  7. android 中JNI开发中如何使用Socket
  8. 自定义 Android Preference——SpinnerPr
  9. Android中的UI更新
  10. Android 迁移到 Androidx