首页 > 其他分享 >UsageStatsService详解

UsageStatsService详解

时间:2023-03-16 19:22:05浏览次数:37  
标签:int UsageStatsService long public 详解 static 事件 final

 

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

相关文章

  • 三、UserDetailsService详解
    当什么也没有配置的时候,账号和密码是由SpringSecurity定义生成的。而在实际项目中账号和密码都是从数据库中查询出来的。所以我们要通过自定义逻辑控制认证逻辑。​如......
  • 四、PasswordEncoder密码解析器详解
    ​ SpringSecurity要求容器中必须有PasswordEncoder实例。所以当自定义登录逻辑时要求必须给容器注入PaswordEncoder的bean对象1.接口介绍​encode():把参数按照特定......
  • 四、PasswordEncoder密码解析器详解
    ​ SpringSecurity要求容器中必须有PasswordEncoder实例。所以当自定义登录逻辑时要求必须给容器注入PaswordEncoder的bean对象1.接口介绍​encode():把参数按照特定......
  • SublimeREPL设置详解——实现代码传递(Eval in REPL)
    1.安装前题:安装packagecontrol,过程省略。windows10,python3.10(自定义的build),Sublimebuild4126。安装:packagecontrol安装sublimeREPL。2.测试2.1运行方......
  • Linux根目录详解
    /  根目录:根目录,文件的最顶端,整个文件系统的根目录/bin  用户二进制文件:存放系统所需的重要命令/sbin  系统二进制文件:存放一些系统管理的命令,一般只能由超级权......
  • wgcloud详解 - 初始添加ping监测正常,过一会又ping不通的问题
    WGCLOUD有个模块【PING监测】,可以监测各种网络设备、网关、链路是否能正常ping通,如果ping不通说明网络不通,或设备已经下线,系统会发送告警通知提醒我在刚开始添加PING监测后,......
  • 前端开发:JS中原型和原型链的使用详解
    前言在前端开发过程中,涉及到JS原理相关的内容也就是常用的几大模块,不仅常用而且很重要,但是涉及到原理的话会有点难懂,尤其是对JS接触不太久的开发者来讲。本篇博文就来分享一......
  • explain详解
    一、explain输出列ColumnMeaning意义idTheidentifierSELECTSELECT的序列号select_typeThetypeSELECTSELECT的类型tableThetablefortheoutput......
  • Mysql——事务隔离级别详解
        ......
  • MySQL三大日志——binlog、redo log和undo log详解
              ......