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