1.概述
UsageStatsService 它是收集、聚合和保存应用程序使用数据的服务, 这些数据可以被 AppOps 授权的应用查询。源码路径 framework/base/services/usage/java/com/android/server/usage/下。
2.服务的启动
#我们只看关键代码和流程 #1 /frameworks/base/services/java/com/android/server/SystemServer.java /** * The main entry point from zygote. */ public static void main(String[] args) { new SystemServer().run(); } #2 private void run() { '''''''''''' // Start services. try { traceBeginAndSlog("StartServices"); startBootstrapServices(); startCoreServices(); // 在这个方法中启动UsageStatsService服务 startOtherServices(); SystemServerInitThreadPool.shutdown(); } catch (Throwable ex) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting system services", ex); throw ex; } finally { traceEnd(); } } #3 private void startCoreServices() { '''''''''''' // Tracks application usage stats. traceBeginAndSlog("StartUsageService"); mSystemServiceManager.startService(UsageStatsService.class); mActivityManagerService.setUsageStatsManager( LocalServices.getService(UsageStatsManagerInternal.class)); traceEnd(); .......... }
从上可以看出它是由系统SystemServer进程启动的,UsageStatsService 又是继承系统基类SystemService服务,接下来,在看看onStart()生命周期方法中的代码
# framework/base/services/usage/java/com/android/server/usage/UsageStatsService.java @Override public void onStart() { ''''''''''''' # 第一点 File systemDataDir = new File(Environment.getDataDirectory(), "system"); mUsageStatsDir = new File(systemDataDir, "usagestats"); mUsageStatsDir.mkdirs(); if (!mUsageStatsDir.exists()) { throw new IllegalStateException("Usage stats directory does not exist: " + mUsageStatsDir.getAbsolutePath()); } # 第二点 publishLocalService(UsageStatsMMOVE_TO_BACKGROUNDanagerInternal.class, new LocalService()); publishBinderService(Context.USAGE_STATS_SERVICE, new BinderService()); # 第三点 // Make sure we initialize the data, in case job scheduler needs it early. getUserDataAndInitializeIfNeededLocked(UserHandle.USER_SYSTEM, mSystemTimeSnapshot); '''''''''''' } # /frameworks/base/services/core/java/com/android/server/SystemService.java protected final void publishBinderService(String name, IBinder service, boolean allowIsolated, int dumpPriority) { ServiceManager.addService(name, service, allowIsolated, dumpPriority); }
第一点: 创建 data/system_ce/0/usagestats 文件夹,可以得知设备统计数据文件都是放到此目录下的
第二点: publishBinderService这个方法,就是 USS 向 ServiceManager 注册自己,这样子客户端通过 ServiceManager.getService(Context.USAGE_STATS_SERVICE) 就可以获取USS服务了。
第三点: 初始化UserUsageStatsService,每个用户(主用户,访客)的USS服务类,它是真正做事情的类,统计有Activity的启动和退出, Service启动和停止, 分享,锁屏,解锁,设备启动和关机等事件。
2.3 业务处理
# framework/base/services/usage/java/com/android/server/usage/UsageStatsService.java private static final long TWENTY_MINUTES = 20 * 60 * 1000; private static final long FLUSH_INTERVAL = COMPRESS_TIME ? TEN_SECONDS : TWENTY_MINUTES; @Override public void onStatsUpdated() { mHandler.sendEmptyMessageDelayed(MSG_FLUSH_TO_DISK, FLUSH_INTERVAL); } class H extends Handler { public H(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch (msg.what) { ........ case MSG_FLUSH_TO_DISK: flushToDisk(); break;
USS 每20分钟更新一次数据并存入到/data/system/usagestats/路径下的XML文件中,XML的所有操作,例如读,写等,都被封装在类UsageStatsXmlV2.java中,统一由UsageStatsDatabase去操作读写数据。
private void persistPendingEventsLocked(int userId) { final LinkedList<Event> pendingEvents = mReportedEvents.get(userId); if (pendingEvents == null || pendingEvents.isEmpty()) { return; } final File usageStatsDeDir = new File(Environment.getDataSystemDeDirectory(userId), "usagestats"); if (!usageStatsDeDir.mkdirs() && !usageStatsDeDir.exists()) { throw new IllegalStateException("Usage stats DE directory does not exist: " + usageStatsDeDir.getAbsolutePath()); } final File pendingEventsFile = new File(usageStatsDeDir, "pendingevents_" + System.currentTimeMillis()); final AtomicFile af = new AtomicFile(pendingEventsFile); FileOutputStream fos = null; try { fos = af.startWrite(); UsageStatsProtoV2.writePendingEvents(fos, pendingEvents); af.finishWrite(fos); fos = null; pendingEvents.clear(); } catch (Exception e) { Slog.e(TAG, "Failed to write " + pendingEventsFile.getAbsolutePath() + " for user " + userId); } finally { af.failWrite(fos); // when fos is null (successful write), this will no-op } }
3. UsageStatsManager
3.1 定义
提供对此设备的使用统计数据的访问。 使用数据的访问时间间隔可以用天、周、月和年。简单理解为客户端对象,用来和USS通信的对象,就好比 AcitivityManager 与 AMS 的关系。我们来看看类主要的方法:
方法 作用和用途
queryAndAggregateUsageStats(long beginTime, long endTime) 获取指定时间区间内使用统计数据,以应用包名为键值进行数据合并。
queryConfigurations(int intervalType, long beginTime, long endTime) 获取指定时间区间内硬件配置信息统计数据。
queryEventStats(int intervalType, long beginTime, long endTime) 获取指定时间区间内发生组件状态变化事件统计数据。
queryEvents(long beginTime, long endTime) 获取指定时间区间内组件状态变化事件
queryEventsForSelf(long beginTime, long endTime) 与queryEvents相似,获取指定时间区间内本应用的组件状态变化事件
queryUsageStats(int intervalType, long beginTime, long endTime 获取指定时间区间内应用使用统计数据。
queryEventStats和 queryUsageStats 这两个方法比较重要,与我们的需求强相关:
3.2 EventStats
它是在指定时间区间内某个类型事件统计数据的封装类,它有一个内部类Event类,这里面才是应用真正的事件统计信息. 我们可以去看看定义哪些事件类型变量:
/** * An event representing a state change for a component. */ public static final class Event { //Activity Resume 和 pause 事件 public static final int ACTIVITY_RESUMED= 1; public static final int ACTIVITY_PAUSED = 2; public static final int END_OF_DAY = 3; public static final int CONTINUE_PREVIOUS_DAY = 4; //设备configuration改变事件 public static final int CONFIGURATION_CHANGE = 5; //表示系统以某种方式与应用进行了交互的事件。 public static final int SYSTEM_INTERACTION = 6; //表示用户以某种方式与应用进行了交互的事件。 public static final int USER_INTERACTION = 7; //表示用户进行过快捷方式操作的事件 public static final int SHORTCUT_INVOCATION = 8; //表示用户为 ChooserActivity 选择了一个应用事件 public static final int CHOOSER_ACTION = 9; //用户查看了通知的事件类型 public static final int NOTIFICATION_SEEN = 10; // public static final int STANDBY_BUCKET_CHANGED = 11; //表示应用发布中断通知的事件类型。 public static final int NOTIFICATION_INTERRUPTION = 12; // public static final int SLICE_PINNED_PRIV = 13; public static final int SLICE_PINNED = 14; //表示屏幕已进入交互状态的事件 public static final int SCREEN_INTERACTIVE = 15; //表示屏幕处于非交互状态事件 public static final int SCREEN_NON_INTERACTIVE = 16; //设备锁屏事件 public static final int KEYGUARD_SHOWN = 17; //设备解锁事件 public static final int KEYGUARD_HIDDEN = 18; //启动一个前台service事件 public static final int FOREGROUND_SERVICE_START = 19; //停止一个前台service事件 public static final int FOREGROUND_SERVICE_STOP = 20; //表示前台服务在时间间隔开始时处于启动状态。 public static final int CONTINUING_FOREGROUND_SERVICE = 21; //表示当统计信息在时间间隔结束时翻转时前台服务处于启动状态。 public static final int ROLLOVER_FOREGROUND_SERVICE = 22; //Activity处于stopped 和 Destoryed 状态 public static final int ACTIVITY_STOPPED = 23; public static final int ACTIVITY_DESTROYED = 24; //表示更新数据到磁盘事件 public static final int FLUSH_TO_DISK = 25; // 设备启动和关机事件 public static final int DEVICE_SHUTDOWN = 26; public static final int DEVICE_STARTUP = 27; }
3.3 UsageStats
这个类包含针对特定时间范围的应用程序包的使用情况统计信息,这里面的数据就是我们需要的应用使用情况的统计信息,该类里面主要包含了五个方法分别是:
标签:int,UsageStatsService,long,public,详解,static,事件,final From: https://www.cnblogs.com/wanglongjiang/p/17223869.html