10a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani/**
20a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani * Copyright (C) 2015 The Android Open Source Project
30a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani *
40a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani * Licensed under the Apache License, Version 2.0 (the "License"); you may not
50a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani * use this file except in compliance with the License. You may obtain a copy
60a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani * of the License at
70a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani *
80a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani * http://www.apache.org/licenses/LICENSE-2.0
90a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani *
100a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani * Unless required by applicable law or agreed to in writing, software
110a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
120a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
130a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani * License for the specific language governing permissions and limitations
140a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani * under the License.
150a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani */
160a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani
170a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasanipackage com.android.server.usage;
180a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani
19a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport android.os.Environment;
20a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport android.os.SystemClock;
210a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasaniimport android.util.ArrayMap;
22a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport android.util.AtomicFile;
23a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport android.util.Slog;
240a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasaniimport android.util.SparseArray;
25a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport android.util.TimeUtils;
26a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport android.util.Xml;
270a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani
28a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport com.android.internal.annotations.VisibleForTesting;
29a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport com.android.internal.util.FastXmlSerializer;
300a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasaniimport com.android.internal.util.IndentingPrintWriter;
310a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani
32a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport libcore.io.IoUtils;
33a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
34a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport org.xmlpull.v1.XmlPullParser;
35a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport org.xmlpull.v1.XmlPullParserException;
36a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
37a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport java.io.BufferedOutputStream;
38a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport java.io.BufferedReader;
39a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport java.io.File;
40a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport java.io.FileInputStream;
41a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport java.io.FileOutputStream;
42a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport java.io.FileReader;
43a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport java.io.IOException;
44a93542f9d341897f3206f775fd5720663b17504fAmith Yamasaniimport java.nio.charset.StandardCharsets;
45a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
460a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani/**
470a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani * Keeps track of recent active state changes in apps.
480a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani * Access should be guarded by a lock by the caller.
490a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani */
500a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasanipublic class AppIdleHistory {
510a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani
52a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private static final String TAG = "AppIdleHistory";
53a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
54a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    // History for all users and all packages
55a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private SparseArray<ArrayMap<String,PackageHistory>> mIdleHistory = new SparseArray<>();
56a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private long mLastPeriod = 0;
570a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani    private static final long ONE_MINUTE = 60 * 1000;
580a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani    private static final int HISTORY_SIZE = 100;
590a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani    private static final int FLAG_LAST_STATE = 2;
600a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani    private static final int FLAG_PARTIAL_ACTIVE = 1;
616776849dc5ff851a225745393f082b702754e278Amith Yamasani    private static final long PERIOD_DURATION = UsageStatsService.COMPRESS_TIME ? ONE_MINUTE
620a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani            : 60 * ONE_MINUTE;
630a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani
64a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    @VisibleForTesting
65a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    static final String APP_IDLE_FILENAME = "app_idle_stats.xml";
66a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private static final String TAG_PACKAGES = "packages";
67a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private static final String TAG_PACKAGE = "package";
68a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private static final String ATTR_NAME = "name";
69a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    // Screen on timebase time when app was last used
70a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private static final String ATTR_SCREEN_IDLE = "screenIdleTime";
71a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    // Elapsed timebase time when app was last used
72a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private static final String ATTR_ELAPSED_IDLE = "elapsedIdleTime";
73a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
74a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    // device on time = mElapsedDuration + (timeNow - mElapsedSnapshot)
75a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private long mElapsedSnapshot; // Elapsed time snapshot when last write of mDeviceOnDuration
76a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private long mElapsedDuration; // Total device on duration since device was "born"
77a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
78a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    // screen on time = mScreenOnDuration + (timeNow - mScreenOnSnapshot)
79a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private long mScreenOnSnapshot; // Elapsed time snapshot when last write of mScreenOnDuration
80a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private long mScreenOnDuration; // Total screen on duration since device was "born"
81a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
82a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private long mElapsedTimeThreshold;
83a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private long mScreenOnTimeThreshold;
84a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private final File mStorageDir;
85a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
86a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private boolean mScreenOn;
87a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
88a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private static class PackageHistory {
89a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        final byte[] recent = new byte[HISTORY_SIZE];
90a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        long lastUsedElapsedTime;
91a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        long lastUsedScreenTime;
92a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
93a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
94a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    AppIdleHistory(long elapsedRealtime) {
95a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        this(Environment.getDataSystemDirectory(), elapsedRealtime);
96a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
97a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
98a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    @VisibleForTesting
99a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    AppIdleHistory(File storageDir, long elapsedRealtime) {
100a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        mElapsedSnapshot = elapsedRealtime;
101a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        mScreenOnSnapshot = elapsedRealtime;
102a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        mStorageDir = storageDir;
10361d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        readScreenOnTime();
104a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
105a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
106a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    public void setThresholds(long elapsedTimeThreshold, long screenOnTimeThreshold) {
107a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        mElapsedTimeThreshold = elapsedTimeThreshold;
108a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        mScreenOnTimeThreshold = screenOnTimeThreshold;
109a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
110a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
11161d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani    public void updateDisplay(boolean screenOn, long elapsedRealtime) {
112a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        if (screenOn == mScreenOn) return;
113a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
114a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        mScreenOn = screenOn;
115a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        if (mScreenOn) {
116a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            mScreenOnSnapshot = elapsedRealtime;
117a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        } else {
118a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            mScreenOnDuration += elapsedRealtime - mScreenOnSnapshot;
119a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            mElapsedDuration += elapsedRealtime - mElapsedSnapshot;
120a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            mElapsedSnapshot = elapsedRealtime;
121a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        }
122a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
123a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
12461d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani    public long getScreenOnTime(long elapsedRealtime) {
125a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        long screenOnTime = mScreenOnDuration;
126a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        if (mScreenOn) {
127a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            screenOnTime += elapsedRealtime - mScreenOnSnapshot;
128a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        }
129a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        return screenOnTime;
130a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
131a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
132a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    @VisibleForTesting
133a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    File getScreenOnTimeFile() {
134a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        return new File(mStorageDir, "screen_on_time");
135a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
136a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
13761d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani    private void readScreenOnTime() {
138a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        File screenOnTimeFile = getScreenOnTimeFile();
139a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        if (screenOnTimeFile.exists()) {
140a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            try {
141a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                BufferedReader reader = new BufferedReader(new FileReader(screenOnTimeFile));
142a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                mScreenOnDuration = Long.parseLong(reader.readLine());
143a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                mElapsedDuration = Long.parseLong(reader.readLine());
144a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                reader.close();
145a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            } catch (IOException | NumberFormatException e) {
146a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            }
147a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        } else {
14861d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani            writeScreenOnTime();
149a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        }
150a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
151a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
15261d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani    private void writeScreenOnTime() {
153a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        AtomicFile screenOnTimeFile = new AtomicFile(getScreenOnTimeFile());
154a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        FileOutputStream fos = null;
155a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        try {
156a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            fos = screenOnTimeFile.startWrite();
157a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            fos.write((Long.toString(mScreenOnDuration) + "\n"
158a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                    + Long.toString(mElapsedDuration) + "\n").getBytes());
159a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            screenOnTimeFile.finishWrite(fos);
160a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        } catch (IOException ioe) {
161a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            screenOnTimeFile.failWrite(fos);
162a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        }
163a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
164a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
165a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    /**
166a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani     * To be called periodically to keep track of elapsed time when app idle times are written
167a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani     */
16861d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani    public void writeAppIdleDurations() {
169a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        final long elapsedRealtime = SystemClock.elapsedRealtime();
170a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        // Only bump up and snapshot the elapsed time. Don't change screen on duration.
171a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        mElapsedDuration += elapsedRealtime - mElapsedSnapshot;
172a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        mElapsedSnapshot = elapsedRealtime;
17361d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        writeScreenOnTime();
174a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
175a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
17661d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani    public void reportUsage(String packageName, int userId, long elapsedRealtime) {
17761d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
17861d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        PackageHistory packageHistory = getPackageHistory(userHistory, packageName,
179a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                elapsedRealtime);
180a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
181a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        shiftHistoryToNow(userHistory, elapsedRealtime);
182a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
183a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        packageHistory.lastUsedElapsedTime = mElapsedDuration
184a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                + (elapsedRealtime - mElapsedSnapshot);
18561d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        packageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
186a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        packageHistory.recent[HISTORY_SIZE - 1] = FLAG_LAST_STATE | FLAG_PARTIAL_ACTIVE;
187a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
188a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
189a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    public void setIdle(String packageName, int userId, long elapsedRealtime) {
19061d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
19161d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        PackageHistory packageHistory = getPackageHistory(userHistory, packageName,
192a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                elapsedRealtime);
193a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
194a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        shiftHistoryToNow(userHistory, elapsedRealtime);
1956776849dc5ff851a225745393f082b702754e278Amith Yamasani
196a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        packageHistory.recent[HISTORY_SIZE - 1] &= ~FLAG_LAST_STATE;
197a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
198a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
199a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private void shiftHistoryToNow(ArrayMap<String, PackageHistory> userHistory,
200a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            long elapsedRealtime) {
201a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        long thisPeriod = elapsedRealtime / PERIOD_DURATION;
2020a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani        // Has the period switched over? Slide all users' package histories
203a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        if (mLastPeriod != 0 && mLastPeriod < thisPeriod
204a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                && (thisPeriod - mLastPeriod) < HISTORY_SIZE - 1) {
205a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            int diff = (int) (thisPeriod - mLastPeriod);
2066776849dc5ff851a225745393f082b702754e278Amith Yamasani            final int NUSERS = mIdleHistory.size();
2070a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani            for (int u = 0; u < NUSERS; u++) {
2086776849dc5ff851a225745393f082b702754e278Amith Yamasani                userHistory = mIdleHistory.valueAt(u);
209a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                for (PackageHistory idleState : userHistory.values()) {
2100a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani                    // Shift left
211a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                    System.arraycopy(idleState.recent, diff, idleState.recent, 0,
212a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                            HISTORY_SIZE - diff);
2130a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani                    // Replicate last state across the diff
2140a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani                    for (int i = 0; i < diff; i++) {
215a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                        idleState.recent[HISTORY_SIZE - i - 1] =
216a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                            (byte) (idleState.recent[HISTORY_SIZE - diff - 1] & FLAG_LAST_STATE);
2170a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani                    }
2180a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani                }
2190a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani            }
2200a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani        }
221a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        mLastPeriod = thisPeriod;
2220a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani    }
2230a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani
22461d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani    private ArrayMap<String, PackageHistory> getUserHistory(int userId) {
225a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        ArrayMap<String, PackageHistory> userHistory = mIdleHistory.get(userId);
2266776849dc5ff851a225745393f082b702754e278Amith Yamasani        if (userHistory == null) {
2276776849dc5ff851a225745393f082b702754e278Amith Yamasani            userHistory = new ArrayMap<>();
2286776849dc5ff851a225745393f082b702754e278Amith Yamasani            mIdleHistory.put(userId, userHistory);
22961d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani            readAppIdleTimes(userId, userHistory);
2306776849dc5ff851a225745393f082b702754e278Amith Yamasani        }
2316776849dc5ff851a225745393f082b702754e278Amith Yamasani        return userHistory;
2326776849dc5ff851a225745393f082b702754e278Amith Yamasani    }
2336776849dc5ff851a225745393f082b702754e278Amith Yamasani
23461d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani    private PackageHistory getPackageHistory(ArrayMap<String, PackageHistory> userHistory,
235a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            String packageName, long elapsedRealtime) {
236a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        PackageHistory packageHistory = userHistory.get(packageName);
2376776849dc5ff851a225745393f082b702754e278Amith Yamasani        if (packageHistory == null) {
238a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            packageHistory = new PackageHistory();
23961d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani            packageHistory.lastUsedElapsedTime = getElapsedTime(elapsedRealtime);
24061d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani            packageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
2416776849dc5ff851a225745393f082b702754e278Amith Yamasani            userHistory.put(packageName, packageHistory);
2426776849dc5ff851a225745393f082b702754e278Amith Yamasani        }
2436776849dc5ff851a225745393f082b702754e278Amith Yamasani        return packageHistory;
2446776849dc5ff851a225745393f082b702754e278Amith Yamasani    }
2456776849dc5ff851a225745393f082b702754e278Amith Yamasani
246a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    public void onUserRemoved(int userId) {
2476776849dc5ff851a225745393f082b702754e278Amith Yamasani        mIdleHistory.remove(userId);
2486776849dc5ff851a225745393f082b702754e278Amith Yamasani    }
2496776849dc5ff851a225745393f082b702754e278Amith Yamasani
25061d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani    public boolean isIdle(String packageName, int userId, long elapsedRealtime) {
25161d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
252a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        PackageHistory packageHistory =
25361d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani                getPackageHistory(userHistory, packageName, elapsedRealtime);
254a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        if (packageHistory == null) {
255a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            return false; // Default to not idle
256a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        } else {
25761d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani            return hasPassedThresholds(packageHistory, elapsedRealtime);
258a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        }
259a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
260a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
26161d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani    private long getElapsedTime(long elapsedRealtime) {
262a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        return (elapsedRealtime - mElapsedSnapshot + mElapsedDuration);
263a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
264a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
26561d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani    public void setIdle(String packageName, int userId, boolean idle, long elapsedRealtime) {
26661d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
26761d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        PackageHistory packageHistory = getPackageHistory(userHistory, packageName,
268a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                elapsedRealtime);
26961d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        packageHistory.lastUsedElapsedTime = getElapsedTime(elapsedRealtime)
270a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                - mElapsedTimeThreshold;
27161d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        packageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime)
272a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                - (idle ? mScreenOnTimeThreshold : 0) - 1000 /* just a second more */;
273a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
274a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
27561d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani    public void clearUsage(String packageName, int userId) {
27661d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        ArrayMap<String, PackageHistory> userHistory = getUserHistory(userId);
277bdda1e076eb30bf88749a1a349f9bb6f52434ecdAmith Yamasani        userHistory.remove(packageName);
278bdda1e076eb30bf88749a1a349f9bb6f52434ecdAmith Yamasani    }
279bdda1e076eb30bf88749a1a349f9bb6f52434ecdAmith Yamasani
28061d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani    private boolean hasPassedThresholds(PackageHistory packageHistory, long elapsedRealtime) {
281a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        return (packageHistory.lastUsedScreenTime
28261d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani                    <= getScreenOnTime(elapsedRealtime) - mScreenOnTimeThreshold)
283a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                && (packageHistory.lastUsedElapsedTime
28461d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani                        <= getElapsedTime(elapsedRealtime) - mElapsedTimeThreshold);
285a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
286a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
287a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    private File getUserFile(int userId) {
288a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        return new File(new File(new File(mStorageDir, "users"),
289a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                Integer.toString(userId)), APP_IDLE_FILENAME);
290a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
291a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
29261d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani    private void readAppIdleTimes(int userId, ArrayMap<String, PackageHistory> userHistory) {
293a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        FileInputStream fis = null;
294a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        try {
295a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            AtomicFile appIdleFile = new AtomicFile(getUserFile(userId));
296a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            fis = appIdleFile.openRead();
297a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            XmlPullParser parser = Xml.newPullParser();
298a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            parser.setInput(fis, StandardCharsets.UTF_8.name());
299a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
300a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            int type;
301a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            while ((type = parser.next()) != XmlPullParser.START_TAG
302a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                    && type != XmlPullParser.END_DOCUMENT) {
303a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                // Skip
304a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            }
305a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
306a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            if (type != XmlPullParser.START_TAG) {
307a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                Slog.e(TAG, "Unable to read app idle file for user " + userId);
308a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                return;
309a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            }
310a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            if (!parser.getName().equals(TAG_PACKAGES)) {
311a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                return;
312a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            }
313a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
314a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                if (type == XmlPullParser.START_TAG) {
315a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                    final String name = parser.getName();
316a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                    if (name.equals(TAG_PACKAGE)) {
317a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                        final String packageName = parser.getAttributeValue(null, ATTR_NAME);
318a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                        PackageHistory packageHistory = new PackageHistory();
319a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                        packageHistory.lastUsedElapsedTime =
320a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                                Long.parseLong(parser.getAttributeValue(null, ATTR_ELAPSED_IDLE));
321a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                        packageHistory.lastUsedScreenTime =
322a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                                Long.parseLong(parser.getAttributeValue(null, ATTR_SCREEN_IDLE));
323a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                        userHistory.put(packageName, packageHistory);
324a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                    }
325a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                }
326a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            }
327a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        } catch (IOException | XmlPullParserException e) {
328a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            Slog.e(TAG, "Unable to read app idle file for user " + userId);
329a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        } finally {
330a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            IoUtils.closeQuietly(fis);
331a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        }
332a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
333a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
33461d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani    public void writeAppIdleTimes(int userId) {
335a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        FileOutputStream fos = null;
336a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        AtomicFile appIdleFile = new AtomicFile(getUserFile(userId));
337a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        try {
338a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            fos = appIdleFile.startWrite();
339a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            final BufferedOutputStream bos = new BufferedOutputStream(fos);
340a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
341a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            FastXmlSerializer xml = new FastXmlSerializer();
342a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            xml.setOutput(bos, StandardCharsets.UTF_8.name());
343a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            xml.startDocument(null, true);
344a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            xml.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
345a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
346a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            xml.startTag(null, TAG_PACKAGES);
347a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
34861d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani            ArrayMap<String,PackageHistory> userHistory = getUserHistory(userId);
349a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            final int N = userHistory.size();
350a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            for (int i = 0; i < N; i++) {
351a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                String packageName = userHistory.keyAt(i);
352a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                PackageHistory history = userHistory.valueAt(i);
353a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                xml.startTag(null, TAG_PACKAGE);
354a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                xml.attribute(null, ATTR_NAME, packageName);
355a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                xml.attribute(null, ATTR_ELAPSED_IDLE,
356a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                        Long.toString(history.lastUsedElapsedTime));
357a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                xml.attribute(null, ATTR_SCREEN_IDLE,
358a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                        Long.toString(history.lastUsedScreenTime));
359a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani                xml.endTag(null, TAG_PACKAGE);
360a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            }
361a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
362a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            xml.endTag(null, TAG_PACKAGES);
363a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            xml.endDocument();
364a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            appIdleFile.finishWrite(fos);
365a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        } catch (Exception e) {
366a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            appIdleFile.failWrite(fos);
367a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            Slog.e(TAG, "Error writing app idle file for user " + userId);
368a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        }
3690a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani    }
3700a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani
3710a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani    public void dump(IndentingPrintWriter idpw, int userId) {
372a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        idpw.println("Package idle stats:");
373a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        idpw.increaseIndent();
374a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        ArrayMap<String, PackageHistory> userHistory = mIdleHistory.get(userId);
375a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        final long elapsedRealtime = SystemClock.elapsedRealtime();
37661d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        final long totalElapsedTime = getElapsedTime(elapsedRealtime);
37761d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        final long screenOnTime = getScreenOnTime(elapsedRealtime);
378a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        if (userHistory == null) return;
379a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        final int P = userHistory.size();
380a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        for (int p = 0; p < P; p++) {
381a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            final String packageName = userHistory.keyAt(p);
382a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            final PackageHistory packageHistory = userHistory.valueAt(p);
383a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            idpw.print("package=" + packageName);
384a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            idpw.print(" lastUsedElapsed=");
385a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            TimeUtils.formatDuration(totalElapsedTime - packageHistory.lastUsedElapsedTime, idpw);
386a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            idpw.print(" lastUsedScreenOn=");
387a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            TimeUtils.formatDuration(screenOnTime - packageHistory.lastUsedScreenTime, idpw);
38861d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani            idpw.print(" idle=" + (isIdle(packageName, userId, elapsedRealtime) ? "y" : "n"));
389a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            idpw.println();
390a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        }
391a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        idpw.println();
392a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        idpw.print("totalElapsedTime=");
39361d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        TimeUtils.formatDuration(getElapsedTime(elapsedRealtime), idpw);
394a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        idpw.println();
395a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        idpw.print("totalScreenOnTime=");
39661d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani        TimeUtils.formatDuration(getScreenOnTime(elapsedRealtime), idpw);
397a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        idpw.println();
398a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        idpw.decreaseIndent();
399a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    }
400a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani
401a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani    public void dumpHistory(IndentingPrintWriter idpw, int userId) {
402a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        ArrayMap<String, PackageHistory> userHistory = mIdleHistory.get(userId);
403a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani        final long elapsedRealtime = SystemClock.elapsedRealtime();
4040a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani        if (userHistory == null) return;
4050a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani        final int P = userHistory.size();
4060a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani        for (int p = 0; p < P; p++) {
4070a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani            final String packageName = userHistory.keyAt(p);
408a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani            final byte[] history = userHistory.valueAt(p).recent;
4090a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani            for (int i = 0; i < HISTORY_SIZE; i++) {
4100a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani                idpw.print(history[i] == 0 ? '.' : 'A');
4110a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani            }
41261d5fd7fee3250bdf4b6ddfbccbd6bceae9436c6Amith Yamasani            idpw.print(" idle=" + (isIdle(packageName, userId, elapsedRealtime) ? "y" : "n"));
4130a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani            idpw.print("  " + packageName);
4140a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani            idpw.println();
4150a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani        }
4160a11e69428d4c00dfcb368c1eb4e60ad8e0dc918Amith Yamasani    }
417a93542f9d341897f3206f775fd5720663b17504fAmith Yamasani}
418