UsageStatsService.java revision 760ec4a095567457707abe764cf4dfda0ed84032
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006-2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server.am;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.app.IUsageStats;
2055280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ComponentName;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.os.PkgUsageStats;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Process;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ServiceManager;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileInputStream;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileNotFoundException;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileOutputStream;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Calendar;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Collections;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Set;
456447ca30b8e41c22c7214f201120327057e356dcDianne Hackbornimport java.util.TimeZone;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This service collects the statistics associated with usage
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * of various components, like when a particular package is launched or
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * paused and aggregates events like number of time a component is launched
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * total duration of a component launch.
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic final class UsageStatsService extends IUsageStats.Stub {
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final String SERVICE_NAME = "usagestats";
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean localLOGV = false;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "UsageStats";
576447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
586447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn    // Current on-disk Parcel version
59760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn    private static final int VERSION = 1005;
606447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
61760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn    private static final int CHECKIN_VERSION = 4;
626447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
636447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn    private static final String FILE_PREFIX = "usage-";
646447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
656447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn    private static final int FILE_WRITE_INTERVAL = 30*60*1000; //ms
666447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
676447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn    private static final int MAX_NUM_FILES = 5;
686447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
69f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn    private static final int NUM_LAUNCH_TIME_BINS = 10;
70f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn    private static final int[] LAUNCH_TIME_BINS = {
71f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn        250, 500, 750, 1000, 1500, 2000, 3000, 4000, 5000
72f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn    };
736447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static IUsageStats sService;
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Context mContext;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // structure used to maintain statistics since the last checkin.
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final private Map<String, PkgUsageStatsExtended> mStats;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Lock to update package stats. Methods suffixed by SLOCK should invoked with
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // this lock held
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final Object mStatsLock;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Lock to write to file. Methods suffixed by FLOCK should invoked with
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // this lock held.
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final Object mFileLock;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Order of locks is mFileLock followed by mStatsLock to avoid deadlocks
85760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn    private String mLastResumedPkg;
86760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn    private String mLastResumedComp;
87760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn    private boolean mIsResumed;
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private File mFile;
896447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn    private String mFileLeaf;
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    //private File mBackupFile;
916447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn    private long mLastWriteElapsedTime;
926447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn    private File mDir;
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Calendar mCal;
946447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn    private int mLastWriteDay;
956447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
966447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn    static class TimeStats {
97760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn        int count;
98f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn        int[] times = new int[NUM_LAUNCH_TIME_BINS];
996447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
100f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn        TimeStats() {
101f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn        }
1026447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
103760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn        void incCount() {
104760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            count++;
105760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn        }
106760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn
1076447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        void add(int val) {
108f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn            final int[] bins = LAUNCH_TIME_BINS;
109f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn            for (int i=0; i<NUM_LAUNCH_TIME_BINS-1; i++) {
110f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                if (val < bins[i]) {
111f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                    times[i]++;
112f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                    return;
1136447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                }
1146447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            }
115f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn            times[NUM_LAUNCH_TIME_BINS-1]++;
1166447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        }
1176447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
118f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn        TimeStats(Parcel in) {
119760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            count = in.readInt();
120f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn            final int[] localTimes = times;
121f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn            for (int i=0; i<NUM_LAUNCH_TIME_BINS; i++) {
122f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                localTimes[i] = in.readInt();
1236447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            }
124f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn        }
125f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn
126f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn        void writeToParcel(Parcel out) {
127760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            out.writeInt(count);
128f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn            final int[] localTimes = times;
129f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn            for (int i=0; i<NUM_LAUNCH_TIME_BINS; i++) {
130f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                out.writeInt(localTimes[i]);
1316447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            }
1326447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        }
1336447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn    }
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class PkgUsageStatsExtended {
1366447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        final HashMap<String, TimeStats> mLaunchTimes
1376447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                = new HashMap<String, TimeStats>();
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int mLaunchCount;
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long mUsageTime;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long mPausedTime;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long mResumedTime;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PkgUsageStatsExtended() {
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLaunchCount = 0;
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mUsageTime = 0;
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1476447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
1486447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        PkgUsageStatsExtended(Parcel in) {
1496447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            mLaunchCount = in.readInt();
1506447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            mUsageTime = in.readLong();
1516447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            if (localLOGV) Log.v(TAG, "Launch count: " + mLaunchCount
1526447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                    + ", Usage time:" + mUsageTime);
1536447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
1546447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            final int N = in.readInt();
1556447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            if (localLOGV) Log.v(TAG, "Reading comps: " + N);
1566447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            for (int i=0; i<N; i++) {
1576447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                String comp = in.readString();
158f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                if (localLOGV) Log.v(TAG, "Component: " + comp);
159f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                TimeStats times = new TimeStats(in);
160f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                mLaunchTimes.put(comp, times);
1616447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            }
1626447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        }
1636447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
164760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn        void updateResume(boolean launched) {
165760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            if (launched) {
166760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                mLaunchCount ++;
167760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            }
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mResumedTime = SystemClock.elapsedRealtime();
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1706447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void updatePause() {
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPausedTime =  SystemClock.elapsedRealtime();
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mUsageTime += (mPausedTime - mResumedTime);
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1756447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
176760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn        void addLaunchCount(String comp) {
177760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            TimeStats times = mLaunchTimes.get(comp);
178760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            if (times == null) {
179760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                times = new TimeStats();
180760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                mLaunchTimes.put(comp, times);
181760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            }
182760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            times.incCount();
183760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn        }
184760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn
1856447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        void addLaunchTime(String comp, int millis) {
1866447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            TimeStats times = mLaunchTimes.get(comp);
1876447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            if (times == null) {
1886447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                times = new TimeStats();
1896447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                mLaunchTimes.put(comp, times);
1906447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            }
1916447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            times.add(millis);
1926447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        }
1936447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
194f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn        void writeToParcel(Parcel out) {
1956447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            out.writeInt(mLaunchCount);
1966447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            out.writeLong(mUsageTime);
1976447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            final int N = mLaunchTimes.size();
1986447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            out.writeInt(N);
1996447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            if (N > 0) {
2006447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                for (Map.Entry<String, TimeStats> ent : mLaunchTimes.entrySet()) {
2016447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                    out.writeString(ent.getKey());
2026447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                    TimeStats times = ent.getValue();
203f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                    times.writeToParcel(out);
2046447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                }
2056447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            }
2066447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        }
2076447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void clear() {
2096447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            mLaunchTimes.clear();
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLaunchCount = 0;
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mUsageTime = 0;
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2156447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn    UsageStatsService(String dir) {
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStats = new HashMap<String, PkgUsageStatsExtended>();
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStatsLock = new Object();
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFileLock = new Object();
2196447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        mDir = new File(dir);
2206447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        mCal = Calendar.getInstance(TimeZone.getTimeZone("GMT+0"));
2216447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
2226447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        mDir.mkdir();
2236447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
2246447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        // Remove any old usage files from previous versions.
2256447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        File parentDir = mDir.getParentFile();
2266447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        String fList[] = parentDir.list();
2276447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        if (fList != null) {
2286447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            String prefix = mDir.getName() + ".";
2296447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            int i = fList.length;
2306447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            while (i > 0) {
2316447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                i--;
2326447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                if (fList[i].startsWith(prefix)) {
2336447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                    Log.i(TAG, "Deleting old usage file: " + fList[i]);
2346447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                    (new File(parentDir, fList[i])).delete();
2356447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                }
2366447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            }
2376447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        }
2386447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Update current stats which are binned by date
2406447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        mFileLeaf = getCurrentDateStr(FILE_PREFIX);
2416447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        mFile = new File(mDir, mFileLeaf);
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        readStatsFromFile();
2436447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        mLastWriteElapsedTime = SystemClock.elapsedRealtime();
2446447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        // mCal was set by getCurrentDateStr(), want to use that same time.
2456447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        mLastWriteDay = mCal.get(Calendar.DAY_OF_YEAR);
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Utility method to convert date into string.
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private String getCurrentDateStr(String prefix) {
2526447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        mCal.setTimeInMillis(System.currentTimeMillis());
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder sb = new StringBuilder();
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (prefix != null) {
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append(prefix);
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2576447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        sb.append(mCal.get(Calendar.YEAR));
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int mm = mCal.get(Calendar.MONTH) - Calendar.JANUARY +1;
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mm < 10) {
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append("0");
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(mm);
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int dd = mCal.get(Calendar.DAY_OF_MONTH);
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (dd < 10) {
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append("0");
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(dd);
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sb.toString();
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Parcel getParcelForFile(File file) throws IOException {
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        FileInputStream stream = new FileInputStream(file);
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        byte[] raw = readFully(stream);
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Parcel in = Parcel.obtain();
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        in.unmarshall(raw, 0, raw.length);
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        in.setDataPosition(0);
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        stream.close();
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return in;
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void readStatsFromFile() {
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        File newFile = mFile;
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mFileLock) {
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (newFile.exists()) {
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    readStatsFLOCK(newFile);
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Check for file limit before creating a new file
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    checkFileLimitFLOCK();
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    newFile.createNewFile();
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IOException e) {
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.w(TAG,"Error : " + e + " reading data from file:" + newFile);
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void readStatsFLOCK(File file) throws IOException {
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Parcel in = getParcelForFile(file);
3006447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        int vers = in.readInt();
3016447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        if (vers != VERSION) {
3026447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            Log.w(TAG, "Usage stats version changed; dropping");
3036447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            return;
3046447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        }
3056447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        int N = in.readInt();
3066447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        while (N > 0) {
3076447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            N--;
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String pkgName = in.readString();
3096447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            if (pkgName == null) {
3106447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                break;
3116447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            }
3126447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            if (localLOGV) Log.v(TAG, "Reading package #" + N + ": " + pkgName);
3136447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            PkgUsageStatsExtended pus = new PkgUsageStatsExtended(in);
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mStatsLock) {
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mStats.put(pkgName, pus);
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ArrayList<String> getUsageStatsFileListFLOCK() {
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check if there are too many files in the system and delete older files
3226447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        String fList[] = mDir.list();
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fList == null) {
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ArrayList<String> fileList = new ArrayList<String>();
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (String file : fList) {
3286447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            if (!file.startsWith(FILE_PREFIX)) {
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (file.endsWith(".bak")) {
3326447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                (new File(mDir, file)).delete();
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fileList.add(file);
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return fileList;
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void checkFileLimitFLOCK() {
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Get all usage stats output files
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ArrayList<String> fileList = getUsageStatsFileListFLOCK();
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fileList == null) {
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Strange but we dont have to delete any thing
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = fileList.size();
3486447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        if (count <= MAX_NUM_FILES) {
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Sort files
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Collections.sort(fileList);
3536447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        count -= MAX_NUM_FILES;
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Delete older files
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String fileName = fileList.get(i);
3576447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            File file = new File(mDir, fileName);
3586447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            Log.i(TAG, "Deleting usage file : " + fileName);
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            file.delete();
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3636447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn    private void writeStatsToFile(boolean force) {
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mFileLock) {
3656447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            mCal.setTimeInMillis(System.currentTimeMillis());
3666447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            final int curDay = mCal.get(Calendar.DAY_OF_YEAR);
3676447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            // Determine if the day changed...  note that this will be wrong
3686447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            // if the year has changed but we are in the same day of year...
3696447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            // we can probably live with this.
3706447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            final boolean dayChanged =  curDay != mLastWriteDay;
3716447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            long currElapsedTime = SystemClock.elapsedRealtime();
3726447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            if (!force) {
3736447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                if (((currElapsedTime-mLastWriteElapsedTime) < FILE_WRITE_INTERVAL) &&
3746447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                        (!dayChanged)) {
3756447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                    // wait till the next update
3766447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                    return;
3776447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                }
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Get the most recent file
3806447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            mFileLeaf = getCurrentDateStr(FILE_PREFIX);
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Copy current file to back up
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            File backupFile =  new File(mFile.getPath() + ".bak");
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mFile.renameTo(backupFile);
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Write mStats to file
386f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                writeStatsFLOCK();
3876447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                mLastWriteElapsedTime = currElapsedTime;
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (dayChanged) {
3896447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                    mLastWriteDay = curDay;
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // clear stats
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    synchronized (mStats) {
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mStats.clear();
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
3946447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                    mFile = new File(mDir, mFileLeaf);
3956447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                    checkFileLimitFLOCK();
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Delete the backup file
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (backupFile != null) {
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    backupFile.delete();
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IOException e) {
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.w(TAG, "Failed writing stats to file:" + mFile);
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (backupFile != null) {
4046447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                    mFile.delete();
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    backupFile.renameTo(mFile);
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
411f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn    private void writeStatsFLOCK() throws IOException {
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        FileOutputStream stream = new FileOutputStream(mFile);
4136447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        try {
4146447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            Parcel out = Parcel.obtain();
415f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn            writeStatsToParcelFLOCK(out);
4166447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            stream.write(out.marshall());
4176447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            out.recycle();
4186447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            stream.flush();
4196447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        } finally {
4206447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            stream.close();
4216447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        }
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
424f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn    private void writeStatsToParcelFLOCK(Parcel out) {
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mStatsLock) {
4266447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            out.writeInt(VERSION);
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Set<String> keys = mStats.keySet();
4286447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            out.writeInt(keys.size());
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (String key : keys) {
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                PkgUsageStatsExtended pus = mStats.get(key);
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.writeString(key);
432f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                pus.writeToParcel(out);
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void publish(Context context) {
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ServiceManager.addService(SERVICE_NAME, asBinder());
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
44255280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn    public void shutdown() {
44355280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn        Log.w(TAG, "Writing usage stats before shutdown...");
44455280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn        writeStatsToFile(true);
44555280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn    }
44655280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static IUsageStats getService() {
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sService != null) {
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return sService;
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        IBinder b = ServiceManager.getService(SERVICE_NAME);
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sService = asInterface(b);
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sService;
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void noteResumeComponent(ComponentName componentName) {
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        enforceCallingPermission();
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String pkgName;
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mStatsLock) {
460760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            if ((componentName == null) ||
461760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                    ((pkgName = componentName.getPackageName()) == null)) {
462760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                return;
463760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            }
464760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn
465760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            final boolean samePackage = pkgName.equals(mLastResumedPkg);
466760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            if (mIsResumed) {
467760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                if (samePackage) {
468760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                    Log.w(TAG, "Something wrong here, didn't expect "
469760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                            + pkgName + " to be resumed");
470760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                    return;
471760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                }
472760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn
473760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                if (mLastResumedPkg != null) {
474760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                    // We last resumed some other package...  just pause it now
475760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                    // to recover.
476760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                    Log.w(TAG, "Unexpected resume of " + pkgName
477760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                            + " while already resumed in " + mLastResumedPkg);
478760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                    PkgUsageStatsExtended pus = mStats.get(mLastResumedPkg);
479760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                    if (pus != null) {
480760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                        pus.updatePause();
481760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                    }
482760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                }
483760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            }
484760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn
485760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            final boolean sameComp = samePackage
486760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                    && componentName.getClassName().equals(mLastResumedComp);
487760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn
488760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            mIsResumed = true;
489760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            mLastResumedPkg = pkgName;
490760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            mLastResumedComp = componentName.getClassName();
491760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn
492760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            if (localLOGV) Log.i(TAG, "started component:" + pkgName);
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            PkgUsageStatsExtended pus = mStats.get(pkgName);
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (pus == null) {
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                pus = new PkgUsageStatsExtended();
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mStats.put(pkgName, pus);
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
498760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            pus.updateResume(!samePackage);
499760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            if (!sameComp) {
500760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                pus.addLaunchCount(mLastResumedComp);
501760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            }
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void notePauseComponent(ComponentName componentName) {
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        enforceCallingPermission();
5076447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mStatsLock) {
509760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            String pkgName;
510760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            if ((componentName == null) ||
511760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                    ((pkgName = componentName.getPackageName()) == null)) {
512760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                return;
513760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            }
514760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            if (!mIsResumed) {
515760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                Log.w(TAG, "Something wrong here, didn't expect "
516760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                        + pkgName + " to be paused");
517760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                return;
518760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            }
519760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            mIsResumed = false;
520760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn
521760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn            if (localLOGV) Log.i(TAG, "paused component:"+pkgName);
522760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            PkgUsageStatsExtended pus = mStats.get(pkgName);
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (pus == null) {
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Weird some error here
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.w(TAG, "No package stats for pkg:"+pkgName);
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pus.updatePause();
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
531760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn
532760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn        // Persist current data to file if needed.
533760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn        writeStatsToFile(false);
5346447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn    }
5356447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
5366447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn    public void noteLaunchTime(ComponentName componentName, int millis) {
5376447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        enforceCallingPermission();
5386447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        String pkgName;
5396447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        if ((componentName == null) ||
5406447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                ((pkgName = componentName.getPackageName()) == null)) {
5416447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            return;
5426447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        }
5436447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
5446447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        // Persist current data to file if needed.
5456447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        writeStatsToFile(false);
5466447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
5476447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        synchronized (mStatsLock) {
5486447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            PkgUsageStatsExtended pus = mStats.get(pkgName);
5496447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            if (pus != null) {
5506447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                pus.addLaunchTime(componentName.getClassName(), millis);
5516447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            }
5526447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        }
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void enforceCallingPermission() {
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (Binder.getCallingPid() == Process.myPid()) {
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Binder.getCallingPid(), Binder.getCallingUid(), null);
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public PkgUsageStats getPkgUsageStats(ComponentName componentName) {
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                android.Manifest.permission.PACKAGE_USAGE_STATS, null);
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String pkgName;
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((componentName == null) ||
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ((pkgName = componentName.getPackageName()) == null)) {
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mStatsLock) {
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            PkgUsageStatsExtended pus = mStats.get(pkgName);
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (pus == null) {
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project               return null;
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new PkgUsageStats(pkgName, pus.mLaunchCount, pus.mUsageTime);
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public PkgUsageStats[] getAllPkgUsageStats() {
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                android.Manifest.permission.PACKAGE_USAGE_STATS, null);
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mStatsLock) {
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Set<String> keys = mStats.keySet();
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int size = keys.size();
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (size <= 0) {
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            PkgUsageStats retArr[] = new PkgUsageStats[size];
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int i = 0;
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (String key: keys) {
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                PkgUsageStatsExtended pus = mStats.get(key);
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                retArr[i] = new PkgUsageStats(key, pus.mLaunchCount, pus.mUsageTime);
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                i++;
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return retArr;
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static byte[] readFully(FileInputStream stream) throws java.io.IOException {
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int pos = 0;
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int avail = stream.available();
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        byte[] data = new byte[avail];
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (true) {
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int amt = stream.read(data, pos, data.length-pos);
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (amt <= 0) {
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return data;
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pos += amt;
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            avail = stream.available();
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (avail > data.length-pos) {
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                byte[] newData = new byte[pos+avail];
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                System.arraycopy(data, 0, newData, 0, pos);
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                data = newData;
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6196447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn    private void collectDumpInfoFLOCK(PrintWriter pw, boolean isCompactOutput,
6206447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            boolean deleteAfterPrint) {
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        List<String> fileList = getUsageStatsFileListFLOCK();
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fileList == null) {
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Collections.sort(fileList);
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (String file : fileList) {
6276447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            if (deleteAfterPrint && file.equalsIgnoreCase(mFileLeaf)) {
6286447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                // In this mode we don't print the current day's stats, since
6296447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                // they are incomplete.
6306447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                continue;
6316447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            }
6326447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            File dFile = new File(mDir, file);
6336447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            String dateStr = file.substring(FILE_PREFIX.length());
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Parcel in = getParcelForFile(dFile);
6366447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                collectDumpInfoFromParcelFLOCK(in, pw, dateStr, isCompactOutput);
6376447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                if (deleteAfterPrint) {
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Delete old file after collecting info only for checkin requests
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    dFile.delete();
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (FileNotFoundException e) {
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.w(TAG, "Failed with "+e+" when collecting dump info from file : " + file);
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IOException e) {
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.w(TAG, "Failed with "+e+" when collecting dump info from file : "+file);
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void collectDumpInfoFromParcelFLOCK(Parcel in, PrintWriter pw,
6516447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            String date, boolean isCompactOutput) {
6526447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        StringBuilder sb = new StringBuilder(512);
6536447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        if (isCompactOutput) {
6546447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            sb.append("D:");
6556447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            sb.append(CHECKIN_VERSION);
6566447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            sb.append(',');
6576447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        } else {
6586447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            sb.append("Date: ");
6596447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        }
6606447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(date);
6626447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
6636447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        int vers = in.readInt();
6646447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        if (vers != VERSION) {
6656447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            sb.append(" (old data version)");
6666447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            pw.println(sb.toString());
6676447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            return;
6686447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        }
6696447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
6706447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        pw.println(sb.toString());
6716447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        int N = in.readInt();
6726447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
6736447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        while (N > 0) {
6746447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            N--;
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String pkgName = in.readString();
6766447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            if (pkgName == null) {
6776447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                break;
6786447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            }
6796447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            sb.setLength(0);
6806447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            PkgUsageStatsExtended pus = new PkgUsageStatsExtended(in);
6816447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            if (isCompactOutput) {
6826447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                sb.append("P:");
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sb.append(pkgName);
684760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                sb.append(',');
6856447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                sb.append(pus.mLaunchCount);
686760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                sb.append(',');
6876447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                sb.append(pus.mUsageTime);
6886447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                sb.append('\n');
6896447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                final int NC = pus.mLaunchTimes.size();
6906447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                if (NC > 0) {
6916447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                    for (Map.Entry<String, TimeStats> ent : pus.mLaunchTimes.entrySet()) {
6926447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                        sb.append("A:");
6936447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                        sb.append(ent.getKey());
6946447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                        TimeStats times = ent.getValue();
695760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                        sb.append(',');
696760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                        sb.append(times.count);
697f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                        for (int i=0; i<NUM_LAUNCH_TIME_BINS; i++) {
698f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                            sb.append(",");
699f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                            sb.append(times.times[i]);
700f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                        }
7016447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                        sb.append('\n');
7026447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                    }
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7046447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
7056447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            } else {
7066447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                sb.append("  ");
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sb.append(pkgName);
7086447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                sb.append(": ");
7096447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                sb.append(pus.mLaunchCount);
7106447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                sb.append(" times, ");
7116447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                sb.append(pus.mUsageTime);
7126447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                sb.append(" ms");
7136447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                sb.append('\n');
7146447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                final int NC = pus.mLaunchTimes.size();
7156447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                if (NC > 0) {
7166447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                    for (Map.Entry<String, TimeStats> ent : pus.mLaunchTimes.entrySet()) {
7176447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                        sb.append("    ");
7186447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                        sb.append(ent.getKey());
7196447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                        TimeStats times = ent.getValue();
720760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                        sb.append(": ");
721760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                        sb.append(times.count);
722760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                        sb.append(" starts");
723f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                        int lastBin = 0;
724f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                        for (int i=0; i<NUM_LAUNCH_TIME_BINS-1; i++) {
725f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                            if (times.times[i] != 0) {
726760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                                sb.append(", ");
727f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                                sb.append(lastBin);
728f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                                sb.append('-');
729f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                                sb.append(LAUNCH_TIME_BINS[i]);
730760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                                sb.append("ms=");
731f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                                sb.append(times.times[i]);
732f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                            }
733f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                            lastBin = LAUNCH_TIME_BINS[i];
734f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                        }
735f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                        if (times.times[NUM_LAUNCH_TIME_BINS-1] != 0) {
736760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                            sb.append(", ");
737f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                            sb.append(">=");
738f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                            sb.append(lastBin);
739760ec4a095567457707abe764cf4dfda0ed84032Dianne Hackborn                            sb.append("ms=");
740f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                            sb.append(times.times[NUM_LAUNCH_TIME_BINS-1]);
741f210d6b75e2c0fe60b90c074ff9f615c1137f23eDianne Hackborn                        }
7426447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                        sb.append('\n');
7436447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                    }
7446447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn                }
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7466447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
7476447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            pw.write(sb.toString());
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Searches array of arguments for the specified string
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param args array of argument strings
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param value value to search for
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if the value is contained in the array
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static boolean scanArgs(String[] args, String value) {
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (args != null) {
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (String arg : args) {
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (value.equals(arg)) {
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return true;
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The data persisted to file is parsed and the stats are computed.
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
7736447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        final boolean isCheckinRequest = scanArgs(args, "--checkin");
7746447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        final boolean isCompactOutput = isCheckinRequest || scanArgs(args, "-c");
7756447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        final boolean deleteAfterPrint = isCheckinRequest || scanArgs(args, "-d");
7766447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
7776447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        // Make sure the current stats are written to the file.  This
7786447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        // doesn't need to be done if we are deleting files after printing,
7796447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        // since it that case we won't print the current stats.
7806447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        if (!deleteAfterPrint) {
7816447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            writeStatsToFile(true);
7826447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn        }
7836447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mFileLock) {
7856447ca30b8e41c22c7214f201120327057e356dcDianne Hackborn            collectDumpInfoFLOCK(pw, isCompactOutput, deleteAfterPrint);
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
790