19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007-2008 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;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.Notification;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.NotificationManager;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.PendingIntent;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.IPackageDataObserver;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.IPackageManager;
27197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornimport android.content.pm.PackageManager;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
29f882efadd378e0476b7362e474f3a20dcf1c0d27Dianne Hackbornimport android.os.Environment;
304b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkeyimport android.os.FileObserver;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Process;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ServiceManager;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.StatFs;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties;
395ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackbornimport android.os.UserHandle;
40be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkeyimport android.os.storage.StorageManager;
4143866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongkerimport android.provider.Settings;
42197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornimport android.text.format.Formatter;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.EventLog;
448a9b22056b13477f59df934928c00c58b5871c95Joe Onoratoimport android.util.Slog;
45197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornimport android.util.TimeUtils;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
47be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkeyimport java.io.File;
48be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkeyimport java.io.FileDescriptor;
49be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkeyimport java.io.PrintWriter;
50be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
5243866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker * This class implements a service to monitor the amount of disk
5343866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker * storage space on the device.  If the free storage on device is less
5443866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker * than a tunable threshold value (a secure settings parameter;
5543866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker * default 10%) a low memory notification is displayed to alert the
5643866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker * user. If the user clicks on the low memory notification the
5743866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker * Application Manager application gets launched to let the user free
5843866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker * storage space.
5943866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker *
6043866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker * Event log events: A low memory event with the free storage on
6143866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker * device in bytes is logged to the event log when the device goes low
6243866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker * on storage space.  The amount of free storage on the device is
6343866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker * periodically logged to the event log. The log interval is a secure
6443866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker * settings parameter with a default value of 12 hours.  When the free
6543866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker * storage differential goes below a threshold (again a secure
6643866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker * settings parameter with a default value of 2MB), the free memory is
6743866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker * logged to the event log.
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
69cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Rootpublic class DeviceStorageMonitorService extends Binder {
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "DeviceStorageMonitorService";
71be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DEBUG = false;
7343a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato    private static final boolean localLOGV = false;
74be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DEVICE_MEMORY_WHAT = 1;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MONITOR_INTERVAL = 1; //in minutes
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int LOW_MEMORY_NOTIFICATION_ID = 1;
78be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DEFAULT_FREE_STORAGE_LOG_INTERVAL_IN_MINUTES = 12*60; //in minutes
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final long DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD = 2 * 1024 * 1024; // 2MB
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final long DEFAULT_CHECK_INTERVAL = MONITOR_INTERVAL*60*1000;
82be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey
833161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker    private long mFreeMem;  // on /data
84197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    private long mFreeMemAfterLastCacheClear;  // on /data
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private long mLastReportedFreeMem;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private long mLastReportedFreeMemTime;
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mLowMemFlag=false;
88bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby    private boolean mMemFullFlag=false;
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Context mContext;
90be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey    private ContentResolver mResolver;
913161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker    private long mTotalMemory;  // on /data
923161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker    private StatFs mDataFileStats;
933161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker    private StatFs mSystemFileStats;
943161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker    private StatFs mCacheFileStats;
95be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey
96be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey    private static final File DATA_PATH = Environment.getDataDirectory();
97be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey    private static final File SYSTEM_PATH = Environment.getRootDirectory();
98be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey    private static final File CACHE_PATH = Environment.getDownloadCacheDirectory();
99be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey
1003161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker    private long mThreadStartTime = -1;
1013161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker    private boolean mClearSucceeded = false;
1023161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker    private boolean mClearingCache;
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Intent mStorageLowIntent;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Intent mStorageOkIntent;
105bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby    private Intent mStorageFullIntent;
106bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby    private Intent mStorageNotFullIntent;
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private CachePackageDataObserver mClearCacheObserver;
1084b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey    private final CacheFileDeletedObserver mCacheFileDeletedObserver;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int _TRUE = 1;
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int _FALSE = 0;
111197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // This is the raw threshold that has been set at which we consider
112197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // storage to be low.
113bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby    private long mMemLowThreshold;
114197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // This is the threshold at which we start trying to flush caches
115197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // to get below the low threshold limit.  It is less than the low
116197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // threshold; we will allow storage to get a bit beyond the limit
117197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // before flushing and checking if we are actually low.
118197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    private long mMemCacheStartTrimThreshold;
119197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // This is the threshold that we try to get to when deleting cache
120197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // files.  This is greater than the low threshold so that we will flush
121197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // more files than absolutely needed, to reduce the frequency that
122197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    // flushing takes place.
123197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    private long mMemCacheTrimToThreshold;
124be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey    private long mMemFullThreshold;
1253161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This string is used for ServiceManager access to this class.
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
129cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root    public static final String SERVICE = "devicestoragemonitor";
1303161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1323161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker    * Handler that checks the amount of disk space on the device and sends a
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    * notification if the device runs low on disk space
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    */
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Handler mHandler = new Handler() {
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
138bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby            //don't handle an invalid message
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (msg.what != DEVICE_MEMORY_WHAT) {
1408a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.e(TAG, "Will not process invalid message");
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            checkMemory(msg.arg1 == _TRUE);
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
1463161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class CachePackageDataObserver extends IPackageDataObserver.Stub {
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onRemoveCompleted(String packageName, boolean succeeded) {
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClearSucceeded = succeeded;
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClearingCache = false;
1518a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if(localLOGV) Slog.i(TAG, " Clear succeeded:"+mClearSucceeded
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    +", mClearingCache:"+mClearingCache+" Forcing memory check");
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            postCheckMemoryMsg(false, 0);
1543161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker        }
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1563161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final void restatDataDir() {
1583161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker        try {
159be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey            mDataFileStats.restat(DATA_PATH.getAbsolutePath());
1603161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker            mFreeMem = (long) mDataFileStats.getAvailableBlocks() *
1613161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker                mDataFileStats.getBlockSize();
1623161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker        } catch (IllegalArgumentException e) {
1633161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker            // use the old value of mFreeMem
1643161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker        }
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Allow freemem to be overridden by debug.freemem for testing
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String debugFreeMem = SystemProperties.get("debug.freemem");
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!"".equals(debugFreeMem)) {
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mFreeMem = Long.parseLong(debugFreeMem);
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17043866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker        // Read the log interval from secure settings
171be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey        long freeMemLogInterval = Settings.Global.getLong(mResolver,
172625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey                Settings.Global.SYS_FREE_STORAGE_LOG_INTERVAL,
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                DEFAULT_FREE_STORAGE_LOG_INTERVAL_IN_MINUTES)*60*1000;
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //log the amount of free memory in event log
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long currTime = SystemClock.elapsedRealtime();
1763161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker        if((mLastReportedFreeMemTime == 0) ||
1773161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker           (currTime-mLastReportedFreeMemTime) >= freeMemLogInterval) {
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLastReportedFreeMemTime = currTime;
1793161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker            long mFreeSystem = -1, mFreeCache = -1;
1803161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker            try {
181be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey                mSystemFileStats.restat(SYSTEM_PATH.getAbsolutePath());
1823161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker                mFreeSystem = (long) mSystemFileStats.getAvailableBlocks() *
1833161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker                    mSystemFileStats.getBlockSize();
1843161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker            } catch (IllegalArgumentException e) {
1853161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker                // ignore; report -1
1863161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker            }
1873161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker            try {
188be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey                mCacheFileStats.restat(CACHE_PATH.getAbsolutePath());
1893161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker                mFreeCache = (long) mCacheFileStats.getAvailableBlocks() *
1903161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker                    mCacheFileStats.getBlockSize();
1913161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker            } catch (IllegalArgumentException e) {
1923161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker                // ignore; report -1
1933161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker            }
194ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker            EventLog.writeEvent(EventLogTags.FREE_STORAGE_LEFT,
1953161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker                                mFreeMem, mFreeSystem, mFreeCache);
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19743866e0c48bb0effe8805afd62b253e50ca7d591Doug Zongker        // Read the reporting threshold from secure settings
198be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey        long threshold = Settings.Global.getLong(mResolver,
199625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey                Settings.Global.DISK_FREE_CHANGE_REPORTING_THRESHOLD,
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD);
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // If mFree changed significantly log the new value
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long delta = mFreeMem - mLastReportedFreeMem;
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (delta > threshold || delta < -threshold) {
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLastReportedFreeMem = mFreeMem;
205ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker            EventLog.writeEvent(EventLogTags.FREE_STORAGE_CHANGED, mFreeMem);
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2083161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final void clearCache() {
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mClearCacheObserver == null) {
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Lazy instantiation
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClearCacheObserver = new CachePackageDataObserver();
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mClearingCache = true;
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
2168a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (localLOGV) Slog.i(TAG, "Clearing cache");
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            IPackageManager.Stub.asInterface(ServiceManager.getService("package")).
218197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    freeStorageAndNotify(mMemCacheTrimToThreshold, mClearCacheObserver);
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (RemoteException e) {
2208a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            Slog.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClearingCache = false;
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClearSucceeded = false;
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2253161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final void checkMemory(boolean checkCache) {
2273161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker        //if the thread that was started to clear cache is still running do nothing till its
2283161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker        //finished clearing cache. Ideally this flag could be modified by clearCache
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // and should be accessed via a lock but even if it does this test will fail now and
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //hopefully the next time this flag will be set to the correct value.
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if(mClearingCache) {
2328a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if(localLOGV) Slog.i(TAG, "Thread already running just skip");
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //make sure the thread is not hung for too long
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long diffTime = System.currentTimeMillis() - mThreadStartTime;
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if(diffTime > (10*60*1000)) {
2368a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Thread that clears cache file seems to run for ever");
2373161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker            }
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            restatDataDir();
2408a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            if (localLOGV)  Slog.v(TAG, "freeMemory="+mFreeMem);
2413161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //post intent to NotificationManager to display icon if necessary
243bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby            if (mFreeMem < mMemLowThreshold) {
244197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                if (checkCache) {
245197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    // We are allowed to clear cache files at this point to
246197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    // try to get down below the limit, because this is not
247197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    // the initial call after a cache clear has been attempted.
248197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    // In this case we will try a cache clear if our free
249197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    // space has gone below the cache clear limit.
250197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    if (mFreeMem < mMemCacheStartTrimThreshold) {
251197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                        // We only clear the cache if the free storage has changed
252197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                        // a significant amount since the last time.
253197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                        if ((mFreeMemAfterLastCacheClear-mFreeMem)
254197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                                >= ((mMemLowThreshold-mMemCacheStartTrimThreshold)/4)) {
255197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                            // See if clearing cache helps
256197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                            // Note that clearing cache is asynchronous and so we do a
257197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                            // memory check again once the cache has been cleared.
258197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                            mThreadStartTime = System.currentTimeMillis();
259197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                            mClearSucceeded = false;
260197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                            clearCache();
261197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                        }
262197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    }
263197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                } else {
264197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    // This is a call from after clearing the cache.  Note
265197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    // the amount of free storage at this point.
266197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    mFreeMemAfterLastCacheClear = mFreeMem;
267197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    if (!mLowMemFlag) {
268197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                        // We tried to clear the cache, but that didn't get us
269197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                        // below the low storage limit.  Tell the user.
2708a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                        Slog.i(TAG, "Running low on memory. Sending notification");
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sendNotification();
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mLowMemFlag = true;
273197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    } else {
274197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                        if (localLOGV) Slog.v(TAG, "Running low on memory " +
275197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                                "notification already sent. do nothing");
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
279197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                mFreeMemAfterLastCacheClear = mFreeMem;
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mLowMemFlag) {
2818a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                    Slog.i(TAG, "Memory available. Cancelling notification");
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    cancelNotification();
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mLowMemFlag = false;
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
286bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby            if (mFreeMem < mMemFullThreshold) {
287bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby                if (!mMemFullFlag) {
288bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby                    sendFullNotification();
289bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby                    mMemFullFlag = true;
290bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby                }
291bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby            } else {
292bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby                if (mMemFullFlag) {
293bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby                    cancelFullNotification();
294bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby                    mMemFullFlag = false;
295bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby                }
296bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby            }
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2988a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        if(localLOGV) Slog.i(TAG, "Posting Message again");
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //keep posting messages to itself periodically
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        postCheckMemoryMsg(true, DEFAULT_CHECK_INTERVAL);
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3023161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void postCheckMemoryMsg(boolean clearCache, long delay) {
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Remove queued messages
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler.removeMessages(DEVICE_MEMORY_WHAT);
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler.sendMessageDelayed(mHandler.obtainMessage(DEVICE_MEMORY_WHAT,
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                clearCache ?_TRUE : _FALSE, 0),
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                delay);
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3103161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    * Constructor to run service. initializes the disk space threshold value
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    * and posts an empty message to kickstart the process.
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    */
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public DeviceStorageMonitorService(Context context) {
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLastReportedFreeMemTime = 0;
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
318be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey        mResolver = mContext.getContentResolver();
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //create StatFs object
320be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey        mDataFileStats = new StatFs(DATA_PATH.getAbsolutePath());
321be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey        mSystemFileStats = new StatFs(SYSTEM_PATH.getAbsolutePath());
322be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey        mCacheFileStats = new StatFs(CACHE_PATH.getAbsolutePath());
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //initialize total storage on device
324197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        mTotalMemory = (long)mDataFileStats.getBlockCount() *
325197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                        mDataFileStats.getBlockSize();
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStorageLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW);
3274b3309211ed6f3532b44481945a4725143d50b8aJeff Hamilton        mStorageLowIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStorageOkIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK);
3294b3309211ed6f3532b44481945a4725143d50b8aJeff Hamilton        mStorageOkIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
330bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby        mStorageFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_FULL);
331bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby        mStorageFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
332bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby        mStorageNotFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_NOT_FULL);
333bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby        mStorageNotFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
334be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey
335bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby        // cache storage thresholds
336be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey        final StorageManager sm = StorageManager.from(context);
337be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey        mMemLowThreshold = sm.getStorageLowBytes(DATA_PATH);
338be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey        mMemFullThreshold = sm.getStorageFullBytes(DATA_PATH);
339be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey
340197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        mMemCacheStartTrimThreshold = ((mMemLowThreshold*3)+mMemFullThreshold)/4;
341197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        mMemCacheTrimToThreshold = mMemLowThreshold
342197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                + ((mMemLowThreshold-mMemCacheStartTrimThreshold)*2);
343197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        mFreeMemAfterLastCacheClear = mTotalMemory;
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkMemory(true);
3454b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey
3464b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey        mCacheFileDeletedObserver = new CacheFileDeletedObserver();
3474b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey        mCacheFileDeletedObserver.startWatching();
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3493161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    * This method sends a notification to NotificationManager to display
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    * an error dialog indicating low disk space and launch the Installer
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    * application
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    */
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final void sendNotification() {
3568a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        if(localLOGV) Slog.i(TAG, "Sending low memory notification");
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //log the event to event log with the amount of free storage(in bytes) left on the device
358ab5c49c7e7f5f61040650109a76f38a443fb852dDoug Zongker        EventLog.writeEvent(EventLogTags.LOW_STORAGE, mFreeMem);
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //  Pack up the values and broadcast them to everyone
360f882efadd378e0476b7362e474f3a20dcf1c0d27Dianne Hackborn        Intent lowMemIntent = new Intent(Environment.isExternalStorageEmulated()
361f882efadd378e0476b7362e474f3a20dcf1c0d27Dianne Hackborn                ? Settings.ACTION_INTERNAL_STORAGE_SETTINGS
362f882efadd378e0476b7362e474f3a20dcf1c0d27Dianne Hackborn                : Intent.ACTION_MANAGE_PACKAGE_STORAGE);
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lowMemIntent.putExtra("memory", mFreeMem);
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lowMemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3653161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker        NotificationManager mNotificationMgr =
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (NotificationManager)mContext.getSystemService(
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Context.NOTIFICATION_SERVICE);
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CharSequence title = mContext.getText(
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.string.low_internal_storage_view_title);
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CharSequence details = mContext.getText(
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.string.low_internal_storage_view_text);
37250cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn        PendingIntent intent = PendingIntent.getActivityAsUser(mContext, 0,  lowMemIntent, 0,
37350cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                null, UserHandle.CURRENT);
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Notification notification = new Notification();
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        notification.icon = com.android.internal.R.drawable.stat_notify_disk_full;
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        notification.tickerText = title;
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        notification.flags |= Notification.FLAG_NO_CLEAR;
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        notification.setLatestEventInfo(mContext, title, details, intent);
37950cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn        mNotificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification,
38050cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                UserHandle.ALL);
381aa4b3c79f28560930e256ec5e2c5a7a4c20f5542Dianne Hackborn        mContext.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Cancels low storage notification and sends OK intent.
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final void cancelNotification() {
3888a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        if(localLOGV) Slog.i(TAG, "Canceling low memory notification");
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        NotificationManager mNotificationMgr =
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (NotificationManager)mContext.getSystemService(
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Context.NOTIFICATION_SERVICE);
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //cancel notification since memory has been freed
39350cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn        mNotificationMgr.cancelAsUser(null, LOW_MEMORY_NOTIFICATION_ID, UserHandle.ALL);
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3955ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        mContext.removeStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
3965ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        mContext.sendBroadcastAsUser(mStorageOkIntent, UserHandle.ALL);
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3983161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker
399bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby    /**
400bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby     * Send a notification when storage is full.
401bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby     */
402bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby    private final void sendFullNotification() {
403bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby        if(localLOGV) Slog.i(TAG, "Sending memory full notification");
404aa4b3c79f28560930e256ec5e2c5a7a4c20f5542Dianne Hackborn        mContext.sendStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
405bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby    }
406bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby
407bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby    /**
408bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby     * Cancels memory full notification and sends "not full" intent.
409bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby     */
410bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby    private final void cancelFullNotification() {
411bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby        if(localLOGV) Slog.i(TAG, "Canceling memory full notification");
4125ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        mContext.removeStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
4135ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        mContext.sendBroadcastAsUser(mStorageNotFullIntent, UserHandle.ALL);
414bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby    }
415bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void updateMemory() {
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int callingUid = getCallingUid();
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if(callingUid != Process.SYSTEM_UID) {
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // force an early check
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        postCheckMemoryMsg(true, 0);
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
42462e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root
42562e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root    /**
42662e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root     * Callable from other things in the system service to obtain the low memory
42762e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root     * threshold.
42862e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root     *
42962e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root     * @return low memory threshold in bytes
43062e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root     */
43162e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root    public long getMemoryLowThreshold() {
43262e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root        return mMemLowThreshold;
43362e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root    }
43462e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root
43562e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root    /**
43662e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root     * Callable from other things in the system process to check whether memory
43762e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root     * is low.
43862e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root     *
43962e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root     * @return true is memory is low
44062e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root     */
44162e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root    public boolean isMemoryLow() {
44262e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root        return mLowMemFlag;
44362e1b4e9d41a01db423b5e4684ecf529ed46106dKenny Root    }
4444b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey
4454b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey    public static class CacheFileDeletedObserver extends FileObserver {
4464b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey        public CacheFileDeletedObserver() {
4474b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey            super(Environment.getDownloadCacheDirectory().getAbsolutePath(), FileObserver.DELETE);
4484b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey        }
4494b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey
4504b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey        @Override
4514b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey        public void onEvent(int event, String path) {
4524b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey            EventLogTags.writeCacheFileDeleted(path);
4534b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey        }
4544b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey    }
455197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
456197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    @Override
457197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
458197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
459197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                != PackageManager.PERMISSION_GRANTED) {
460197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
461197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            pw.println("Permission Denial: can't dump " + SERVICE + " from from pid="
462197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    + Binder.getCallingPid()
463197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                    + ", uid=" + Binder.getCallingUid());
464197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn            return;
465197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        }
466197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn
467197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        pw.println("Current DeviceStorageMonitor state:");
468197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        pw.print("  mFreeMem="); pw.print(Formatter.formatFileSize(mContext, mFreeMem));
469197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                pw.print(" mTotalMemory=");
470197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                pw.println(Formatter.formatFileSize(mContext, mTotalMemory));
471197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        pw.print("  mFreeMemAfterLastCacheClear=");
472197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                pw.println(Formatter.formatFileSize(mContext, mFreeMemAfterLastCacheClear));
473197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        pw.print("  mLastReportedFreeMem=");
474197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                pw.print(Formatter.formatFileSize(mContext, mLastReportedFreeMem));
475197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                pw.print(" mLastReportedFreeMemTime=");
476197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                TimeUtils.formatDuration(mLastReportedFreeMemTime, SystemClock.elapsedRealtime(), pw);
477197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                pw.println();
478197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        pw.print("  mLowMemFlag="); pw.print(mLowMemFlag);
479197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                pw.print(" mMemFullFlag="); pw.println(mMemFullFlag);
480197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        pw.print("  mClearSucceeded="); pw.print(mClearSucceeded);
481197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                pw.print(" mClearingCache="); pw.println(mClearingCache);
482197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        pw.print("  mMemLowThreshold=");
483197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                pw.print(Formatter.formatFileSize(mContext, mMemLowThreshold));
484197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                pw.print(" mMemFullThreshold=");
485197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                pw.println(Formatter.formatFileSize(mContext, mMemFullThreshold));
486197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn        pw.print("  mMemCacheStartTrimThreshold=");
487197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                pw.print(Formatter.formatFileSize(mContext, mMemCacheStartTrimThreshold));
488197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                pw.print(" mMemCacheTrimToThreshold=");
489197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn                pw.println(Formatter.formatFileSize(mContext, mMemCacheTrimToThreshold));
490197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackborn    }
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
492