[android]获取各应用的启动次数和运行时间
16lz
2021-01-25
android本身有PkgUsageStats等相关类来统计应用使用情况,但这些类在SDK不公开,只能通过反射或者在源码环境下才能访问到。所以,针对这一特点,如果需要获取应用使用信息,可以采取反射或者源码下开发这两种方式。
1、在源码环境下(源码环境下可以访问一些标记为hide的方法),代码如下:
2、通过反射来调用,代码如下:
这是获取信息的两种实现方式,另外,要想让程序能够正常运行并成功获取到数据,我们还需要做如下的配置:
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
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"
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)
我们可以先获取当前系统所有安装包包名,再根据包名逐个通过此方法去获取对应包名的启动次数和运行时间。
更多相关文章
- 【Android】安卓AVD无法上网解决方案
- Android(安卓)从入门到资深学习路线
- android事件拦截处理机制图解
- android TIPS小结
- 浅谈Android程序与JavaScript脚本的交互
- 海神平台Crash监控SDK(Android)开发经验总结
- 斐波那契函数的优化
- Android(安卓)显示Intent和隐示Intent
- Android(安卓)AIDL远程调用