UsageStatsService.java revision 0a11e69428d4c00dfcb368c1eb4e60ad8e0dc918
1/**
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy
6 * of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16
17package com.android.server.usage;
18
19import android.Manifest;
20import android.app.ActivityManagerNative;
21import android.app.AppGlobals;
22import android.app.AppOpsManager;
23import android.app.admin.DevicePolicyManager;
24import android.app.usage.ConfigurationStats;
25import android.app.usage.IUsageStatsManager;
26import android.app.usage.UsageEvents;
27import android.app.usage.UsageEvents.Event;
28import android.app.usage.UsageStats;
29import android.app.usage.UsageStatsManagerInternal;
30import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
31import android.appwidget.AppWidgetManager;
32import android.content.BroadcastReceiver;
33import android.content.ComponentName;
34import android.content.Context;
35import android.content.Intent;
36import android.content.IntentFilter;
37import android.content.pm.PackageInfo;
38import android.content.pm.PackageManager;
39import android.content.pm.ParceledListSlice;
40import android.content.pm.UserInfo;
41import android.content.res.Configuration;
42import android.database.ContentObserver;
43import android.hardware.display.DisplayManager;
44import android.net.Uri;
45import android.os.BatteryManager;
46import android.os.Binder;
47import android.os.Environment;
48import android.os.Handler;
49import android.os.IDeviceIdleController;
50import android.os.Looper;
51import android.os.Message;
52import android.os.PowerManager;
53import android.os.Process;
54import android.os.RemoteException;
55import android.os.ServiceManager;
56import android.os.SystemClock;
57import android.os.UserHandle;
58import android.os.UserManager;
59import android.provider.Settings;
60import android.util.ArraySet;
61import android.util.AtomicFile;
62import android.util.Log;
63import android.util.Slog;
64import android.util.SparseArray;
65import android.view.Display;
66
67import com.android.internal.annotations.GuardedBy;
68import com.android.internal.os.BackgroundThread;
69import com.android.internal.util.IndentingPrintWriter;
70import com.android.server.DeviceIdleController;
71import com.android.server.SystemService;
72
73import java.io.BufferedReader;
74import java.io.File;
75import java.io.FileDescriptor;
76import java.io.FileOutputStream;
77import java.io.FileReader;
78import java.io.IOException;
79import java.io.PrintWriter;
80import java.util.ArrayList;
81import java.util.Arrays;
82import java.util.List;
83
84/**
85 * A service that collects, aggregates, and persists application usage data.
86 * This data can be queried by apps that have been granted permission by AppOps.
87 */
88public class UsageStatsService extends SystemService implements
89        UserUsageStatsService.StatsUpdatedListener {
90
91    static final String TAG = "UsageStatsService";
92
93    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
94
95    private static final long TEN_SECONDS = 10 * 1000;
96    private static final long ONE_MINUTE = 60 * 1000;
97    private static final long TWENTY_MINUTES = 20 * 60 * 1000;
98    private static final long FLUSH_INTERVAL = DEBUG ? TEN_SECONDS : TWENTY_MINUTES;
99    private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds.
100
101    static final long DEFAULT_APP_IDLE_THRESHOLD_MILLIS = DEBUG ? ONE_MINUTE * 4
102            : 1L * 24 * 60 * ONE_MINUTE; // 1 day
103    static final long DEFAULT_CHECK_IDLE_INTERVAL = DEBUG ? ONE_MINUTE / 4
104            : 8 * 60 * ONE_MINUTE; // 8 hours
105    static final long DEFAULT_PAROLE_INTERVAL = DEBUG ? ONE_MINUTE * 10
106            : 24 * 60 * ONE_MINUTE; // 24 hours between paroles
107    static final long DEFAULT_PAROLE_DURATION = DEBUG ? ONE_MINUTE
108            : 10 * ONE_MINUTE; // 10 minutes
109
110    // Handler message types.
111    static final int MSG_REPORT_EVENT = 0;
112    static final int MSG_FLUSH_TO_DISK = 1;
113    static final int MSG_REMOVE_USER = 2;
114    static final int MSG_INFORM_LISTENERS = 3;
115    static final int MSG_FORCE_IDLE_STATE = 4;
116    static final int MSG_CHECK_IDLE_STATES = 5;
117    static final int MSG_CHECK_PAROLE_TIMEOUT = 6;
118    static final int MSG_PAROLE_END_TIMEOUT = 7;
119
120    private final Object mLock = new Object();
121    Handler mHandler;
122    AppOpsManager mAppOps;
123    UserManager mUserManager;
124    AppWidgetManager mAppWidgetManager;
125    IDeviceIdleController mDeviceIdleController;
126    private DisplayManager mDisplayManager;
127    private PowerManager mPowerManager;
128
129    private final SparseArray<UserUsageStatsService> mUserState = new SparseArray<>();
130    private File mUsageStatsDir;
131    long mRealTimeSnapshot;
132    long mSystemTimeSnapshot;
133
134    boolean mAppIdleParoled;
135    private boolean mScreenOn;
136    private long mLastAppIdleParoledTime;
137    long mAppIdleDurationMillis;
138    long mCheckIdleIntervalMillis = DEFAULT_CHECK_IDLE_INTERVAL;
139    long mScreenOnTime;
140    long mScreenOnSystemTimeSnapshot;
141
142    @GuardedBy("mLock")
143    private AppIdleHistory mAppIdleHistory = new AppIdleHistory();
144
145    private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener>
146            mPackageAccessListeners = new ArrayList<>();
147
148    public UsageStatsService(Context context) {
149        super(context);
150    }
151
152    @Override
153    public void onStart() {
154        mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
155        mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
156
157        mHandler = new H(BackgroundThread.get().getLooper());
158
159        File systemDataDir = new File(Environment.getDataDirectory(), "system");
160        mUsageStatsDir = new File(systemDataDir, "usagestats");
161        mUsageStatsDir.mkdirs();
162        if (!mUsageStatsDir.exists()) {
163            throw new IllegalStateException("Usage stats directory does not exist: "
164                    + mUsageStatsDir.getAbsolutePath());
165        }
166
167        IntentFilter userActions = new IntentFilter(Intent.ACTION_USER_REMOVED);
168        userActions.addAction(Intent.ACTION_USER_STARTED);
169        getContext().registerReceiverAsUser(new UserActionsReceiver(), UserHandle.ALL, userActions,
170                null, null);
171
172        IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
173        deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
174        deviceStates.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
175        getContext().registerReceiver(new DeviceStateReceiver(), deviceStates);
176        synchronized (mLock) {
177            cleanUpRemovedUsersLocked();
178        }
179
180        mRealTimeSnapshot = SystemClock.elapsedRealtime();
181        mSystemTimeSnapshot = System.currentTimeMillis();
182        // Look at primary user's secure setting for this. TODO: Maybe apply different
183        // thresholds for different users.
184        mAppIdleDurationMillis = Settings.Secure.getLongForUser(getContext().getContentResolver(),
185                Settings.Secure.APP_IDLE_DURATION, DEFAULT_APP_IDLE_THRESHOLD_MILLIS,
186                UserHandle.USER_OWNER);
187
188        publishLocalService(UsageStatsManagerInternal.class, new LocalService());
189        publishBinderService(Context.USAGE_STATS_SERVICE, new BinderService());
190    }
191
192    @Override
193    public void onBootPhase(int phase) {
194        if (phase == PHASE_SYSTEM_SERVICES_READY) {
195            // Observe changes to the threshold
196            new SettingsObserver(mHandler).registerObserver();
197            mAppWidgetManager = getContext().getSystemService(AppWidgetManager.class);
198            mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
199                    ServiceManager.getService(DeviceIdleController.SERVICE_NAME));
200            mDisplayManager = (DisplayManager) getContext().getSystemService(
201                    Context.DISPLAY_SERVICE);
202            mPowerManager = getContext().getSystemService(PowerManager.class);
203
204            mScreenOnSystemTimeSnapshot = System.currentTimeMillis();
205            synchronized (this) {
206                mScreenOnTime = readScreenOnTimeLocked();
207            }
208            mDisplayManager.registerDisplayListener(mDisplayListener, null);
209            synchronized (this) {
210                updateDisplayLocked();
211            }
212        } else if (phase == PHASE_BOOT_COMPLETED) {
213            setAppIdleParoled(getContext().getSystemService(BatteryManager.class).isCharging());
214        }
215    }
216
217    private class UserActionsReceiver extends BroadcastReceiver {
218
219        @Override
220        public void onReceive(Context context, Intent intent) {
221            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
222            if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
223                if (userId >= 0) {
224                    mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget();
225                }
226            } else if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) {
227                if (userId >=0) {
228                    postCheckIdleStates();
229                }
230            }
231        }
232    }
233
234    private class DeviceStateReceiver extends BroadcastReceiver {
235        @Override
236        public void onReceive(Context context, Intent intent) {
237            final String action = intent.getAction();
238            if (BatteryManager.ACTION_CHARGING.equals(action)
239                    || BatteryManager.ACTION_DISCHARGING.equals(action)) {
240                setAppIdleParoled(BatteryManager.ACTION_CHARGING.equals(action));
241            } else if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
242                onDeviceIdleModeChanged();
243            }
244        }
245    }
246
247    private final DisplayManager.DisplayListener mDisplayListener
248            = new DisplayManager.DisplayListener() {
249
250        @Override public void onDisplayAdded(int displayId) {
251        }
252
253        @Override public void onDisplayRemoved(int displayId) {
254        }
255
256        @Override public void onDisplayChanged(int displayId) {
257            if (displayId == Display.DEFAULT_DISPLAY) {
258                synchronized (UsageStatsService.this.mLock) {
259                    updateDisplayLocked();
260                }
261            }
262        }
263    };
264
265    @Override
266    public void onStatsUpdated() {
267        mHandler.sendEmptyMessageDelayed(MSG_FLUSH_TO_DISK, FLUSH_INTERVAL);
268    }
269
270    private void cleanUpRemovedUsersLocked() {
271        final List<UserInfo> users = mUserManager.getUsers(true);
272        if (users == null || users.size() == 0) {
273            throw new IllegalStateException("There can't be no users");
274        }
275
276        ArraySet<String> toDelete = new ArraySet<>();
277        String[] fileNames = mUsageStatsDir.list();
278        if (fileNames == null) {
279            // No users to delete.
280            return;
281        }
282
283        toDelete.addAll(Arrays.asList(fileNames));
284
285        final int userCount = users.size();
286        for (int i = 0; i < userCount; i++) {
287            final UserInfo userInfo = users.get(i);
288            toDelete.remove(Integer.toString(userInfo.id));
289        }
290
291        final int deleteCount = toDelete.size();
292        for (int i = 0; i < deleteCount; i++) {
293            deleteRecursively(new File(mUsageStatsDir, toDelete.valueAt(i)));
294        }
295    }
296
297    /** Paroled here means temporary pardon from being inactive */
298    void setAppIdleParoled(boolean paroled) {
299        synchronized (mLock) {
300            if (mAppIdleParoled != paroled) {
301                mAppIdleParoled = paroled;
302                if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleParoled);
303                if (paroled) {
304                    mLastAppIdleParoledTime = checkAndGetTimeLocked();
305                    postNextParoleTimeout();
306                }
307                postCheckIdleStates();
308            }
309        }
310    }
311
312    private void postNextParoleTimeout() {
313        if (DEBUG) Slog.d(TAG, "Posting MSG_CHECK_PAROLE_TIMEOUT");
314        mHandler.removeMessages(MSG_CHECK_PAROLE_TIMEOUT);
315        // Compute when the next parole needs to happen. We check more frequently than necessary
316        // since the message handler delays are based on elapsedRealTime and not wallclock time.
317        // The comparison is done in wallclock time.
318        long timeLeft = (mLastAppIdleParoledTime + DEFAULT_PAROLE_INTERVAL)
319                - checkAndGetTimeLocked();
320        if (timeLeft < 0) {
321            timeLeft = 0;
322        }
323        mHandler.sendEmptyMessageDelayed(MSG_CHECK_PAROLE_TIMEOUT, timeLeft / 10);
324    }
325
326    private void postParoleEndTimeout() {
327        if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_END_TIMEOUT");
328        mHandler.removeMessages(MSG_PAROLE_END_TIMEOUT);
329        mHandler.sendEmptyMessageDelayed(MSG_PAROLE_END_TIMEOUT, DEFAULT_PAROLE_DURATION);
330    }
331
332    void postCheckIdleStates() {
333        mHandler.removeMessages(MSG_CHECK_IDLE_STATES);
334        mHandler.sendEmptyMessage(MSG_CHECK_IDLE_STATES);
335    }
336
337    /** Check all running users' apps to see if they enter an idle state. */
338    void checkIdleStates() {
339        final int[] runningUsers;
340        try {
341            runningUsers = ActivityManagerNative.getDefault().getRunningUserIds();
342        } catch (RemoteException re) {
343            return;
344        }
345
346        for (int i = 0; i < runningUsers.length; i++) {
347            final int userId = runningUsers[i];
348            List<PackageInfo> packages =
349                    getContext().getPackageManager().getInstalledPackages(
350                            PackageManager.GET_DISABLED_COMPONENTS
351                                | PackageManager.GET_UNINSTALLED_PACKAGES,
352                            userId);
353            synchronized (mLock) {
354                final long timeNow = checkAndGetTimeLocked();
355                final int packageCount = packages.size();
356                for (int p = 0; p < packageCount; p++) {
357                    final String packageName = packages.get(p).packageName;
358                    final boolean isIdle = isAppIdleFiltered(packageName, userId);
359                    mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
360                            userId, isIdle ? 1 : 0, packageName));
361                    mAppIdleHistory.addEntry(packageName, userId, isIdle, timeNow);
362                }
363            }
364        }
365        mHandler.sendEmptyMessageDelayed(MSG_CHECK_IDLE_STATES, mCheckIdleIntervalMillis);
366    }
367
368    /** Check if it's been a while since last parole and let idle apps do some work */
369    void checkParoleTimeout() {
370        synchronized (mLock) {
371            if (!mAppIdleParoled) {
372                final long timeSinceLastParole = checkAndGetTimeLocked() - mLastAppIdleParoledTime;
373                if (timeSinceLastParole > DEFAULT_PAROLE_INTERVAL) {
374                    if (DEBUG) Slog.d(TAG, "Crossed default parole interval");
375                    setAppIdleParoled(true);
376                    // Make sure it ends at some point
377                    postParoleEndTimeout();
378                } else {
379                    if (DEBUG) Slog.d(TAG, "Not long enough to go to parole");
380                    postNextParoleTimeout();
381                }
382            }
383        }
384    }
385
386    void updateDisplayLocked() {
387        boolean screenOn = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY).getState()
388                != Display.STATE_OFF;
389        if (screenOn == mScreenOn) return;
390
391        mScreenOn = screenOn;
392        long now = System.currentTimeMillis();
393        if (mScreenOn) {
394            mScreenOnSystemTimeSnapshot = now;
395        } else {
396            mScreenOnTime += now - mScreenOnSystemTimeSnapshot;
397            writeScreenOnTimeLocked(mScreenOnTime);
398        }
399    }
400
401    private long getScreenOnTimeLocked(long now) {
402        if (mScreenOn) {
403            return now - mScreenOnSystemTimeSnapshot + mScreenOnTime;
404        } else {
405            return mScreenOnTime;
406        }
407    }
408
409    private File getScreenOnTimeFile() {
410        return new File(mUsageStatsDir, UserHandle.USER_OWNER + "/screen_on_time");
411    }
412
413    private long readScreenOnTimeLocked() {
414        long screenOnTime = 0;
415        File screenOnTimeFile = getScreenOnTimeFile();
416        if (screenOnTimeFile.exists()) {
417            try {
418                BufferedReader reader = new BufferedReader(new FileReader(screenOnTimeFile));
419                screenOnTime = Long.parseLong(reader.readLine());
420                reader.close();
421            } catch (IOException | NumberFormatException e) {
422            }
423        } else {
424            writeScreenOnTimeLocked(screenOnTime);
425        }
426        return screenOnTime;
427    }
428
429    private void writeScreenOnTimeLocked(long screenOnTime) {
430        AtomicFile screenOnTimeFile = new AtomicFile(getScreenOnTimeFile());
431        FileOutputStream fos = null;
432        try {
433            fos = screenOnTimeFile.startWrite();
434            fos.write(Long.toString(screenOnTime).getBytes());
435            screenOnTimeFile.finishWrite(fos);
436        } catch (IOException ioe) {
437            screenOnTimeFile.failWrite(fos);
438        }
439    }
440
441    void onDeviceIdleModeChanged() {
442        final boolean deviceIdle = mPowerManager.isDeviceIdleMode();
443        if (DEBUG) Slog.i(TAG, "DeviceIdleMode changed to " + deviceIdle);
444        synchronized (mLock) {
445            final long timeSinceLastParole = checkAndGetTimeLocked() - mLastAppIdleParoledTime;
446            if (!deviceIdle
447                    && timeSinceLastParole >= DEFAULT_PAROLE_INTERVAL) {
448                if (DEBUG) Slog.i(TAG, "Bringing idle apps out of inactive state due to deviceIdleMode=false");
449                postNextParoleTimeout();
450                setAppIdleParoled(true);
451            } else if (deviceIdle) {
452                if (DEBUG) Slog.i(TAG, "Device idle, back to prison");
453                setAppIdleParoled(false);
454            }
455        }
456    }
457
458    private static void deleteRecursively(File f) {
459        File[] files = f.listFiles();
460        if (files != null) {
461            for (File subFile : files) {
462                deleteRecursively(subFile);
463            }
464        }
465
466        if (!f.delete()) {
467            Slog.e(TAG, "Failed to delete " + f);
468        }
469    }
470
471    private UserUsageStatsService getUserDataAndInitializeIfNeededLocked(int userId,
472            long currentTimeMillis) {
473        UserUsageStatsService service = mUserState.get(userId);
474        if (service == null) {
475            service = new UserUsageStatsService(getContext(), userId,
476                    new File(mUsageStatsDir, Integer.toString(userId)), this);
477            service.init(currentTimeMillis, getScreenOnTimeLocked(currentTimeMillis));
478            mUserState.put(userId, service);
479        }
480        return service;
481    }
482
483    /**
484     * This should be the only way to get the time from the system.
485     */
486    private long checkAndGetTimeLocked() {
487        final long actualSystemTime = System.currentTimeMillis();
488        final long actualRealtime = SystemClock.elapsedRealtime();
489        final long expectedSystemTime = (actualRealtime - mRealTimeSnapshot) + mSystemTimeSnapshot;
490        boolean resetBeginIdleTime = false;
491        if (Math.abs(actualSystemTime - expectedSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) {
492            // The time has changed.
493
494            // Check if it's severe enough a change to reset screenOnTime
495            if (Math.abs(actualSystemTime - expectedSystemTime) > mAppIdleDurationMillis) {
496                mScreenOnSystemTimeSnapshot = actualSystemTime;
497                mScreenOnTime = 0;
498                resetBeginIdleTime = true;
499            }
500            final int userCount = mUserState.size();
501            for (int i = 0; i < userCount; i++) {
502                final UserUsageStatsService service = mUserState.valueAt(i);
503                service.onTimeChanged(expectedSystemTime, actualSystemTime, resetBeginIdleTime);
504            }
505            mRealTimeSnapshot = actualRealtime;
506            mSystemTimeSnapshot = actualSystemTime;
507        }
508        return actualSystemTime;
509    }
510
511    /**
512     * Assuming the event's timestamp is measured in milliseconds since boot,
513     * convert it to a system wall time.
514     */
515    private void convertToSystemTimeLocked(UsageEvents.Event event) {
516        event.mTimeStamp = Math.max(0, event.mTimeStamp - mRealTimeSnapshot) + mSystemTimeSnapshot;
517    }
518
519    /**
520     * Called by the Binder stub
521     */
522    void shutdown() {
523        synchronized (mLock) {
524            mHandler.removeMessages(MSG_REPORT_EVENT);
525            flushToDiskLocked();
526        }
527    }
528
529    /**
530     * Called by the Binder stub.
531     */
532    void reportEvent(UsageEvents.Event event, int userId) {
533        synchronized (mLock) {
534            final long timeNow = checkAndGetTimeLocked();
535            convertToSystemTimeLocked(event);
536
537            final UserUsageStatsService service =
538                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
539            final long lastUsed = service.getBeginIdleTime(event.mPackage);
540            final long screenOnTime = getScreenOnTimeLocked(timeNow);
541            final boolean previouslyIdle = hasPassedIdleTimeout(lastUsed, screenOnTime);
542            service.reportEvent(event, screenOnTime);
543            // Inform listeners if necessary
544            if ((event.mEventType == Event.MOVE_TO_FOREGROUND
545                    || event.mEventType == Event.MOVE_TO_BACKGROUND
546                    || event.mEventType == Event.INTERACTION)) {
547                if (previouslyIdle) {
548                    // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
549                    mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
550                            /* idle = */ 0, event.mPackage));
551                    mAppIdleHistory.addEntry(event.mPackage, userId, false, timeNow);
552                }
553            }
554        }
555    }
556
557    /**
558     * Forces the app's beginIdleTime to reflect idle or active. If idle, then it rolls back the
559     * beginIdleTime to a point in time thats behind the threshold for idle.
560     */
561    void forceIdleState(String packageName, int userId, boolean idle) {
562        synchronized (mLock) {
563            final long timeNow = checkAndGetTimeLocked();
564            final long screenOnTime = getScreenOnTimeLocked(timeNow);
565            final long deviceUsageTime = screenOnTime - (idle ? mAppIdleDurationMillis : 0) - 5000;
566
567            final UserUsageStatsService service =
568                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
569            final long lastUsed = service.getBeginIdleTime(packageName);
570            final boolean previouslyIdle = hasPassedIdleTimeout(lastUsed,
571                    getScreenOnTimeLocked(timeNow));
572            service.setBeginIdleTime(packageName, deviceUsageTime);
573            // Inform listeners if necessary
574            if (previouslyIdle != idle) {
575                // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
576                mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
577                        /* idle = */ idle ? 1 : 0, packageName));
578                mAppIdleHistory.addEntry(packageName, userId, idle, timeNow);
579            }
580        }
581    }
582
583    /**
584     * Called by the Binder stub.
585     */
586    void flushToDisk() {
587        synchronized (mLock) {
588            flushToDiskLocked();
589        }
590    }
591
592    /**
593     * Called by the Binder stub.
594     */
595    void removeUser(int userId) {
596        synchronized (mLock) {
597            Slog.i(TAG, "Removing user " + userId + " and all data.");
598            mUserState.remove(userId);
599            cleanUpRemovedUsersLocked();
600        }
601    }
602
603    /**
604     * Called by the Binder stub.
605     */
606    List<UsageStats> queryUsageStats(int userId, int bucketType, long beginTime, long endTime) {
607        synchronized (mLock) {
608            final long timeNow = checkAndGetTimeLocked();
609            if (!validRange(timeNow, beginTime, endTime)) {
610                return null;
611            }
612
613            final UserUsageStatsService service =
614                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
615            return service.queryUsageStats(bucketType, beginTime, endTime);
616        }
617    }
618
619    /**
620     * Called by the Binder stub.
621     */
622    List<ConfigurationStats> queryConfigurationStats(int userId, int bucketType, long beginTime,
623            long endTime) {
624        synchronized (mLock) {
625            final long timeNow = checkAndGetTimeLocked();
626            if (!validRange(timeNow, beginTime, endTime)) {
627                return null;
628            }
629
630            final UserUsageStatsService service =
631                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
632            return service.queryConfigurationStats(bucketType, beginTime, endTime);
633        }
634    }
635
636    /**
637     * Called by the Binder stub.
638     */
639    UsageEvents queryEvents(int userId, long beginTime, long endTime) {
640        synchronized (mLock) {
641            final long timeNow = checkAndGetTimeLocked();
642            if (!validRange(timeNow, beginTime, endTime)) {
643                return null;
644            }
645
646            final UserUsageStatsService service =
647                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
648            return service.queryEvents(beginTime, endTime);
649        }
650    }
651
652    private boolean isAppIdleUnfiltered(String packageName, int userId) {
653        synchronized (mLock) {
654            final long timeNow = checkAndGetTimeLocked();
655            final UserUsageStatsService service =
656                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
657            long beginIdleTime = service.getBeginIdleTime(packageName);
658            return hasPassedIdleTimeout(beginIdleTime, getScreenOnTimeLocked(timeNow));
659        }
660    }
661
662    /**
663     * @param timestamp when the app was last used in device usage timebase
664     * @param currentTime current time in device usage timebase
665     * @return whether it's been used far enough in the past to be considered inactive
666     */
667    boolean hasPassedIdleTimeout(long timestamp, long currentTime) {
668        return timestamp <= currentTime - mAppIdleDurationMillis;
669    }
670
671    void addListener(AppIdleStateChangeListener listener) {
672        synchronized (mLock) {
673            if (!mPackageAccessListeners.contains(listener)) {
674                mPackageAccessListeners.add(listener);
675            }
676        }
677    }
678
679    void removeListener(AppIdleStateChangeListener listener) {
680        synchronized (mLock) {
681            mPackageAccessListeners.remove(listener);
682        }
683    }
684
685    /**
686     * Checks if an app has been idle for a while and filters out apps that are excluded.
687     * It returns false if the current system state allows all apps to be considered active.
688     * This happens if the device is plugged in or temporarily allowed to make exceptions.
689     * Called by interface impls.
690     */
691    boolean isAppIdleFiltered(String packageName, int userId) {
692        if (packageName == null) return false;
693        synchronized (mLock) {
694            // Temporary exemption, probably due to device charging or occasional allowance to
695            // be allowed to sync, etc.
696            if (mAppIdleParoled) {
697                return false;
698            }
699        }
700        if (packageName.equals("android")) return false;
701        try {
702            if (mDeviceIdleController.isPowerSaveWhitelistApp(packageName)) {
703                return false;
704            }
705        } catch (RemoteException re) {
706        }
707        // TODO: Optimize this check
708        if (isActiveDeviceAdmin(packageName, userId)) {
709            return false;
710        }
711
712        if (mAppWidgetManager != null
713                && mAppWidgetManager.isBoundWidgetPackage(packageName, userId)) {
714            return false;
715        }
716
717        return isAppIdleUnfiltered(packageName, userId);
718    }
719
720    void setAppIdle(String packageName, boolean idle, int userId) {
721        if (packageName == null) return;
722
723        mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName)
724                .sendToTarget();
725    }
726
727    private boolean isActiveDeviceAdmin(String packageName, int userId) {
728        DevicePolicyManager dpm = getContext().getSystemService(DevicePolicyManager.class);
729        if (dpm == null) return false;
730        List<ComponentName> components = dpm.getActiveAdminsAsUser(userId);
731        if (components == null) return false;
732        final int size = components.size();
733        for (int i = 0; i < size; i++) {
734            if (components.get(i).getPackageName().equals(packageName)) {
735                return true;
736            }
737        }
738        return false;
739    }
740
741    void informListeners(String packageName, int userId, boolean isIdle) {
742        for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
743            listener.onAppIdleStateChanged(packageName, userId, isIdle);
744        }
745    }
746
747    private static boolean validRange(long currentTime, long beginTime, long endTime) {
748        return beginTime <= currentTime && beginTime < endTime;
749    }
750
751    private void flushToDiskLocked() {
752        final int userCount = mUserState.size();
753        for (int i = 0; i < userCount; i++) {
754            UserUsageStatsService service = mUserState.valueAt(i);
755            service.persistActiveStats();
756        }
757
758        mHandler.removeMessages(MSG_FLUSH_TO_DISK);
759    }
760
761    /**
762     * Called by the Binder stub.
763     */
764    void dump(String[] args, PrintWriter pw) {
765        synchronized (mLock) {
766            final long screenOnTime = getScreenOnTimeLocked(checkAndGetTimeLocked());
767            IndentingPrintWriter idpw = new IndentingPrintWriter(pw, "  ");
768            ArraySet<String> argSet = new ArraySet<>();
769            argSet.addAll(Arrays.asList(args));
770
771            final int userCount = mUserState.size();
772            for (int i = 0; i < userCount; i++) {
773                idpw.printPair("user", mUserState.keyAt(i));
774                idpw.println();
775                idpw.increaseIndent();
776                if (argSet.contains("--checkin")) {
777                    mUserState.valueAt(i).checkin(idpw, screenOnTime);
778                } else {
779                    mUserState.valueAt(i).dump(idpw, screenOnTime);
780                    idpw.println();
781                    if (args.length > 0 && "history".equals(args[0])) {
782                        mAppIdleHistory.dump(idpw, mUserState.keyAt(i));
783                    }
784                }
785                idpw.decreaseIndent();
786            }
787            pw.write("Screen On Timebase:" + mScreenOnTime + "\n");
788        }
789    }
790
791    class H extends Handler {
792        public H(Looper looper) {
793            super(looper);
794        }
795
796        @Override
797        public void handleMessage(Message msg) {
798            switch (msg.what) {
799                case MSG_REPORT_EVENT:
800                    reportEvent((UsageEvents.Event) msg.obj, msg.arg1);
801                    break;
802
803                case MSG_FLUSH_TO_DISK:
804                    flushToDisk();
805                    break;
806
807                case MSG_REMOVE_USER:
808                    removeUser(msg.arg1);
809                    break;
810
811                case MSG_INFORM_LISTENERS:
812                    informListeners((String) msg.obj, msg.arg1, msg.arg2 == 1);
813                    break;
814
815                case MSG_FORCE_IDLE_STATE:
816                    forceIdleState((String) msg.obj, msg.arg1, msg.arg2 == 1);
817                    break;
818
819                case MSG_CHECK_IDLE_STATES:
820                    checkIdleStates();
821                    break;
822
823                case MSG_CHECK_PAROLE_TIMEOUT:
824                    checkParoleTimeout();
825                    break;
826
827                case MSG_PAROLE_END_TIMEOUT:
828                    if (DEBUG) Slog.d(TAG, "Ending parole");
829                    setAppIdleParoled(false);
830                    break;
831
832                default:
833                    super.handleMessage(msg);
834                    break;
835            }
836        }
837    }
838
839    /**
840     * Observe settings changes for Settings.Secure.APP_IDLE_DURATION.
841     */
842    private class SettingsObserver extends ContentObserver {
843
844        SettingsObserver(Handler handler) {
845            super(handler);
846        }
847
848        void registerObserver() {
849            getContext().getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
850                    Settings.Secure.APP_IDLE_DURATION), false, this, UserHandle.USER_OWNER);
851        }
852
853        @Override
854        public void onChange(boolean selfChange, Uri uri, int userId) {
855            mAppIdleDurationMillis = Settings.Secure.getLongForUser(getContext().getContentResolver(),
856                    Settings.Secure.APP_IDLE_DURATION, DEFAULT_APP_IDLE_THRESHOLD_MILLIS,
857                    UserHandle.USER_OWNER);
858            mCheckIdleIntervalMillis = Math.min(DEFAULT_CHECK_IDLE_INTERVAL,
859                    mAppIdleDurationMillis / 4);
860            postCheckIdleStates();
861        }
862    }
863
864    private class BinderService extends IUsageStatsManager.Stub {
865
866        private boolean hasPermission(String callingPackage) {
867            final int callingUid = Binder.getCallingUid();
868            if (callingUid == Process.SYSTEM_UID) {
869                return true;
870            }
871            final int mode = mAppOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS,
872                    callingUid, callingPackage);
873            if (mode == AppOpsManager.MODE_DEFAULT) {
874                // The default behavior here is to check if PackageManager has given the app
875                // permission.
876                return getContext().checkCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS)
877                        == PackageManager.PERMISSION_GRANTED;
878            }
879            return mode == AppOpsManager.MODE_ALLOWED;
880        }
881
882        @Override
883        public ParceledListSlice<UsageStats> queryUsageStats(int bucketType, long beginTime,
884                long endTime, String callingPackage) {
885            if (!hasPermission(callingPackage)) {
886                return null;
887            }
888
889            final int userId = UserHandle.getCallingUserId();
890            final long token = Binder.clearCallingIdentity();
891            try {
892                final List<UsageStats> results = UsageStatsService.this.queryUsageStats(
893                        userId, bucketType, beginTime, endTime);
894                if (results != null) {
895                    return new ParceledListSlice<>(results);
896                }
897            } finally {
898                Binder.restoreCallingIdentity(token);
899            }
900            return null;
901        }
902
903        @Override
904        public ParceledListSlice<ConfigurationStats> queryConfigurationStats(int bucketType,
905                long beginTime, long endTime, String callingPackage) throws RemoteException {
906            if (!hasPermission(callingPackage)) {
907                return null;
908            }
909
910            final int userId = UserHandle.getCallingUserId();
911            final long token = Binder.clearCallingIdentity();
912            try {
913                final List<ConfigurationStats> results =
914                        UsageStatsService.this.queryConfigurationStats(userId, bucketType,
915                                beginTime, endTime);
916                if (results != null) {
917                    return new ParceledListSlice<>(results);
918                }
919            } finally {
920                Binder.restoreCallingIdentity(token);
921            }
922            return null;
923        }
924
925        @Override
926        public UsageEvents queryEvents(long beginTime, long endTime, String callingPackage) {
927            if (!hasPermission(callingPackage)) {
928                return null;
929            }
930
931            final int userId = UserHandle.getCallingUserId();
932            final long token = Binder.clearCallingIdentity();
933            try {
934                return UsageStatsService.this.queryEvents(userId, beginTime, endTime);
935            } finally {
936                Binder.restoreCallingIdentity(token);
937            }
938        }
939
940        @Override
941        public boolean isAppInactive(String packageName, int userId) {
942            try {
943                userId = ActivityManagerNative.getDefault().handleIncomingUser(Binder.getCallingPid(),
944                        Binder.getCallingUid(), userId, false, true, "isAppInactive", null);
945            } catch (RemoteException re) {
946                return false;
947            }
948            final long token = Binder.clearCallingIdentity();
949            try {
950                return UsageStatsService.this.isAppIdleFiltered(packageName, userId);
951            } finally {
952                Binder.restoreCallingIdentity(token);
953            }
954        }
955
956        @Override
957        public void setAppInactive(String packageName, boolean idle, int userId) {
958            final int callingUid = Binder.getCallingUid();
959            try {
960                userId = ActivityManagerNative.getDefault().handleIncomingUser(
961                        Binder.getCallingPid(), callingUid, userId, false, true,
962                        "setAppIdle", null);
963            } catch (RemoteException re) {
964                return;
965            }
966            getContext().enforceCallingPermission(Manifest.permission.CHANGE_APP_IDLE_STATE,
967                    "No permission to change app idle state");
968            final long token = Binder.clearCallingIdentity();
969            try {
970                PackageInfo pi = AppGlobals.getPackageManager()
971                        .getPackageInfo(packageName, 0, userId);
972                if (pi == null) return;
973                UsageStatsService.this.setAppIdle(packageName, idle, userId);
974            } catch (RemoteException re) {
975            } finally {
976                Binder.restoreCallingIdentity(token);
977            }
978        }
979
980        @Override
981        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
982            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
983                    != PackageManager.PERMISSION_GRANTED) {
984                pw.println("Permission Denial: can't dump UsageStats from pid="
985                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
986                        + " without permission " + android.Manifest.permission.DUMP);
987                return;
988            }
989            UsageStatsService.this.dump(args, pw);
990        }
991    }
992
993    /**
994     * This local service implementation is primarily used by ActivityManagerService.
995     * ActivityManagerService will call these methods holding the 'am' lock, which means we
996     * shouldn't be doing any IO work or other long running tasks in these methods.
997     */
998    private class LocalService extends UsageStatsManagerInternal {
999
1000        @Override
1001        public void reportEvent(ComponentName component, int userId, int eventType) {
1002            if (component == null) {
1003                Slog.w(TAG, "Event reported without a component name");
1004                return;
1005            }
1006
1007            UsageEvents.Event event = new UsageEvents.Event();
1008            event.mPackage = component.getPackageName();
1009            event.mClass = component.getClassName();
1010
1011            // This will later be converted to system time.
1012            event.mTimeStamp = SystemClock.elapsedRealtime();
1013
1014            event.mEventType = eventType;
1015            mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
1016        }
1017
1018        @Override
1019        public void reportEvent(String packageName, int userId, int eventType) {
1020            if (packageName == null) {
1021                Slog.w(TAG, "Event reported without a package name");
1022                return;
1023            }
1024
1025            UsageEvents.Event event = new UsageEvents.Event();
1026            event.mPackage = packageName;
1027
1028            // This will later be converted to system time.
1029            event.mTimeStamp = SystemClock.elapsedRealtime();
1030
1031            event.mEventType = eventType;
1032            mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
1033        }
1034
1035        @Override
1036        public void reportConfigurationChange(Configuration config, int userId) {
1037            if (config == null) {
1038                Slog.w(TAG, "Configuration event reported with a null config");
1039                return;
1040            }
1041
1042            UsageEvents.Event event = new UsageEvents.Event();
1043            event.mPackage = "android";
1044
1045            // This will later be converted to system time.
1046            event.mTimeStamp = SystemClock.elapsedRealtime();
1047
1048            event.mEventType = UsageEvents.Event.CONFIGURATION_CHANGE;
1049            event.mConfiguration = new Configuration(config);
1050            mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
1051        }
1052
1053        @Override
1054        public boolean isAppIdle(String packageName, int userId) {
1055            return UsageStatsService.this.isAppIdleFiltered(packageName, userId);
1056        }
1057
1058        @Override
1059        public void prepareShutdown() {
1060            // This method *WILL* do IO work, but we must block until it is finished or else
1061            // we might not shutdown cleanly. This is ok to do with the 'am' lock held, because
1062            // we are shutting down.
1063            shutdown();
1064        }
1065
1066        @Override
1067        public void addAppIdleStateChangeListener(AppIdleStateChangeListener listener) {
1068            UsageStatsService.this.addListener(listener);
1069        }
1070
1071        @Override
1072        public void removeAppIdleStateChangeListener(
1073                AppIdleStateChangeListener listener) {
1074            UsageStatsService.this.removeListener(listener);
1075        }
1076    }
1077}
1078