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

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 block
			e.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.<br>
	 */
	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.usageTime
				String 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"
<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集合,代码如下:

 

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<String, Map<String, Long>> 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) 

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


评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值