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