FileDocCategorySizeDatePackage
UsageStatsService.javaAPI DocAndroid 5.1 API18339Thu Mar 12 22:22:42 GMT 2015com.android.server.usage

UsageStatsService

public class UsageStatsService extends com.android.server.SystemService implements UserUsageStatsService.StatsUpdatedListener
A service that collects, aggregates, and persists application usage data. This data can be queried by apps that have been granted permission by AppOps.

Fields Summary
static final String
TAG
static final boolean
DEBUG
private static final long
TEN_SECONDS
private static final long
TWENTY_MINUTES
private static final long
FLUSH_INTERVAL
private static final long
TIME_CHANGE_THRESHOLD_MILLIS
static final int
MSG_REPORT_EVENT
static final int
MSG_FLUSH_TO_DISK
static final int
MSG_REMOVE_USER
private final Object
mLock
android.os.Handler
mHandler
android.app.AppOpsManager
mAppOps
android.os.UserManager
mUserManager
private final android.util.SparseArray
mUserState
private File
mUsageStatsDir
long
mRealTimeSnapshot
long
mSystemTimeSnapshot
Constructors Summary
public UsageStatsService(android.content.Context context)


       
        super(context);
    
Methods Summary
private longcheckAndGetTimeLocked()
This should be the only way to get the time from the system.

        final long actualSystemTime = System.currentTimeMillis();
        final long actualRealtime = SystemClock.elapsedRealtime();
        final long expectedSystemTime = (actualRealtime - mRealTimeSnapshot) + mSystemTimeSnapshot;
        if (Math.abs(actualSystemTime - expectedSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) {
            // The time has changed.
            final int userCount = mUserState.size();
            for (int i = 0; i < userCount; i++) {
                final UserUsageStatsService service = mUserState.valueAt(i);
                service.onTimeChanged(expectedSystemTime, actualSystemTime);
            }
            mRealTimeSnapshot = actualRealtime;
            mSystemTimeSnapshot = actualSystemTime;
        }
        return actualSystemTime;
    
private voidcleanUpRemovedUsersLocked()

        final List<UserInfo> users = mUserManager.getUsers(true);
        if (users == null || users.size() == 0) {
            throw new IllegalStateException("There can't be no users");
        }

        ArraySet<String> toDelete = new ArraySet<>();
        String[] fileNames = mUsageStatsDir.list();
        if (fileNames == null) {
            // No users to delete.
            return;
        }

        toDelete.addAll(Arrays.asList(fileNames));

        final int userCount = users.size();
        for (int i = 0; i < userCount; i++) {
            final UserInfo userInfo = users.get(i);
            toDelete.remove(Integer.toString(userInfo.id));
        }

        final int deleteCount = toDelete.size();
        for (int i = 0; i < deleteCount; i++) {
            deleteRecursively(new File(mUsageStatsDir, toDelete.valueAt(i)));
        }
    
private voidconvertToSystemTimeLocked(UsageEvents.Event event)
Assuming the event's timestamp is measured in milliseconds since boot, convert it to a system wall time.

        event.mTimeStamp = Math.max(0, event.mTimeStamp - mRealTimeSnapshot) + mSystemTimeSnapshot;
    
private static voiddeleteRecursively(java.io.File f)

        File[] files = f.listFiles();
        if (files != null) {
            for (File subFile : files) {
                deleteRecursively(subFile);
            }
        }

        if (!f.delete()) {
            Slog.e(TAG, "Failed to delete " + f);
        }
    
voiddump(java.lang.String[] args, java.io.PrintWriter pw)
Called by the Binder stub.

        synchronized (mLock) {
            IndentingPrintWriter idpw = new IndentingPrintWriter(pw, "  ");
            ArraySet<String> argSet = new ArraySet<>();
            argSet.addAll(Arrays.asList(args));

            final int userCount = mUserState.size();
            for (int i = 0; i < userCount; i++) {
                idpw.printPair("user", mUserState.keyAt(i));
                idpw.println();
                idpw.increaseIndent();
                if (argSet.contains("--checkin")) {
                    mUserState.valueAt(i).checkin(idpw);
                } else {
                    mUserState.valueAt(i).dump(idpw);
                }
                idpw.decreaseIndent();
            }
        }
    
voidflushToDisk()
Called by the Binder stub.

        synchronized (mLock) {
            flushToDiskLocked();
        }
    
private voidflushToDiskLocked()

        final int userCount = mUserState.size();
        for (int i = 0; i < userCount; i++) {
            UserUsageStatsService service = mUserState.valueAt(i);
            service.persistActiveStats();
        }

        mHandler.removeMessages(MSG_FLUSH_TO_DISK);
    
private UserUsageStatsServicegetUserDataAndInitializeIfNeededLocked(int userId, long currentTimeMillis)

        UserUsageStatsService service = mUserState.get(userId);
        if (service == null) {
            service = new UserUsageStatsService(getContext(), userId,
                    new File(mUsageStatsDir, Integer.toString(userId)), this);
            service.init(currentTimeMillis);
            mUserState.put(userId, service);
        }
        return service;
    
public voidonStart()

        mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
        mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
        mHandler = new H(BackgroundThread.get().getLooper());

        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());
        }

        getContext().registerReceiver(new UserRemovedReceiver(),
                new IntentFilter(Intent.ACTION_USER_REMOVED));

        synchronized (mLock) {
            cleanUpRemovedUsersLocked();
        }

        mRealTimeSnapshot = SystemClock.elapsedRealtime();
        mSystemTimeSnapshot = System.currentTimeMillis();

        publishLocalService(UsageStatsManagerInternal.class, new LocalService());
        publishBinderService(Context.USAGE_STATS_SERVICE, new BinderService());
    
public voidonStatsUpdated()

        mHandler.sendEmptyMessageDelayed(MSG_FLUSH_TO_DISK, FLUSH_INTERVAL);
    
java.util.ListqueryConfigurationStats(int userId, int bucketType, long beginTime, long endTime)
Called by the Binder stub.

        synchronized (mLock) {
            final long timeNow = checkAndGetTimeLocked();
            if (!validRange(timeNow, beginTime, endTime)) {
                return null;
            }

            final UserUsageStatsService service =
                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
            return service.queryConfigurationStats(bucketType, beginTime, endTime);
        }
    
android.app.usage.UsageEventsqueryEvents(int userId, long beginTime, long endTime)
Called by the Binder stub.

        synchronized (mLock) {
            final long timeNow = checkAndGetTimeLocked();
            if (!validRange(timeNow, beginTime, endTime)) {
                return null;
            }

            final UserUsageStatsService service =
                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
            return service.queryEvents(beginTime, endTime);
        }
    
java.util.ListqueryUsageStats(int userId, int bucketType, long beginTime, long endTime)
Called by the Binder stub.

        synchronized (mLock) {
            final long timeNow = checkAndGetTimeLocked();
            if (!validRange(timeNow, beginTime, endTime)) {
                return null;
            }

            final UserUsageStatsService service =
                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
            return service.queryUsageStats(bucketType, beginTime, endTime);
        }
    
voidremoveUser(int userId)
Called by the Binder stub.

        synchronized (mLock) {
            Slog.i(TAG, "Removing user " + userId + " and all data.");
            mUserState.remove(userId);
            cleanUpRemovedUsersLocked();
        }
    
voidreportEvent(UsageEvents.Event event, int userId)
Called by the Binder stub.

        synchronized (mLock) {
            final long timeNow = checkAndGetTimeLocked();
            convertToSystemTimeLocked(event);

            final UserUsageStatsService service =
                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
            service.reportEvent(event);
        }
    
voidshutdown()
Called by the Binder stub

        synchronized (mLock) {
            mHandler.removeMessages(MSG_REPORT_EVENT);
            flushToDiskLocked();
        }
    
private static booleanvalidRange(long currentTime, long beginTime, long endTime)

        return beginTime <= currentTime && beginTime < endTime;