Android 取得应用程序的启动次数和运行时间等信息

Android 取得应用程序的启动次数和运行时间等信息

使用情景:最近有个需求是统计后台应用运行时间,如果一个应用在后台运行超过一定时间就Kill掉进程,达到省电的目的。此时就可以使用PkgUsageStats这个类来实现啦! 通过com.android.internal.os.PkgUsageStats这个类可以得到一个应用程序的启动次数,运行时间等信息,功能强大,但是google并没有将这个类作为API接口提供给开发者,如果在android源码下开发,可以通过以下代码来使用这个类: import com.android.internal.app.IUsageStats; import com.android.internal.os.PkgUsageStats; //比较两个应用程序的启动次数和运行时间 public final int compare(ApplicationInfo a, ApplicationInfo b) { ComponentName aName = a.intent.getComponent(); ComponentName bName = b.intent.getComponent(); int result = 0; // get usagestats service IUsageStats mUsageStatsService = IUsageStats.Stub .asInterface(ServiceManager.getService("usagestats")); try { // get PkgUsageStats PkgUsageStats aStats = mUsageStatsService.getPkgUsageStats(aName); PkgUsageStats bStats = mUsageStatsService.getPkgUsageStats(bName); if (aStats != null && bStats != null) { if ((aStats.launchCount > bStats.launchCount) || ((aStats.launchCount == bStats.launchCount) && (aStats.usageTime > bStats.usageTime))) result = -1; else if ((aStats.launchCount < bStats.launchCount) || ((aStats.launchCount == bStats.launchCount) && (aStats.usageTime < bStats.usageTime))) result = 1; else { result = 0; } } else if (aStats != null && bStats == null) { result = -1; } else if (aStats == null && bStats != null) { result = 1; } } catch (RemoteException e) { Log.i("TAG", "get package usage stats fail"); } return result; } 那么如果想在sdk中使用这个 类要如果作呢--可以使用反射 的方法,代码如下: public final int compare(ApplicationInfo a, ApplicationInfo b) { ComponentName aName = a.intent.getComponent(); ComponentName bName = b.intent.getComponent(); int aLaunchCount, bLaunchCount; long aUseTime, bUseTime; int result = 0; try { // 获得ServiceManager类 Class ServiceManager = Class .forName("android.os.ServiceManager"); // 获得ServiceManager的getService方法 Method getService = ServiceManager.getMethod("getService", java.lang.String.class); // 调用getService获取RemoteService Object oRemoteService = getService.invoke(null, "usagestats"); // 获得IUsageStats.Stub类 Class cStub = Class .forName("com.android.internal.app.IUsageStats$Stub"); // 获得asInterface方法 Method asInterface = cStub.getMethod("asInterface", android.os.IBinder.class); // 调用asInterface方法获取IUsageStats对象 Object oIUsageStats = asInterface.invoke(null, oRemoteService); // 获得getPkgUsageStats(ComponentName)方法 Method getPkgUsageStats = oIUsageStats.getClass().getMethod( "getPkgUsageStats", ComponentName.class); // 调用getPkgUsageStats 获取PkgUsageStats对象 Object aStats = getPkgUsageStats.invoke(oIUsageStats, aName); Object bStats = getPkgUsageStats.invoke(oIUsageStats, bName); // 获得PkgUsageStats类 Class PkgUsageStats = Class .forName("com.android.internal.os.PkgUsageStats"); aLaunchCount = PkgUsageStats.getDeclaredField("launchCount") .getInt(aStats); bLaunchCount = PkgUsageStats.getDeclaredField("launchCount") .getInt(bStats); aUseTime = PkgUsageStats.getDeclaredField("usageTime").getLong( aStats); bUseTime = PkgUsageStats.getDeclaredField("usageTime").getLong( bStats); if ((aLaunchCount > bLaunchCount) || ((aLaunchCount == bLaunchCount) && (aUseTime > bUseTime))) result = 1; else if ((aLaunchCount < bLaunchCount) || ((aLaunchCount == bLaunchCount) && (aUseTime < bUseTime))) result = -1; else { result = 0; } } catch (Exception e) { Log.e("###", e.toString(), e); } return result; } 如何看自己的android的详细使用信息: 我们使用Andoroid手机时想看看自己的手机的使用情况,那么我们又如何去操作呢?也是必需得像程序这样要自己写一个程序才能查看吧,如果用户不是编程的,那得怎么办,呵,其实我们查看自己的手机使用详情是没有那么复杂的,今天androidkaifa.com就会大家说一下如何查询自己的手机的使用情况,下面是具体的查看方法, 其实查看方法非常简单,直接进入Android的工程模式即可,操作步骤如下:(笔者的android手机系统是4.2) 1、首先进入Android手机操作系统的拨号界面,直接输入“*#*#4636#*#*”(不加引号)即可以快速进入Android操作系统的工程测试模式。 2、在“测试”模式菜单中有手机信息“Phone information”、电池信息“Battery information”、WI-FI信息“WI-FI information”、使用状态“Usage statistics”四个选项。 3、我们点击选择第二项“Battery information”进入电池信息,然后就可以看到手机电池的详细信息了,其中包括电量等级、电池状态、温度、电池材质、电压等等信息。 4: 我们相应点击其实的选择就可以看到其实的相应的使用详细信息 ================================================================================================================== import com.android.internal.app.IUsageStats; import com.android.settings.R; import android.app.Activity; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; import com.android.internal.os.PkgUsageStats; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.Spinner; import android.widget.TextView; import android.widget.AdapterView.OnItemSelectedListener; /** * Activity to display package usage statistics. */ public class UsageStats extends Activity implements OnItemSelectedListener { private static final String TAG="UsageStatsActivity"; private static final boolean localLOGV = true; private Spinner mTypeSpinner; private ListView mListView; private IUsageStats mUsageStatsService; private LayoutInflater mInflater; private UsageStatsAdapter mAdapter; private PackageManager mPm; public static class AppNameComparator implements Comparator { Map mAppLabelList; AppNameComparator(Map appList) { mAppLabelList = appList; } public final int compare(PkgUsageStats a, PkgUsageStats b) { String alabel = mAppLabelList.get(a.packageName).toString(); String blabel = mAppLabelList.get(b.packageName).toString(); return alabel.compareTo(blabel); } } public static class LaunchCountComparator implements Comparator { public final int compare(PkgUsageStats a, PkgUsageStats b) { // return by descending order return b.launchCount - a.launchCount; } } public static class UsageTimeComparator implements Comparator { public final int compare(PkgUsageStats a, PkgUsageStats b) { long ret = a.usageTime-b.usageTime; if (ret == 0) { return 0; } if (ret < 0) { return 1; } return -1; } } // View Holder used when displaying views static class AppViewHolder { TextView pkgName; TextView launchCount; TextView usageTime; } class UsageStatsAdapter extends BaseAdapter { // Constants defining order for display order private static final int _DISPLAY_ORDER_USAGE_TIME = 0; private static final int _DISPLAY_ORDER_LAUNCH_COUNT = 1; private static final int _DISPLAY_ORDER_APP_NAME = 2; private int mDisplayOrder = _DISPLAY_ORDER_USAGE_TIME; private List mUsageStats; private LaunchCountComparator mLaunchCountComparator; private UsageTimeComparator mUsageTimeComparator; private AppNameComparator mAppLabelComparator; private HashMap mAppLabelMap; UsageStatsAdapter() { mUsageStats = new ArrayList(); mAppLabelMap = new HashMap(); PkgUsageStats[] stats; try { stats = mUsageStatsService.getAllPkgUsageStats(); } catch (RemoteException e) { Log.e(TAG, "Failed initializing usage stats service"); return; } if (stats == null) { return; } for (PkgUsageStats ps : stats) { mUsageStats.add(ps); // load application labels for each application CharSequence label; try { ApplicationInfo appInfo = mPm.getApplicationInfo(ps.packageName, 0); label = appInfo.loadLabel(mPm); } catch (NameNotFoundException e) { label = ps.packageName; } mAppLabelMap.put(ps.packageName, label); } // Sort list mLaunchCountComparator = new LaunchCountComparator(); mUsageTimeComparator = new UsageTimeComparator(); mAppLabelComparator = new AppNameComparator(mAppLabelMap); sortList(); } public int getCount() { return mUsageStats.size(); } public Object getItem(int position) { return mUsageStats.get(position); } public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { // A ViewHolder keeps references to children views to avoid unneccessary calls // to findViewById() on each row. AppViewHolder holder; // When convertView is not null, we can reuse it directly, there is no need // to reinflate it. We only inflate a new View when the convertView supplied // by ListView is null. if (convertView == null) { convertView = mInflater.inflate(R.layout.usage_stats_item, null); // Creates a ViewHolder and store references to the two children views // we want to bind data to. holder = new AppViewHolder(); holder.pkgName = (TextView) convertView.findViewById(R.id.package_name); holder.launchCount = (TextView) convertView.findViewById(R.id.launch_count); holder.usageTime = (TextView) convertView.findViewById(R.id.usage_time); convertView.setTag(holder); } else { // Get the ViewHolder back to get fast access to the TextView // and the ImageView. holder = (AppViewHolder) convertView.getTag(); } // Bind the data efficiently with the holder PkgUsageStats pkgStats = mUsageStats.get(position); if (pkgStats != null) { CharSequence label = mAppLabelMap.get(pkgStats.packageName); holder.pkgName.setText(label); holder.launchCount.setText(String.valueOf(pkgStats.launchCount)); holder.usageTime.setText(String.valueOf(pkgStats.usageTime)+" ms"); } else { Log.w(TAG, "No usage stats info for package:" + position); } return convertView; } void sortList(int sortOrder) { if (mDisplayOrder == sortOrder) { // do nothing return; } mDisplayOrder= sortOrder; sortList(); } private void sortList() { if (mDisplayOrder == _DISPLAY_ORDER_USAGE_TIME) { if (localLOGV) Log.i(TAG, "Sorting by usage time"); Collections.sort(mUsageStats, mUsageTimeComparator); } else if (mDisplayOrder == _DISPLAY_ORDER_LAUNCH_COUNT) { if (localLOGV) Log.i(TAG, "Sorting launch count"); Collections.sort(mUsageStats, mLaunchCountComparator); } else if (mDisplayOrder == _DISPLAY_ORDER_APP_NAME) { if (localLOGV) Log.i(TAG, "Sorting by application name"); Collections.sort(mUsageStats, mAppLabelComparator); } notifyDataSetChanged(); } } /** Called when the activity is first created. */ protected void onCreate(Bundle icicle) { super.onCreate(icicle); mUsageStatsService = IUsageStats.Stub.asInterface(ServiceManager.getService("usagestats")); if (mUsageStatsService == null) { Log.e(TAG, "Failed to retrieve usagestats service"); return; } mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); mPm = getPackageManager(); setContentView(R.layout.usage_stats); mTypeSpinner = (Spinner) findViewById(R.id.typeSpinner); mTypeSpinner.setOnItemSelectedListener(this); mListView = (ListView) findViewById(R.id.pkg_list); // Initialize the inflater mAdapter = new UsageStatsAdapter(); mListView.setAdapter(mAdapter); } public void onItemSelected(AdapterView parent, View view, int position, long id) { mAdapter.sortList(position); } public void onNothingSelected(AdapterView parent) { // do nothing } }

================================================================================

来源网络:

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

[java]

view plain

copy

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、通过反射来调用,代码如下:

[java]

view plain

copy

/** * 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.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"

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

[java]

view plain

copy

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)

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

相关推荐

NBA2K生涯模式十载回顾:从菜鸟到球星的篮球梦实现之路
买篮球应该去哪里试摸?
365bet客服

买篮球应该去哪里试摸?

📅 07-03 👁️ 1914
问道手游改5到改6要花多少钱?平民玩家省钱攻略与成本全解析
迎接4k时代 百度影棒3试用体验 彰显极清魅力